Python (programming language)/Fun

From Uncyclopedia, the content-free encyclopedia
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.