import argparse import re from enum import Enum 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 definitions 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 class DangerLevel(Enum): NONE = 1 LOW = 2 MODERATE = 3 HIGH = 4 EXTREME = 5 class DangerType(Enum): HOSTILE = 1 AT_WAR = 2 DESERT = 3 JUNGLE = 4 OCEAN = 5 ATMOSPHERE = 6 class Destination(NamedTuple): world: str system: str | None sector: str | None # Class definitions 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()