Reputation: 23
I am trying to create a script that flips a coin untill either "heads" is flipped 3 times in a row, or " tails" is flipped 3 times in a row.
My attempt is a quite long snippet of code that does not do what I want it to do. It simply prints out "heads" once and loops on forever:
import random
cointosses = []
total_count = 0
while total_count >= 0:
tosses = random.randint(1,2)
total_count += 1
if tosses == 1:
cointosses.append("heads")
if tosses == 2:
cointosses.append("tails")
print(cointosses)
seq_counter1 = 0
seq_counter2 = 0
total_seq = 0
while total_seq <= 3:
check1 = "heads"
check2= "tails"
for toss in cointosses:
if toss == check1:
seq_counter1 +=1
seq_counter2 = 0
if seq_counter1 == 3:
total_seq = 3
break
if toss == check2:
seq_counter1 = 0
seq_counter2 +=1
if seq_counter2 == 3:
total_seq = 3
break
if total_seq == 3:
break
I'm sure there is some much simpler way of doing this, but I can't seem to figure it out.
Upvotes: 1
Views: 1205
Reputation: 322
The inner while loop only terminates if the variable total_seq contains a value greater than 3. Since the only values that could possibly be assigned to it are 0 and 3 (according to your code), this while loop will go on forever.
...
total_seq = 0 #<-----------------------
while total_seq <= 3:
...
for toss in cointosses:
if toss == check1:
...
if seq_counter1 == 3:
total_seq = 3 #<-----------------------
break
if toss == check2:
...
if seq_counter2 == 3:
total_seq = 3 #<-----------------------
break
...
random.randint(...) gives you one value which is stored in the cointosses list (which means: you only flip the coin once). The inner for loop assumes however, that you have a large number of tosses already stored in the list. It only sets total_seq to 3 if it can find 3 consecutive coinflips.
Otherwise it will just repeat the inner while loop and do the same thing again without adding new coinflips (outer while is never reached again)
tosses = random.randint(1,2)
...
if tosses == 1:
cointosses.append("heads")
if tosses == 2:
cointosses.append("tails")
...
for toss in cointosses:
...
if seq_counter1 == 3:
total_seq = 3
break
...
if seq_counter2 == 3:
total_seq = 3
break
...
Since you only coinflip once (as discussed in problem 2) the "previous coinflip" is always just the first one you did. This means that you coinflip once at the beginning and either increment seq_counter1 or seq_counter2 to 3 depending on the result of that first flip.
...
seq_counter1 = 0
seq_counter2 = 0
...
while total_seq < 3:
...
if toss == check1:
seq_counter1 +=1
seq_counter2 = 0
...
if toss == check2:
seq_counter1 = 0
seq_counter2 +=1
...
...
All three problems can be solved by removing the inner while loop and simply execute its code in the outer one:
import random
cointosses = []
total_count = 0
while total_count >= 0:
tosses = random.randint(1,2)
total_count += 1
if tosses == 1:
cointosses.append("heads")
if tosses == 2:
cointosses.append("tails")
print(cointosses)
seq_counter1 = 0
seq_counter2 = 0
total_seq = 0
check1 = "heads"
check2= "tails"
for toss in cointosses:
if toss == check1:
seq_counter1 +=1
seq_counter2 = 0
if seq_counter1 == 3:
total_seq = 3
break
if toss == check2:
seq_counter1 = 0
seq_counter2 +=1
if seq_counter2 == 3:
total_seq = 3
break
if total_seq == 3:
break
This works because the condition total_seq == 3 is already tested by the last if statement in the outer loop.
This code however is not verry perfomant since you build a list and iterate over it again and again. You are iterating over everything every time you append one cointoss. However if you think about it: You only need to check if the newly appended element creates a consecutive row.
If you want to do this right, you should do it with only one loop (no nested loops) :)
Upvotes: 1
Reputation: 51633
You do never leave your while
loop that checks your list. The break
statements only leaves the for
-loop (setting total_seq = 3
) - your while
loops until total_seq
is greater then 3 -> endless loop:
while total_seq <= 3: # this is never been left because <= 3 check1 = "heads" # ^^ smaller equal check2= "tails" for toss in cointosses: if toss == check1: seq_counter1 +=1 seq_counter2 = 0 if seq_counter1 == 3: total_seq = 3 break # breaks out of the for but total_seq = 3 so in while if toss == check2: seq_counter1 = 0 seq_counter2 +=1 if seq_counter2 == 3: total_seq = 3 break # breaks out of the for but total_seq = 3 so in while
You can simplify your code a lot by simply adding to the list and checking if the last 3 elements are equal instead of checking the whole list every time:
import random
def toss():
"""Return randomly 'heads' or 'tails'."""
return "heads" if (random.randint(1,2) == 1) else "tails"
# need at least 3 tosses to finish
cointosses = []
for _ in range(3):
cointosses.append(toss())
print(cointosses)
# repeat until the set(..) of the last 3 elements contains exactly 1 item
while not len(set(cointosses[-3:]))==1:
cointosses.append(toss())
print(cointosses)
print(f"It took {len(cointosses)} tosses to get 3 equal ones.")
Output 2 runs:
['tails']
['tails', 'tails']
['tails', 'tails', 'heads']
['tails', 'tails', 'heads', 'heads']
['tails', 'tails', 'heads', 'heads', 'heads']
It took 5 tosses to get 3 equal ones.
['tails']
['tails', 'tails']
['tails', 'tails', 'heads']
['tails', 'tails', 'heads', 'heads']
['tails', 'tails', 'heads', 'heads', 'tails']
['tails', 'tails', 'heads', 'heads', 'tails', 'heads']
['tails', 'tails', 'heads', 'heads', 'tails', 'heads', 'tails']
['tails', 'tails', 'heads', 'heads', 'tails', 'heads', 'tails', 'tails']
['tails', 'tails', 'heads', 'heads', 'tails', 'heads', 'tails', 'tails', 'heads']
['tails', 'tails', 'heads', 'heads', 'tails', 'heads', 'tails', 'tails', 'heads', 'heads']
['tails', 'tails', 'heads', 'heads', ... snipp ..., 'tails', 'heads', 'heads', 'tails']
['tails', 'tails', 'heads', 'heads', ... snipp ..., 'heads', 'heads', 'tails', 'tails']
['tails', 'tails', 'heads', 'heads', ... snipp ..., 'heads', 'tails', 'tails', 'tails']
It took 13 tosses to get 3 equal ones.
If you dislike set()
you could also check:
while not all(i == cointosses[-1] for i in cointosses[-3:-1]):
# rest identical
Doku:
Upvotes: 2