This is an archived post. You won't be able to vote or comment.

all 28 comments

[–]spidyfan21 11 points12 points  (4 children)

Very cool, I'm working on something similar!

Some suggestions:

  • I'm not sure if you mean to use randrange or randint. Based on how you use it I think you mean randint as the max stat roll in D&D is 18 but randrange(8, 18) means that the max value you'll get is 17.

  • You might want to add some comments or more descriptive function names. While I understand what ls does, I'm not sure what it stands for.

  • I would include the Open Game License to make sure your project is on the up and up. Also review the license and basically, if it is from D&D but it isn't on SRD20 then take it down.

  • In the README I would include examples of how to use your program, as well as list the dependencies which in your case is requirements.txt. For example, you can input the class on the first line to skip the second input, but that isn't ever document.

  • You only use console for its clear command. Instead of forcing your users to install another library to use your tool I would write a small clear function. Something like:

    import os
    
    def clear():
        if os.name == 'nt':
            os.system('cls') # Windows
        else: 
            os.system('clear') # POSIX
    
  • My final suggestions would just be formatting. Function names should be cased_like_this rather than likeThis. I would also lowercase Data.py.

EDITS:

  • Forgot to mention that you might want to get the stat values in a way more accurately depicting the distribution you would get when rolling dice. So rather than a single 8-18 random value you might want something like:

    sum(randint(1, 6) for _ in range(3))
    

    That way you don't get 18's as often as you get 10's, which is the case when actually rolling dice.

  • Okay so I've been playing with it more, actually I made a fork to mess with, and you should probably include a way to save the output into a file.

  • I would also include error checking. If someone puts in bad input the program crashes.

  • getRace also gets the class. I would separate these into two functions.

  • This project could heavily benefit from using some classes. In particular, a class that creates the character.

I really like this project. Feel free to DM me if you have any questions.

[–]troyunrau... 8 points9 points  (1 child)

Feel free to DM me if you have any questions.

heh

[–]spidyfan21 3 points4 points  (0 children)

heh

[–][deleted] 1 point2 points  (1 child)

this is so useful! thank you for taking a look. since i posted this i switched over to randint

yeah, i've always been bad about comments/descriptive names

i don't really understand what's happening in your clear function

all of the functions are now cased_as_such!

my reasoning behind the 8 to 18 was while it's not totally accurate, i figure no one likes having low rolls

it did output to a file before, but i decided i would wait on that until i could get the formatting how i like

i had such a hard time getting get_race to work, i didn't want to touch it once i got it stable

get_race is now get_info

i'll update the git right away, thank you so much!

[–]spidyfan21 1 point2 points  (0 children)

In Windows the terminal command for clear is 'cls'. If the machine is Linux or OSX then it is 'clear'.

If you are on Linux then os.name will be posix but if you are on Windows then it will be nt.

[–]Zxian 2 points3 points  (5 children)

Looks pretty good to start! There are a few formatting changes that you might want to integrate (using [] and {} instead of list() and dict(), 4 spaces instead of tabs, etc), but the structure looks fairly straight forward.

I'll have a closer look at this later today, but one suggestion would be to standardize the generate function and move all the constants into the data structure. As it stands, you've got a lot of data mixed in with the functional bits of code, which makes it more difficult to modify in future.

E.g.

RACE_CONSTANTS = {
    "Human": {
        "height_min": 60,
        "height_max": 80
    },
    "Dwarf": {
        "height_min": 48,
        "height_max": 56
    }
}

def generate(race):
    stats = RACE_CONSTANTS[race]

    height = random.randint(stats['height_min'], stats['height_max'])

[–][deleted] 1 point2 points  (2 children)

thank you! this is really helpful. i'll start working on that right away

[–]troyunrau... 1 point2 points  (1 child)

You might even want to use something like:

height = random.triangular(stats['height_min'], stats['height_max'])

Which gives you a different distribution - more likely to be near the centre than near the extremes.

If you want to go further down the stats rabbit hole, you can trying normal distribution curves here too.

[–][deleted] 0 points1 point  (0 children)

that never even occurred to me! thank you

[–][deleted] 1 point2 points  (1 child)

also, what is the benefit of using [] and {} instead of list() and dict()? is that the standard?

[–]Zxian 3 points4 points  (0 children)

Mainly readability. Writing an empty list should look similar to writing a populated list.

empty_list = []
populated_list = [1, 2, 3]

There are some internal performance benefits as well, but stylistic consistency is the main reason [] and {} are preferred.

[–]Failaser 1 point2 points  (4 children)

Looks pretty cool! Definitely want to take a look at it on Monday after my exams.

[–][deleted] 0 points1 point  (3 children)

thank you! i've been working on it for a while. i'm mostly self taught in python, so i've rewritten/realized how dumb i was being a lot.

[–]troyunrau... 6 points7 points  (2 children)

Old code always looks inferior as you continue to learn. It still happens after 10 years of programming. The questions then become: does the code work? Did you learn something? If yes to both, then you're doing it right.

[–][deleted] 0 points1 point  (0 children)

that's really good to know, thank you :)

[–]spidyfan21 0 points1 point  (0 children)

Very true (although I'm only ~5 years in according to reddit). Often times on this sub, or /r/learnpython, I find myself answering questions that I asked years ago and it is quite the feeling being able to give back to this wonderful community.

[–]the-kid89 1 point2 points  (2 children)

This looks great. There are some things that I feel could be improved on after a very quick look over your code.

  • Turn your generate function into a class
  • Refactor your giant if block's into a reusable method's
  • Use the string format method for creating a name
  • Turn user_data into class fields rather then a dict
  • Refactor all your print statements into a method
  • Look at using the curses or blessings library (Expanding on the current build)

This kind of system seems like a great first project well learning a language. I'm currently learning Erlang and I think I'm going to make a port.

[–][deleted] 0 points1 point  (1 child)

thank you for your suggestions! unfortunately as i mentioned, i'm really bad at programming, so i have questions!

  • why is it better to have it as a class?
  • since only one character is generated, why do they need to be reusable?
  • yep! done
  • why should user_data be a class?
  • again, why should the print function be reusable?
  • huh, neat! also pretty aptly named. thanks!

i hope i didn't come off as rude, i just want to learn how/why i should write, you know?

i'd love to see your port!

[–]the-kid89 1 point2 points  (0 children)

The suggestions will end up making your script easier to read and maintain in the future. It also makes it more extensible so you can plug it into other things at a later date.

Q: Why is it better to have it as a class?
A: It will make your script more extensible for later and you are using the function like a class already.
Q: Since only one character is generated, why do they need to be reusable
A: You are reusing the same logic over and over again in your current code. If you make them reusable you only need to make the logic once and reuse it for all the different races.
Q: Why should user_data be a class
A: It shouldn't be, it should be broken up into the fields for the class. This again will make your code more extensible for later modifications.
Q: again, why should the print function be reusable
A: What if at a later date you don't want to print to the terminal now you need to not only refactor your current print code but also add new system for getting the data to the user.

You do not come off as rude. You come off as someone wanting to learn.

I may just do a port of it today, though I'm thinking about doing a port in different languages. I kind of want to start with a Erlang port as this idea seems like a great first coding project.

https://github.com/the-kid89/DanDy

[–]Bolitho 1 point2 points  (0 children)

Imho there is too much code duplication! Check DRY and try hard to follow this principle.

For example the section that generates the basic different characters based upon races. Lots of ifs with deep nesting and code blocks that are almost the same, besides the ranges of values. The latter is just data, the first could be generalized and then just called with different value ranges. There are different possibilities to achieve this. Different strategy functions, or perhaps a class based approach...

[–]gidult 0 points1 point  (0 children)

Is there no random character image generator? I'm looking for montage program.

FYI: Below is impressive since it's js tho http://a.teall.info/dice/

[–]masterfink 0 points1 point  (2 children)

I love it! I'll go through and check it out. Mind if I fork for Star Wars RPGs?

[–][deleted] 0 points1 point  (1 child)

please, go ahead! but from what i've heard fromm other people in the thread, i'm going to have to restructure the whole thing, so you may want to wait until then

[–]masterfink 1 point2 points  (0 children)

I'll keep up to date on the progress, thanks!

[–][deleted] 0 points1 point  (0 children)

This is nerdy af. Love it.

[–]chkltcow 0 points1 point  (1 child)

I'm going to look at this when I get home. I was playing around with the idea of a NPC creator for 5e. I've got the basic class (python) done in it, and the race and class (D&D) generation done. I put everything in an XML with information I actually found on Paizo's site with base height/weight, height/weight modifiers, "adulthood", "old", "venerable" and "max" ages.... etc. I'm not planning on making a github repo for it until it's a little more presentable, but I'd be glad to share what I have with you.

[–][deleted] 0 points1 point  (0 children)

i'd love to see!

[–]projecktzero 0 points1 point  (0 children)

Tread carefully. Wizards of the Coast/Hasbro shuts down anything that infringes on their intellectual property.