I am trying to get some probability by simulating a game (assimilation) using python.
A and B play a game where they take turns to throw a coin (A starts first), and the first one to throw a head wins. But their coins are biased! A's coin has a 1 in 5 chance of coming up heads, and B's coin has a 1 in 3 chance of coming up heads.
The code should simulate it and answer this question: What is the probability of A winning if he goes first?
By solving through mathematically, I came to this solution: 3/7.
This is what I've done so far, but it doesn't give me the expected number.
import numpy as np
def P1_win_prob_weighted_coin_game(num_games, prob_heads=.5):
player_one_wins = 0
for n in range(0,num_games):
num_flips = 0
win = 0
while win == 0:
turn = np.random.uniform(0,1)
num_flips += 1
if turn <= prob_heads:
if num_flips % 2 != 0:
player_one_wins += 1
win += 1
return float(player_one_wins)/float(num_games)
What am I doing wrong?
I think I got it.
First, define a function that plays one game and tells me who the winner was.
def get_winner(prob_to_win=[1/5, 1/3]):
''' Tells who the winner was.
Params:
prob_to_win is a list with the probabilites of each player to win
Returns:
the index of the player who won (based on prob_to_win)
'''
number_of_players = len(prob_to_win)
while True:
for player in range(number_of_players):
coin_flip = np.random.uniform()
if coin_flip <= prob_to_win[player]:
return player
Next, define the names, probabilites and number of games to play (observeations)
player_names = ['A', 'B']
player_probs = [1/5, 1/3]
number_of_games = 500000
Let the games begin! (Note: for more verbosity, you can uncomment the print line)
player_win_count = [0, 0]
for i in range(number_of_games):
winner = get_winner(player_probs)
player_win_count[winner] += 1
# print(f'The winner was {player_names[winner]} ({player_win_count[winner]} wins so far)')
Finally, get and display the results.
for (player, wins) in zip(player_names, player_win_count):
chances = wins/number_of_games
print(f'Statistics (with {number_of_games} observations) tell that player {player} has {chances} chances to win against others')
Outputs:
Statistics (with 500000 observations) tell that player A has 0.427982 chances to win against others
Statistics (with 500000 observations) tell that player B has 0.572018 chances to win against others
Which is very close to the probability that you calculated 3/7.
Hope it helps! This was fun :)
Related
Consider the following code
import random
fruits = [0, 0]
for _ in range(1000):
if random.choices(['apple', 'orange'], weights=[0.5, 0.5])[0] == 'apple':
fruits[0] += 1
else:
fruits[1] += 1
Looks pretty standard, predictable "output" in the list fruits. But what if you instead let it run for an unknown period of time, face-offs on top of each other, and certain criterion must be met.
def game():
pts_apple = 0
pts_orange = 0
while True:
if random.choices(['apple', 'orange'], weights=[0.54, 0.46])[0] == 'apple':
pts_apple += 1
else:
pts_orange += 1
if pts_apple >= 5 and pts_apple - pts_orange >= 3: # change for bigger differences
pts_apple = 0
pts_orange = 0
fruits[0] += 1
break
elif pts_orange >= 5 and pts_orange - pts_apple >= 3:
pts_apple = 0
pts_orange = 0
fruits[1] += 1
break
What I've noticed is the disparity is more prominent when the criterion for minimum number of points increases, and the when the difference between them must be greater. So, what is going on? I have though about this for quite som time, but I'm stumped. Why would the probability of a winner change so radically? I can only think of one reason
There is som kind of "stacking" going on. So, you win one, but then you must win another, then yet another and so on, until you meet the criteria. Because 'apple' has greater odds, there is a greater chance for 'apple' to win.
Am I missing something?
Also, how would you go about minimizing the disparity, if you have to use certain numbers? You want to be able to find the probability before you do the computation, but you don't know the number of 'face-offs'! For example, if you stack them, two 'face-offs' has 'apple' at a two-win probability of .54 * .54, right? But what if there are 200 'face-offs' before you find a winner? Do you use a normal distribution?
Cheers!
It looks like the code you've provided simulates a simple game where players can choose to play as either an "apple" or an "orange". In each round of the game, a player wins a point if they choose the fruit that is chosen by the random.choices function. The game continues until one player has scored at least five points and has at least a three-point lead over the other player. When this happens, the winning player's score is added to the fruits list and the game resets.
The key difference between the first code snippet and the game() function is that the first code snippet simply counts how many times an "apple" or an "orange" is chosen by the random.choices function, while the game() function simulates a game where players can win and lose points. This means that the output of the game() function will be different from the output of the first code snippet.
One thing to note is that the game() function has a potential for an infinite loop, because it does not have any conditions for ending the game if it goes on for too long. This could potentially cause problems if the function is allowed to run for a very long time. It might be a good idea to add a maximum number of rounds or a timeout to the game to prevent this from happening.
I have to make a card game in which the starting player changes after each round or mini round (up to me to decide) but I have no clue how to alternate between the 2 players. After reading online, I tried using the cycle function from itertools but that creates further problems...
The problem is that I do not know how to alternate between the 2 players without messing up the rest of the program (displaying the player's hand and the scoring system)
To clarify in advance, the code snippets I am about to provide work perfectly as long as I do not alternate between the starting players.
Code:
print("Player 1, your cards are: ", hands[0])
print("Player 2, your cards are: ", hands[1])
In this case I want the hands index to change accordingly to the Player if i use the cycle function.
if cards.bigger_card(hands[0][play_1 - 1], hands[1][play_2 - 1], trump[0][1]) == 0:
print("Congrats Player 2! You won this mini round.")
score["score_2"] += 1
else:
print("Congrats Player 1! You won this mini round.")
score["score_1"] += 1
Here the score should update according to the Player that won the round.
I'm not sure if I've understood your question well enough. But I'll try.
To simply alternate between two index i.e. 0, 1, you can add a variable to store current turn and alternating it like this:
currentTurn = 0
def switchTurn():
return (currentTurn + 1) % 2
Usage:
print(currentTurn)
# output: 0
switchTurn()
print(currentTurn)
# output: 1
print(hands[currentTurn])
# output player 2nd's hands (or cards)
The issue is that the number of stones the computer takes differs from the number that is displayed on the screen.
I know it's cause the function is being repeated twice. But I can't find a way to store the random number generated and use that number for printing AND subtracting
[Also I know this can be done without using functions but it is required]
Here is the code:
import random
stones = random.randint(15, 30)
turn = 0
while stones > 0:
if turn == 0:
def player_announce():
print('There are', stones, 'stones. How many would you like?', end=' ')
def invalid_entry():
print('Enter a number from 1-3.')
player_announce()
player_stones = int(input(''))
if player_stones > 3 or player_stones < 1:
invalid_entry()
else:
stones = stones - player_stones
turn = 1
else:
def draw_stones():
computer_stones = random.randint(1, 3)
return computer_stones
print('There are', stones, 'stones. The computer takes', draw_stones())
stones -= draw_stones()
turn = 0
if turn == 0:
print('The computer beats the player!')
else:
print('The player beats the computer!')
The simple answer is to call draw_stones once and store the result:
computers_stones = draw_stones()
print('There are', stones, 'stones. The computer takes', computers_stones)
stones -= computers_stones
Once you've got it working, I advise you get someone to read over the whole thing for you there are a lot of things you could do better!
I'm a beginner in python trying to create a RPS game where human is playing against a computer. The game is created such that it would be played over a number of determined rounds (best of 3 rounds). A draw is considered a point for each side.
My problem is setting the while condition. Initially I did this:
while (player_count + computer_count) != winning_score : where the game ends when all round are played. However there will be instances where not all rounds needs to be played and the winner can already be determined (because of draws, each player will get a point).
How do I change the while condition such that when either players get winning_score/2 + 1, the game ends?
hi you can probably do it like this
winning_count = winning_score/2+1
while(player_count < winning_count) and (computer_count < winning_count):
...
Once either the player win or the computer win is more than the winning count, it goes to False and the loop breaks
Just in case you want to have another perspective on how to implement the game (and how to determine the winner), I exhort you to play with the following version:
import random
options = {1: 'Rock', 2: 'Scissors', 3: 'Paper'}
def play():
score = [0, 0]
while not any(wins == 3 for wins in score):
print(f'SCORE\tUser: {score[0]} - PC: {score[1]}')
user_selection = int(input('Enter your selection:{}> '.format(
''.join([f'\n{n}: {option}\n' for n, option in options.items()]))))
pc_selection = random.randint(1, 3)
print(f'{options[user_selection]} vs. {options[pc_selection]}')
if user_selection in (pc_selection - 1, pc_selection + 2):
print('User wins')
score[0] += 1
elif user_selection == pc_selection:
print('Draw')
else:
print('PC Wins')
score[1] += 1
input('\n_____ ENTER TO PROCEED _____')
winner = 'User' if score[0] == 3 else 'PC'
print(f'\n{winner} won the match!')
play()
Hopefully you will find here something useful and new for your learning process.
I'm trying to make a code for a multiplayer dice rolling game where the user can input how many players.
I want the code to repeat until a player reaches 100 points and go on a cycle between all the players.
I've tried all sorts of functions/modules for this and asked peers and some teachers, searched online for this and all over stack overflow but couldn't find an answer.
playerPoints = {}
toRoll = ""
minPlayers = 2
maxPlayers = 4
winner = 100
double1 = 25
def players(numberOfPlayers):
numberOfPlayers = 0
while numberOfPlayers not in (str(i) for i in range (minPlayers,maxPlayers)):
numberOfPlayers = int(numberOfPlayers)
for i in range(numberOfPlayers):
playerPoints["score{}".format(i+1)] = 0
return numberOfPlayers
def diceroll():
die1 = randint(1,6)
die2 = randint(1,6)
return die1, die2
roll = 0
while roll not in (str(i) for i in toRoll):
roll = input("Press enter to roll both dice")
if roll == toRoll:
print(str(die1) + " and " + str(die2))
break
I want the code to continue however I am stuck at this point where the code only asks how many players are there and then breaks.
I called the function by doing:
numberOfPlayers = input("How many players are there? (2-4)")
players(numberOfPlayers)
diceroll(die1, die2)
roll()
Possible fix for your problem
There are all kinds of return statements in your code which makes it impossible for some code to be executed. Like in the diceroll function where you return die1 and die2 in:
return die1, die2
The code after that line is never exectuted because the function returns some values.
You say that you execute the function like so:
numberOfPlayers = input("How many players are there? (2-4)")
players(numberOfPlayers)
diceroll(die1, die2)
roll()
However, the diceroll function takes zero parameters, while you give it two (die1 and die2), this won't work. Also I don't see a roll function in your code, so that will give you an error as well.
How I would have done it
So, I know StackOverflow is not the place where we write code for you. But since there were all kinds of things in your code that I found weird. I have rewritten the code as how I would have done it:
import random
playerPoints = []
minPlayers = 2
players = 0
maxscore = 100
amountOfDice = 2
gameRound = 0
def setPlayers():
while True:
players = input("How many players are playing?\n")
if players.isdigit():
players = int(players)
if minPlayers <= players:
for i in range(players):
playerPoints.append(0)
return players
def diceroll(player, amountOfDice):
throw = 0
print("\tPlayer {0}s turn:".format(player + 1))
for i in range(amountOfDice):
die = random.randint(1, 6)
print("\t\tPlayer {0} has thrown die {1} which landed on {2}".format(player + 1, i + 1, die))
throw += die
playerPoints[player] += throw
print("\tPlayer {0}s score is now: {1}".format(player + 1, playerPoints[player]))
return throw
def checkWin(maxscore):
for player in range(players):
if (playerPoints[player] >= maxscore):
print("Player {0} wins!".format(player + 1))
return True
return False
if __name__ == "__main__":
players = setPlayers()
while True:
gameRound += 1
print("Round: {0}".format(gameRound))
for i in range(players):
diceroll(i, amountOfDice)
if (checkWin(maxscore)):
break
Now, first off, I removed some restrictions in the players function (and changed the name to setPlayers). Your code didn't have a check if the input was a number, which could result in an error. I also removed the restriction of 4 players, because the code works with every amount (if 2 or higher ofcourse).
The diceroll function now takes the player that will roll as an argument as well as the amount of dice that will be rolled.
I also added the checkWin function which checks if a player has won. It takes the maximum score as an argument.
Now this probably isn't the fastest code, however I think its understandable. If you have any questions about it, feel free to ask.