I have 3 die, each with 13 sides. You have to "roll" them until you get all three to be the same value (shown below).
ct = 1
import random
min = 1
max = 13
roll_again = "yes"
while roll_again == "yes" or roll_again == "y" or roll_again == "":
print "This is attempt number: ", + ct
print "Now, rolling the dice..."
print "The values are...."
die1 = random.randint(min, max)
die2 = random.randint(min, max)
die3 = random.randint(min, max)
print die1
print die2
print die3
ct += 1
if die1 == die2:
if die2 == die3:
print "Congrats! You win! hooray! You got it on attempt number ", + ct
ct = 1
roll_again = raw_input("Roll the dice again? ")
This all works fine,
but I wanted the 1 face to be able to come up 5 times more than the rest (like a weighted die), and the face 13 to come up .5 times than the others (excluding the 1 value of course). Is this possible in Python 2.7?
I once posted an answer to a similar question (albeit in Java) in which someone wanted to choose letters of the alphabet with varying probabilities. You could take either of the approaches I suggested there.
The most general approach is to calculate the probability of choosing each number. You might have a list of (number, probability) tuples, for example
choices = [(1, 0.2), (2, 0.05), (3, 0.3113), ...]
and then you can make your random choice by choosing a random number between 0 and 1, iterating over the list, adding up probabilities as you go, and when you reach a sum which is larger than the random number you chose, stop and return the corresponding choice.
def random_choice(choices):
r = random.random()
cdf = 0
for number, cumulative_probability in choices:
cdf += cumulative_probability
if r < cdf:
return number
return choices[-1][0]
(Note that itertools.accumulate() doesn't exist in Python 2, otherwise you could use that here.)
If you happen to be using Numpy, it has this functionality built in as numpy.random.choice(numbers, p=probabilities).
If all your probabilities are multiples of a certain value, though, you might be better off using random.choice(). To do this, you'd create a list of the possible choices without probabilities, repeating each one enough to get the relative proportions you want. For example,
choices = [1, 1, 1, 2, 3, 3, 4]
would cause 1 to be three times as likely as 2 or 4, and 3 to be twice as likely as 2 or 4. Then just call random.choice(choices) each time you want to roll the die.
In your case, the second approach seems well suited, but you could use either. I'll leave it to you to figure out the proper definition of choices for your case. ;-)
I think the tool you're looking for is numpy.random.choice()
This tool allows you to generate a number following a non equiprobable probability law by giving list of the probability of all events as parameter
probability_A = 0.1
probability_B = 0.5
probability_C = 0.4
print(numpy.random.choice(numpy.arange(1, 4), p = [probability_A, probability_B, probability_C]))
In your situation, you first need to calculate the probabilities.
If you know that the number "1" has a weight of 5 and the number "13" a weight of five, you can generate a vector (a list in Python language) this way:
weights = [5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.5]
probabilities = [weight/sum(weights) for weight in weights]
And finally
numpy.random.choice(numpy.arange(1, 14), p = probabilities)
Related
So i was learning how to handle probabilities and how to plot them in Python. I came across a problem where i needed to find the probability of the sum of 2 dices being > 7 or odd. I know the result is around 75% but it was translating that to Python that i had a problem with. My code to solve the problem is something like this:
import random
import numpy as np
dice = [1,2,3,4,5,6]
value = 0
simulation_number = len(dice)**2
percentage = []
for i in range(0,simulation_number):
dice1 = random.choice(dice)
dice2 = random.choice(dice)
random_match = dice1,dice2
if (sum(random_match))>7 or (sum(random_match)%2) != 0:
value += 1
percentage.append(np.round((value/simulation_number)*100,2))
print(percentage,"%")
It works just fine but everytime i run the code it gives a different solution because the loop is repeating outcomes for random_match. How do I include in the code the condition of not repeating random_match values?
Generating random values from 1 to 6 won't work. Assume that you are tossing a coin 10 times. theoretically you should get 5 heads and 5 tails. But that does not happens in real life because of sampling error. When you generate random values, there is always some sampling error.
import random
import numpy as np
dice = [1,2,3,4,5,6]
value = 0
simulation_number = len(dice)**2
for i in range(len(dice)):
for j in range(len(dice)):
dice1 = dice[i]
dice2 = dice[j]
x = dice1+dice2
if x>7 or x%2== 1:
value += 1
percentage = np.round((value/simulation_number)*100,2)
print(f'{percentage} %')
This works as you need every case only once. Using random might take same case again and again
I guess you're looking for random.sample:
import random
dice = [1,2,3,4,5,6]
dice1, dice2 = random.sample(dice, 2)
I need 3 unique random numbers between 1 to 20.
I have a loop generating 3 random numbers from 1-20. And I don't want there to be any repeats. I have something that works for the first two numbers. But in my code the first and third numbers can still be the same which needs to be fixed.
i = 1
while i <= 3:
x = random.randint(1, 20)
print(choice([i for i in range(1, 20) if i != [x]]))
i += 1
Is there a better way to achieve this in Python?
You can use random.sample(). Below example will return you 3 unique random numbers between 1 to 20.
>>> import random
>>> sample_count = 3 # count of required unique numbers
>>> start_range, end_range = 1, 20 # start and end range
>>> random.sample(range(start_range, end_range+1), sample_count)
[4, 1, 14]
Please refer random.sample() documentation for more details.
I am trying to find the occurrences of each number for sides going 1 up to the number of sides on a dice roll. I would like the program to find the number of occurrences for each number that is in listRolls.
Example: if there were a 6 sided dice then it would be 1 up to 6 and the list would roll the dice x amount of times and I would like to find how many times the dice rolled a 1 so on and so forth.
I am new to python and trying to learn it! Any help would be appreciated!
import random
listRolls = []
# Randomly choose the number of sides of dice between 6 and 12
# Print out 'Will be using: x sides' variable = numSides
def main() :
global numSides
global numRolls
numSides = sides()
numRolls = rolls()
rollDice()
counterInputs()
listPrint()
def rolls() :
# for rolls in range(1):
###################################
## CHANGE 20, 50 to 200, 500 ##
##
x = (random.randint(20, 50))
print('Ran for: %s rounds' %(x))
print ('\n')
return x
def sides():
# for sides in range(1):
y = (random.randint(6, 12))
print ('\n')
print('Will be using: %s sides' %(y))
return y
def counterInputs() :
counters = [0] * (numSides + 1) # counters[0] is not used.
value = listRolls
# if value >= 1 and value <= numSides :
# counters[value] = counters[value] + 1
for i in range(1, len(counters)) :
print("%2d: %4d" % (i, value[i]))
print ('\n')
# Face value of die based on each roll (numRolls = number of times die is
thrown).
# numSides = number of faces)
def rollDice():
i = 0
while (i < numRolls):
x = (random.randint(1, numSides))
listRolls.append(x)
# print (x)
i = i + 1
# print ('Done')
def listPrint():
for i, item in enumerate(listRolls):
if (i+1)%13 == 0:
print(item)
else:
print(item,end=', ')
print ('\n')
main()
Fastest way (I know of) is using Counter() from collections (see bottom for dict-only replacement):
import random
from collections import Counter
# create our 6-sided dice
sides = range(1,7)
num_throws = 1000
# generates num_throws random values and counts them
counter = Counter(random.choices(sides, k = num_throws))
print (counter) # Counter({1: 181, 3: 179, 4: 167, 5: 159, 6: 159, 2: 155})
collections.Counter([iterable-or-mapping])) is a specialized dictionary that counts the occurences in the iterable you give it.
random.choices(population, weights=None, *, cum_weights=None, k=1) uses the given iterable (a range(1,7) == 1,2,3,4,5,6 and draws k things from it, returning them as list.
range(from,to[,steps]) generates a immutable sequence and makes random.choices perform even better then when using a list.
As more complete program including inputting facecount and throw-numbers with validation:
def inputNumber(text,minValue):
"""Ask for numeric input using 'text' - returns integer of minValue or more. """
rv = None
while not rv:
rv = input(text)
try:
rv = int(rv)
if rv < minValue:
raise ValueError
except:
rv = None
print("Try gain, number must be {} or more\n".format(minValue))
return rv
from collections import Counter
import random
sides = range(1,inputNumber("How many sides on the dice? [4+] ",4)+1)
num_throws = inputNumber("How many throws? [1+] ",1)
counter = Counter(random.choices(sides, k = num_throws))
print("")
for k in sorted(counter):
print ("Number {} occured {} times".format(k,counter[k]))
Output:
How many sides on the dice? [4+] 1
Try gain, number must be 4 or more
How many sides on the dice? [4+] a
Try gain, number must be 4 or more
How many sides on the dice? [4+] 5
How many throws? [1+] -2
Try gain, number must be 1 or more
How many throws? [1+] 100
Number 1 occured 22 times
Number 2 occured 20 times
Number 3 occured 22 times
Number 4 occured 23 times
Number 5 occured 13 times
You are using python 2.x way of formatting string output, read about format(..) and its format examples.
Take a look at the very good answers for validating input from user: Asking the user for input until they give a valid response
Replacement for Counter if you aren't allowed to use it:
# create a dict
d = {}
# iterate over all values you threw
for num in [1,2,2,3,2,2,2,2,2,1,2,1,5,99]:
# set a defaultvalue of 0 if key not exists
d.setdefault(num,0)
# increment nums value by 1
d[num]+=1
print(d) # {1: 3, 2: 8, 3: 1, 5: 1, 99: 1}
You could trim this down a bit using a dictionary. For stuff like dice I think a good option is to use random.choice and just draw from a list that you populate with the sides of the dice. So to start, we can gather rolls and sides from the user using input(). Next we can use the sides to generate our list that we pull from, you could use randint method in place of this, but for using choice we can make a list in range(1, sides+1). Next we can initiate a dictionary using dict and make a dictionary that has all the sides as keys with a value of 0. Now looks like this d = {1:0, 2:0...n+1:0}.From here now we can use a for loop to populate our dictionary adding 1 to whatever side is rolled. Another for loop will let us print out our dictionary. Bonus. I threw in a max function that takes the items in our dictionary and sorts them by their values and returns the largest tuple of (key, value). We can then print a most rolled statement.
from random import choice
rolls = int(input('Enter the amount of rolls: '))
sides = int(input('Enter the amound of sides: '))
die = list(range(1, sides+1))
d = dict((i,0) for i in die)
for i in range(rolls):
d[choice(die)] += 1
print('\nIn {} rolls, you rolled: '.format(rolls))
for i in d:
print('\tRolled {}: {} times'.format(i, d[i]))
big = max(d.items(), key=lambda x: x[1])
print('{} was rolled the most, for a total of {} times'.format(big[0], big[1]))
Enter the amount of rolls: 5
Enter the amound of sides: 5
In 5 rolls, you rolled:
Rolled 1: 1 times
Rolled 2: 2 times
Rolled 3: 1 times
Rolled 4: 1 times
Rolled 5: 0 times
2 was rolled the most, for a total of 2 times
I haven't found anything even relevant to my question, so i may be asking it wrong.
I am working on an exercise where I am given sequential values starting at 1 and going to n, but not in order. I must find a missing value from the list.
My method is to add the full 1 => n value in a for loop but I can't figure out how to add n - 1 non-sequential values each as its own line of input in order to subtract it from the full value to get the missing one.
I have been searching modifications to for loops or just how to add n inputs of non-sequential numbers. If I am simply asking the wrong question, I am happy to do my own research if someone could point me in the right direction.
total = 0
for i in range (1 , (int(input())) + 1):
total += i
print(total)
for s in **?????(int(input()))**:
total -= s
print(total)
sample input:
5
3
2
5
1
expected output: 4
To fill in the approach you're using in your example code:
total = 0
n = int(input("How long is the sequence? "))
for i in range(1, n+1):
total += i
for i in range(1, n):
total -= int(input("Enter value {}: ".format(i)))
print("Missing value is: " + str(total))
That first for loop is unnecessary though. First of all, your loop is equivalent to the sum function:
total = sum(range(1,n+1))
But you can do away with any iteration altogether by using the formula:
total = int(n*(n+1)/2) # division causes float output so you have to convert back to an int
I don't know if you are supposed to create the initial data (with the missing item), so I added some lines to generate this sequence:
import random
n = 12 # or n = int(input('Enter n: ')) to get user input
# create a shuffled numeric sequence with one missing value
data = list(range(1,n+1))
data.remove(random.randrange(1,n+1))
random.shuffle(data)
print(data)
# create the corresponding reference sequence (without missing value)
data2 = list(range(1,n+1))
# find missing data with your algorithm
print("Missing value =", sum(data2)-sum(data))
Here is the output:
[12, 4, 11, 5, 2, 7, 1, 6, 8, 9, 10]
Missing value = 3
I'm trying to understand this solution of the Monty Hall problem, I understand most of the code, but am stuck on two pieces.
Below is the code, but specifically I'm stuck on these two parts
result[bad] = np.random.randint(0,3, bad.sum())
and the entire switch_guess function.
If anyone could explain in plain English for me that would be awesome.
#Simulates picking a prize door
def simulate_prizedoor(nsim):
return np.random.randint(0,3,(nsim))
#Simulates the doors guessed
def simulate_guesses(nsim):
return np.zeros(nsim, dtype=np.int)
#Simulates the "game host" showing whats behind a door
def goat_door(prize_doors, guesses):
result = np.random.randint(0,3, prize_doors.size)
while True:
bad = (result == prize_doors) | (result == guesses)
if not bad.any():
return result
result[bad] = np.random.randint(0,3, bad.sum())
#Used to change your guess
def switch_guess(guesses, goat_doors):
result = np.zeros(guesses.size)
switch = {(0, 1): 2, (0, 2): 1, (1, 0): 2, (1, 2): 1, (2, 0): 1, (2, 1): 0}
for i in [0,1,2]:
#print "i = ", i
for j in [0,1,2]:
#print "j = ", j
mask = (guesses == i) & (goat_doors == j)
#print "mask = ", mask
if not mask.any():
continue
result = np.where(mask, np.ones_like(result) * switch[(i, j)], result)
return result
#Calculates the win percentage
def win_percentage(guesses, prizedoors):
return 100 * (guesses == prizedoors).mean()
#The code to pull everything together
nsim = 10000
#keep guesses
print "Win percentage when keeping original door"
print win_percentage(simulate_prizedoor(nsim), simulate_guesses(nsim))
#switch
pd = simulate_prizedoor(nsim)
guess = simulate_guesses(nsim)
goats = goat_door(pd, guess)
guess = switch_guess(guess, goats)
print "Win percentage when switching doors"
print win_percentage(pd, guess)
… specifically I'm stuck on these two parts
result[bad] = np.random.randint(0,3, bad.sum())
Let's break this down into pieces. It may help to reduce that 10000 to something small, like 5, so you can print out the values (either with print calls, or in the debugger) and see what's going on.
When we start this function, prize_doors is going to have 5 random values from 0 to 2, like 2 2 0 1 2, and guesses will have 5 values, all 0, like 0 0 0 0 0. result will therefore start off with 5 random values from 0 to 2, like 0 2 2 0 1.
Each first time through the loop, bad will be a list of 5 bool values, which are each True if the corresponding value in result matches the corresponding value in either prize_doors or guesses. So, in this example, True True False True False, because guess #1 matches prize_doors, and guesses #0 and #3 match goats.
Unfortunately, we're just going to go around that loop forever, because there's nothing inside the loop that modifies result, and therefore bad is going to be the same forever, and doing the same check forever is always going to return the same values.
But if you indent that result[bad] = … line so it's inside the loop, that changes everything. So, let's assume that's what you were supposed to do, and you just copied it wrong.
When treated as numbers, True and False have values 1 and 0, respectively. So, bad.sum() is a count of how many matches there were in bad—in this case, 3.
So, np.random.randint(0, 3, bad.sum()) picks 3 random values from 0 to 2, let's say 1 0 1.
Now, result[bad] selects all of the elements of result for which the corresponding value in bad is True, so in this example it's result[0], result[1], and result[3].
So we end up assigning that 1 0 1 to those three selected locations, so result is now 1 0 2 1 1.
So, next time through the loop, bad is now True False False False False. We've still got at least one True value, so we run that result[bad] = line again. This time, bad.sum() is 1, so we pick 1 random value, let's say 0, and we then assign that 1 value to result[0], so result is now 0 0 2 1 1.
The next time through, bad is now False False False False False, so bad.any() is False, so we're done.
In other words, each time through, we take all the values that don't match either the prize door or the goat door, and pick a new door for them, until finally there are no such values.
It also confused me, until 5 mins ago when I finally figured it out.
Since the first question has been solved, I will only talk about the second one.
The intuition goes like this : given a sequence of (guesses, goatdoors),in the (i,j) loop, there are always some simulation (e.g., simulation[0] and simulation[5]) that 'hit' by the (i,j), that is the say, the 0th and 5th simulation have guess i and goatdoor j.
Variable mask record 0 and 5 in this example. Then result in 0th and 5th can be decided, because in these simulation, the only possible door to switch to is determined by i and j. So np.where refreshes result in these simulation, leave other simulations unchanged.
Intuition is above. You need to know how np.where work if you want to know what I'm talking about. Good luck.