Python Monty hall n number of doors - python

I have a model of the Monty Hall program running but I need to figure out how to ask the user for the number of doors of in this case, hiding places. The code for the simulation works, it's just the starting section I need help with. This is what I have so far, thanks for any help in advance.
import random
#Ask the user for how many runs to simumlate
runs = int(input("How many games do you want to simulate?"))
switchwins, nonswitchwins, switchlosses, nonswitchlosses = 0, 0, 0, 0
# Get the random number started with a seed
random.seed()
#run once for user switching and once for user not switching
for swap in True,False:
# Do everything for the number of runs we have
for i in range(runs):
#Ask the user for the number of hiding places which must be greater than 3
while True:
hidingplaces = int(input("This game requires 3 or more hiding places. How many would you like?"))
if hidingplaces < 3:
#return error
raise ValueError(f'doors must be greater than three, not {hidingplaces}')
else:
break
# All prizes are nothing apart from one which holds the coin
prizes = ['nothing', 'nothing', 'coin']
# Randomly mix them up
random.shuffle(prizes)
#select a random location
ChoiceA = random.randrange(hidingplaces)
# print("Before the prize is revealed, I will show you what is in one of the other hiding places")
# remove one of the other hiding places which has nothing as a prize and isn't ChoiceA
for currentlocation, contents in enumerate(prizes):
if currentlocation != ChoiceA and contents == "nothing":
showlocation = currentlocation
# print("There is nothing in this location", showlocation)
break
if swap:
#swap to the other location
for currentlocation, contents in enumerate(prizes):
if currentlocation != ChoiceA and currentlocation != showlocation:
swap_to = currentlocation
# check if the swapped choice is a win
if prizes[swap_to] == "coin":
switchwins +=1
else:
switchlosses +=1
# when not swapping locations check for win
else:
if prizes[ChoiceA] == "coin":
nonswitchwins +=1
else:
nonswitchlosses +=1
print("This is the number of wins if the user switched", round((switchwins/runs)*100,1), "%")
print("This is the number of wins if the user didn't switch", round((nonswitchwins/runs)*100,1),"%")
The error I'm getting is:
IndexError Traceback (most recent call last)
<ipython-input-15-e7e700a3b515> in <module>()
57 # when not swapping locations check for win
58 else:
---> 59 if prizes[ChoiceA] == "coin":
60 nonswitchwins +=1
61 else:
IndexError: list index out of range

The problem you're reporting is not, after all, with the user input routine. It is that you are allowing the user to specify hidingplaces > 3 while at the same time hardcoding the list prizes to have exactly 3 entries. ChoiceA, which can be (randomly) set to any number less than hidingplaces, is used as an index into prizes. It raises the exception you report whenever ChoiceA happens to be greater than 2.
Strategies to fix this might include (a) making use of the value of hidingplaces when you define the list of prizes or (b) using ChoiceA % len(prizes) as the index into prizes instead of just ChoiceA. Note that these have different effects on the statistical behavior of the simulation: the correct choice depends on how you want it to behave. From the comment next to your existing definition of prizes, this definition is probably what you intend:
prizes = [ 'coin' ] + [ 'nothing' ] * ( hidingplaces - 1 )

I have fixed your code. I rewrote it and simplified it, fixed some syntax errors, and fixed some indent errors.
Check the comments in the code.
EDIT: I have fixed the code.
def askDoors():
'''
Ask the user for the number of hiding places which must be greater than 3
'''
return int(input("This game requires 3 or more hiding places. How many would you like?"))
hidingplaces = askDoors()
while hidingplaces < 3:
# return error
print('Doors must be greater than three, not %d.' % hidingplaces)
hidingplaces = askDoors()
print('Start.') # put game here (recommended to use a function)
EDIT: For the second problem, just change prizes to prizes = ['coin'] and add this right after it.
for i in range(hidingplaces):
prizes.append('nothing')

Related

trying to +1 to random.seed() for every loop

I'm working on a casino program that gets a bet ($1-$50) from the user, then pulls a slot machine to display a three-string combination of "7", "cherries", "bar", or "(space)". Certain combinations will trigger a bet multiplier, and the user will win back this amount. The run should look like this: ask user for bet, show user the pull and their winnings, then ask user for a new bet, display a new pull, and so on.
Right now, I have everything down except for a couple problems - I cannot make it so that the program generates a new random combination for each pull. Secondly, the main loop continues forever, printing the user's pull and winnings forever. Below is the method that generates either "7", "cherries", etc.
def rand_string(self):
random.seed(0)
# produces a number between 0 and 999
test_num = random.randrange(1000)
# precompute cutoffs
bar_cutoff = 10 * TripleString.BAR_PCT
cherries_cutoff = bar_cutoff + 10 * TripleString.CHERRIES_PCT
space_cutoff = cherries_cutoff + 10 * TripleString.SPACE_PCT
# bar = 38%, cherries = 40%, space = 7%, seven = 15%
if test_num < bar_cutoff:
return TripleString.BAR
elif test_num < cherries_cutoff:
return TripleString.CHERRIES
elif test_num < space_cutoff:
return TripleString.SPACE
else:
return TripleString.SEVEN
And here is the loop in main:
while(True):
if bet == 0: #a bet of $0 ends the program
print("Please come again!")
break
else:
print("whirrr...and your pull is " +\
object.pull())
object.display(None)
I thought I could solve this by somehow adding 1 to random.seed() for each loop (we begin with random.seed(0), but for each new pull 1 is added so that random.seed(1) and so on), but I don't know how to go about doing this and I'm not even sure if it's doable. If someone could point out my mistakes here, that'd be great. (sorry if this makes no sense, I'm very new to Python).
You should only call random.seed(0) once in the program. By seeding every time you are reseting the pseudo random number generator and forcing it to produce the same number.
random.seed(0)
while(True):
if bet == 0: #a bet of $0 ends the program
...
You can read more about random seeding here.

How to make a poll in python with lists

I am trying to make a poll as an exercise that uses user input to find where people want to go on vacation. Here is my code so far:
done = False
places = []
while done == False:
dreamvacation = input("What is your dream vacation? ")
if dreamvacation == "quit":
for item in places:
number = places.count(item)
if number == 1:
print("{} occured in the list 1 time.".format(item))
else:
print("{} occured in the list {} times.".format(item, number))
while number > 0:
places.remove(item)
number -= 1
done = True
places.append(dreamvacation)
Basically it does the poll and each time someone enters something, it adds it to the list. Then when someone says quit, it counts the items and says something different depending on how many times the vacation spot occurred. If it occurs multiple times, I had the other duplicates removed after they were counted using a while loop. But, when it removes duplicates, the whole list shifted and the index spot moved forward thus skipping a spot. For example:
[a(index is here),b,c,a,]
After the counting, both a's would be removed and the index position would move forward:
[b,c(index is here)]
How can I make it so the index position stays in the same spot while the list shifts?
If I can do this, then I could have my program remove duplicates and singles after the letter is counted.
You do not need to delete entries of places. It only makes it hard to keep track. Please see the following example. I re-structured your code a little bit as well:
done = False
places = []
# user input stage
while not done:
dream_loc = input('where to go? ')
if dream_loc == 'quit':
done = True
else:
places.append(dream_loc)
# counting stage
for loc in set(places):
count = places.count(loc)
if count == 1:
print("{} occured in the list 1 time.".format(loc))
else:
print("{} occured in the list {} times.".format(loc, count))

How do I make the program track user inputs at the loop code?

I have created a game called 'guessing game'. Story is: computer generates a number and the user have 3 chances to guess the number that the computer generates. It is nice and easy to code but I would like to add a small detail to that and thats where I got the problem.
What I am asking from you guys is to help me on how/what to add something to the code so that it can associate new input with the previous one and calculate the print response in accordance to that.
import random
listte = range(1, 21) # list contains 1-20
number = random.choice(listte) # computer generated number from the list
for i in range(3):
answer = int(input("What is your guess?"))
prevanswer = None # I came up with this but not really working?
if answer == number:
print "OH YEAH you got it!"
elif answer < number:
print "make it higher"
# this elif is not working with below codes
elif answer < number and answer > prevanswer:
print "still higher"
elif answer > number:
print "lower!"
prevanswer = i # also not working but this is what I came up with
An example execution scenario:
computer generated : 15
guess 1 : 17
prints "lower!"
guess 2: 10
print "make it higher"
guess 3: 12
print "still higher"
Extra: I would also love if you add a code where it says "you have no more choice left" when the user used all of 3 guesses.
First, move the setting of prevanswer = None to before the loop. Otherwise, you're erasing the memory of what went before.
Second, take a look at your if/elsif code sequence. You have the right tests, but in the wrong order:
elif answer < number:
This will execute EVERY TIME answer is less than number. Below that you have:
elif answer < number and answer > prevanswer:
This is "good" code, in the sense that it should accomplish what you seem to want. But this is a MORE RESTRICTED case than the earlier one. That is, whenever answer < number, only SOMETIMES will answer > prevanswer. So you should check for the subset of possibilities BEFORE the general case of all answer < number.
Try this:
elif answer < number and answer > prevanswer: # specific case
...
elif answer < number: # general case
And finally, don't set
prevanswer = i
but rather
prevanswer = answer

Multiple Same Numbers Entered in Guessing Game; Loop Stops Working?

I've been making a 4 number guessing game to learn python that meets three criteria:
replayable
tells player how many tries it took to guess correct answer
tells player how many numbers are correct to steer player to right answer
I thought I met the criteria but there is this really weird bug that happens in the game. If you try to guess the number using trial and error; the game breaks and doesn't detect that your answer is right. If the answer is '[1, 2, 3, 4]' and you try to get the answer by doing '[1, 1, 1, 1]' then '[1, 2, 2, 2,]' and eventually get '[1, 2, 3, 4]'; the program will say that the 4 numbers match but it won't let you win the game and just asks you to play again. This bug has been really killing me and I hope the person reading understands what I'm trying to say.
Sorry about the big long block of code but, the problem could be anywhere here but I honestly cannot see it; I will annotate as best as I can to make it look less confusing. I just... why is this happening!?
def compareLists(a, b): # to compare the guessed numbers and random numbers
return list(set(a) & set(b))
rNums = random.sample(range(10), 4) # random list of numbers
def start():
count = 0 # count for number of tries
global rNums
gNums = [] # guessed numbers
print(rNums) # cheating to save time
flag = True # to stop the guessing loop
while flag:
print("Get ready to guess 4 numbers!")
for i in range(0, 4): # asks the player 4 times to input a number
x = int(input("Guess: "))
gNums.append(x) # puts numbers in guessed numbers
comparison = len(compareLists(rNums, gNums)) # storing the length of the list of similar numbers
isCorrect = gNums == rNums # to check if lists are the same
print("You guessed: ", gNums) # telling player what they have guessed
if isCorrect: # if the lists are the same
if count > 1:
print("You win!! It only took you %d tries!" %count) # telling the player how many tries it took
else: #congratulating the player on a flawless guess
print("I CAN'T BELIEVE WHAT I'M SEEING!!!")
print("YOU GOT IT IN ONE GO!!")
count += 1 # increment count
rNums = random.sample(range(10), 4) # generate new numbers
gNums.clear()
pAgain = input("Play again?")
if pAgain.lower() in ('y', 'yes'): # replaying the game
continue
elif pAgain.lower() in ('n', 'no'):
flag = False
else:
print("Incorrect syntax!")
else:
print("You guessed " + str(comparison) + " numbers right, keep guessing!") # tells the player how many numbers are similar so the player can get a more educated guess
gNums.clear() # empties guessed numbers
count += 1 # increment count
print("Number of tries so far: %d" %count) # showing player number of tries so far
Your comparison for checking if the two lists are the same isn't working:
isCorrect = gNums == rNums # to check if lists are the same
The above code is checking if the two lists are identical, but the elements have to be in the same order.
For your test, you can just check if the number that match (ignoring order) is equal to the length of the list of numbers:
isCorrect = comparison == len(gNums) # to check if lists are the same
For more information on comparing lists regardless of order, see this answer.
Also, you should increment your count before you do your comparison with 1, or else your program will say you only took one go when you actually took two.

Loop and validation in number guessing game

I have previously studied Visual Basic for Applications and am slowly getting up to speed with python this week. As I am a new programmer, please bear with me. I understand most of the concepts so far that I've encountered but currently am at a brick wall.
I've written a few functions to help me code a number guessing game. The user enters a 4 digit number. If it matches the programs generated one (I've coded this already) a Y is appended to the output list. If not, an N.
EG. I enter 4567, number is 4568. Output printed from the list is YYYN.
import random
def A():
digit = random.randint(0, 9)
return digit
def B():
numList = list()
for counter in range(0,4):
numList.append(A())
return numList
def X():
output = []
number = input("Please enter the first 4 digit number: ")
number2= B()
for i in range(0, len(number)):
if number[i] == number2[i]:
results.append("Y")
else:
results.append("N")
print(output)
X()
I've coded all this however theres a few things it lacks:
A loop. I don't know how I can loop it so I can get it to ask again. I only want the person to be able to guess 5 times. I'm imagining some sort of for loop with a counter like "From counter 1-5, when I reach 5 I end" but uncertain how to program this.
I've coded a standalone validation code snippet but don't know how I could integrate this in the loop, so for instance if someone entered 444a it should say that this is not a valid entry and let them try again. I made an attempt at this below.
while myNumber.isnumeric() == True and len(myNumber) == 4:
for i in range(0, 4)):
if myNumber[i] == progsNumber[i]:
outputList.append("Y")
else:
outputList.append("N")
Made some good attempts at trying to work this out but struggling to patch it all together. Is anyone able to show me some direction into getting this all together to form a working program? I hope these core elements that I've coded might help you help me!
To answer both your questions:
Loops, luckily, are easy. To loop over some code five times you can set tries = 5, then do while tries > 0: and somewhere inside the loop do a tries -= 1.
If you want to get out of the loop ahead of time (when the user answered correctly), you can simply use the break keyword to "break" out of the loop. You could also, if you'd prefer, set tries = 0 so loop doesn't continue iterating.
You'd probably want to put your validation inside the loop in an if (with the same statements as the while loop you tried). Only check if the input is valid and otherwise continue to stop with the current iteration of your loop and continue on to the next one (restart the while).
So in code:
answer = [random.randint(0, 9) for i in range(4)]
tries = 5
while tries > 0:
number = input("Please enter the first 4 digit number: ")
if not number.isnumeric() or not len(number) == len(answer):
print('Invalid input!')
continue
out = ''
for i in range(len(answer)):
out += 'Y' if int(number[i]) == answer[i] else 'N'
if out == 'Y' * len(answer):
print('Good job!')
break
tries -= 1
print(out)
else:
print('Aww, you failed')
I also added an else after the while for when tries reaches zero to catch a failure (see the Python docs or maybe this SO answer)

Categories