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.
1 Answer 1
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))
-
\$\begingroup\$ What is the difference between "in (2,3,12)" and "in {2,3,12}" ? \$\endgroup\$Meph-– Meph-2019年02月20日 09:40:28 +00:00Commented Feb 20, 2019 at 9:40
-
\$\begingroup\$ @Meph-: The first one is a
tuple
and the latter one aset
. For small collections there will be basically no difference, but aset
hasO(1)
membership testing, while atuple
is slightly faster to construct, but hasO(n)
membership testing. On my machine1 in (2, 3, 12)
takes 53.9 ns ± 0.361 ns and1 in {2, 3, 12}
takes 55.2 ns ± 2.07 ns. \$\endgroup\$Graipher– Graipher2019年02月20日 09:42:05 +00:00Commented 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\$Graipher– Graipher2019年02月20日 09:47:15 +00:00Commented 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\$Kevin– Kevin2019年02月20日 09:59:42 +00:00Commented 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\$Kevin– Kevin2019年02月20日 10:17:33 +00:00Commented Feb 20, 2019 at 10:17
Explore related questions
See similar questions with these tags.