|  |  | @@ -0,0 +1,205 @@ | 
		
	
		
			
			|  |  |  | import argparse, re | 
		
	
		
			
			|  |  |  | from string import Template | 
		
	
		
			
			|  |  |  | from typing import NamedTuple | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | from jinja2 import Environment, PackageLoader, select_autoescape | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # global variables | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | env = Environment( | 
		
	
		
			
			|  |  |  | loader=PackageLoader("swjg"), | 
		
	
		
			
			|  |  |  | autoescape=select_autoescape | 
		
	
		
			
			|  |  |  | ) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | parser = argparse.ArgumentParser() | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # helper functions | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def get_identifiers_from_template(template): | 
		
	
		
			
			|  |  |  | # Template.get_identifiers() doesn't appear until Python 3.11 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Don't substitute anything; get the raw string | 
		
	
		
			
			|  |  |  | template_str = Template.safe_substitute() | 
		
	
		
			
			|  |  |  | matches = re.findall("\$[a-z0-9_\.]+", template_str) | 
		
	
		
			
			|  |  |  | matches = [x[1:] for x in matches] | 
		
	
		
			
			|  |  |  | return matches | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # classes and such | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | class Destination(NamedTuple): | 
		
	
		
			
			|  |  |  | world: str | 
		
	
		
			
			|  |  |  | system: str|None | 
		
	
		
			
			|  |  |  | sector: str|None | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | class Mission: | 
		
	
		
			
			|  |  |  | output_destination_template = Template("to $world in the $system system") | 
		
	
		
			
			|  |  |  | output_sector_template = Template(", part of the $sector,") | 
		
	
		
			
			|  |  |  | value_template = Template("for $value credits") | 
		
	
		
			
			|  |  |  | error_template = Template("You haven't given this mission some of the values it needs. Please check: $potential_values") | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def __init__(self, destination:Destination, value:int, *args, **kwargs): | 
		
	
		
			
			|  |  |  | # destination: Destination (see above) | 
		
	
		
			
			|  |  |  | self.world = destination.world if destination.world is not None else None | 
		
	
		
			
			|  |  |  | self.system = destination.system if destination.system is not None else destination.world | 
		
	
		
			
			|  |  |  | self.sector = destination.sector if destination.sector is not None else None | 
		
	
		
			
			|  |  |  | self.value = value | 
		
	
		
			
			|  |  |  | # for arg, val in kwargs.items(): | 
		
	
		
			
			|  |  |  | #     setattr(self, arg, val) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def assemble_templates(self) -> list: | 
		
	
		
			
			|  |  |  | # Override this in children | 
		
	
		
			
			|  |  |  | template_list = [] | 
		
	
		
			
			|  |  |  | if self.world != None: | 
		
	
		
			
			|  |  |  | template_list.append(self.output_destination_template) | 
		
	
		
			
			|  |  |  | if self.sector != None: | 
		
	
		
			
			|  |  |  | template_list.append(self.output_sector_template) | 
		
	
		
			
			|  |  |  | template_list.append(self.value_template) | 
		
	
		
			
			|  |  |  | return template_list | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def get_current_values(self) -> dict: | 
		
	
		
			
			|  |  |  | return { | 
		
	
		
			
			|  |  |  | "world": self.world, | 
		
	
		
			
			|  |  |  | "system": self.system, | 
		
	
		
			
			|  |  |  | "sector": self.sector, | 
		
	
		
			
			|  |  |  | "value": self.value | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def missing_values(self) -> list: | 
		
	
		
			
			|  |  |  | object_vars = vars(self) | 
		
	
		
			
			|  |  |  | missing = [] | 
		
	
		
			
			|  |  |  | for key, val in object_vars.items(): | 
		
	
		
			
			|  |  |  | if val == None: | 
		
	
		
			
			|  |  |  | missing.append(key) | 
		
	
		
			
			|  |  |  | return missing | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def assemble_text(self) -> str: | 
		
	
		
			
			|  |  |  | missing_vals = self.missing_values() | 
		
	
		
			
			|  |  |  | templates = self.assemble_templates() | 
		
	
		
			
			|  |  |  | if len(templates) == 0 or len(missing_vals) != 0: # either both of these should be true or neither should | 
		
	
		
			
			|  |  |  | raise ValueError(self.error_template.substitute(potential_values=missing_vals)) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | current_values = self.get_current_values() | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | output = [] | 
		
	
		
			
			|  |  |  | for template in templates: | 
		
	
		
			
			|  |  |  | output.append(template.substitute(**current_values)) | 
		
	
		
			
			|  |  |  | out_text = " ".join(output) | 
		
	
		
			
			|  |  |  | out_text = out_text.replace(" ,", ",") | 
		
	
		
			
			|  |  |  | out_text += "." | 
		
	
		
			
			|  |  |  | return out_text | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | class PassengerMission(Mission): | 
		
	
		
			
			|  |  |  | output_initial_template = Template("Bring $number passengers") | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def __init__(self, number:int, *args, **kwargs): | 
		
	
		
			
			|  |  |  | super(PassengerMission, self).__init__(*args, **kwargs) | 
		
	
		
			
			|  |  |  | self.number = number | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def get_current_values(self) -> dict: | 
		
	
		
			
			|  |  |  | base_dict = super(PassengerMission, self).get_current_values() | 
		
	
		
			
			|  |  |  | new_dict = { | 
		
	
		
			
			|  |  |  | "number": self.number | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | base_dict.update(new_dict) | 
		
	
		
			
			|  |  |  | return base_dict | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def assemble_templates(self): | 
		
	
		
			
			|  |  |  | template_list = [self.output_initial_template] | 
		
	
		
			
			|  |  |  | template_list.extend(super(PassengerMission, self).assemble_templates()) | 
		
	
		
			
			|  |  |  | return template_list | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def assemble_text(self) -> str: | 
		
	
		
			
			|  |  |  | return super(PassengerMission, self).assemble_text() | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | class CargoMission(Mission): | 
		
	
		
			
			|  |  |  | output_initial_template = Template("Deliver $tons tons of $item") | 
		
	
		
			
			|  |  |  | output_time_timeplate = Template("in the next $time days") | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def __init__(self, tons:int, item:str, time:int, *args, **kwargs): | 
		
	
		
			
			|  |  |  | # tons: integer | 
		
	
		
			
			|  |  |  | # item: string (this will not be pluralized in the text) | 
		
	
		
			
			|  |  |  | # time: integer (number of days the crew have to complete delivery) | 
		
	
		
			
			|  |  |  | # value: integer (value in credits) | 
		
	
		
			
			|  |  |  | super(CargoMission, self).__init__(*args, **kwargs) | 
		
	
		
			
			|  |  |  | self.tons = tons | 
		
	
		
			
			|  |  |  | self.item = item | 
		
	
		
			
			|  |  |  | self.time = time | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def get_current_values(self) -> dict: | 
		
	
		
			
			|  |  |  | base_dict = super(CargoMission, self).get_current_values() | 
		
	
		
			
			|  |  |  | new_dict = { | 
		
	
		
			
			|  |  |  | "tons": self.tons, | 
		
	
		
			
			|  |  |  | "item": self.item, | 
		
	
		
			
			|  |  |  | "time": self.time | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | base_dict.update(new_dict) | 
		
	
		
			
			|  |  |  | return base_dict | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def assemble_templates(self): | 
		
	
		
			
			|  |  |  | template_list = [self.output_initial_template] | 
		
	
		
			
			|  |  |  | if self.time is not None: | 
		
	
		
			
			|  |  |  | template_list.append(self.output_time_timeplate) | 
		
	
		
			
			|  |  |  | template_list.extend(super(CargoMission, self).assemble_templates()) | 
		
	
		
			
			|  |  |  | return template_list | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def assemble_text(self) -> str: | 
		
	
		
			
			|  |  |  | return super(CargoMission, self).assemble_text() | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | class GroupMission(Mission): | 
		
	
		
			
			|  |  |  | output_initial_template = Template("Bring $number members of a $group") | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def __init__(self, number:int, group:str, *args, **kwargs): | 
		
	
		
			
			|  |  |  | super(GroupMission, self).__init__(*args, **kwargs) | 
		
	
		
			
			|  |  |  | self.number = number | 
		
	
		
			
			|  |  |  | self.group = group | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def get_current_values(self) -> dict: | 
		
	
		
			
			|  |  |  | base_dict = super(GroupMission, self).get_current_values() | 
		
	
		
			
			|  |  |  | new_dict = { | 
		
	
		
			
			|  |  |  | "number": self.number, | 
		
	
		
			
			|  |  |  | "group": self.group | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | base_dict.update(new_dict) | 
		
	
		
			
			|  |  |  | return base_dict | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def assemble_templates(self): | 
		
	
		
			
			|  |  |  | template_list = [self.output_initial_template] | 
		
	
		
			
			|  |  |  | template_list.extend(super(GroupMission, self).assemble_templates()) | 
		
	
		
			
			|  |  |  | return template_list | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def assemble_text(self) -> str: | 
		
	
		
			
			|  |  |  | return super(GroupMission, self).assemble_text() | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # the function that does the thing | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | def main(): | 
		
	
		
			
			|  |  |  | import random | 
		
	
		
			
			|  |  |  | mission_types = [PassengerMission, CargoMission, GroupMission] | 
		
	
		
			
			|  |  |  | missions = [] | 
		
	
		
			
			|  |  |  | for _ in range(5): | 
		
	
		
			
			|  |  |  | current_mission = random.choice(mission_types) | 
		
	
		
			
			|  |  |  | destination = Destination("Alderaan", None, "Core Worlds") | 
		
	
		
			
			|  |  |  | number = random.randint(1,8) | 
		
	
		
			
			|  |  |  | tons = random.randint(4, 12) | 
		
	
		
			
			|  |  |  | item = random.choice(["gravel", "computer chips", "spice", "live ysalamiri", "empty shipping containers"]) | 
		
	
		
			
			|  |  |  | time = random.randint(7, 31) | 
		
	
		
			
			|  |  |  | value = random.randint(20, 120) * 1000 | 
		
	
		
			
			|  |  |  | group = None | 
		
	
		
			
			|  |  |  | if current_mission == GroupMission: | 
		
	
		
			
			|  |  |  | group = random.choice(["family", "performing troupe", "acrobatic troupe"]) | 
		
	
		
			
			|  |  |  | missions.append(current_mission(destination=destination, number=number, tons=tons, item=item, time=time, value=value, group=group)) | 
		
	
		
			
			|  |  |  | for mission in missions: | 
		
	
		
			
			|  |  |  | # print(mission, mission.__dict__) | 
		
	
		
			
			|  |  |  | print(mission.assemble_text()) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | # Don't do anything if the module is loaded wholesale into something else | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if __name__ == "__main__": | 
		
	
		
			
			|  |  |  | main() |