Kill_Modification = [mod_1, mod_2, mod_3, mod_4]

#----------------------------------
# Story Results
#----------------------------------
One = StoryNode("MurderBlackmailer_Request_from_Invoker", {"Node_Type" : "Info"}, A)
One.set_modification(Move_1)
Two = StoryNode("Go_To_Victim", {"Node_Type" : "Go_To"}, B)
Two.set_modification(Move_2)
Three = StoryNode("Kill_Victim", {"Node_Type" : "MurderBlackmailer"}, B)
Three.set_modification(Kill_Modification)
Four = StoryNode("Return_to_Invoker", {"Node_Type" : "Return"}, A)
Four.set_modification(Move_1)

MurderBlackmailer_Story = StoryGraph("MurderBlackmailer_Story", [One, Two, Three, Four])
MurderBlackmailer_Story.connect(One, {}, Two)
MurderBlackmailer_Story.connect(Two, {}, Three)
MurderBlackmailer_Story.connect(Three, {}, Four)

MurderBlackmailer_Rule = RewriteRule(None, MurderBlackmailer, MurderBlackmailer_Story, None, "Murder_Blackmailer")

#----------------------------------------------------
# GiveGift Skeleton
#----------------------------------------------------

#----------------------------------
# Social Condition
#----------------------------------
A = SocialNode("Invoker", {"type" : "NPC", "alive" : True})
B = SocialNode("Recipient", {"type" : "NPC", "alive" : True})
Exemplo n.º 2
0
	def initialize_narrative(self):
		
		#-----------------------------------
		# Create the Beginning Narrative Format
		#-----------------------------------
				
		#Create the starting node and ending node
		start_node = StoryNode("Start_Quest", {"Node_Type" : "Start"}, "N/A")
		end_node = StoryNode("End_Quest", {"Node_Type" : "End"}, "N/A")

		#Initialize our narrative
		self._narrative = StoryGraph("New_Quest", [start_node, end_node])
		self._narrative.initialize()
		
		print "Creating Initial Narrative"
		#-----------------------------------
		#We will go throughout all our rules and find matching results
		#-----------------------------------
		print "Searching for Possible Narrative Rules..."
		matching_rules = self.get_possible_rules(self._story_init_rules, self._social_graph)

		print "Found " + str(len(matching_rules)) + " possible rules"
		if len(matching_rules) <= 0:
			print "ERROR - No Matching Rules found, No more stories may be created"
			return False
			
		#Rules for picking the matching narrative
		#At the moment it is a random choice

		if self._verbose:
			print "Found the Following Matching Initialization Rules: "
			for rule in matching_rules:
				print "\t" + rule[1].get_name()

		resultant = choice(matching_rules)
		resulting_rule = resultant[1]

		#Rules for picking the matching group
		#At the moment it is a random choice
		resulting_group = choice(resultant[0])
		#-----------------------------------
		#Now we set the cast for our narrative
		#-----------------------------------
		cast = {}
		
		#The cast is stored as a dictionary where the name in the condition narrative
		#is the key for the node it relates to
		for i in range(len(resulting_group)):
			cast[resulting_rule.get_social_condition().get_nodes()[i].get_name()] = resulting_group[i]
		
		#The player always participates in the narrative by default
		cast["Player"] = self._social_graph.get_player()
		
		self._narrative.set_cast(cast)
		
		#-----------------------------------
		#Now we set the preconditions for our narrative
		#-----------------------------------
		
		#We will convert the original social condition into a set of preconditions
		for i in range(len(resulting_group)):
			cur_node = resulting_rule.get_social_condition().get_nodes()[i]
			cur_attr = cur_node.get_attributes()
			
			#First we will create all of the attribute preconditions
			for key in cur_attr.keys():
				condition = Condition(True)
				
				condition.set_first_object(resulting_group[i])
				condition.set_key(key)
				condition.set_value(cur_attr[key])
				
				self._narrative.add_precondition(condition)
			
			#Following this, we will create all of the edge preconditions
			for edge in cur_node.get_outgoing_edges():

				condition = Condition(False)

				condition.set_first_object(resulting_group[i])
				condition.set_second_object(cast[edge.get_to_node().get_name()])
				condition.set_key(edge.get_name().keys()[0])
				condition.set_value(edge.get_name()[edge.get_name().keys()[0]])

				self._narrative.add_precondition(condition)
		
		#-----------------------------------
		#Now we construct our narrative skeleton using this modification
		#-----------------------------------
		story_modification = resulting_rule.get_story_modification()
		
		#Set up our nodes
		for node in story_modification.get_nodes():
			
			#Get the index of the story node
			index = resulting_rule.get_social_condition().get_nodes().index(node.get_target())
			
			#We can then pick the actual target from our group
			target = resulting_group[index]
			
			#Also, add the target as an attribute
			node.add_attribute("Target", target.get_name())

			#And link the story node to this target
			node.set_linked_to_node(target)
			
			#Finally, add the node to the story
			self._narrative.add_node(node)
		
		#Edges are currently empty for narratives
		for edge in story_modification.get_edges():
			self._narrative.add_edge(edge)
		
		return True
Exemplo n.º 3
0
    def readGraph(self):

        tree = ET.parse(self._filename)
        root = tree.getroot()

        #Get our graph name
        graph_name = root.attrib.get('name')

        #Process the nodes
        node_list = []
        for node in root.iter('node'):

            story_node_name = node.attrib['name']
            node_attributes = {}

            #Get the target
            node_target = node.find('target').text

            #Get the node type
            node_attributes['Node_Type'] = node.find('nodetype').text

            #Get the attributes
            for attribute in node.findall('attr'):
                attribute_type = attribute.attrib.get('type')
                attribute_name = attribute.attrib.get('name')
                attribute_value = attribute.find('value').text
                if attribute_type == 'bool':
                    node_attributes[attribute_name] = (
                        attribute_value == "True")
                elif attribute_type == 'int':
                    node_attributes[attribute_name] = int(attribute_value)
                elif attribute_type == 'float':
                    node_attributes[attribute_name] = float(attribute_value)
                else:
                    node_attributes[attribute_name] = attribute_value

            new_node = StoryNode(story_node_name, node_attributes,
                                 self._graph.get_node_from_name(node_target))

            if not node.attrib['modification'] == 'None':
                modification_filename = self._path + "Modifications/" + node.attrib[
                    'modification']
                modification_reader = XMLModificationReader(
                    modification_filename)
                modification = modification_reader.readModification()
                new_node.set_modification(modification)

            node_list.append(new_node)

        #Create the Return Graph
        returnGraph = StoryGraph(graph_name, node_list)

        #Begin Making the connections
        for connection in root.iter('connection'):
            connect_from = connection.attrib.get('from')
            from_node = returnGraph.get_node_from_name(connect_from)

            connect_to = connection.attrib.get('to')
            to_node = returnGraph.get_node_from_name(connect_to)

            relation = connection.find('relation').attrib

            if relation.keys()[0] == "none":
                relation = {}

            returnGraph.connect(from_node, relation, to_node)

        return returnGraph
Exemplo n.º 4
0
class Scheduler:
	
	"""The initialization function
	
	Args:
		social_graph (Graph): The main relation graph for our game
		story_initialization_rules (RewriteRule Array): The story generation rules
		rewrite_rules (RewriteRule Array): The story modification rules
	"""
	def __init__(self, social_graph, story_initialization_rules, rewrite_rules, metrics_to_optimize, max_number_of_rewrites, stats_output, verbose=True):
		self._social_graph = social_graph
		self._story_init_rules = story_initialization_rules
		self._rewrite_rules = rewrite_rules
		self._num_applications = {}
		self._verbose = verbose
		self._stats_output = stats_output
		self._divider = "--------------------------------------"
		self._valids = 0
		self._invalids = 0
		self._metrics_to_optimize = metrics_to_optimize
		
		self._metrics_to_optimize_name_only = []

		for metric in self._metrics_to_optimize:
			self._metrics_to_optimize_name_only.append(metric[0])
			
		self._use_metric_rewriting = (not len(metrics_to_optimize) == 0)

		self._max_number_of_rewrites = max_number_of_rewrites

		self._start_rewriting_time = 0
		self._end_rewriting_time = 0
		self._start_validation_time = 0
		self._end_validation_time = 0

		# Here we define a number of applications, refering to the number
		# of times each rule has been used, this allows us to 
		# set restrictions on the number of times each rule can be applied
		self.reset_num_applications()
	
	def get_valids(self):
		return self._valids

	def get_invalids(self):
		return self._invalids
#--------------------------------------------------------------
#	Functions for the Number of Applications Dictionary
#--------------------------------------------------------------

	""" Reset our number of applications dictionary
	"""
	def reset_num_applications(self):
		
		#Set all of our entries to zero, ie. no applications
		for rule in self._rewrite_rules:
			self._num_applications[rule.get_story_modification().get_name()] = 0
		
	"""Get the number of applications of a specific rule
	
	Args:
		rule (RewriteRule): The rule to be searched for in the num_applications dictionary
	"""
	def get_num_applications(self, rule):
		#Return the number of applications of that specific rule
		return self._num_applications[rule.get_story_modification().get_name()]
		
	"""Increment the number of applications of a specific rule
	
	Args:
		rule (RewriteRule): The rule we are incrementing, most likely due to its application
	"""	
	def inc_num_applications(self, rule):
		self._num_applications[rule.get_story_modification().get_name()] += 1
	
	"""Check if we are allowed to apply a specific rule
	
	Args:
		rule (RewriteRule): The rule we are checking
		
	Returns:
		(Boolean): True if we can still apply this rule
	"""
	def is_allowed(self, rule):
		
		if rule.get_apply_once():
			if self.get_num_applications(rule) > 0:
				return False
			else:
				return True
		else:
			return True
			
#--------------------------------------------------------------
#	Getters and Setters
#--------------------------------------------------------------

	"""Get our social graph
	
	Returns:
		(SocialGraph): The graph we are using
	"""
	def get_social_graph(self):
		return self._social_graph

#--------------------------------------------------------------
#	Scheduler Helper Functions
#--------------------------------------------------------------

	"""The call to make for getting all possible rules from the list of possible
	available rules
	"""
	def get_possible_rules(self, ruleset, graph):
				
		possible_rules = []
		
		#Check each of our rewrite rules
		for rule in ruleset:
			print rule.get_name()
			#Get the story condition
			if isinstance(graph, StoryGraph):
				condition = rule.get_story_condition()
			else:
				condition = rule.get_social_condition()
				
			#Get the results
			results = graph.contains_subgraph(condition)
			
			#If we have this story condition and can still rewrite, make the modification
			#if cur_node.contains_subnode(story_condition) and refinements_remaining > 0:
			if len(results) > 0:
				if self.is_allowed(rule):	
					possible_rules.append([results, rule])		
		return possible_rules
		
	"""Check the social condition for the narrative
	"""
	def get_social_results(self, chosen_rule, narrative):
		#Prepare our social condition for checking using a subgraph check
		#by assigning any of the necessary cast names to the node to refine
		#the graph search
		social_condition = chosen_rule.get_social_condition()
		
		num_matches = 0
		for node in social_condition.get_nodes():
			if node.get_name() in narrative.get_cast():
				new_name = narrative.get_cast()[node.get_name()].get_name()
				node.add_attribute("name", new_name)
				num_matches += 1

		if num_matches > 0:
			return self._social_graph.contains_subgraph(social_condition)
		else:
			return []		
		
	""" Apply a given rule to a graph
	
	Args:
		chosen_results([story_nodes, rule]): An array containing both the rule, and the corresponding story nodes
		social_results (Array): An array of possible social situations
		narrative: The narrative we are applying the rule to
	"""
	def applyRule(self, chosen_results, social_results, narrative):
		
		#Get the rule from our chosen results
		chosen_rule = chosen_results[1]

		#Get the new story nodes from our results
		resulting_story_nodes = choice(chosen_results[0])
		
		#Get the resulting story nodes for our rewrite
		result = choice(social_results)

		#Get the social condition from our rule
		social_condition = chosen_rule.get_social_condition()
		
		#Add any new cast members necessary
		for i in range(len(result)):
			if not social_condition.get_nodes()[i].get_name() in narrative.get_cast():
				narrative.add_cast(social_condition.get_nodes()[i].get_name(), result[i])
				
		story_modification = chosen_rule.get_story_modification()

		#Make our new graph
		nodes = []
		for node in story_modification.get_nodes():
			target = narrative.get_cast()[node.get_target().get_name()]
			new_node = node.Copy_Story_Node()
			new_node.set_linked_to_node(target)
			new_node.add_attribute("Target", target.get_name())
			nodes.append(new_node)

		new_graph = Graph("Temp", nodes)
		
		adj = story_modification.get_adjacency()
		for row in range(len(adj)):
			for col in range(len(adj)):
				if adj[row][col] == 1:
					adj[col][row] = 0
					new_graph.connect(nodes[row], {}, nodes[col])
		
		backup_narrative = narrative.Copy()
								
		narrative.replace_node_with_new(narrative.get_node_from_name(resulting_story_nodes[0].get_name()), new_graph)

		narrative.fix_graph()
		self._social_graph.make_node_postconditions(narrative)
		narrative.initialize_conditions()
		narrative.refine_lost_conditions()
		
		print "Validating Final Story\n"

		if self._verbose:
			print self._divider
			for node in narrative.get_nodes():
				
				print "Preconditions for " + node.get_name()
				for con in node.get_preconditions():
					print con
				print "\nPostconditions for " + node.get_name()
				for con in node.get_postconditions():
					print con
				print "\nLost Conditions for " + node.get_name()
				for con in node.get_lostconditions():
					print con	
				print "\n" + self._divider	
		
		valid = narrative.validate_story()
		if not valid:
			print "INVALID STORY"
			self._invalids += 1
			print "VALIDS = " + str(self._valids)
			print "INVALIDS = " + str(self._invalids)
			return backup_narrative
		else:
			print "VALID STORY"
			self._valids += 1
			print "VALIDS = " + str(self._valids)
			print "INVALIDS = " + str(self._invalids)
			return narrative
			
#--------------------------------------------------------------
#	Scheduler Functions
#--------------------------------------------------------------
		
	"""Initialize our narrative
	
	Returns:
		(Boolean): True if a narrative has been created, false otherwise
	"""
	
	def initialize_narrative(self):
		
		#-----------------------------------
		# Create the Beginning Narrative Format
		#-----------------------------------
				
		#Create the starting node and ending node
		start_node = StoryNode("Start_Quest", {"Node_Type" : "Start"}, "N/A")
		end_node = StoryNode("End_Quest", {"Node_Type" : "End"}, "N/A")

		#Initialize our narrative
		self._narrative = StoryGraph("New_Quest", [start_node, end_node])
		self._narrative.initialize()
		
		print "Creating Initial Narrative"
		#-----------------------------------
		#We will go throughout all our rules and find matching results
		#-----------------------------------
		print "Searching for Possible Narrative Rules..."
		matching_rules = self.get_possible_rules(self._story_init_rules, self._social_graph)

		print "Found " + str(len(matching_rules)) + " possible rules"
		if len(matching_rules) <= 0:
			print "ERROR - No Matching Rules found, No more stories may be created"
			return False
			
		#Rules for picking the matching narrative
		#At the moment it is a random choice

		if self._verbose:
			print "Found the Following Matching Initialization Rules: "
			for rule in matching_rules:
				print "\t" + rule[1].get_name()

		resultant = choice(matching_rules)
		resulting_rule = resultant[1]

		#Rules for picking the matching group
		#At the moment it is a random choice
		resulting_group = choice(resultant[0])
		#-----------------------------------
		#Now we set the cast for our narrative
		#-----------------------------------
		cast = {}
		
		#The cast is stored as a dictionary where the name in the condition narrative
		#is the key for the node it relates to
		for i in range(len(resulting_group)):
			cast[resulting_rule.get_social_condition().get_nodes()[i].get_name()] = resulting_group[i]
		
		#The player always participates in the narrative by default
		cast["Player"] = self._social_graph.get_player()
		
		self._narrative.set_cast(cast)
		
		#-----------------------------------
		#Now we set the preconditions for our narrative
		#-----------------------------------
		
		#We will convert the original social condition into a set of preconditions
		for i in range(len(resulting_group)):
			cur_node = resulting_rule.get_social_condition().get_nodes()[i]
			cur_attr = cur_node.get_attributes()
			
			#First we will create all of the attribute preconditions
			for key in cur_attr.keys():
				condition = Condition(True)
				
				condition.set_first_object(resulting_group[i])
				condition.set_key(key)
				condition.set_value(cur_attr[key])
				
				self._narrative.add_precondition(condition)
			
			#Following this, we will create all of the edge preconditions
			for edge in cur_node.get_outgoing_edges():

				condition = Condition(False)

				condition.set_first_object(resulting_group[i])
				condition.set_second_object(cast[edge.get_to_node().get_name()])
				condition.set_key(edge.get_name().keys()[0])
				condition.set_value(edge.get_name()[edge.get_name().keys()[0]])

				self._narrative.add_precondition(condition)
		
		#-----------------------------------
		#Now we construct our narrative skeleton using this modification
		#-----------------------------------
		story_modification = resulting_rule.get_story_modification()
		
		#Set up our nodes
		for node in story_modification.get_nodes():
			
			#Get the index of the story node
			index = resulting_rule.get_social_condition().get_nodes().index(node.get_target())
			
			#We can then pick the actual target from our group
			target = resulting_group[index]
			
			#Also, add the target as an attribute
			node.add_attribute("Target", target.get_name())

			#And link the story node to this target
			node.set_linked_to_node(target)
			
			#Finally, add the node to the story
			self._narrative.add_node(node)
		
		#Edges are currently empty for narratives
		for edge in story_modification.get_edges():
			self._narrative.add_edge(edge)
		
		return True

	"""The process of writing our narrative. It involves generating a narrative to write to and
	applying the set of rewrites
	
	Returns (StoryGraph): The final narrative
	"""
	def write_narrative(self):
		
		#Create the final narrative
		self._final_narrative = self._narrative.Copy()
		
		#Connect the starting and ending node where appropriate
		for cur_node in self._final_narrative.get_nodes():	
			
			#Starting Node
			if (len(cur_node.get_incoming_edges()) == 0) and (not cur_node == self._final_narrative.get_start_node()) and (not cur_node == self._final_narrative.get_end_node()):
				self._final_narrative.connect(self._final_narrative.get_start_node(), {}, cur_node)
									
			#Ending Node
			if (len(cur_node.get_outgoing_edges()) == 0) and (not cur_node == self._final_narrative.get_start_node()) and (not cur_node == self._final_narrative.get_end_node()):
				self._final_narrative.connect(cur_node, {}, self._final_narrative.get_end_node())
		
		self._social_graph.make_node_postconditions(self._final_narrative)
		self._final_narrative.initialize_conditions()
		self._final_narrative.refine_lost_conditions()
		
		print "-------------------------------------------------\n"
		for node in self._final_narrative.get_nodes():
			
			print "Preconditions for " + node.get_name()
			for con in node.get_preconditions():
				print con
			print "\nPostconditions for " + node.get_name()
			for con in node.get_postconditions():
				print con
			print "\nLost Conditions for " + node.get_name()
			for con in node.get_lostconditions():
				print con	
			print "\n-------------------------------"		
		
		#-----------------------------------
		#Begin the process of rewriting the narrative
		#-----------------------------------
		
		#Make sure we have a reset number of applications dictionary
		self.reset_num_applications()

		#This monitors if we have any rewrites possible
		can_rewrite = True
		
		#This monitors our total number of rewrites
		num_rewrites = 0
		
		#-----------------------------------
		# Start applying the rewrite rules
		#-----------------------------------
		#While we can, attempt to apply rewrite rules to the narrative
		while can_rewrite and (num_rewrites < self._max_number_of_rewrites):
			
			#Get all rules which could possibly be applied
			possible_rules = self.get_possible_rules(self._rewrite_rules, self._final_narrative)
			
			#If we have no possible rules, then we have rewritten the story as much as possible
			if len(possible_rules) > 0:
				#---------------------------
				# WIP WIP WIP
				# Here we can cycle between whether
				# we want to rewrite stories according to
				# metrics or not
				# WIP WIP WIP
				#---------------------------
				self._start_rewriting_time = time.time()
				if self._use_metric_rewriting:
					self.metric_rewrite(possible_rules, self._final_narrative)
				else:
					self.non_metric_rewrite(possible_rules, self._final_narrative)
			
			else:
				can_rewrite = False
			
			#After each iteration, update our number of rewrites
			num_rewrites += 1
		
		return self._final_narrative
			
	"""Perform a Graph Rewrite without using metrics
	"""
	def non_metric_rewrite(self, possible_rules, narrative):
		
		#Pick our rule, and its result randomly for a non metric re-write
		result_rule_pair = choice(possible_rules)
		
		#Get our chosen rule from the pair
		chosen_rule = result_rule_pair[1]
	
		#Increment that rule, since we are now applying it
		self.inc_num_applications(chosen_rule)
		
		#Get the social results for our narrative and rule
		social_results = self.get_social_results(chosen_rule, narrative)
		
		#If we have a result, apply the rule
		if len(social_results) > 0:	
			self.applyRule(result_rule_pair, social_results, narrative)

	"""Do a Metric Enhanced Rewrite
	"""
	def metric_rewrite(self, possible_rules, narrative):
		
		candidate_narratives = []
		candidate_rules = []
		
		#Check all possible rules
		for result_rule_pair in possible_rules:
			
			#Make a new candidate narrative
			candidate_narrative = narrative.Copy()
			
			#Get a new candidate rule
			candidate_rule = result_rule_pair[1]
			
			#Check if the rule has social results
			social_results = self.get_social_results(candidate_rule, candidate_narrative)
			
			#If so we have a potential narrative/rule
			if len(social_results) > 0:
				result_candidate = self.applyRule(result_rule_pair, social_results, candidate_narrative)
				candidate_narratives.append(result_candidate)
				candidate_rules.append(candidate_rule)
				
		#If we have potential rules, we can now pick the best narrative
		#based off of metrics		
		if len(candidate_narratives) > 0:
			
			#First gather all the metrics
			metric_results = []
			
			for candidate_narrative in candidate_narratives:
				metrics = Metrics(candidate_narrative.Copy(), self._metrics_to_optimize_name_only, self._social_graph.get_preconditions())
				metric_results.append(metrics.getMetrics(True))

			#Now, using these results and our weights, pick the best metric
			optimal_narrative = self.pick_optimal_narrative(metric_results)
			
			#Increment the number of applications
			self.inc_num_applications(candidate_rules[optimal_narrative])
			#Set the new narrative
			self._final_narrative = candidate_narratives[optimal_narrative]
			
	"""Used in Metric Rewrite, get optimal narrative
	"""
	def pick_optimal_narrative(self, metric_results):
		
		scores = []
		for i in metric_results:
			scores.append(0)
			
		for optimize in self._metrics_to_optimize:
			metric_name = optimize[0]
			metric_weight = optimize[1]

			results = []
			for result in metric_results:
				results.append(result[metric_name])
				
			max_value = float(max(results))
			
			for i in range(len(results)):
				if not max_value == 0:
					scores[i] += (results[i]/max_value) * metric_weight
		
		score_results, score_indices = self.sort_with_indexes(scores)
		
		final_possibilities = []
		for i in range(len(score_results)):
			if score_results[i] == max(score_results):
				final_possibilities.append(score_indices[i])
				
		optimal_narrative = choice(final_possibilities)
		return optimal_narrative
	
	def sort_with_indexes(self, data):
		sorted_data = sorted(enumerate(data), key=lambda key: key[1], reverse=True)
		indexes = range(len(data))
		indexes.sort(key=lambda key: sorted_data[key][0])
		return [i[1] for i in sorted_data], indexes
Exemplo n.º 5
0
#----------------------------------
# Social Condition
#----------------------------------
Monster = SocialNode("Monster", {"alive": True})
Recipient = SocialNode("Recipient", {"alive" : True})

Ambush_Social_Condition = Graph("Stolen_Gift_Social_Condition", [Monster, Recipient])
Ambush_Social_Condition.connect(Monster, {"Hates" : "N/A"}, Recipient)
#----------------------------------
# Social Modification
#----------------------------------
#----------------------------------
# Story Condition
#----------------------------------
Murder = StoryNode("Give_Gift", {"Node_Type" : "Give_Item"}, Recipient)
Ambush_Story_Condition = StoryGraph("Stolen_Gift_Condition", [Murder])

#----------------------------------
# Story Outcome
#----------------------------------
Spare = StoryNode("Stolen_Gift", {"Node_Type" : "Robbery", "Additional" : "Branched_Node"}, Monster)
Foigh = StoryNode("Fight_For_Gift", {"Node_Type" : "Fight", "Additional" : "Branched_Node"}, Monster)
Ambush_Story_Outcome = StoryGraph("Stolen_Gift_Story_Outcome", [Murder, Foigh, Spare])
Ambush_Story_Outcome.connect(Spare, {}, Foigh)
Ambush_Rule = RewriteRule(Ambush_Story_Condition, Ambush_Social_Condition, Ambush_Story_Outcome, None, "Stolen_Gift", True)
##----------------------------------------------------
## Ambush Skeleton
##----------------------------------------------------
#
##----------------------------------
## Social Condition
Exemplo n.º 6
0
    def readGraph(self):
        
        tree = ET.parse(self._filename)
        root = tree.getroot()
        
        #Get our graph name
        graph_name = root.attrib.get('name')
        
        #Process the nodes
        node_list = []
        for node in root.iter('node'):
            
            story_node_name = node.attrib['name']
            node_attributes = {}
            
            #Get the target
            node_target = node.find('target').text

            #Get the node type
            node_attributes['Node_Type'] = node.find('nodetype').text
              
            #Get the attributes
            for attribute in node.findall('attr'):
                attribute_type = attribute.attrib.get('type')
                attribute_name = attribute.attrib.get('name')
                attribute_value = attribute.find('value').text
                if attribute_type == 'bool':
                    node_attributes[attribute_name] = (attribute_value == "True")
                elif attribute_type == 'int':
                    node_attributes[attribute_name] = int(attribute_value)
                elif attribute_type == 'float':
                    node_attributes[attribute_name] = float(attribute_value)
                else:
                    node_attributes[attribute_name] = attribute_value
                    
            new_node = StoryNode(story_node_name, node_attributes, self._graph.get_node_from_name(node_target))
           
            if not node.attrib['modification'] == 'None':
                modification_filename = self._path + "Modifications/" + node.attrib['modification']
                modification_reader = XMLModificationReader(modification_filename)
                modification = modification_reader.readModification()        
                new_node.set_modification(modification)

            node_list.append(new_node)
            
        #Create the Return Graph
        returnGraph = StoryGraph(graph_name, node_list)
        
        #Begin Making the connections
        for connection in root.iter('connection'):
            connect_from = connection.attrib.get('from')
            from_node = returnGraph.get_node_from_name(connect_from)
            
            connect_to = connection.attrib.get('to')
            to_node= returnGraph.get_node_from_name(connect_to)
            
            relation = connection.find('relation').attrib
            
            if relation.keys()[0] == "none":
                relation = {}
                
            returnGraph.connect(from_node, relation, to_node)
        
        return returnGraph
Exemplo n.º 7
0
    def initialize_narrative(self):

        #-----------------------------------
        # Create the Beginning Narrative Format
        #-----------------------------------

        #Create the starting node and ending node
        start_node = StoryNode("Start_Quest", {"Node_Type": "Start"}, "N/A")
        end_node = StoryNode("End_Quest", {"Node_Type": "End"}, "N/A")

        #Initialize our narrative
        self._narrative = StoryGraph("New_Quest", [start_node, end_node])
        self._narrative.initialize()

        print "Creating Initial Narrative"
        #-----------------------------------
        #We will go throughout all our rules and find matching results
        #-----------------------------------
        print "Searching for Possible Narrative Rules..."
        matching_rules = self.get_possible_rules(self._story_init_rules,
                                                 self._social_graph)

        print "Found " + str(len(matching_rules)) + " possible rules"
        if len(matching_rules) <= 0:
            print "ERROR - No Matching Rules found, No more stories may be created"
            return False

        #Rules for picking the matching narrative
        #At the moment it is a random choice

        if self._verbose:
            print "Found the Following Matching Initialization Rules: "
            for rule in matching_rules:
                print "\t" + rule[1].get_name()

        resultant = choice(matching_rules)
        resulting_rule = resultant[1]

        #Rules for picking the matching group
        #At the moment it is a random choice
        resulting_group = choice(resultant[0])
        #-----------------------------------
        #Now we set the cast for our narrative
        #-----------------------------------
        cast = {}

        #The cast is stored as a dictionary where the name in the condition narrative
        #is the key for the node it relates to
        for i in range(len(resulting_group)):
            cast[resulting_rule.get_social_condition().get_nodes()
                 [i].get_name()] = resulting_group[i]

        #The player always participates in the narrative by default
        cast["Player"] = self._social_graph.get_player()

        self._narrative.set_cast(cast)

        #-----------------------------------
        #Now we set the preconditions for our narrative
        #-----------------------------------

        #We will convert the original social condition into a set of preconditions
        for i in range(len(resulting_group)):
            cur_node = resulting_rule.get_social_condition().get_nodes()[i]
            cur_attr = cur_node.get_attributes()

            #First we will create all of the attribute preconditions
            for key in cur_attr.keys():
                condition = Condition(True)

                condition.set_first_object(resulting_group[i])
                condition.set_key(key)
                condition.set_value(cur_attr[key])

                self._narrative.add_precondition(condition)

            #Following this, we will create all of the edge preconditions
            for edge in cur_node.get_outgoing_edges():

                condition = Condition(False)

                condition.set_first_object(resulting_group[i])
                condition.set_second_object(
                    cast[edge.get_to_node().get_name()])
                condition.set_key(edge.get_name().keys()[0])
                condition.set_value(edge.get_name()[edge.get_name().keys()[0]])

                self._narrative.add_precondition(condition)

        #-----------------------------------
        #Now we construct our narrative skeleton using this modification
        #-----------------------------------
        story_modification = resulting_rule.get_story_modification()

        #Set up our nodes
        for node in story_modification.get_nodes():

            #Get the index of the story node
            index = resulting_rule.get_social_condition().get_nodes().index(
                node.get_target())

            #We can then pick the actual target from our group
            target = resulting_group[index]

            #Also, add the target as an attribute
            node.add_attribute("Target", target.get_name())

            #And link the story node to this target
            node.set_linked_to_node(target)

            #Finally, add the node to the story
            self._narrative.add_node(node)

        #Edges are currently empty for narratives
        for edge in story_modification.get_edges():
            self._narrative.add_edge(edge)

        return True
Exemplo n.º 8
0
class Scheduler:
    """The initialization function
	
	Args:
		social_graph (Graph): The main relation graph for our game
		story_initialization_rules (RewriteRule Array): The story generation rules
		rewrite_rules (RewriteRule Array): The story modification rules
	"""
    def __init__(self,
                 social_graph,
                 story_initialization_rules,
                 rewrite_rules,
                 metrics_to_optimize,
                 max_number_of_rewrites,
                 stats_output,
                 verbose=True):
        self._social_graph = social_graph
        self._story_init_rules = story_initialization_rules
        self._rewrite_rules = rewrite_rules
        self._num_applications = {}
        self._verbose = verbose
        self._stats_output = stats_output
        self._divider = "--------------------------------------"
        self._valids = 0
        self._invalids = 0
        self._metrics_to_optimize = metrics_to_optimize

        self._metrics_to_optimize_name_only = []

        for metric in self._metrics_to_optimize:
            self._metrics_to_optimize_name_only.append(metric[0])

        self._use_metric_rewriting = (not len(metrics_to_optimize) == 0)

        self._max_number_of_rewrites = max_number_of_rewrites

        self._start_rewriting_time = 0
        self._end_rewriting_time = 0
        self._start_validation_time = 0
        self._end_validation_time = 0

        # Here we define a number of applications, refering to the number
        # of times each rule has been used, this allows us to
        # set restrictions on the number of times each rule can be applied
        self.reset_num_applications()

    def get_valids(self):
        return self._valids

    def get_invalids(self):
        return self._invalids
#--------------------------------------------------------------
#	Functions for the Number of Applications Dictionary
#--------------------------------------------------------------

    """ Reset our number of applications dictionary
	"""
    def reset_num_applications(self):

        #Set all of our entries to zero, ie. no applications
        for rule in self._rewrite_rules:
            self._num_applications[
                rule.get_story_modification().get_name()] = 0

    """Get the number of applications of a specific rule
	
	Args:
		rule (RewriteRule): The rule to be searched for in the num_applications dictionary
	"""

    def get_num_applications(self, rule):
        #Return the number of applications of that specific rule
        return self._num_applications[rule.get_story_modification().get_name()]

    """Increment the number of applications of a specific rule
	
	Args:
		rule (RewriteRule): The rule we are incrementing, most likely due to its application
	"""

    def inc_num_applications(self, rule):
        self._num_applications[rule.get_story_modification().get_name()] += 1

    """Check if we are allowed to apply a specific rule
	
	Args:
		rule (RewriteRule): The rule we are checking
		
	Returns:
		(Boolean): True if we can still apply this rule
	"""

    def is_allowed(self, rule):

        if rule.get_apply_once():
            if self.get_num_applications(rule) > 0:
                return False
            else:
                return True
        else:
            return True

#--------------------------------------------------------------
#	Getters and Setters
#--------------------------------------------------------------

    """Get our social graph
	
	Returns:
		(SocialGraph): The graph we are using
	"""
    def get_social_graph(self):
        return self._social_graph

#--------------------------------------------------------------
#	Scheduler Helper Functions
#--------------------------------------------------------------

    """The call to make for getting all possible rules from the list of possible
	available rules
	"""
    def get_possible_rules(self, ruleset, graph):

        possible_rules = []

        #Check each of our rewrite rules
        for rule in ruleset:
            print rule.get_name()
            #Get the story condition
            if isinstance(graph, StoryGraph):
                condition = rule.get_story_condition()
            else:
                condition = rule.get_social_condition()

            #Get the results
            results = graph.contains_subgraph(condition)

            #If we have this story condition and can still rewrite, make the modification
            #if cur_node.contains_subnode(story_condition) and refinements_remaining > 0:
            if len(results) > 0:
                if self.is_allowed(rule):
                    possible_rules.append([results, rule])
        return possible_rules

    """Check the social condition for the narrative
	"""

    def get_social_results(self, chosen_rule, narrative):
        #Prepare our social condition for checking using a subgraph check
        #by assigning any of the necessary cast names to the node to refine
        #the graph search
        social_condition = chosen_rule.get_social_condition()

        num_matches = 0
        for node in social_condition.get_nodes():
            if node.get_name() in narrative.get_cast():
                new_name = narrative.get_cast()[node.get_name()].get_name()
                node.add_attribute("name", new_name)
                num_matches += 1

        if num_matches > 0:
            return self._social_graph.contains_subgraph(social_condition)
        else:
            return []

    """ Apply a given rule to a graph
	
	Args:
		chosen_results([story_nodes, rule]): An array containing both the rule, and the corresponding story nodes
		social_results (Array): An array of possible social situations
		narrative: The narrative we are applying the rule to
	"""

    def applyRule(self, chosen_results, social_results, narrative):

        #Get the rule from our chosen results
        chosen_rule = chosen_results[1]

        #Get the new story nodes from our results
        resulting_story_nodes = choice(chosen_results[0])

        #Get the resulting story nodes for our rewrite
        result = choice(social_results)

        #Get the social condition from our rule
        social_condition = chosen_rule.get_social_condition()

        #Add any new cast members necessary
        for i in range(len(result)):
            if not social_condition.get_nodes()[i].get_name(
            ) in narrative.get_cast():
                narrative.add_cast(social_condition.get_nodes()[i].get_name(),
                                   result[i])

        story_modification = chosen_rule.get_story_modification()

        #Make our new graph
        nodes = []
        for node in story_modification.get_nodes():
            target = narrative.get_cast()[node.get_target().get_name()]
            new_node = node.Copy_Story_Node()
            new_node.set_linked_to_node(target)
            new_node.add_attribute("Target", target.get_name())
            nodes.append(new_node)

        new_graph = Graph("Temp", nodes)

        adj = story_modification.get_adjacency()
        for row in range(len(adj)):
            for col in range(len(adj)):
                if adj[row][col] == 1:
                    adj[col][row] = 0
                    new_graph.connect(nodes[row], {}, nodes[col])

        backup_narrative = narrative.Copy()

        narrative.replace_node_with_new(
            narrative.get_node_from_name(resulting_story_nodes[0].get_name()),
            new_graph)

        narrative.fix_graph()
        self._social_graph.make_node_postconditions(narrative)
        narrative.initialize_conditions()
        narrative.refine_lost_conditions()

        print "Validating Final Story\n"

        if self._verbose:
            print self._divider
            for node in narrative.get_nodes():

                print "Preconditions for " + node.get_name()
                for con in node.get_preconditions():
                    print con
                print "\nPostconditions for " + node.get_name()
                for con in node.get_postconditions():
                    print con
                print "\nLost Conditions for " + node.get_name()
                for con in node.get_lostconditions():
                    print con
                print "\n" + self._divider

        valid = narrative.validate_story()
        if not valid:
            print "INVALID STORY"
            self._invalids += 1
            print "VALIDS = " + str(self._valids)
            print "INVALIDS = " + str(self._invalids)
            return backup_narrative
        else:
            print "VALID STORY"
            self._valids += 1
            print "VALIDS = " + str(self._valids)
            print "INVALIDS = " + str(self._invalids)
            return narrative

#--------------------------------------------------------------
#	Scheduler Functions
#--------------------------------------------------------------

    """Initialize our narrative
	
	Returns:
		(Boolean): True if a narrative has been created, false otherwise
	"""
    def initialize_narrative(self):

        #-----------------------------------
        # Create the Beginning Narrative Format
        #-----------------------------------

        #Create the starting node and ending node
        start_node = StoryNode("Start_Quest", {"Node_Type": "Start"}, "N/A")
        end_node = StoryNode("End_Quest", {"Node_Type": "End"}, "N/A")

        #Initialize our narrative
        self._narrative = StoryGraph("New_Quest", [start_node, end_node])
        self._narrative.initialize()

        print "Creating Initial Narrative"
        #-----------------------------------
        #We will go throughout all our rules and find matching results
        #-----------------------------------
        print "Searching for Possible Narrative Rules..."
        matching_rules = self.get_possible_rules(self._story_init_rules,
                                                 self._social_graph)

        print "Found " + str(len(matching_rules)) + " possible rules"
        if len(matching_rules) <= 0:
            print "ERROR - No Matching Rules found, No more stories may be created"
            return False

        #Rules for picking the matching narrative
        #At the moment it is a random choice

        if self._verbose:
            print "Found the Following Matching Initialization Rules: "
            for rule in matching_rules:
                print "\t" + rule[1].get_name()

        resultant = choice(matching_rules)
        resulting_rule = resultant[1]

        #Rules for picking the matching group
        #At the moment it is a random choice
        resulting_group = choice(resultant[0])
        #-----------------------------------
        #Now we set the cast for our narrative
        #-----------------------------------
        cast = {}

        #The cast is stored as a dictionary where the name in the condition narrative
        #is the key for the node it relates to
        for i in range(len(resulting_group)):
            cast[resulting_rule.get_social_condition().get_nodes()
                 [i].get_name()] = resulting_group[i]

        #The player always participates in the narrative by default
        cast["Player"] = self._social_graph.get_player()

        self._narrative.set_cast(cast)

        #-----------------------------------
        #Now we set the preconditions for our narrative
        #-----------------------------------

        #We will convert the original social condition into a set of preconditions
        for i in range(len(resulting_group)):
            cur_node = resulting_rule.get_social_condition().get_nodes()[i]
            cur_attr = cur_node.get_attributes()

            #First we will create all of the attribute preconditions
            for key in cur_attr.keys():
                condition = Condition(True)

                condition.set_first_object(resulting_group[i])
                condition.set_key(key)
                condition.set_value(cur_attr[key])

                self._narrative.add_precondition(condition)

            #Following this, we will create all of the edge preconditions
            for edge in cur_node.get_outgoing_edges():

                condition = Condition(False)

                condition.set_first_object(resulting_group[i])
                condition.set_second_object(
                    cast[edge.get_to_node().get_name()])
                condition.set_key(edge.get_name().keys()[0])
                condition.set_value(edge.get_name()[edge.get_name().keys()[0]])

                self._narrative.add_precondition(condition)

        #-----------------------------------
        #Now we construct our narrative skeleton using this modification
        #-----------------------------------
        story_modification = resulting_rule.get_story_modification()

        #Set up our nodes
        for node in story_modification.get_nodes():

            #Get the index of the story node
            index = resulting_rule.get_social_condition().get_nodes().index(
                node.get_target())

            #We can then pick the actual target from our group
            target = resulting_group[index]

            #Also, add the target as an attribute
            node.add_attribute("Target", target.get_name())

            #And link the story node to this target
            node.set_linked_to_node(target)

            #Finally, add the node to the story
            self._narrative.add_node(node)

        #Edges are currently empty for narratives
        for edge in story_modification.get_edges():
            self._narrative.add_edge(edge)

        return True

    """The process of writing our narrative. It involves generating a narrative to write to and
	applying the set of rewrites
	
	Returns (StoryGraph): The final narrative
	"""

    def write_narrative(self):

        #Create the final narrative
        self._final_narrative = self._narrative.Copy()

        #Connect the starting and ending node where appropriate
        for cur_node in self._final_narrative.get_nodes():

            #Starting Node
            if (len(cur_node.get_incoming_edges()) == 0) and (
                    not cur_node == self._final_narrative.get_start_node()
            ) and (not cur_node == self._final_narrative.get_end_node()):
                self._final_narrative.connect(
                    self._final_narrative.get_start_node(), {}, cur_node)

            #Ending Node
            if (len(cur_node.get_outgoing_edges()) == 0) and (
                    not cur_node == self._final_narrative.get_start_node()
            ) and (not cur_node == self._final_narrative.get_end_node()):
                self._final_narrative.connect(
                    cur_node, {}, self._final_narrative.get_end_node())

        self._social_graph.make_node_postconditions(self._final_narrative)
        self._final_narrative.initialize_conditions()
        self._final_narrative.refine_lost_conditions()

        print "-------------------------------------------------\n"
        for node in self._final_narrative.get_nodes():

            print "Preconditions for " + node.get_name()
            for con in node.get_preconditions():
                print con
            print "\nPostconditions for " + node.get_name()
            for con in node.get_postconditions():
                print con
            print "\nLost Conditions for " + node.get_name()
            for con in node.get_lostconditions():
                print con
            print "\n-------------------------------"

        #-----------------------------------
        #Begin the process of rewriting the narrative
        #-----------------------------------

        #Make sure we have a reset number of applications dictionary
        self.reset_num_applications()

        #This monitors if we have any rewrites possible
        can_rewrite = True

        #This monitors our total number of rewrites
        num_rewrites = 0

        #-----------------------------------
        # Start applying the rewrite rules
        #-----------------------------------
        #While we can, attempt to apply rewrite rules to the narrative
        while can_rewrite and (num_rewrites < self._max_number_of_rewrites):

            #Get all rules which could possibly be applied
            possible_rules = self.get_possible_rules(self._rewrite_rules,
                                                     self._final_narrative)

            #If we have no possible rules, then we have rewritten the story as much as possible
            if len(possible_rules) > 0:
                #---------------------------
                # WIP WIP WIP
                # Here we can cycle between whether
                # we want to rewrite stories according to
                # metrics or not
                # WIP WIP WIP
                #---------------------------
                self._start_rewriting_time = time.time()
                if self._use_metric_rewriting:
                    self.metric_rewrite(possible_rules, self._final_narrative)
                else:
                    self.non_metric_rewrite(possible_rules,
                                            self._final_narrative)

            else:
                can_rewrite = False

            #After each iteration, update our number of rewrites
            num_rewrites += 1

        return self._final_narrative

    """Perform a Graph Rewrite without using metrics
	"""

    def non_metric_rewrite(self, possible_rules, narrative):

        #Pick our rule, and its result randomly for a non metric re-write
        result_rule_pair = choice(possible_rules)

        #Get our chosen rule from the pair
        chosen_rule = result_rule_pair[1]

        #Increment that rule, since we are now applying it
        self.inc_num_applications(chosen_rule)

        #Get the social results for our narrative and rule
        social_results = self.get_social_results(chosen_rule, narrative)

        #If we have a result, apply the rule
        if len(social_results) > 0:
            self.applyRule(result_rule_pair, social_results, narrative)

    """Do a Metric Enhanced Rewrite
	"""

    def metric_rewrite(self, possible_rules, narrative):

        candidate_narratives = []
        candidate_rules = []

        #Check all possible rules
        for result_rule_pair in possible_rules:

            #Make a new candidate narrative
            candidate_narrative = narrative.Copy()

            #Get a new candidate rule
            candidate_rule = result_rule_pair[1]

            #Check if the rule has social results
            social_results = self.get_social_results(candidate_rule,
                                                     candidate_narrative)

            #If so we have a potential narrative/rule
            if len(social_results) > 0:
                result_candidate = self.applyRule(result_rule_pair,
                                                  social_results,
                                                  candidate_narrative)
                candidate_narratives.append(result_candidate)
                candidate_rules.append(candidate_rule)

        #If we have potential rules, we can now pick the best narrative
        #based off of metrics
        if len(candidate_narratives) > 0:

            #First gather all the metrics
            metric_results = []

            for candidate_narrative in candidate_narratives:
                metrics = Metrics(candidate_narrative.Copy(),
                                  self._metrics_to_optimize_name_only,
                                  self._social_graph.get_preconditions())
                metric_results.append(metrics.getMetrics(True))

            #Now, using these results and our weights, pick the best metric
            optimal_narrative = self.pick_optimal_narrative(metric_results)

            #Increment the number of applications
            self.inc_num_applications(candidate_rules[optimal_narrative])
            #Set the new narrative
            self._final_narrative = candidate_narratives[optimal_narrative]

    """Used in Metric Rewrite, get optimal narrative
	"""

    def pick_optimal_narrative(self, metric_results):

        scores = []
        for i in metric_results:
            scores.append(0)

        for optimize in self._metrics_to_optimize:
            metric_name = optimize[0]
            metric_weight = optimize[1]

            results = []
            for result in metric_results:
                results.append(result[metric_name])

            max_value = float(max(results))

            for i in range(len(results)):
                if not max_value == 0:
                    scores[i] += (results[i] / max_value) * metric_weight

        score_results, score_indices = self.sort_with_indexes(scores)

        final_possibilities = []
        for i in range(len(score_results)):
            if score_results[i] == max(score_results):
                final_possibilities.append(score_indices[i])

        optimal_narrative = choice(final_possibilities)
        return optimal_narrative

    def sort_with_indexes(self, data):
        sorted_data = sorted(enumerate(data),
                             key=lambda key: key[1],
                             reverse=True)
        indexes = range(len(data))
        indexes.sort(key=lambda key: sorted_data[key][0])
        return [i[1] for i in sorted_data], indexes