Search code examples
pythonpython-3.xfiledirectory-structurecodeanywhere

Is it better to have multiple files for scripts or just one large script file with every function?


I started a project about a year ago involving a simple terminal-based RPG with Python 3. Without really thinking about it I just jumped into it. I started with organizing multiple scripts for each.. well, function. But halfway into the project, for the end goal I'm not sure if it's easier/more efficient to just have one very large script file or multiple files.

Since I'm using the cmd module for the terminal, I'm realizing getting the actual app running to be a looping game might be challenging with all these external files, but at the same time I have a __init__.py file to combine all the functions for the main run script. Here's the file structure.

File Structure

To clarify I'm not the greatest programmer, and I'm a novice in Python. I'm not sure of the compatibility issues yet with the cmd module.

So my question is this; Should I keep this structure and it should work as intended? Or should I combine all those assets scripts into one file? Or even put them apart of the start.py that uses cmd? Here's the start function, plus some snippets of various scripts.

start.py

from assets import *
from cmd import Cmd
import pickle
from test import TestFunction
import time
import sys
import os.path
import base64

class Grimdawn(Cmd):

    def do_start(self, args):
        """Start a new game with a brand new hero."""
        #fill
    def do_test(self, args):
        """Run a test script. Requires dev password."""
        password = str(base64.b64decode("N0tRMjAxIEJSRU5ORU1BTg=="))
        if len(args) == 0:
            print("Please enter the password for accessing the test script.")
        elif args == password:
            test_args = input('> Enter test command.\n> ')
            try:
                TestFunction(test_args.upper())
            except IndexError:
                print('Enter a command.')
        else:
            print("Incorrect password.")
    def do_quit(self, args):
        """Quits the program."""
        print("Quitting.")
        raise SystemExit


if __name__ == '__main__':

    prompt = Grimdawn()
    prompt.prompt = '> '
    #ADD VERSION SCRIPT TO PULL VERSION FROM FOR PRINT
    prompt.cmdloop('Joshua B - Grimdawn v0.0.3 |')

test.py

from assets import *
def TestFunction(args):
    player1 = BaseCharacter()
    player2 = BerserkerCharacter('Jon', 'Snow')
    player3 = WarriorCharacter('John', 'Smith')
    player4 = ArcherCharacter('Alexandra', 'Bobampkins')
    shop = BaseShop()
    item = BaseItem()
    #//fix this to look neater, maybe import switch case function
    if args == "BASE_OFFENSE":
        print('Base Character: Offensive\n-------------------------\n{}'.format(player1.show_player_stats("offensive")))
        return
    elif args == "BASE_DEFENSE":
        print('Base Character: Defensive\n-------------------------\n{}'.format(player1.show_player_stats("defensive")))
        return

 *   *   *

player.py

#import functions used by script
#random is a math function used for creating random integers
import random
#pickle is for saving/loading/writing/reading files
import pickle
#sys is for system-related functions, such as quitting the program
import sys
#create a class called BaseCharacter, aka an Object()
class BaseCharacter:
    #define what to do when the object is created, or when you call player = BaseCharacter()
    def __init__(self):
        #generate all the stats. these are the default stats, not necessarily used by the final class when player starts to play.
        #round(random.randint(25,215) * 2.5) creates a random number between 25 and 215, multiplies it by 2.5, then roudns it to the nearest whole number
        self.gold = round(random.randint(25, 215) * 2.5)
        self.currentHealth = 100
        self.maxHealth = 100
        self.stamina = 10
        self.resil = 2
        self.armor = 20
        self.strength = 15
        self.agility = 10
        self.criticalChance = 25
        self.spellPower = 15
        self.intellect = 5
        self.speed = 5
        self.first_name = 'New'
        self.last_name = 'Player'
        self.desc = "Base Description"
        self.class_ = None
        self.equipment = [None] * 6
    #define the function to update stats when the class is set
    def updateStats(self, attrs, factors):
        #try to do a function
        try:
            #iterate, or go through data
            for attr, fac in zip(attrs, factors):
                val = getattr(self, attr)
                setattr(self, attr, val * fac)
        #except an error with a value given or not existing values
        except:
            raise("Error updating stats.")
    #print out the stats when called
    #adding the category line in between the ( ) makes it require a parameter when called
    def show_player_stats(self, category):
 *   *   *

note

The purpose of the scripts is to show what kind of structure they have so it helps support the question of whether I should combine or not


Solution

  • The way you have it currently is fine, personally I much prefer a lot of files as it's a lot easier to maintain. The main issue I see is that all of your code is going under assets, so either you'll end up with everything dumped there (defeating the point of calling it that), or you'll eventually end up with a bit of a mess of folders once you start coding other bits such as the world/levels and so on.

    A quite common way of designing projects is your root would be Grimdawn, which contians one file to call your code, then all your actual code goes in Grimdawn/grimdawn. I would personally forget the assets folder and instead put everything at the root of that folder, and only go deeper if some of the files get more complex or could be grouped.

    I would suggest something like this (put in a couple of additions as an example):

    Grimdawn/characters/Jon_Snow
    Grimdawn/characters/New_Player
    Grimdawn/start.py
    Grimdawn/grimdawn/utils/(files containing generic functions that are not game specific)
    Grimdawn/grimdawn/classes.py
    Grimdawn/grimdawn/combat.py
    Grimdawn/grimdawn/items.py
    Grimdawn/grimdawn/mobs/generic.py
    Grimdawn/grimdawn/mobs/bosses.py
    Grimdawn/grimdawn/player.py
    Grimdawn/grimdawn/quests/quest1.py
    Grimdawn/grimdawn/quests/quest2.py
    Grimdawn/grimdawn/shops.py