2
\$\begingroup\$

I did another exercise, this time it simulates n games of craps(dice game) and outputs the wins and win percentage!

#craps.py -- Simulates multiple games of craps
# and estimates the probability that the player wins.
import random
def output(wins, total):
 winrate = wins / total
 print("The player won {0} of {1} games ({2:0.2%})".format(wins, total, winrate))
def rolldies():
 dice1 = random.randint(1, 6)
 dice2 = random.randint(1, 6)
 roll = dice1 + dice2
 return roll
def simOneGame():
 initial_roll = rolldies()
 if initial_roll == 2 or initial_roll == 3 or initial_roll == 12:
 return True # won
 elif initial_roll == 7 or initial_roll == 11:
 return False #lost
 else:
 #Roll until roll is 7 or initial roll
 roll = rolldies()
 while roll != 7 and roll != initial_roll:
 roll = rolldies()
 if roll == 7:
 return True #won
 else:
 #roll is inital_roll
 return False #lost
def simNGames(games_to_sim):
 wins = 0
 for i in range(games_to_sim):
 if simOneGame():
 wins += 1
 return wins
def main():
 games_to_sim = int(input("How many games to simulate? "))
 wins = simNGames(games_to_sim)
 output(wins, games_to_sim)
if __name__ == "__main__":
 main()

Always open for suggestions on what to improve/do differently or more pythonic.

asked Feb 20, 2019 at 8:43
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

First, Python has an official style-guide, PEP8, which programmers are encouraged to follow. This makes it easier for other Python programmers to read your code. PEP8 recommends using lower_case both for variable and function names, which I have used in the code below.

In your output function you use string formatting (good). However note that if you just want to paste the values in order, there is no need to explicitly mention the indices. So you could write "The player won {} of {} games ({:0.2%})".format(wins, total, winrate). But there is an even easier way in Python 3.6+: f-strings. I also think this is not enough to put it into a function, I would just leave it as a single line in main:

print(f"The player won {wins} of {total} games ({wins/total:0.2%})")

Your rolldies function could be made more general if it accepted a parameter telling it how many dice to roll. You can also use a list comprehension here, or random.choices:

def roll_dice(n=2):
 return sum(random.randint(1, 6) for _ in range(n))
DIE = [1, 2, 3, 4, 5, 6]
def roll_dice(n=2):
 return sum(random.choices(DIE, k=n))

Note that the singular is "die" and the plural is "dice", not "dies".

In your simOneGame function, instead of chaining a lot of comparisons with or, just use in:

def sim_game():
 initial_roll = roll_dice()
 if initial_roll in {2, 3, 12}:
 return True # won
 elif initial_roll in {7, 11}:
 return False # lost

Your rolling in the else branch can also be a bit shortened:

 else:
 #Roll until roll is 7 or initial roll
 roll = roll_dice()
 while roll not in {7, initial_roll}:
 roll = roll_dice()
 return roll == 7 # 7 wins

You could theoretically replace the while loop with a single random.choices call, but you would have to manually set the probabilities to the right values.

The simNGames function can be shortened a lot by using the fact that False == 0 and True == 1:

def sim_n_games(n):
 return sum(sim_game() for _ in range(n))
answered Feb 20, 2019 at 9:35
\$\endgroup\$
13
  • \$\begingroup\$ What is the difference between "in (2,3,12)" and "in {2,3,12}" ? \$\endgroup\$ Commented Feb 20, 2019 at 9:40
  • \$\begingroup\$ @Meph-: The first one is a tuple and the latter one a set. For small collections there will be basically no difference, but a set has O(1) membership testing, while a tuple is slightly faster to construct, but has O(n) membership testing. On my machine 1 in (2, 3, 12) takes 53.9 ns ± 0.361 ns and 1 in {2, 3, 12} takes 55.2 ns ± 2.07 ns. \$\endgroup\$ Commented Feb 20, 2019 at 9:42
  • \$\begingroup\$ @Meph-: And for completeness sake (and to show that it is better than chaining or), 1 == 2 or 1 == 3 or 1 == 12 takes 73.3 ns ± 0.658 ns. \$\endgroup\$ Commented Feb 20, 2019 at 9:47
  • 1
    \$\begingroup\$ I'll put the formatting changes to use! Thanks. As to using "in", i simply havent learned that yet(tuples, sets),it will probably come later in my programming book, but I'll implement it right away. Really seems to be the better choice. Sorry for the die/dice mixup haha. \$\endgroup\$ Commented Feb 20, 2019 at 9:59
  • \$\begingroup\$ Okay, it seems like print(f"The player won {wins} of {total} games ({wins/total:0.2%})") doesn't work. i think you can't calculate anything in there \$\endgroup\$ Commented Feb 20, 2019 at 10:17

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.