4
\$\begingroup\$

I'm developing a big (for me, as a beginner) terminal program "Brainfuck - The Game", in which you have to complete Brainfuck challenges. I would like your review on existing code (and project structuring) before I continue to expand it even more.

main.py

""" Brainfuck - the game. """

def main ():
    """ The main function. """
    print ("Type 'help' for a list of supported commands.")
    # Every command is a seperate method & has full access to shared class
    shared = m_shared.Shared()
    commands = { "help" : m_help.help,
                 "exit" : m_exit.exit }
    # The loop
    while shared.is_running:
        commands[shared.prompt_command(shared.COMMANDS)](shared)

if __name__ == "__main__":
    # Here and further on "m_" stands for "module"
    import m_shared
    import m_help
    import m_exit
    main()

m_shared.py

""" A module that contains Shared class. """

import m_statscontainer

class Shared (object):
    """ Holds everything that's shared among command functions. """

    # Subclasses that help to divide this huge class into some smaller chunks
    stats_container = m_statscontainer.Stats_Container()

    # Constants
    COMMANDS = ["help", "exit", "run", "open", "save", "setcell", "def",
                "code", "limit", "del", "edit", "reset", "debug", "memo",
                "brainfuck", "challenge", "random", "stats", "credits"]
    DEFAULT_STEP_LIMIT = 10000 # Protects program from infinite loops

    # Variables
    is_running = True
    last_input = []
    # Variables for the brainfuck program
    limit = DEFAULT_STEP_LIMIT
    memory_world = {}
    definitions = {}
    code = []
    compiled_code = []

    # Methods
    def __init__(self):
        """ Initializes the Shared class. """
        pass

    def prompt_command(self, valid_commands):
        """ Repeatedly prompts input unitl valid command can be returned. """
        user_input = []
        while user_input == [] or user_input[0] not in valid_commands:
            # Prompt input
            user_input = input(">> ").lower().split()
            if user_input != [] and user_input[0] not in valid_commands:
                if self.easter_egg(' '.join(user_input)):
                    continue
                print ("'{}' is not a supported command.".format(user_input[0]))
            # Collect data
            self.stats_container.collect_command_data(user_input, valid_commands)
        # Return successfully if correct command is entered
        self.last_input = user_input
        return user_input[0]

    def easter_egg(self, user_input):
        # TODO: make this a dictionary and extended to, like, 100 phrases
        if user_input == "if you're happy and you know it, clap your hands!":
            print ("*clap* *clap*")
        elif user_input == "if you're happy and you know it, syntax error!":
            print ("Syntax error!")
        elif user_input == "happy":
            print ("'happy' was unexpected at this time.")
        elif user_input == "bug":
            print ("It's not a bug, it's a feature!")
        else:
            return False
        return True

m_statscontainer.py contains a blank Stats_Container class

m_help.py

""" A module that contains the help command related stuff. """

COMMAND_INFORMATION = {
    "help"      : "",
    "exit"      : "",
    "run"       : "",
    "open"      : "",
    "save"      : "",
    "setcell"   : "",
    "def"       : "",
    "code"      : "",
    "limit"     : "",
    "del"       : "",
    "edit"      : "",
    "reset"     : "",
    "debug"     : "",
    "memo"      : "",
    "brainfuck" : "",
    "challenge" : "",
    "random"    : "",
    "stats"     : "",
    "credits"   : "" }

def help(shared):
    if len(shared.last_input) == 1:
        print ("Supported commands:", ', '.join(shared.COMMANDS))
        print ("Type 'help' [command] for more information about that command.")
    else:
        if shared.last_input[1] in shared.COMMANDS:
            print (COMMAND_INFORMATION[last_input[1]])
        else:
            print ("No information available about '{}' command", \
                   format(sharedlast_input[1]))

m_exit.py

""" A module that contains the exit command related stuff. """

def exit(shared):
    print ("Goodbye!")
    shared.is_running = False
\$\endgroup\$
4
\$\begingroup\$

I have a few minor comments, like "move the import statements to the top", but my biggest concern is the confusing structure. Why do you need a class? A warning sign that something isn't a class, or shouldn't be a class, is a class with two methods, one of which is __init__. Your init is even empty. Okay, your class has three methods, but I'd still count that.

Why do you need so many modules? The most worrying example of this is, I think, m_exit.py. If you start writing modules for a single two-line function, there's something wrong.

\$\endgroup\$
  • \$\begingroup\$ The Shared class will get bigger. I need a class because I need variables and functions that can be shared among every command method and stay in memory throughout runtime. What about consistency? If every command will have a separate module, shouldn't it be so in every case no matter the command module size? Some command modules will be bigger than others, but everyone will have a separate module for consistency. \$\endgroup\$ – Marius Macijauskas Apr 11 '15 at 14:40
  • 1
    \$\begingroup\$ Am I wrong in assuming you will never have more than one instance of your class? You don't necessarily need a class for "variables and functions that can be shared among every command method and stay in memory throughout runtime". Data can be given to functions through parameters (which makes it more readable anyways, in my opinion), even across modules. But okay, without seeing how your full program will look like eventually, it's hard to judge. I'm just saying: In the current state of your code, I would definitely not use a class. \$\endgroup\$ – L3viathan Apr 11 '15 at 14:53
  • 4
    \$\begingroup\$ @MariusMacijauskas - As a side-note, from a site-scope perspective, arguing about "what will be needed" is a strong indication that the question is off-topic because the code is not yet working the way it is intended to work. The "what if" game is not on-topic here, only the code presented in the question. \$\endgroup\$ – rolfl Apr 11 '15 at 14:56
  • 1
    \$\begingroup\$ Thank You. Moved imports to the top, added docstrings, expanding the class and modules. I'm sorry if this is a bit off-topic, I just wanted to know if I'm not doing a complete nonsense in structural terms before I expand it. Going to post a vastly bigger version soon to fill in the missing context. \$\endgroup\$ – Marius Macijauskas Apr 11 '15 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.