Python (programming language)/Fun

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==
## 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==
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.