123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- import argparse
- import re
- from enum import Enum
- from string import Template
- from typing import NamedTuple
-
- from jinja2 import Environment, PackageLoader, select_autoescape
-
- import items
- from destinations import DESTINATIONS, SYSTEMS, Destination, DestinationType
-
- # 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
-
-
- def get_destination_type_from_enum(destination):
- dtype = destination.type
- dtype_name = dtype._name_
- dtype_name_lower = dtype_name.lower()
- dtype_name_nou = dtype_name_lower.replace("_", " ")
- if dtype_name_nou[0] in ["a", "e", "i", "o", "u"]:
- # it's only "asteroid" and "ocean" now but it might expand
- dtype_name_final = "an " + dtype_name_nou
- else:
- dtype_name_final = "a " + dtype_name_nou
- return dtype_name_final
-
-
- # Class definitions
-
-
- class Mission:
- output_destination_template = Template(
- "to $world $destination_type 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.name if destination.name is not None else None
- self.system = (
- destination.system if destination.system is not None else destination.name
- )
- self.sector = destination.sector if destination.sector is not None else None
- self.destination_type = get_destination_type_from_enum(destination)
- self.value = value
-
- 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 + "," if self.world != "" else "",
- "system": self.system,
- "sector": self.sector,
- "destination_type": self.destination_type,
- "value": self.value,
- }
-
- def missing_values(self) -> list:
- object_vars = vars(self)
- missing = []
- for key, val in object_vars.items():
- if val is None and key != "time": # time is optional
- 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 | None, *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)
- dest_type = random.randint(1, 5)
- if dest_type < 3: # world, 40% chance
- destination = random.choice(DESTINATIONS)
- else:
- system = random.choice(SYSTEMS)
- destination = Destination(
- name="",
- system=system[0],
- sector=system[1],
- type=(
- DestinationType.STATION
- if random.randint(0, 1) == 0
- else DestinationType.ASTEROID_BASE
- ),
- )
- item, time, tons, number, value, group = [None] * 6
- if current_mission == CargoMission:
- current_item = random.choice(items.ITEMS)
- tons = random.randint(
- current_item.potential_tons[0], current_item.potential_tons[1]
- )
- value = random.randint(*current_item.potential_values) * 1000
- item = current_item.name
- if current_item.potential_times is not None:
- if current_item.chance_for_time is not None:
- is_there_a_time = random.random() * 100
- # print(current_item.chance_for_time, is_there_a_time, is_there_a_time < current_item.chance_for_time)
- if is_there_a_time < current_item.chance_for_time:
- time = random.randint(
- current_item.potential_times[0],
- current_item.potential_times[1],
- )
- else:
- number = random.randint(1, 8)
- time = random.randint(7, 31)
- value = random.randint(20, 120) * 1000
- 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()
|