Python (programming language)/Fun
Jump to navigation
Jump to search
Python has a highly flexible syntax, allowing a diverse range of design patterns and paradigms. Python has also absorbed features from a bunch other languages, allowing programmers proficient in different domains to get creative with Python. Below is an implementation of the text-based terminal strategy game Fun Science for Kids in Python 3.11, in order to gain a deeper understanding of its uniquely weird syntax and features.
Source[edit | edit source]
## FSfK, a multiplayer text adventure & research industry simulation ## Moves: 'r' - research ## 'p' - plagiarize ## 'a [TARGET]' - attack player/group of name TARGET ## 'g [PLAYER]' - group with player PLAYER ## 'd' - disband current group if in one ## See the detailed rules at [[Fun_Science_for_Kids]] ## This file is entirely written in Notepad on a Windows machine. ## Linux users please pay the CRLF no mind. #ifndef ENCYCLOPEDIA_H #define ENCYCLOPEDIA_H #include <iostream> import sys class Numms: """ Constants """ # status codes YEP = 1 NOPE = 0 NO_NO_NO_NEVER_IN_AN_ETERNITY = -1 # player UNINITALIZED = 0 FAILED = 2 INACTIVE = 3 ACTIVE = 4 GROUPED = 5 ascii_uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" cmp_attribs = ["n_members", "papers", "reput"] def wtf(msg): print("WTF! Program terminated: %s" %msg) exit(Numms.NO_NO_NO_NEVER_IN_AN_ETERNITY) def wth(msg): print("WTH? Smth's wrong: %s" %msg) def wti(msg): print("We tersely inform you: %s" %msg) class Entity: """ Stores player stats. """ def __init__(self, id): self.id = id self.status = Numms.UNINITALIZED def init_real(self, name): self.name = name self.members = set() self.members.add(self.id) self.n_members = 1 self.papers = 3 # individuals start with 3/0 self.reput = 0 self.status = Numms.ACTIVE def init_real_real(self, name, members, papers, reput): self.name = name self.members = members self.n_members = len(members) self.papers = papers self.reput = reput self.status = Numms.INACTIVE # groups have a 1-round cooldown def getter(self): wtf("does a getter do") def display_stats(self): print("<Entity %s> papers %d, reput %d, status %d" %(self.name, self.papers, self.reput, self.status)) # print is best function def on_death(self, cause): print("<Entity %s> Oh no! I failed due to %s." %(self.name, cause)) self.__del__() # if it doesn't work try commenting out this (and other) line(s) class RandomShit: """ utils, play order sorter, grouping, disbanding """ def __init__(self, max_papers): self.entities = dict() self.n_entities = 0 self.max_papers = max_papers self.play_order = [] def add_entity(self, e): self.entities[e.id] = e self.n_entities += 1 def which_group_are_you_in(self, e_unknown): # legacy fuinctoin. for k, e in self.entities: if len(e.members)==1: # not group continue if e_unknown.name in e.members: return(e) wth("Player %s is not in any group." %e_unknown.name) return None # failed to find def kill_child(self, id_victim, cause): if not id_victim in self.entities: wth("Entity %s does not exist." %id_victim) return self.entities[id_victim].on_death(cause) self.entities.pop(id_victim) def test_for_dead(self): e_deads = [] for k in self.entities: e = self.entities[k] if e.papers <= 0 or e.reput <= -3 or e.status == Numms.FAILED: e_deads = e_deads + list(e.members) for k in e_deads: self.kill_child(k, "for sacrifice") def test_for_paper_overflow(self, e_last_acted): sum_papers = 0 for k in self.entities: sum_papers += self.entities[k].papers if sum_papers > self.max_papers: wti("The research field is now saturated at %d papers! o.o" %self.max_papers) e_last_acted.papers = e_last_acted.papers - (sum_papers - self.max_papers) def g(self, e_agent, e_patient): e_group = Entity(id = self.n_entities) #m = e_agent.members.add(e_patient.members) # "Unhashable type"? Wtf is a hash m = set() for member in e_agent.members: m.add(member) for member in e_patient.members: m.add(member) n = "".join([self.entities[id].name for id in sorted(m)]) p = e_agent.papers + e_patient.papers r = e_agent.reput + e_patient.reput e_group.init_real_real(n, m, p, r) # passes arguments n, m, p, and r to method init_real_real of object e_group e_agent.reput += 1 e_agent.status = Numms.GROUPED e_patient.status = Numms.GROUPED id = self.n_entities self.entities[id] = e_group self.n_entities += 1 def d(self, e_agent): e_group = which_group_are_you_in(e_agent) if not e_group: return m = e_group.members m = m - e_agent.name e_agent.reput -= 2 e_agent.papers = e_group.papers # I commented the code very well for k in m: self.entities[k].papers = 1 e_agent.papers -= 1 self.entities.pop(e_group.name) self.n_entities -= 1 def __is_e1_better_than_e2_if_yes_return_one_if_no_return_negative_one(self, e1, e2): for attrib in cmp_attribs: value1 = e1.__getattribute__(attrib) value2 = e2.__getattribute__(attrib) if value1 < value2: return(-1) elif value1 > value2: return(1) return(-1) # all stats identical def parse_play_order(self): entities_temp = dict(self.entities) self.play_order = [] for i in range(self.n_entities): e_temp = Entity(id = -1) e_temp.init_real_real("dummy", set(), 0, 0) for k in entities_temp: if self.__is_e1_better_than_e2_if_yes_return_one_if_no_return_negative_one(entities_temp[k], e_temp)==1: e_temp = entities_temp[k] if e_temp.id!=-1: entities_temp.pop(e_temp.id) self.play_order.append(e_temp.id) else: wth("We encountered an unexpected issue. The game can keep running but may crash at any time.") # fucking fuckity fuck!! class DataManager: """ Manages data. """ def __init__(self): if len(sys.argv) == 1: wti("Usage: FSfK.py [number of players]") exit(0) self.n_players = int(sys.argv[1]) if self.n_players<=0 or self.n_players>=len(ascii_uppercase): wtf("I am batman") self.r = RandomShit(max_papers = 5 * self.n_players) for i in range(self.n_players): name = ascii_uppercase[i] e_player_i = Entity(id = i) e_player_i.init_real(name) self.r.add_entity(e_player_i) is_win = False self.round = 0 while not is_win: self.new_round() self.r.parse_play_order() #print("sequence of play is", self.r.play_order) for id in self.r.play_order: if self.r.entities[id].status != Numms.ACTIVE: continue ret = Numms.NOPE while ret != Numms.YEP: ret = self.parse_cmd(self.r.entities[id]) self.r.test_for_dead() is_win = self.function_that_does_this() self.round += 1 def new_round(self): print("Round %d" %self.round) for k in self.r.entities: e = self.r.entities[k] # weak copy, changes to this also changes the original if e.status!=Numms.GROUPED: e.status = Numms.ACTIVE self.r.entities[k].display_stats() def get_id_from_name(self, name_entity): for k in self.r.entities: e = self.r.entities[k] if e.name==name_entity: return(e.id) return(None) def function_that_does_this(self): if self.r.n_entities<=2: return(True) else: return(False) def parse_cmd(self, e_agent): print("<%s> >>> " %e_agent.name, end="") cmd = input() if cmd=="end": wti("Exiting game...") exit(0) elif cmd=="": wth("cmd is empty.") return(Numms.NOPE) move = cmd[0] if e_agent.status==Numms.GROUPED and move!='d': wth("Your group has acted and you can't act, however you can disband") return(Numms.NOPE) if move=='r': e_agent.papers += e_agent.n_members e_agent.reput += e_agent.n_members #wti("You made a contribution to science. +1/+1") self.r.test_for_paper_overflow(e_agent) return(Numms.YEP) elif move=='p': e_agent.papers = e_agent.papers + e_agent.n_members + 1 e_agent.reput -= 1 #wti("You got all the plagiarizz +2/-1") self.r.test_for_paper_overflow(e_agent) return(Numms.YEP) elif move=='a': if not " " in cmd: wth("Please specify the name of the target to attack") return(Numms.NOPE) name_patient = cmd.split(" ")[1] id_patient = self.get_id_from_name(name_patient) if not id_patient: wth("There is no player named %s." %name_patient) return(Numms.NOPE) e_patient = self.r.entities[id_patient] if e_agent.name==e_patient.name: wti("You used self-deprecation, which is fine") e_agent.reput -= 1 e_patient.papers -= e_agent.n_members #wti("Great job! Your attack got their papers retracted.") return(Numms.YEP) elif move=='d': status = -1 if status!=2: wth("Player is not in a group.") return(Numms.NOPE) self.r.d(e_agent) #wti("The group has been disbanded.") return(Numms.YEP) elif move=='g': if not " " in cmd: wth("Please specify an entity to group with") return(Numms.NOPE) name_patient = cmd.split(" ")[1] id_patient = self.get_id_from_name(name_patient) e_patient = self.r.entities[id_patient] if e_agent.name==name_patient: wth("Cannot group with yourself.") return(Numms.NOPE) elif not id_patient: wth("There is no player named '%s'." %name_patient) return(Numms.NOPE) elif e_patient.status==Numms.GROUPED: wth("Player %s is already in a group." %name_patient) return(Numms.NOPE) elif e_agent.n_members>=2 or e_patient.n_members>=2: wth("Group coalescing requires a VIP subscription.") return(Numms.NOPE) self.r.g(e_agent, e_patient) #wti("Academic friendship has formed") return(Numms.YEP) else: wth("Unknown command.") return(Numms.NOPE) game = DataManager() # all the code you'll ever need #endif // FSfK.py
It's a joke[edit | edit source]
This is the worst... thing I've ever written. Considering it displays all sorts of undocumented behavior, this implementation is very buggy and generally unplayable, but bugs have a mind of their own and they don't want to get fixed. Also remember: NO WARRANTY [sic] is given.