Probability Dice Game in Python with two dices - python

I want to interate 1000 times over the following function to find out if you win or loose money in this game.
The game is designed as such that you throw a pair of dice and get money back or loose money. Let's say we start with 5 coins.
Throwing a 12 yields 1.5 coins.
Throwing an 11 yields 1 coins.
Throwing a 10 yields 0.5 coins.
Throwing a 9,8 or 7 yields nothing.
Throwing a 6,5,4,3,2 or 1 deducts 0.5 coins from your amount of coins.
This is what my implementation looks like so far:
def luckCalc():
amount = 5
# if 12 then 1/36 chance
if random.randrange(1,7) == 6 and random.randrange(1,7) == 6:
amount = amount + 1.5
# if 11 then 2/36 chance
elif (random.randrange(1,7) == 5 and random.randrange(1,7) == 6) or (random.randrange(1,7) == 6 and random.randrange(1,7) == 5):
amount = amount + 1
# if 10 then 3/36 chance
elif (random.randrange(1,7) == 5 and random.randrange(1,7) == 5) or (random.randrange(1,7) == 4 and random.randrange(1,7) == 6) or (random.randrange(1,7) == 6 and random.randrange(1,7) == 4):
amount = amount + 0.5
# if 9,8,7
# 4/36 + 5/36 + 6/36 chance
# 1+6, 2+5, 3+4, 4+3, 5+2, 6+1 chance
# 2+6, 3+5, 4+4, 5+3, 6+2 chance
# 3+6, 4+5, 5+4, 6+3 chance
# then no change in amount
# if 6,5,4,3,2,1
# chances...
# then amount -0.5
return amount
# Iterate over the dice throwing simulator and calculate total
total = 0.0
for a in range(1000):
total = total + luckCalc()
print (total)
I stopped coding towards the end of the function, because I recognised that there must be a more elegant solution on how to achieve this. Any interesting suggestions, what is this Monte Carlo I keep hearing about?

Each time you call random.randrange(1,7), you generate a new random number. Since you're testing a single "turn", roll twice:
def roll_die():
return random.randrange(1, 7)
total = roll_die() + roll_die()
And see if the sum is in a range:
def play_turn():
total = roll_die() + roll_die()
if total == 12:
return 1.5
elif total == 11:
return 1.0
elif total == 10:
return 0.5
elif total <= 6:
return -0.5
else: # total is 7, 8, or 9
return 0
Here's the result of 100,000 rounds:
>>> from collections import Counter
>>> counts = Counter(play_turn() for i in xrange(100000))
>>> counts
Counter({-0.5: 41823, 0: 41545, 0.5: 8361, 1.0: 5521, 1.5: 2750})
>>> probabilities = {score: count / 100000.0 for score, count in counts.items()}
>>> probabilities
{-0.5: 0.41823, 0: 0.41545, 0.5: 0.08361, 1.0: 0.05521, 1.5: 0.0275}

You can actually roll (ha!) everything you are doing into a single function:
from random import randrange
def play_game(rolls=1000, amount=5, n=6):
"""Play game 'rolls' times, starting with 'amount' on 'n'-sided dice."""
for i in range(rolls):
roll = randrange(1, n+1) + randrange(1, n+1)
if roll == 12:
amount += 1.5
elif roll == 11:
amount += 1
elif roll == 10:
amount += 0.5
elif roll < 7:
amount -= 0.5
return amount

I notice a few things in your code. First, for the 6-1 cases you're not actually subtracting 0.5 from the amount. Second, since you don't pass in the initial amount each loop you're adding between 5 and 6.5 to your total, which makes the total pretty pointless.
A more effective total would be to pass in the amount each time:
def luckCalc( amount ):
And then for your loop:
total = 5.0
for a in range(1000):
total = luckCalc(total)
Blender's answer, which just posted as I was writing this, is a great way to simplify your main function.

I personally like setting up my results table as an array (or a dictionary, but this suited my purpose better since every result was one of a small number of possible integers), with the index of each dice roll set to the value of the resulting change. See below.
import random
def luckCalc(coins=5):
diceroll = random.randint(1,6)+random.randint(1,6) #roll them bones
#here's that table I was talking about....
results_table = ['index 0 is blank',"you can't roll a one on two dice",-.5,-.5,-.5,-.5,-.5,0,0,0,.5,1,1.5]
coins += results_table[diceroll] #changes your coins value based on your roll (as an index of results_table)
if results_table[diceroll] > 0: #change the string if your result was + or -
result = "gained {}".format(results_table[diceroll])
else:
result = "lost {}".format(results_table[diceroll]*-1)
print("You {} coins, putting you at {}".format(result,coins)) #report back to the user
return coins #this is how you save your output
#CONSTANTS GO HERE -- YOU CAN CHANGE THESE TO CHANGE YOUR PROGRAM
STARTING_COINS = 5
HOW_MANY_ITERATIONS = 1000
#this way we don't modify a constant
coins = STARTING_COINS
#do it how many times?
for _ in range(HOW_MANY_ITERATIONS): #oh yeah that many times
coins = luckCalc(coins) #runs the function and saves the result back to coins
#report to the user your final result.
print("After {} rolls, your final total is {}".format(HOW_MANY_ITERATIONS,coins))

Related

A code to decide whether, or not, a given number of different coins possible to form an exact given amount of dollars

(Using loops or recursion), I'm trying to write a python function where the user enters an amount of dollars (say:1.25) and number of coins (say:6), then the function decides whether, or not, it is possible to form the exact amount of dollars using the exact given number of coins, assuming that the coins are quarters (0.25), dimes (0.10), nickels (0.05) and pennies (0.010). the function can use any one of the coins multiple times, but the total number of coins used must be equal to the exact number passed to the function.
e.g: if we pass 1.00 dollar and number of 6 coins: should return True because we can use (3 quarters + 2 dimes + 1 nickel)
1.25 dollars using 5 coins: True >> (5 quarters)
1.25 dollars using 8 coins: True >> (3 quarters + 5 dimes)
1.25 dollars using 7 coins: False.
I have the idea of the solution in my mind but couldn't transform it to a python code: the function has to start iterating through the group of coins we have (starting from the highest coin: 0.25) and multiply it by the number passed. While the result is higher than the given amount of dollars, the number of coins passed should be decremented by 1. When we get to a point where the result of (number * coin) is less than the given amount of dollars, the amount should be (the given amount - (number * coin)) and the number of coins should be (the given number - the number used so far). I have been trying for few days to make a python code out of this. This is what I've done so far.
`
def total(dollars, num):
dollars = float(dollars)
sofar = 0
num = round(num, 2)
coins = [0.25, 0.10, 0.05, 0.01]
possible = False
if not possible:
for x in range(len(coins)):
if num * coins[x] == dollars:
possible = True
elif num * coins[x] > dollars:
num -= 1
sofar += 1
else:
dollars -= num * coins[x]
num = sofar
return possible
`
When I pass (1.25, 5) to the function >> True
(1.25, 6) >> False
(1.25, 7) >> False
(1.25, 8) >> False (which is a wrong returned value)
Thanks in advance
Here's a working solution without recursion, but does use list comprehension. Not sure how large your coin set is expected to grow to and since this calculates the sum for all combinations it won't scale nicely.
from itertools import combinations_with_replacement
list_of_coins = [0.1, 0.05, 0.25] # dimes, nickles, quarters
number_of_coins = 6 # as your example gives
sum_value = 1.0 # as your example gives
def will_it_sum(list_of_coins, number_of_coins, sum_value):
list_of_combos = list(combinations_with_replacement(iter(list_of_coins), number_of_coins))
summed_list = [sum(item) for item in list_of_combos]
summed_to_desired_value = [i for i in summed_list if i == sum_value]
if len(summed_to_desired_value) > 0:
return True
else:
return False
number_of_coins = 7
sum_value = 1.25
will_it_sum(list_of_coins, number_of_coins, sum_value)
Below the solution that uses what python has already built-in. This will probably not go well as an exercise solution.
from itertools import combinations_with_replacement
def total(dollars, num):
cents = int(dollars*100)
coins = [25, 10, 5, 1]
return any(sum(comb) == cents for comb in combinations_with_replacement(coins, num))
Alternatively, if the combination should be returned:
from itertools import combinations_with_replacement
def total(dollars, num):
cents = int(dollars*100)
coins = [25, 10, 5, 1]
try:
return next(filter(lambda comb: sum(comb) == cents, combinations_with_replacement(coins, num)))
except StopIteration:
return None
This solves the problem without using combinations. This is the algorithm I described above. You start out using as many of the largest coin as you can, then you recursively see if you can fill in with the smaller coins. As soon as you get a match, you win.
Note that I use a helper so I can convert the dollars to integer pennies, to avoid floating point issues.
coins = [25, 10, 5, 1]
def totalhelp(cents, num, which=0):
if which >= len(coins):
return False
cts = coins[which]
# What's the most of this coin we can use?
maxn = min(cents // cts, num)
for i in range(maxn,-1,-1):
amt = i * cts
if amt == cents:
return True
if totalhelp(cents-amt, num-i, which+1):
return True
return False
def total(dollars, num):
cents = int(dollars*100+0.5)
return totalhelp( cents, num )
print( total(1.25, 4 ) )
print( total(1.25, 5 ) )
print( total(1.25, 6 ) )
print( total(1.25, 7 ) )
print( total(1.25, 8 ) )
Output:
False
True
True
True
True

Is there a way the get the sum of randomly generated numbers?

I'm still very new to python so this code is probably not the best way to achieve what I'm looking for.
But regardless, I basically want to create a code that will perform a dice rolling formula and output a total value I can use for data.
what I want to do is get the sum of random generated numbers, however, the amount of numbers generated varies on certain factors, so it can be anywhere from 1 to 3.
Here is a visual representation of what i want:
Roll 3x d20:
(12)(6)(14)
Roll d6 for each value that's equal or greater than 10:
(6)(N/A)(3)
Add 6 to each value"
6+6 = 12
3=6 = 9
(I got the code working up until the above step )
subtract 8 from above values:
12-8 =4
9-8 =1
total:
4+1 = 5
Also I know adding 6 and then subtracting 8 might sound stupid but there's a reason I need it this way.
This is the code I have so far:
import random
while True:
print("_______________________________")
input("press enter to start")
d201 = random.randint(1,20)
d202 = random.randint(1,20)
d203 = random.randint(1,20)
d61 = random.randint(1,6)
d62 = random.randint(1,6)
d63 = random.randint(1,6)
hit = [d201 ,d202 ,d203]
dmg = [d61 ,d62 ,d63]
db = 6
print("hit rolls")
print(hit)
print("damage rolls")
if d201 >= 10:
print(d61, '(roll 1)')
if d202 >= 10:
print(d62, '(roll 2)')
if d203 >= 10:
print(d63, '(roll 3)')
print("damage bonus:")
if d201 >= 10:
print((d61 + db), '(roll 1)+6')
if d202 >= 10:
print((d62 + db), '(roll 2)+6')
if d203 >= 10:
print((d63 + db), '(roll 3)+6')
print("damage total:")
So my first attempt was to add the (d61 + db) , (d62 + db) and (d63 + db) as variables and the creating a variable for those 3, and lastly print the sum of the variable:
dt = [(d61 + db) ,(d62 + db) ,(d63 + db)]
total = sum(dt)
And then at the end of the code:
print("damage total:")
print(total)
How ever this gives me the wrong total, its clearly not taking the results from the previous values.

Python - checking a list for possible patterns and if the list meets a specific condition

I'm a novice making a small game for learning purposes.
The game rolls dice based on the inputs of the user.
The part I'm having trouble with is I want to check for patterns in the list "rolls"
patterns include:
all dice are the same value and the # of sides >=4 EXAMPLE [1, 1, 1, 1] < values are the same, atleast 4 sides. If true then mutiply user_Score by 10
at least half of the dice are >= "average_sum" with the condition that the list must have >= 5 dice
EXAMPLE if avg_sum = 2 and rolls = [2,3,4,1,1,] If true then mutiply user_Score by 5
all of the dice are different values with the conditions # of dice > 4 and # of sides > # of dice
[10, 11, 12, 13, 14]
No pattern matches. -> Multiply user_Score by 1
number_dice = int( input( "How many dice are you using? Must be between 3-6 inclusive" ) )
faces = int( input( "how many sides are on your die? enter a number between 2-20 inclusive: "))
# Set range for number of dice
#generate a random number between 1 and faces
#Add dice_roll to the list
rolls = []
for die in range(number_dice):
dice_roll = random.randint(1, faces)
rolls.append(dice_roll)
#print the score from each dice rolled
print("You have rolled: " + str(rolls))
#calculate sum of score
sum = sum(rolls)
#calculate the average and round to the nearest integer
average_sum = round(sum / number_dice)
print("These die sum to: " + str(sum) + " and have an average value of: " + str(average_sum))
#Calculate the max possible score
max_score = (number_dice * faces)
#calculate the users score
user_score = float( sum / max_score )
print("your max possible score is " + str(max_score))
print("your score is " + str(user_score))
#-----------------------------------------------------------------------------------
#now calculate the bonus factor
#Check if the list "rolls" contains the same value for each index
if rolls == {repeatingvalues???} and rolls {number_dice>=4}:
user_Score * 10
elif rolls == {half of dice > average} and {number_dice >=5}:
user_Score * 5
elif rolls == {all dice have different values} and { number_dice > 4}{faces> number_dice}:
user_score * 8
else:
user_score * 1
Not sure how to make this statement search the list for a pattern^^^^^^
Define a function to check for a repeating pattern that returns True or False
def has_repeats(my_list):
first = my_list[0]
for item in mylist:
if not item == first:
return False
return True
And then define a function to check for a no duplicates that returns True or False
def all_different(my_list):
# Remove duplicates from list
my_list2 = list(dict.fromkeys(my_list))
return len(my_list) == len(my_list2)
And finally define a function to check if half the dice are greater than the average:
def half_greater_than_averge(my_list, average):
a = 0
b = 0
for item in my_list:
if item > average:
a += 1
else:
b += 1
return a > b
So you final checks will be:
if has_repeats(rolls) and number_dice >= 4:
user_Score * 10
elif half_greater_than_averge(rolls, average_sum) and number_dice >= 5:
user_Score * 5
elif all_different(rolls) and number_dice > 4 and faces > number_dice:
user_score * 8
else:
user_score * 1
Check out my solution where add # ------ SOLUTION STARTS HERE -------
I helped refactor your code too. You shouldn't be using sum as a variable name (or identifier) in your code cos it's a reserved python keyword. So I changed it to my_sum. Check if it still works as desired.
import math # import math at the top
import random
number_dice = int( input( "How many dice are you using? Must be between 3-6 inclusive" ) )
faces = int( input( "how many sides are on your die? enter a number between 2-20 inclusive: "))
# Set range for number of dice
#generate a random number between 1 and faces
#Add dice_roll to the list
for die in range(number_dice):
dice_roll = random.randint(1, faces)
rolls.append(dice_roll)
#print the score from each dice rolled
print("You have rolled: " + str(rolls))
#calculate sum of score
my_sum = sum(rolls)
#calculate the average and round to the nearest integer
average_sum = round(my_sum / number_dice)
print("These die sum to: " + str(my_sum) + " and have an average value of: " + str(average_sum))
#Calculate the max possible score
max_score = (number_dice * faces)
#calculate the users score
user_score = float( my_sum / max_score )
print("your max possible score is " + str(max_score))
# ------ SOLUTION STARTS HERE------
rolls.sort()
rolls.reverse()
for item in rolls:
if (rolls.count(item) >= 4) and (number_dice >= 4):
user_score *= 10
break
elif (rolls[math.ceil(len(rolls)/2) -1] >= average_sum ) and (number_dice >= 5):
user_score *= 5
break
elif (sorted(rolls)==sorted(list(set(rolls))))and (number_dice > 4) and (faces > number_dice):
user_score *= 8
break
else:
user_score *= 1
# ------ SOLUTION ENDS HERE------
print("your score is " + str(user_score))
Here is a simple, faster and more 'Pythonic' way of doing it.
if all(x == rolls[0] for x in rolls):
print("Same")
elif len(rolls) == len(set(rolls)):
print("Unique")
elif number_dice/2 <= [x > avg_sum for x in rolls].count(True):
print("Half")
else:
print("No match")
The 'and' conditions are missing. Please feel free to add them.
Bonus
from random import randint
faces = int(input('Number of faces:'))
number_dice = int(input('Number of dice:'))
rolls = [randint(1, faces) for _ in range(number_dice)]
Feel free to explore

Distributing points for lottery.py

I'm trying to figure out how to get my bot to distrubute points from a pot from the lottery game when it ends each time. So each game starts out at 1 point but everytime someone buys a ticket it goes up by a random amount. At the end of fifteen minutes it's supposed to retrieve the players and the pot and based off of where you're ranked in the list your points are determined. So basically if you're first in the list you win over the pot value. And when the ranking goes down your points that you win go down and if your near or at last place you lose points. The sum of all the points that the players earn does not have to equal 0 after they are distrubuted.
For example: Tim got 1st in the lottery. He should get 5676*1.66. Also, all the points you receive from the pot should be different based on your rank in the lottery. But if you're at the end of the list in the lottery you should lose points.
This is what I have so far:
lotteryStart = time.time()
players = []
pot = 1
def buyLottery(name):
if name not in players:
amount = int("30")
if Point.getCost(name, amount) == True:
multiplier = random.randint(217, 453)
pot = int(multiplier+pot)
different = float(time.time() - lotteryStart)
years = int(different / Point.YEAR)
days = int((different % Point.YEAR) / Point.DAY)
hours = int((different % Point.DAY) / Point.HOUR)
mins = int((different % Point.HOUR) / Point.MINUTE)
secs = int(different % Point.MINUTE)
if secs <= 0:
if len(players) > 0:
random.shuffle(players)
for i in range(1,len(players)):
if i == 1:
pot2 = int(pot*1.66)
elif i == 2:
pot2 = int(pot*1.33)
elif i == 3:
pot2 = int(pot)
elif i == 4:
pot = int(pot/1.66) #And so on but i dont want to keep doing elif
I do not understand your lottery; I can't imagine a lottery where you buy a ticket for a random amount and could lose money on top of the ticket price being very popular in real life!
That being said, I think you want to do something like this:
ratios = []
for i in range(-2, len(players) - 2):
if i < 0:
ratios.append(1 - (i * 0.33)) # ratio > 1
else:
ratios.append(1 / (1 + (i * 0.33))) # ratio <= 1
winnings = [pot * r for r in ratios]
You can then easily match players[i] with their winnings[i]. Note that I have assumed that you missed out pot / 1.33 accidentally; otherwise, you will have to adjust this slightly.
For 10 players, I get:
ratios == [1.6600000000000001, 1.33, 1.0, 0.7518796992481203,
0.6024096385542168, 0.5025125628140703, 0.43103448275862066,
0.3773584905660377, 0.33557046979865773, 0.3021148036253776]

Python code for the coin toss issues

I've been writing a program in python that simulates 100 coin tosses and gives the total number of tosses. The problem is that I also want to print the total number of heads and tails.
Here's my code:
import random
tries = 0
while tries < 100:
tries += 1
coin = random.randint(1, 2)
if coin == 1:
print('Heads')
if coin == 2:
print ('Tails')
total = tries
print(total)
I've been racking my brain for a solution and so far I have nothing. Is there any way to get the number of heads and tails printed in addition to the total number of tosses?
import random
samples = [ random.randint(1, 2) for i in range(100) ]
heads = samples.count(1)
tails = samples.count(2)
for s in samples:
msg = 'Heads' if s==1 else 'Tails'
print msg
print "Heads count=%d, Tails count=%d" % (heads, tails)
import random
total_heads = 0
total_tails = 0
count = 0
while count < 100:
coin = random.randint(1, 2)
if coin == 1:
print("Heads!\n")
total_heads += 1
count += 1
elif coin == 2:
print("Tails!\n")
total_tails += 1
count += 1
print("\nOkay, you flipped heads", total_heads, "times ")
print("\nand you flipped tails", total_tails, "times ")
You have a variable for the number of tries, which allows you to print that at the end, so just use the same approach for the number of heads and tails. Create a heads and tails variable outside the loop, increment inside the relevant if coin == X block, then print the results at the end.
Keep a running track of the number of heads:
import random
tries = 0
heads = 0
while tries < 100:
tries += 1
coin = random.randint(1, 2)
if coin == 1:
heads += 1
print('Heads')
if coin == 2:
print ('Tails')
total = tries
print('Total heads '.format(heads))
print('Total tails '.format(tries - heads))
print(total)
import random
tries = 0
heads=0
tails=0
while tries < 100:
tries += 1
coin = random.randint(1, 2)
if coin == 1:
print('Heads')
heads+=1
if coin == 2:
print ('Tails')
tails+=1
total = tries
print(total)
print tails
print heads
tosses = 100
heads = sum(random.randint(0, 1) for toss in range(tosses))
tails = tosses - heads
You could use random.getrandbits() to generate all 100 random bits at once:
import random
N = 100
# get N random bits; convert them to binary string; pad with zeros if necessary
bits = "{1:>0{0}}".format(N, bin(random.getrandbits(N))[2:])
# print results
print('{total} {heads} {tails}'.format(
total=len(bits), heads=bits.count('0'), tails=bits.count('1')))
Output
100 45 55
# Please make sure to import random.
import random
# Create a list to store the results of the for loop; number of tosses are limited by range() and the returned values are limited by random.choice().
tossed = [random.choice(["heads", "tails"]) for toss in range(100)]
# Use .count() and .format() to calculate and substitutes the values in your output string.
print("There are {} heads and {} tails.".format(tossed.count("heads"), tossed.count("tails")))
I ended up with this.
import random
flips = 0
heads = 0
tails = 0
while flips < 100:
flips += 1
coin = random.randint(1, 2)
if coin == 1:
print("Heads")
heads += 1
else:
print("Tails")
tails += 1
total = flips
print(total, "total flips.")
print("With a total of,", heads, "heads and", tails, "tails.")
Here is my code. Hope it will help.
import random
coin = random.randint (1, 2)
tries = 0
heads = 0
tails = 0
while tries != 100:
if coin == 1:
print ("Heads ")
heads += 1
tries += 1
coin = random.randint(1, 2)
elif coin == 2:
print ("Tails ")
tails += 1
tries += 1
coin = random.randint(1, 2)
else:
print ("WTF")
print ("Heads = ", heads)
print ("Tails = ", tails)
import random
print("coin flip begins for 100 times")
tails = 0
heads = 0
count = 0
while count < 100: #to flip not more than 100 times
count += 1
result = random.randint(1,2) #result can only be 1 or 2.
if result == 1: # result 1 is for heads
print("heads")
elif result == 2: # result 2 is for tails
print("tails")
if result == 1:
heads +=1 #this is the heads counter.
if result == 2:
tails +=1 #this is the tails counter.
# with all 3 being the count, heads and tails counters,
# i can instruct the coin flip not to exceed 100 times, of the 100 flips
# with heads and tails counter,
# I now have data to display how of the flips are heads or tails out of 100.
print("completed 100 flips") #just to say 100 flips done.
print("total tails is", tails) #displayed from if result == 2..... tails +=1
print("total heads is", heads)

Categories