2015-09-03 08:22:54

Hi, I am working my way through the python tutorial "Learn Python the Hard Way." I have made it up to while loops and I thought I would try and create a simple dice roll game. The game has a player 1 and player 2, and uses two dice. The first to 100 wins.
I reasoned out one way to create the dice roll, but I was wondering how would you go about creating a dice roll and get the same result as this by using functions. I know that it is better practice to organize your code by using functions.  Every time I try to write this program using functions though, I run into a issue where I need to call a variable from another function, but I have read in multiple places that using global variables is bad practice. So, can someone help me figure out the logic for this? I am using python 3.

Here is my code.


from random import randrange

score1 = 0;
score2 = 0
turn = 0;
while True == True:
    dice = [randrange(1, 7), randrange(1, 7)]
    print ("Press enter to roll...");
    roll = input();
    while roll == "":
        print ("You rolled:");
        for i in dice:
            print (i);
        turn += 1;
        break;
    if (turn % 2 == 0):
        score2 = score2 + dice[0] + dice[1]
    else:
        score1 = score1 + dice[0] + dice[1];
    print ("player 1's score is: %d \nPlayers 2 score is: %d" %(score1, score2));
    if (score1 >= 100 or score2 >= 100):
        print ("Congratulations! you won");
        break;


TJ Breitenfeldt

2015-09-03 10:07:43 (edited by magurp244 2015-09-03 10:20:50)

Its written in Python 2.7.10 so it may require a little tweaking, but this might help:

import random

class dice(object):
    def __init__(self):
        self.score1 = 0
        self.score2 = 0

        self.roll = [0,0]

        self.update()

    def roll_dice(self):
        self.roll = [random.randint(1,7),random.randint(1,7)]

    def update(self):
        while True:
            print('Press enter to roll...')
            box = raw_input()

            if box == 'q':
                break

            self.roll_dice()
            print('You Rolled '+str(self.roll[0])+' and '+str(self.roll[1]))
            self.score1 += sum(self.roll)

            self.roll_dice()
            print('Opponent Rolled '+str(self.roll[0])+' and '+str(self.roll[1]))
            self.score2 += sum(self.roll)

            if self.score1 >= 100:
                print("Congradulations! You win!")
                break

            elif self.score2 >= 100:
                print("You lost!")
                break


dice()
-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2015-09-03 12:49:32

Hi there,

Magurp244 has been faster than me smile) He answered while I tried to understand python syntax a bit... His code is much more advanced and object oriented, but for a quick revision of your own code, take a look to the following:

from random import randrange
def generateNumbers():
    result = [randrange(1, 7), randrange(1, 7)]
    return result

goal = 25;
score1 = 0;
score2 = 0
turn = 0;
while True == True:
    dice = generateNumbers()
    print ("Press enter to roll...");
    roll = input();
    while roll == "":
        print ("You rolled:");
        for i in dice:
            print (i);
        turn += 1;
        break;
    if (turn % 2 == 0):
        score2 = score2 + dice[0] + dice[1]
    else:
        score1 = score1 + dice[0] + dice[1];
    print("player 1's score is: %d \nPlayers 2 score is: %d" %(score1, score2));
    if (score1 >= goal):
        print ("Congratulations! you won");
        break;
    if (score2 >= goal):
        print("Sorry, you loose!");
        break;

It's my first attempt to code in python, using python 3.4, so don't expect much... Oh, and really I don't understand some of those breaks... but it runs big_smile

Talking about global variables, I cannot figure out why someone prevent you from using global variables. In fact, some variables you used (score, turn...) are global variables. It's specially hard to avoid their use working under a non object oriented paradigm as you did in your example, you will need a place to store and share information sooner or later.

2015-09-03 15:00:00

the reason people say not to use global variables, is that this one variable is jumping all around to many different scopes of the program and being modified all the way. so if a bug comes up based on that global variable, it probably will be much harder to pin point exactly what is causing that error if it is global vs local. the idea of structuring your coding into classes and the like does help with some of that. also, using the return statement after functions does help as well.
i'm not sure if the random module differs between python 2 and 3, but i used random.randint(1,6). might just be about the same thing.
fyi, i'd never use true as a variable name. you want to avoid names like that that are already in python, true, false, print, class, and i/j/p. there are probably a few others.

I don’t believe in fighting unnecessarily.  But if something is worth fighting for, then its always a fight worth winning.
check me out on Twitter and on GitHub

2015-09-03 20:41:15

Thanks guys this helped a lot. I have not gotten to using classses yet, but I do see how that would work. I forgot about the return statement to return a value and then use it else where in the program.

I was not intending to create a variable called True, I just wanted a simple generic way of creating a endless loop that I could terminate with conditionals. I thought that you could define the Boolean value True and set it equal to the Boolean value of True to get the endless loop. I don't think I actually created a variable there, I believe both values of True are Boolean values.

2015-09-03 23:15:20

you can create a variable named true (lowercase t) and set it to the boolean value of True (capitol t). but as i said, thats not very good practice. for example, if you are making a while loop to loop until a specific number is rolled i might use:

target_rolled = False
while not target_rolled:
    #blah blah blah code

but you see. use a variable that pertains to what it is you're doing.

I don’t believe in fighting unnecessarily.  But if something is worth fighting for, then its always a fight worth winning.
check me out on Twitter and on GitHub

2015-09-03 23:52:11

I understand. Thank you. I had another question though, I tried to do what Alan recommended by creating the function and returning the value, but I can't seem to get it to work. The error I am getting is that "dice" (my list of die in the function) is undefined.
Can someone help me again.

Here is my code.

from random import randrange

score1 = 0;
score2 = 0
turn = 0;

def DiceList():
    dice = [randrange(1, 7), randrange(1, 7)];
    return dice;

while turn >= 0:
    DiceList();
    print ("Press enter to roll...");
    roll = input();
    while roll == "":
        print ("You rolled:");
        for i in dice:
            print (i);
        turn += 1;
        break;
    if (turn % 2 == 0):
        score2 = score2 + dice[0] + dice[1]
    else:
        score1 = score1 + dice[0] + dice[1];
    print ("player 1's score is: %d \nPlayers 2 score is: %d" %(score1, score2));
    if (score1 >= 100 or score2 >= 100):
        print ("Congratulations! you won");
        break;

2015-09-04 01:01:52

When returning things from functions you have to store it in a variable or it will be lost. For example:

result = DiceList()

This will call Dicelist() which return's dice, its then stored in the result variable for handling. So making that little adjustment it should work fine.

from random import randrange

score1 = 0
score2 = 0
turn = 0

def DiceList():
    dice = [randrange(1, 7), randrange(1, 7)]
    return dice

while turn >= 0:
    dice = DiceList()
    print ("Press enter to roll...")
    roll = raw_input()
    while roll == "":
        print ("You rolled:")
        for i in dice:
            print (i)
        turn += 1
        break
    if (turn % 2 == 0):
        score2 = score2 + dice[0] + dice[1]
    else:
        score1 = score1 + dice[0] + dice[1]
    print ("player 1's score is: %d \nPlayers 2 score is: %d" %(score1, score2))
    if (score1 >= 100 or score2 >= 100):
        print ("Congratulations! you won")
        break
-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2015-09-04 01:54:23

Thank you so much. I got it working. This has helped me get a better handle on functions.

2015-09-04 02:03:27 (edited by frastlin 2015-09-04 02:08:03)

OK, first, that is a little too simple for functions, just use if statements to check it. You need to add something like random turns to make it more reusable. Either that, or add a main menu and whatnot. Here is the basic game, then I will show you when you would use while True:

import random

def roller(player):
    """Pass in the player list and it will roll, print the roll, print the total and return the total."""
    r = random.randint(1, 6)
    player[1] += r
    print("%s rolled %s. Now their score is %s/100" % (player[0], r, player[1]))

def change_turn(current_player, player_list):
    """This is called an iterator and it is a built-in object, but because we are just doing a basic alternator, this is probably better"""
    if current_player[0] == player_list[0][0]:
        return player_list[1]
    else:
        return player_list[0]

def main():
    """This is a nice little trick that will keep you from using global variables. Instead you are using the variables in the main function. Another trick is to use variables in another module which you will see later in Learn Python the Hard Way."""
    player1 = ["Player1", 0]
    player2 = ["Player2", 0]
    player_list = [player1, player2]
    #The next line chooses a random player to start
    current_player = random.choice(player_list)
    winner = None
    print("Welcome to the player dice roler!\n%s is first:" % current_player[0])
    while not winner: #What you were looking for is: while True: but frankly you only use that if you don't want the game to ever stop.
        roller(current_player)
        if current_player[1] >= 100:
            winner = current_player
        else:
            current_player = change_turn(current_player, player_list)
        print("%s: %s, %s: %s" % (player1[0], player1[1], player2[0], player2[1]))
        raw_input("Press return to continue\n")
    print("And the winner is: %s!!! With a final score of %s" % (winner[0], winner[1]))

main()

OK, so here is when you don't want your players to leave:

import random

def roller(player):
    """Pass in the player list and it will roll, print the roll, print the total and return the total."""
    r = random.randint(1, 6)
    player[1] += r
    print("%s rolled %s. Now their score is %s/100" % (player[0], r, player[1]))

def change_turn(current_player, player_list):
    """This is called an iterator and it is a built-in object, but because we are just doing a basic alternator, this is probably better"""
    if current_player[0] == player_list[0][0]:
        return player_list[1]
    else:
        return player_list[0]

def game():
    """We just change the title here so it is not main which is used for the master function"""
    player1 = ["Player1", 0]
    player2 = ["Player2", 0]
    player_list = [player1, player2]
    #The next line chooses a random player to start
    current_player = random.choice(player_list)
    winner = None
    print("Welcome to the player dice roler!\n%s is first:" % current_player[0])
    while not winner: #What you were looking for is: while True: but frankly you only use that if you don't want the game to ever stop.
        roller(current_player)
        if current_player[1] >= 100:
            winner = current_player
        else:
            current_player = change_turn(current_player, player_list)
        print("%s: %s, %s: %s" % (player1[0], player1[1], player2[0], player2[1]))
        raw_input("Press return to continue\n")
    print("And the winner is: %s!!! With a final score of %s" % (winner[0], winner[1]))

def main():
    """Adds a main menu to the game"""
    message = "What would you like to do?\n1. New Game!\n2. exit :("
    print(message)
    while True:
        choice = raw_input("> ")
        if choice == "1":
            game()
            print(message)
        elif choice == "2":
            break


main()

classes make things a whole lot nicer and so do dictionaries, but lists are the most basic. (*huge hint: an instance of a class, dictionary, list and module are pretty much all the same thing.)
Thus saying, can you change this so it uses a dict rather than a list, then when you start classes, can you make a player class rather than a dict?

2015-09-04 02:17:25

Wow, thanks Frastlin I think this is exactly what I wanted. This is a little confusing, but I have learned all of these concepts, so I am going to study your code to try and figure out exactly what your doing.

2015-09-04 02:20:32

Is there any difference between using random.randint and random.randrange?

2015-09-04 02:41:23

Randint return's a single number between x and y. Randrange works very similarly, but you can also configure it to skip sets of numbers. For example, if you write:

random.randrange(0,10,2)

It will return a random number by two step intervals, such as 0, 2, 4, 6, 8, and 10. If you write:

random.randrange(0,100,10)

It will return a random number at ten step intervals, such as 0, 10, 20, 30, etc.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2015-09-04 03:19:28

Hi
Post 7, I have a question.
How to specify the end of the function in python?
Other programing languages use brackets or function, end function keyword, but python does not. We define a function using def keyword. And We write the body of the function. And how to specify the end of the function?

2015-09-04 03:26:38

Functions in python use indentation, so once you stop indenting python knows that everything else is not in the function.

example:

function example():
    print ("This line is indented four spaces");
    print ("All lines in the function must be indented the equal amount of space");
print ("this is not apart of the function because it is not indented and against the margin.");

2015-09-04 03:37:24

Hi
Thanks so much. One more question. Can I use more then one statements with many spaces, like brackets in other languages?

2015-09-04 03:47:12

I am not sure if I understand what you mean by "more then one statements"

You can stack indentations though. Say you have a function and an if statement inside that function, the code with in an if statement is indented just like a function, but because the function has already indented the if statement you would now have to indent the code for the if statement 8 spaces rather than 4 spaces. That may have been confusing, here is an example.

def example():
    print ("this is a line inside the function that is indented 4 spaces");
    if (5 > 3):
        print ("5 is greater than 3. This is indented 8 spaces because you have to indent the code for the if statement");
print ("this is outside the print statement");

you can nest as many statements as you want inside each other like any other language, but you have to keep track of the spacing.

2015-09-04 03:57:52

Then, Can I define a function, indent it with two spaces, Use the if statement, and Can I just end up just the if statement in the function by decreasing a space?
Sorry for my lots of questions. Lol indentation is very confusing

2015-09-04 04:12:17

Yes, you can use any number of spaces as far as I can tell, however using 4 spaces or the tab key seems to be the standard. I have heard in a couple places not to use tabs, but I think it is just preference. I use tabs because it is much easier to work with and Jaws reads tabs very well in ed sharp (the text editor I use). Also, it is not as time consuming having to press the space bar so many times, and you can still stick with the standard since a tab is equal to 4 spaces.

note: I used spaces in my post because it seems to be easier for jaws to identify the indentation since he only reads blank if you are navigating character by character. if you use a screen reader I recommend turning on the setting so that the screen reader will read indents at least just for your preferred tool for editing python code.

2015-09-04 04:23:18

*Note* you don't need to put ; at the end of your lines.
Yes, if you go out an indentation it is like putting a }
Here is sudo javascript python using braces to show you what is going on.
def my_function(){
print("Hello world")
}

so no return is needed, it does it for you. It automatically does:
return None
which is void. As an example:
def my_func(blah):
  if blah.startswith("h"):
    if blah.endswith("d"):
      print("Hello world")
    elif blah.endswith("k"):
      print("No idea")
  else:
    print("Maybe your name?")

You can also make a function in a function, but there is very few reasons for it:
def func1():
  def func2(joe):
    print(joe)
  print("Outside the second function's deffinition, but before the return of function1")
  return function2

function1("My name is frastlin")

2015-09-04 04:36:59

Use tabs for you and do a replace and replace \t with      when giving your code to other people.
(\t = tab)

2015-09-04 06:56:35

Thanks for answering my questions.

2015-09-04 22:52:38

When writing code like what frastlin posted above using so many functions, it seems that you have to work backwards starting near the end of the code and writing upwards. Is this the case, or do most people just learn to plan out the program completely first, and have the ability to think backwards.

2015-09-05 00:51:22

I'm curious, why are people using Python three? The Python the Hard Way tutorial specifically says 2.7.9. Is there any particular reason to use three, other than the fact that it's the latest version?

2015-09-05 02:17:49

@TJ.Breitenfeldt
As a general rule, a program can't use a function that hasn't been defined yet, so for example writing:

stuff()
def stuff():
    print 'stuff'

Would cause an error because the function was called before its code was actually defined. In the case of classes this isn't as much of an issue, though you can still run into a few quirks.


@Orin
Python 3 was written to solve various design flaws in Python 2.x, as well as other technical and performance issues. The problem however is that Python 3.x broke compatibility with Python 2.x, which meant that all the API's and tools developed for 2.x wouldn't work. This more than anything else has slowed peoples transition, a number of libraries since then have added 3.x support, but there are still API's, and/or API's that aren't maintained anymore, that haven't. There are other tutorials out there that cover 3.x specifically, and the differences in syntax and work flow between the two are relatively minor.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer