-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerator.py
127 lines (116 loc) · 5.57 KB
/
generator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import random
from dataloaders import CharacterDataLoader, ObjectDataLoader, LocationDataLoader
from models import Knowledge, Actions, Goal, GoalType, Location
from utilities import safe_append, safe_extend, persons_shop, TAVERN, dump_output
from evaluator import evaluate
import output
class Generator:
'''
Does character interaction simulation to retrieve creative plot-driven narratives.
'''
def __init__(self, **kwargs):
'''
kwargs parameters:
locationCount (int): amount of locations in the story
characterCount (int): amount of characters in the story
objectCount (int): amount of mcguffins in the story
pursuerCount (int): amount of characters whose motivation is to get some mcguffins
adviserCount (int): amount of characters that know where some mcguffin is hidden
redHerringCount (int): amount of characters that think they know where some mcguffin is hidden
manipulatorCount (int): amount of characters that want to manipulate some character into killing another character
iterations (int): amount of steps to generate in the simulation
'''
locationCount = kwargs.get("locationCount", 10)
characterCount = kwargs.get("characterCount", 10)
objectCount = kwargs.get("objectCount", random.randint(1,4))
pursuerCount = kwargs.get("pursuerCount", random.randint(1,3))
adviserCount = kwargs.get("adviserCount", random.randint(1,2))
redHerringCount = kwargs.get("redHerringCount", random.randint(1,4))
manipulatorCount = kwargs.get("manipulatorCount", random.randint(0, 7))
self.iterations = kwargs.get("iterations", 25)
self.step = 0
self.out = []
locations = LocationDataLoader().load(howmany=locationCount, out=self.out)
self.characters = CharacterDataLoader().load(howmany=characterCount, out=self.out)
objects = ObjectDataLoader().load(howmany=objectCount, random_sample=True, out=self.out)
for char in self.characters:
char.setWorldData(locations, objects)
objectLocations = random.sample(locations, len(objects))
for i in range(len(objects)):
objects[i].location = objectLocations[i]
self.out.append(output.ExposObjectPosition(objects[i], objectLocations[i]))
charSample = random.sample(self.characters, pursuerCount + adviserCount + redHerringCount)
for char in charSample[:pursuerCount]:
char.goals.insert(0, Goal(GoalType.GET_OBJECT, objects[i]))
self.out.append(output.ExposOwningMotivation(char, objects[i]))
for char in charSample[pursuerCount:pursuerCount + adviserCount]:
locationKnowledge = Knowledge(char, objects[i], Actions.LOCATED_IN, objectLocations[i], -1)
char.knowledge.append(locationKnowledge)
self.out.append(output.ExposObjectInfo(char, locationKnowledge, True))
for char in charSample[pursuerCount + adviserCount:]:
locale = random.choice(locations)
locationKnowledge = Knowledge(char, objects[i], Actions.LOCATED_IN, locale, -1)
char.knowledge.append(locationKnowledge)
self.out.append(output.ExposObjectInfo(char, locationKnowledge, False))
for _ in range(manipulatorCount):
trio = random.sample(self.characters, 3)
trio[0].goals.insert(0, Goal(GoalType.KILL, trio[1], trio[2]))
self.out.append(output.ExposManipulationMotivation(trio[0], trio[1], trio[2]))
def execute_action(self, action, place, events, chars_to_ignore):
'''
For a given place and action, simulates interractions for pending characters
chars_to_ignore is used to keep track which characters should skip a turn
'''
random.shuffle(events[action])
for tuple in events[action]:
if tuple[0] in chars_to_ignore:
continue
methodTuple = tuple[0].action_methods[action](tuple[1], chars_to_ignore)
context = methodTuple[0]
additionalOutput = methodTuple[1]
self.out.append(output.SomeAction(self.step, tuple[0].location, context, tuple[0], tuple[1], action))
self.out.extend(additionalOutput)
if action.is_witnessed:
for witness in place:
witness.acquire_knowledge(Knowledge(witness, tuple[0], action, tuple[1], self.step))
def generation_step(self):
'''
Does simulation for one step
'''
self.step += 1
places = {}
random.shuffle(self.characters)
for person in list(filter(lambda c: c.dead == False, self.characters)):
person.schedule_step(self.step)
safe_append(places, person.location, person)
self.characters = [c for c in self.characters if c.dead == False]
for place in places:
events = {}
for action in Actions:
events[action] = []
for person1 in places[place]:
for person2 in places[place]:
if person1 == person2:
continue
events[person1.make_decision(person2)].append((person1, person2))
chars_to_ignore = []
for action in self.characters[0].action_methods.keys():
self.execute_action(action, places[place], events, chars_to_ignore)
def run(self, printConsole = False):
'''
Runs the entire simulation and evaluates it
if printConsole set, prints the story to console
Returns tuple, where lhs is list of string lines consisting of a story,
and rhs is evaluated score of the story
'''
for _ in range(self.iterations):
self.generation_step()
protagonist = random.choice(self.characters)
protagonist.protagonist = True
score = evaluate(self.out)
story = output.printOutput(self.out)
if printConsole:
for line in story:
print(line)
print("Evaluated score: {SCORE}".format(SCORE=score))
return (story, score)