Change value in for-loop whilst looping - python

I'm stuck on a dice exercise. For each dice that rolls 6, they need to be excluded from the count and rolled again. Problem is that I don't know how to change the value of a for range loop whilst looping through it, and I'm not sure how to attack it otherwise. Here's where I'm at:
numRolls = 10
initSum = 0
for i in range(0,numRolls):
diceScore = random.randint(1,6)
if(diceScore == 6):
print("You rolled a 6! You receive two extra rolls.")
numRolls = numRolls + 2
# Not making its way to the top of the for-loop
else:
totalSum = initSum + diceScore
print("Done! You've rolled a total of ",totalSum)
totalSum = 0
I'm guessing numRolls in the for-loop is out of scope. The alternative solutions I've come up with would mean absolutely endless amount of separate rolls. Randoming between 1 and 5 is not a viable option.. :)
Can someone point me in the right direction here?

Use a while loop and initialize the counter outside the loop. Then increment both, the counter and numRolls, as and when you want inside the loop
numRolls = 10
rollsSoFar = 0
initSum = 0
while rollsSoFar <= nulRolls:
diceScore = random.randint(1,6)
if(diceScore == 6):
print("You rolled a 6! You receive two extra rolls.")
numRolls = numRolls + 2
else:
totalSum = initSum + diceScore
rollsSoFar += 1
print("Done! You've rolled a total of ",totalSum)
totalSum = 0
Edit: added explanation for why this works
When you create a for loop like for i in range(0,numRolls) you are calling the function range() and passing it parameters 0 and numRolls. range() then gives you back a generator (let's call this generator rollsGenerator) that you iterate over. This generator has been created to give you values 0 to numRolls-1 inclusive.
So your for-loop effectively evaluates to something like for i in rollsGenerator before the first iteration begins.
Then, inside the loop, when you increment the value of numRolls, it doesn't change the number of iterations because rollsGenerator has already been created with the original value of numRolls. The for-loop does not call range(0,numRolls) on every iteration, and so the generator stays the same no matter how you change numRolls.
By using a while-loop, you are basically changing your code to check the latest value of numRolls on each iteration and you skip the whole generator business.

Consider this smaller example:
for i in range(0, 3):
i = i + 1
This is equivalent to
i = 0
i = i + 1
i = 1
i = i + 1
i = 2
i = i + 1
I'm sure you see why your idea doesn't work.
Use while instead of for.
If you count down instead of up, you don't need any more variables.
while numRolls > 0:
numRolls = numRolls - 1
diceScore = random.randint(1,6)
if(diceScore == 6):
print("You rolled a 6! You receive two extra rolls.")
numRolls = numRolls + 2
else:
totalSum = initSum + diceScore
print("Done! You've rolled a total of ",totalSum)
totalSum = 0

Related

Looping a function that changes it's output every iteration

I'm new to python and I'm trying to create something that if the number is odd for example 7 it does this (7 * 3+1) and if it is even for example 6 it does this (6/2) but the problem is that I want to loop this but it updates the number every output from the example earlier 7 I want this to turn to (22/2) and so on and if the number 1 is reached it stops.
output = []
number = 7
def mat(self):
if (self % 2) == 0:
even = self / 2
return even
else:
odd = self * 3 + 1
return odd
while mat(number) != 1:
output.append(mat(number))
output.append(mat(mat(number))
print(output)
this part doesn't work because it will never reach 1 and it only has 1 output (22) starting from the number 7 :
while mat(number) != 1:
output.append(mat(number))
output.append(mat(mat(number))
To update number, you need to assign it:
number = mat(number)
The best place to do this is in the while loop:
while number != 1:
number = mat(number)
For an exercise like this, it makes sense to just print the value on each iteration rather than trying to create an array of results:
while number != 1:
print(number)
number = mat(number)
Just update the value
For while loop:
a = 0
while a<10:
print("Hello World")
a = a + 1
For for loop:
a = 0
for i in range(10):
print("Hello World")
a = a + 1
if a >= 10:
break

Finding a more concise way to add values to empty list Python

I am new to Python and while my task is deemed correct, I know there is a more efficient way to write the code and am looking for advice.
My goal is to count the number of scores (between 1-6) of a dice roll and assign each number to a list. In this case I know the value of the dice roll 'N' - 1 will be the index at which it is added to the list but I am unsure as to how to go about writing it.
import random
dice = [0]*6
for roll in range(1001):
N = random.randint(1,6)
if N == 1:
dice[0] = dice[0] + 1
if N == 2:
dice[1] = dice[1] + 1
if N == 3:
dice[2] = dice[2] + 1
if N == 4:
dice[3] = dice[3] + 1
if N == 5:
dice[4] = dice[4] + 1
if N == 6:
dice[5] = dice[5] + 1
print(f' the number of times the dice rolled 1-6 is as follows {dice}')
You can use N-1 for the index of the list.
dice[N-1] += 1
When dealing with lists of random values, I recommend numpy:
import numpy as np
_, counts = np.unique(np.random.randint(1,7, 1000), return_counts=True)
Here you go:
dice = [0]*6
for roll in range(1001):
dice[random.randint(0, 5)] += 1
print(f' the number of times the dice rolled 1-6 is as follows {dice}')
The list is being indexed with N-1.
import random
a = random.sample(range(1, 1001), 6)
print(a)
This could brief a lot more what you are looking for
https://pynative.com/python-random-sample/

players roll 2 dice till one reaches 100

Each player roll two dice in a row on one turn. The amount of dice obtained is
added to the player's total points. The game ends when one of the players
the first has achieved at least 100 points.
from random import randint
dicesum2 = 0
dicesum1 = 0
while (dicesum1 < 100):
dice1 = [randint(1, 6) for i in range(2)]
dicesum1 += sum(dice1)
print('player 1',dice1,'|',dicesum1)
dice2 = [randint(1, 6) for i in range(2)]
dicesum2 += sum(dice2)
print('player 2',dice2,'|',dicesum2)
i need it to end when one reaches 100. how do i check both?
if a player throws exactly one single, he loses the points obtained in the turn;
how do i check when one of the generated numbers is 1?
I need it to end when one reaches 100. how do i check both?
Learn about what the or logical operator does:
dicesum1 < 100 or dicesum2 < 100
how do i check when one of the generated numbers is 1?
Learn what the in operator does:
if 1 in dice1:
# Apply penalty.
Take a look at this and see if it helps out
from random import randint
def roll():
return [randint(1, 6) for i in range(2)]
def check_for_one(rolls):
for roll in rolls:
# this could be simplified to "if 1 in rolls", this was just my preference
if roll == 1:
return True
return False
dicesum2 = 0
dicesum1 = 0
while True:
d1 = roll()
dicesum1 += sum(d1)
if check_for_one(d1):
print(f"Player 1 rolled a 1 in batch: {d1}")
print(f"Player 1 roll: {d1} | {dicesum1}")
d2 = roll()
dicesum2 += sum(d2)
if check_for_one(d2):
print(f"Player 2 rolled a 1 in batch: {d2}")
print(f"Player 2 roll: {d2} | {dicesum2}")
if dicesum1 >= 100:
print(f"Player 1 won with: {dicesum1}")
break
elif dicesum2 >= 100:
print(f"Player 2 won with: {dicesum2}")
break
So in this example, we shove the roll out to a function and check_for_one which iterates the list you are making checking for ones and returning a boolean.
I changed the loop to while True so the loop wasn't responsible for the more complex condition which can be limiting.
For each player, it performs the roll, sums, checks and reports if a 1 is in the batch, reports the roll.
Finally it checks for the winner and breaks if one is at or over 100, reporting their win.
You can change the while condition as follow :
while (dicesum1 < 100 and dicesum2 < 100):
Alternatively, you can also use break :
...
if dicesum1 >= 100:
break
...
if dicesum2 >= 100:
break

Why doesn't my program count the the last game scores?

I want to input scores of 30 matches of football game and calculate the number of the winning match and total scores. I have 30 input but it doesn't calculate the last match (30th match). What am I to do?
scores=0
win_number=0
game_number=0
x=int(input())
count=0
while count!=30 :
if x==3:
scores=scores+3
win_number=win_number+1
game_number=game_number+1
count=count+1
x=int(input())
elif x==1:
scores=scores+1
win_number=win_number+1
x=int(input())
count=count+1
elif x==0:
game_number=game_number+1
count=count+1
x=int(input())
else :
print(scores,'',win_number,game_number)
Had a little fun refactoring your code. This is what I came up with:
count = 0
scores = 0
win_number = 0
game_number = 0
while count < 30:
x = int(input())
if x not in [0, 1, 3]:
print("Wrong input - enter either 0, 1 or 3")
continue
scores += x
count += 1
game_number += 1
if x == 3 or x == 1: # is x == 1 really a win, though?
win_number = win_number+1
print(scores,'',win_number,game_number)
I will make a simplified use case to explain why your code doesnt work as you think. Imagine we only want 1 score. you set count to 0 and read the first input before your loop. So you have taken the input before the loop started. At this point the count is still set as 0. So you start your loop count != 1. This takes the input you collected outside the loop and adds to the stats. It then increments the count by 1 so the count now equals 1. You then ask for the input again. This second input is given (even though you only wanted 1 match). this input is stored in x and the first iteration of the loop ends. the loop condition count!=1 is now broken so the loop finishes after 1 iteration. so the second input which is allocated to x is never added to the stats. Which is the correct behaviour. The issue is your code structure meant that you would ask for 1 more input but never count the last one and still get 30 matches
Instead you can use a range to generate X number of iterations. Your code can also be cleaned up as there are a lot of lines that occur in each if statement these can be removed from the if and just written once in the loop.
scores=0
win_number = 0
game_number = 0
for _ in range(3):
x = int(input('score: '))
scores += x
if x == 3 or x == 1:
win_number=win_number+1
if x == 3 or x == 0:
game_number += 1
print(scores,win_number,game_number)
CONSOLE
score: 3
score: 1
score: 0
4 2 2

How to print random result multiple times using 'while loop' or other methods?

I am trying to play a game of rolling two dice. The game consists of 500 rounds. In each round, two coins are being rolled at the same time, if both coins have 'heads' then we win £1, if both have 'tails' then we lose £1 and if we have a situation where one coin shows 'heads' and the other coin shows 'tails' or vice versa then we just 'try again'.I am trying to print the final result 20 times, however the 'while loop' does not seem to be working, where am I going wrong?
coin_one = [random.randint(0, 1) for x in range(500)] #flips coin 1 heads or tails 500 times
coin_two = [random.randint(0, 1) for x in range(500)] #flips coin 2 heads or tails 500 times
game = zip(coin_one, coin_two)
def coin_toss_game1():
total = 0
for coin_one, coin_two in game:
if coin_one and coin_two:
total += 1 #if both coin one and two return heads then we win $1
elif not a and not b:
total -= 1 #if both coin one and two return tails then we lose $1
else:
continue #if coin one returns heads and coin two returns tails then we try again
return total
y = 0
while y < 21:
print(coin_toss_game1()) #This is where I am encountering problems with printing result 20 times
y += 1
This is giving a result of:
7
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Its supposed to return a result of something like: 7 2 -5 15 -9 12 ...
what mistake am I making here?
You have two issues here.
1. You're trying to reuse a zip object
In Python 3 (which I assume you're using based on your result), zip() returns a generator. A generator can only be iterated over once. If you try to iterate over it again, it will be empty. This is why all results beyond the first come back as zero... they don't actually do anything.
If you only fix, this, though, you'll still have a problem... all 20 runs will produce the same result.
2. You're using the same sequence of coin flips for all iterations
You generated your coin flips once at the top of the program, and then tried to use the same sequences for all 20 rounds. It shouldn't be surprising that all results will be the same.
The fix for both issues is the same: move the generation of coin flips and zipping into the function so that it gets redone each time you run it:
def coin_toss_game1():
coin_one = [random.randint(0, 1) for x in range(500)]
coin_two = [random.randint(0, 1) for x in range(500)]
game = zip(coin_one, coin_two)
total = 0
for coin_one, coin_two in game:
...
As an aside, a simpler Python idiom for looping a fixed number of times is:
for _ in range(20): # Nothing magical about the underscore... it's just a dummy variable
print(coin_toss_game1())
I think this is the code you're looking for:
def coin_toss_game1():
coin_one = [random.randint(0, 1) for x in range(500)]
coin_two = [random.randint(0, 1) for x in range(500)]
game = zip(coin_one, coin_two)
total = 0
for a, b in game:
if a and b:
total += 1
elif not a and not b:
total -= 1
else:
continue
return total
y = 0
while y < 21:
print(coin_toss_game1())
y += 1
The code you have runs the game once (500 rounds) instead of 20 times. The code above, with each iteration of the while loop, runs the 500 rounds and displays the results. So you get the result of a 500-round game, 20 times.

Categories

Resources