1

I am struggling with the solution of the 'Coin Flip' practice project at the end of chapter 4 in 'Automate the boring stuff' for python programming.
I have two solutions, both yielding a totally different result (first one is clearly false). I am not sure, what is the right solution to the answer.

Solution 1:

import random
nextFlip = []
numberOfStreaks = 0

# Code that creates a list of 10000 'heads' or 'tails' values.

for expNum in range(10000):                
    select = random.randint(0,1)
    if select == 0:
        nextFlip.append('H')
    elif select == 1:
        nextFlip.append('T')
    
# Code that checks if there is a streak of 6 heads or tails in a row.

    for i in range(0,(len(nextFlip)-6)):
        if nextFlip[i] == nextFlip[i+1] == nextFlip[i+2] == nextFlip[i+3] == nextFlip[i+4] == nextFlip[i+5] != nextFlip[i+6]:
            numberOfStreaks +=1


print('Chance of streak: %s%%' % ((numberOfStreaks / 10000)*100)) 

Solution 2:

import random
nextFlip = []
hlist = 0
tlist = 0
numberOfStreaks = 0

# Code that creates a list of 10000 'heads' or 'tails' values.

for expNum in range(10000):                
    select = random.randint(0,1)
    if select == 0:
        nextFlip.append('H')
    elif select == 1:
        nextFlip.append('T')

    
# Code that checks if there is a streak of 6 heads or tails in a row.

    for i in range(0,(len(nextFlip)-6)):
        if nextFlip[i] == 'H':
            hlist += 1
            if hlist == 6:
                numberOfStreaks +=1
            
        elif nextFlip[i] == 'T':
            tlist += 1
            if tlist == 6:
                numberOfStreaks +=1

print('Chance of streak: %s%%' % ((numberOfStreaks / 10000)*100))

Maybe someone can help me and tell me what I did wrong.

Ines1709
  • 19
  • 3
  • What are the different results? What did you expect the results to be? Given the nature of randomness, why did you expect them to be the same? – jarmod Sep 29 '21 at 17:41
  • 1
    Not related to the problem, but you could just use `random.choice(('H', 'T'))` instead of `random.randint(0, 1)` and then converting the numbers to letters. – Barmar Sep 29 '21 at 17:41
  • 2
    What problem does the code need to solve? You haven't described the problem, only shown two solutions, one of which "is clearly false". – Morten Jensen Sep 29 '21 at 17:42
  • don't assume we know what Question 4 of Automate the Boring Stuff is, you need to specify what the problem asks – gold_cy Sep 29 '21 at 17:42
  • 1
    Is your indentation exactly as you have it in your script? Your second `for` loop is indented one level too deep. – Axe319 Sep 29 '21 at 17:43
  • 1
    The second `for` loop shouldn't be inside the first `for` loop. – Barmar Sep 29 '21 at 17:43
  • The second version doesn't actually check for streaks. It's just counting the number of `H` and `T` in the list, and adds `1` to `numberOfStreaks` when the count is 6. – Barmar Sep 29 '21 at 17:47
  • The exercise is this: https://automatetheboringstuff.com/2e/chapter4/#:~:text=Coin%20Flip%20Streaks,bad%20at%20math. The first code yields over 100%, so it must be wrong. – Ines1709 Sep 29 '21 at 18:08
  • I get for the first code > 7000% and for the second 0.02%. After decreasing the indentation of the second for loop as you said, I get 1.43 % for the first code and also 0.02 % for the second. Of course it is a random generator, but the magnitude should be almost equal. I don't know how to calculate it by hand, so I am not sure what to expect. – Ines1709 Sep 29 '21 at 18:12
  • Solution 2 doesn't work. It doesn't count streaks of 6 – KavG Sep 29 '21 at 18:34
  • Are you supposed to check for streaks of exactly 6, or streak lengths of 6 or more. The first one will count a streak of 8 as 3 streaks of 6. Is that the intent? – RufusVS Sep 29 '21 at 18:36
  • in your second version, the hlist should be reset to zero as soon as you get a tail, and the tlist should be reset to zero as soon as you get a head. – RufusVS Sep 29 '21 at 18:38
  • No it should count exactly a streak of 6. Why does it count 8 as 3 streaks of 6? In the second code, after reseting the hlist to 0 again, I also get a number of >100%. – Ines1709 Sep 29 '21 at 18:59

5 Answers5

1

I'm just learning with the same book too. I found this easier to treat as a string, rather than a list. I believe that the problem is asking you to find whether a streak of 6 or more consecutive heads or a streak of 6 or more consecutive tails occurs in 100 tosses of a coin. For each 100 tosses, the result is 0 or 1 (I don't think you count multiple streaks). The 10,000 runs is to gain a reasonable accuracy and avoid sampling error.

import random

number_of_streaks = 0

for experiment_number in range(10000):
    
    # Code that creates a list of 100 'heads' or 'tails' values
    coin_list = ''
    for i in range(100):
        if random.randint(0, 1) == 0:
            coin_list = coin_list + 'H' # heads
        else:
            coin_list = coin_list + 'T' # tails
    
    # Code that checks if there is a streak of 6 heads or tails in a row
    if 'HHHHHH' in coin_list or 'TTTTTT' in coin_list:
        number_of_streaks +=1

print('Chance of streak: %s%%' % (number_of_streaks / 100))

Further to advice in comments from @rchome, I added a simple timer to this original code (https://stackoverflow.com/a/1557584/17555691) and it gave the following response:

Chance of streak: 80.06% --- 0.8480644226074219 seconds ---

Next, I made a small change, using append to a list and then converting to a string:

# Code that creates a list of 100 'heads' or 'tails' values
coin_list = []
for i in range(100):
    if random.randint(0, 1) == 0:
        coin_list.append('H') # heads
    else:
        coin_list.append('T') # tails

# Code that checks if there is a streak of 6 heads or tails in a row
coin_string = ''.join(coin_list)
if 'HHHHHH' in coin_string or 'TTTTTT' in coin_string:
    number_of_streaks +=1

Output from this version:

Chance of streak: 80.26% --- 0.739051342010498 seconds ---

Then made a change, using recommendation from @Alain T:

# Code that creates a list of 100 'heads' or 'tails' values
flips   = "".join(random.choice('HT') for _ in range(100))

# Code that checks if there is a streak of 6 heads or tails in a row
if 'HHHHHH' in flips or 'TTTTTT' in flips:
    number_of_streaks +=1

Output from this version: Chance of streak: 80.74% --- 0.4248924255371094 seconds ---

The above results were quite typical on repeated executions.

  • Just be aware that appending to a string is an `O(len(string))` operation since Python will copy the string to a new memory location and add the next character to it, and doing it in a loop will make the inefficiency even more apparent. It would be more efficient to create the string by appending the coin flip results to a list then using `"".join()` to build the string. – rchome Dec 01 '21 at 02:09
0

This seems to work:-

import random

N = 10_000
S = 6
HEAD = 'H'
TAIL = 'T'
T = [HEAD if random.randint(0, 1) else TAIL for _ in range(N)]
c = T[0]
s = 1
STREAKS = 0
for t in T[1:]:
    if t == c:
        s += 1
        if s == S:
            STREAKS += 1
            s = 0
    else:
        c = t
        s = 1
print(STREAKS)
0

You could generate the random flips using a comprehension and store it in a string to make processing of the streaks easier. Since streaks can overlap, you need to examine subranges starting at every position:

flips   = "".join(random.choice("HT") for _ in range(1000))

streaks = sum(flips[i:i+6] in ('HHHHHH','TTTTTT') for i in range(1000))

The sum() function will convert boolean values to 1 or zero (True is 1), so adding up the result of the streak conditions produces the total.

Alain T.
  • 40,517
  • 4
  • 31
  • 51
0
#Defining Inputs and importing modules
import random
numberOfStreaks = 0
mylist=[]
countH=0
countT=0
conuterTail=[]
conuterHead=[]
for experimentNumber in range(10000):
# Code that creates a list of 10000 'heads' or 'tails' values.
    rndnum=random.randint(0,1);
    if rndnum==0:
        countH=0 # if the random number is "0" then "HEAD" counts will be reset
        mylist.append(['T'])
        countT+=1
    else:
        countT=0 # if the random number is "1" then "TAIL" counts will be reset
        mylist.append(['H'])
        countH+=1
# Code that checks if there is a streak of 6 heads or tails in a row.
    if countT==6:
        conuterTail.append(countT)
    elif  countH==6:
        conuterHead.append(countH);


numberOfStreaks=len(conuterHead)+len(conuterTail)

print('Chance of streak: %s%%' % (numberOfStreaks / 100))
0

I understood the question to be asking: what is the chance that a streak of 6 consecutive like coin tosses would be contained within a set of 100 random coin tosses. I thought this should include instances of multiple streaks within the same set of tosses. Whenever a streak of values reached six in a row, the count was reset to zero, in order to capture the next streak. Some iterations contained no streaks, while others contained multiple. A large number of iterations were averaged to smooth variances. The average value returned was 158-160%, meaning very likely.

import random
numberOfStreaks = 0
countH = 0
countT = 0
iterations_of_experiment = 10000
for experimentNumber in range(iterations_of_experiment):
    #Code that creates a list of 100 'heads' or 'tails' values
    setOfHundred = [] #set list to empty each iteration
    
    for i in range(100):
        if random.randint(0, 1) == 0:
            countT = 0  #Set Tails count to zero on head flip
            setOfHundred.append('H')
            countH += 1
            if countH == 6:
                numberOfStreaks += 1
                countH = 0 #Reset counter to zero to capture -
        else:              #multiple streaks
            countH = 0
            setOfHundred.append('T')
            countT += 1
            if countT == 6: 
                numberOfStreaks += 1
                countT = 0

print('In ' + str(iterations_of_experiment) + \
    ' iterations of 100 coin tosses, there were ' + str(numberOfStreaks) + \
    ' streaks of 6 consecutive like coin flips.')
print('Chance of streak: ' + str(numberOfStreaks / iterations_of_experiment * 100) + '%')
geanakuch
  • 778
  • 7
  • 13
  • 24
Nate S
  • 1
  • 3