Dice game where two players try to get to 49

Is there an easier way to make a dice game where 2 people roll a dice to try and get to 49?

If there is, the program should output the person who has won. After the game has ended, please use the raise SystemExit function to leave the game.

Also, there are some obstacles that you should keep:

• If you roll a double, then move back one space.

• If you roll one amount which is two times larger than another, then move back three spaces.

from random import randint
aa = 0
a = 0
while a < 48:
print ("(P1) You are on square" , a)
b = input("(P1) Press enter to roll the first dice.")
c = (randint(0, 6))
print("The first number you rolled was" , c)
d = (randint(0, 6))
print("The second number you rolled was" , d)
if c == d:
print("They were doubles...")
print("1 square will be taken off if you have moved already")
if a < 1:
print("You will not lose anything.")
print ("(P2) You are on square" , aa)
bb = input("(P2) Press enter to roll the first dice.")
cc = (randint(0, 6))
print("The first number you rolled was" , cc)
dd = (randint(0, 6))
print("The second number you rolled was" , dd)
if cc == dd:
print("They were doubles...")
print("1 square will be taken off if you have moved already")
if aa < 1:
print("You will not lose anything.")
else:
print("You will lose 1 square")
aa = aa - 1
print("Your new amount of squares is" , aa)
elif cc * 2 == dd or cc == dd * 2:
print("One amount was two times bigger than the other...")
print("3 squares will be taken off if you are over 2 squares")
if aa < 3:
print("You will not lose anything.")
else:
print("You will lose 3 squares")
aa = aa - 3
print("Your new amount of squares is" , aa)

else:
ee = cc + dd
print(ee , "will be added...")
aa = aa + ee
if aa > 48:
print("(P2) You have won the game!")
raise SystemExit
else:
print("You will lose 1 square")
a = a - 1
print ("(P2) You are on square" , aa)
bb = input("(P2) Press enter to roll the first dice.")
cc = (randint(0, 6))
print("The first number you rolled was" , cc)
dd = (randint(0, 6))
print("The second number you rolled was" , dd)
if cc == dd:
print("They were doubles...")
print("1 square will be taken off if you have moved already")
if aa < 1:
print("You will not lose anything.")
else:
print("You will lose 1 square")
aa = aa - 1
print("Your new amount of squares is" , aa)
elif cc * 2 == dd or cc == dd * 2:
print("One amount was two times bigger than the other...")
print("3 squares will be taken off if you are over 2 squares")
if aa < 3:
print("You will not lose anything.")
else:
print("You will lose 3 squares")
aa = aa - 3
print("Your new amount of squares is" , aa)

else:
ee = cc + dd
print(ee , "will be added...")
aa = aa + ee
if aa > 48:
print("(P2) You have won the game!")
raise SystemExit

elif c * 2 == d or c == d * 2:
print("One amount was two times bigger than the other...")
print("3 squares will be taken off if you are over 2 squares")
if a < 3:
print("You will not lose anything.")
print ("(P2) You are on square" , aa)
bb = input("(P2) Press enter to roll the first dice.")
cc = (randint(0, 6))
print("The first number you rolled was" , cc)
dd = (randint(0, 6))
print("The second number you rolled was" , dd)
if cc == dd:
print("They were doubles...")
print("1 square will be taken off if you have moved already")
if aa < 1:
print("You will not lose anything.")
else:
print("You will lose 1 square")
aa = aa - 1
print("Your new amount of squares is" , aa)
elif cc * 2 == dd or cc == dd * 2:
print("One amount was two times bigger than the other...")
print("3 squares will be taken off if you are over 2 squares")
if aa < 3:
print("You will not lose anything.")
else:
print("You will lose 3 squares")
aa = aa - 3
print("Your new amount of squares is" , aa)

else:
ee = cc + dd
print(ee , "will be added...")
aa = aa + ee
if aa > 48:
print("(P2) You have won the game!")
raise SystemExit
else:
print("You will lose 3 squares")
a = a - 3
print("Your new amount of squares is" , a)
print ("(P2) You are on square" , aa)
bb = input("(P2) Press enter to roll the first dice.")
cc = (randint(0, 6))
print("The first number you rolled was" , cc)
dd = (randint(0, 6))
print("The second number you rolled was" , dd)
if cc == dd:
print("They were doubles...")
print("1 square will be taken off if you have moved already")
if aa < 1:
print("You will not lose anything.")
else:
print("You will lose 1 square")
aa = aa - 1
print("Your new amount of squares is" , aa)
elif cc * 2 == dd or cc == dd * 2:
print("One amount was two times bigger than the other...")
print("3 squares will be taken off if you are over 2 squares")
if aa < 3:
print("You will not lose anything.")
else:
print("You will lose 3 squares")
aa = aa - 3
print("Your new amount of squares is" , aa)

else:
ee = cc + dd
print(ee , "will be added...")
aa = aa + ee
if aa > 48:
print("(P2) You have won the game!")
raise SystemExit
else:
e = c + d
print(e , "will be added.")
a = a + e
print ("(P2) You are on square" , aa)
bb = input("(P2) Press enter to roll the first dice.")
cc = (randint(0, 6))
print("The first number you rolled was" , cc)
dd = (randint(0, 6))
print("The second number you rolled was" , dd)
if cc == dd:
print("They were doubles...")
print("1 square will be taken off if you have moved already")
if aa < 1:
print("You will not lose anything.")
else:
print("You will lose 1 square")
aa = aa - 1
print("Your new amount of squares is" , aa)
elif cc * 2 == dd or cc == dd * 2:
print("One amount was two times bigger than the other...")
print("3 squares will be taken off if you are over 2 squares")
if aa < 3:
print("You will not lose anything.")
else:
print("You will lose 3 squares")
aa = aa - 3
print("Your new amount of squares is" , aa)

else:
ee = cc + dd
print(ee , "will be added...")
aa = aa + ee
if aa > 48:
print("(P2) You have won the game!")
raise SystemExit

else:
print("(P1) You have won the game!")
raise SystemExit

The simple answer is "yes". But let's take a look at why that's true and how you could make this look better.

First some general notes:

1. Variable Names: In static typed languages it's common to use short names for variables in part because writing out the types provides some documentation. In Python however no such hints exist so we use longer variable names.

2. Grouping Like Things: your code has no data structure to keep each player's information together so things like roles, position, etc are all jumbled together.

3. Reusable Code: Not using a data structure also means that adding players beyond the first is greater than linear effort: you have to write out all the same new variables for each new player, and implement a new level to your loops and if/else statements to handle them. If instead we create a data structure for player information, we can easily create a new instance of that structure for each player. If we then keep the instances in a list, we can iterate over them and reuse the same code to play out each player's turn.

Now some actual code...

Let's make a data structure for players using a dictionary. We could also use a class, but since this game only keeps track of two things: player and position, a dictionary will do. (Note: I'm writing all this in the browser and not checking it for perfect syntax and execution, but the goal is merely to give you an idea what to do, not to do it for you.)

# init player positions
players = {"1": 0, "2": 0 }

The keys are our player numbers, and the values are their position. Now we can iterate over the dict for each players turn.

for player, position in players.items(): #in python2 this would be players.iteritems()
print(''.join(["It's player", player, "'s turn"]))
print("Press any key to roll!")

# rolls are rolls so lets keep them in a list instead of separate variables
# this will also let us do list comprehensions!
rolls = []
# make two rolls
for roll in range(2):
rolls.append(randint(0, 6))
print(''.join(["you rolled ", rolls[-1]]))

if rolls == rolls:
print("oh no doubles!")
if position > 0:
print("you move back one")
players[player] -= 1
else:
print("you're already at 0. at least it can't get worse")
continue # end turn after doubles

# now we have to check if one roll was double the other.
# to simplify the logic, let's order the rolls
rolls.sort()

# do the roll1 2x roll2 check
if rolls*2 < rolls:
print("oh no! One roll more than double the other!!1")
if position > 3:
print("you move back 3!")
players[player] -= 3
else:
print("you haven't moved more than 3. At least it can't get worse!")
players[player] = 0
continue # end turn of we moved backwards

# we didn't move backwards, so we get to move forwards!
players[player] += sum(rolls)
print(''.join(["you move to ", players[player]]))

# check if we won!
if players[player] > 48:
print("you win!")
raise SystemExit
• I am far from a Python expert, but I'm not familiar with this "some string".join(variable).join("some other string") idiom. Is there a reason that you're doing that instead of the far more common "some string {} some other string".format(variable)? – MikeTheLiar Nov 29 '17 at 22:39
• Since you're not using the roll, range(2) may be more readable than range(1,3). – viraptor Nov 29 '17 at 23:10
• Good call viraptor. Fixed. Also fixed up my string.joins cause those were just wrong. @mikeTheLiar ''.join([list of strings]) is the fastest way to join strings in python see: stackoverflow.com/a/1350289/3626160 – TheAtomicOption Nov 30 '17 at 0:01
• There are still some weird joins left, where you should use format. Also, if rolls == rolls: has an off-by-one error, since you only generate two rolls. – Graipher Nov 30 '17 at 7:31
• This is a simple example that is not speed conscious. So you should be writing the most readable, maintainable code, not the fastest code. – Snowbody Nov 30 '17 at 20:24

thanks for sharing your code!

There are a few pretty big issues with your current code.

Variable Names

Your current variable names tell us absolutely nothing about what the variable is, or what it's doing.

a and aa tell us nothing. If someone needs to read through your code following a poorly named variable just to find out it's purpose, that's not a good thing! Remember, other people reading your code didn't write it, they won't know what each variable is unless it has a clear, meaningful name.

Let's just look at this short snippet

print ("(P1) You are on square" , a)
b = input("(P1) Press enter to roll the first dice.")
c = (randint(0, 6))
print("The first number you rolled was" , c)
d = (randint(0, 6))
print("The second number you rolled was" , d)

in 6 lines we have 4 mystery variables. Now, of course I can make a stab at what these are based on context, but I should be able to know what they are from their names! How about this instead:

print ("(P1) You are on square" , player_one_square)
input("(P1) Press enter to roll the first dice.")
rolled_number = (randint(0, 6))
print("The first number you rolled was" , rolled_number)
rolled_number = (randint(0, 6))
print("The second number you rolled was" ,  rolled_number)

Now, these variables have names that indicate what they are, rather than just a single letter.

Also notice I got rid of b completely, you were calling input for the effect of prompting for them to press enter, we're not actually using it so we don't need to save it into a variable!

Something that's sorely lacking from your program is the use of functions. Functions have many benefits, in this particular case, they are a way of re-using code, but also a way of making the code more readable.

A prime candidate here is the constant use of randint(0, 6). Why not put this in a function instead.

def roll():
return random.randint(0, 6)

Now here, we're still using the same number of lines (1), but this gives more meaning to the code.

Code can now look like this

rolled_number = roll()

Another technique that we can use to make code more readable and easier to write (once you get used to it) is by using classes. Consider this partial example of what your code could look like

import random

def roll():
return random.randint(0, 6)

class Player:
def __init__(self):
self.square = 0
self.roll1 = None
self.roll2 = None

def roll(self):
self.roll1 = roll()
self.roll2 = roll()

def rolled_double(self): # insteaf of c == d
return self.roll1 == self.roll2

WINNING_NUMBER = 49 # a named constant rather than a "magic number"

players = [Player(), Player()]

def take_turn(player):
print("You are on square", player.square)
player.roll() # updates the roll1 and roll2 values.
if player.rolled_double():
if player.square < 1:
...

By uses classes, objects, functions with good names, the code starts to read like English!

I won't re-write the whole thing here, I'll leave that to you if you want to try it!

One more thing that stands out, I'm unsure why you raise a SystemExit exception. Exceptions are meant for, well, exceptional situations. A game ending in a normal fashion shouldn't raise an exception, it should just complete, and maybe return the winner or something similar.

It could like like this

game = Game(players)
while !game.is_over():
... # do all your game stuff here

# if we ended then the game is over
winner = game.get_winner()
print("Congratulations," winner, "!")

From your question, it looked like the SystemExit was some sort of requirement, if that's the case, I would ask whoever set the requirement why!

Misc

you can re-write var = var + 1 as var += 1. Similarly for var = var + 3 -> var += 3

Hopefully this review was useful for you, and that you can see the benefits of naming things well and using functions to increase code re usability as well readability on top of reducing code duplication.

• This is good too and amusingly similar to my answer. I would point out that rolls aren't really part of a player, but part of a turn which a player is playing. For example, a player doesn't have reason to save rolls between turns or start their turn with the rolls from the last turn--they start with no rolls and have to make new ones. That leaves only one value inherent per player: position, which for my code made a class overkill. A class is still great if you're adding things like player name, win count, or picture. – TheAtomicOption Nov 29 '17 at 19:25
• Yeah I agree, I initially had done up a player class that had a single value, which there isn't much point to. You're right in that it might make sense that you have a Turn that has a Player and a Roll, I think the main point to take from this answer anyway is the idea of clear naming and structuring your data in some way! – chatton Nov 29 '17 at 19:28