pythoncoin-flipping

Python: Can a coin flip generator be modified to printout certain combinations?


Simply put, I would like to know if there is a way to print out coin flip combinations that only meet a certain criteria. In this case, only those with <=n consecutive H's or T's gets printed.

For example, here's all possible combinations of 5 coin flips using itertools.product*:

>>> list(itertools.product('HT', repeat=5))
[('H', 'H', 'H', 'H', 'H'), ('H', 'H', 'H', 'H', 'T'), ('H', 'H', 'H', 'T', 'H'), ('H', 'H', 'H', 'T', 'T'), 
('H', 'H', 'T', 'H', 'H'), ('H', 'H', 'T', 'H', 'T'), ('H', 'H', 'T', 'T', 'H'), ('H', 'H', 'T', 'T', 'T'), 
('H', 'T', 'H', 'H', 'H'), ('H', 'T', 'H', 'H', 'T'), ('H', 'T', 'H', 'T', 'H'), ('H', 'T', 'H', 'T', 'T'), 
('H', 'T', 'T', 'H', 'H'), ('H', 'T', 'T', 'H', 'T'), ('H', 'T', 'T', 'T', 'H'), ('H', 'T', 'T', 'T', 'T'), 
('T', 'H', 'H', 'H', 'H'), ('T', 'H', 'H', 'H', 'T'), ('T', 'H', 'H', 'T', 'H'), ('T', 'H', 'H', 'T', 'T'), 
('T', 'H', 'T', 'H', 'H'), ('T', 'H', 'T', 'H', 'T'), ('T', 'H', 'T', 'T', 'H'), ('T', 'H', 'T', 'T', 'T'), 
('T', 'T', 'H', 'H', 'H'), ('T', 'T', 'H', 'H', 'T'), ('T', 'T', 'H', 'T', 'H'), ('T', 'T', 'H', 'T', 'T'), 
('T', 'T', 'T', 'H', 'H'), ('T', 'T', 'T', 'H', 'T'), ('T', 'T', 'T', 'T', 'H'), ('T', 'T', 'T', 'T', 'T')]

However, I want the printout to show only the results with no more than three H's or T's in a row. Like this:

[('H', 'H', 'H', 'T', 'H'), ('H', 'H', 'H', 'T', 'T'), ('H', 'H', 'T', 'H', 'H'), ('H', 'H', 'T', 'H', 'T'), 
('H', 'H', 'T', 'T', 'H'), ('H', 'H', 'T', 'T', 'T'), ('H', 'T', 'H', 'H', 'H'), ('H', 'T', 'H', 'H', 'T'), 
('H', 'T', 'H', 'T', 'H'), ('H', 'T', 'H', 'T', 'T'), ('H', 'T', 'T', 'H', 'H'), ('H', 'T', 'T', 'H', 'T'), 
('H', 'T', 'T', 'T', 'H'), ('T', 'H', 'H', 'H', 'T'), ('T', 'H', 'H', 'T', 'H'), ('T', 'H', 'H', 'T', 'T'), 
('T', 'H', 'T', 'H', 'H'), ('T', 'H', 'T', 'H', 'T'), ('T', 'H', 'T', 'T', 'H'), ('T', 'H', 'T', 'T', 'T'), 
('T', 'T', 'H', 'H', 'H'), ('T', 'T', 'H', 'H', 'T'), ('T', 'T', 'H', 'T', 'H'), ('T', 'T', 'H', 'T', 'T'), 
('T', 'T', 'T', 'H', 'H'), ('T', 'T', 'T', 'H', 'T')]

*Obviously this isn't the only method to implement this, it just happen to be the one I came across since I'm still new at programming.

~Update~

dabljues suggested the following:

In [38]: all_combinations = itertools.product('HT', repeat=5) 
    ...: not_more_than_3_combinations = [] 
    ...: for combination in all_combinations: 
    ...:     for _, group in itertools.groupby(combination): 
    ...:         if sum(1 for _ in group) <= 3:            
    ...:             not_more_than_3_combinations.append(combination) 
    ...:         break 
    ...: print(not_more_than_3_combinations)

Not sure how to implement it yet (again, I'm a beginner) but it looks the most promising.

Thanks.


Solution

  • Just bear in mind, that the fact that it even gets printed is because you are using an interpreter. If you would happen to write this code in an editor and run it via e.g. a terminal, there would be no output.

    Now, you want to print those combinations which have no more than 3 Hs or Ts in a row. That's not something that itertools package would do for you. You need to implement this by yourself.

    For example:

    In [38]: all_combinations = itertools.product('HT', repeat=5) 
        ...: not_more_than_3_combinations = [] 
        ...: for combination in all_combinations: 
        ...:     for _, group in itertools.groupby(combination): 
        ...:         if sum(1 for _ in group) <= 3:            
        ...:             not_more_than_3_combinations.append(combination) 
        ...:         break 
        ...: print(not_more_than_3_combinations)
    
    [('H', 'H', 'H', 'T', 'H'), ('H', 'H', 'H', 'T', 'T'), ('H', 'H', 'T', 'H', 'H'), ('H', 'H', 'T', 'H', 'T'), ('H', 'H', 'T', 'T', 'H'), ('H', 'H', 'T', 'T', 'T'), ('H', 'T', 'H', 'H', 'H'), ('H', 'T', 'H', 'H', 'T'), ('H', 'T', 'H', 'T', 'H'), ('H', 'T', 'H', 'T', 'T'), ('H', 'T', 'T', 'H', 'H'), ('H', 'T', 'T', 'H', 'T'), ('H', 'T', 'T', 'T', 'H'), ('H', 'T', 'T', 'T', 'T'), ('T', 'H', 'H', 'H', 'H'), ('T', 'H', 'H', 'H', 'T'), ('T', 'H', 'H', 'T', 'H'), ('T', 'H', 'H', 'T', 'T'), ('T', 'H', 'T', 'H', 'H'), ('T', 'H', 'T', 'H', 'T'), ('T', 'H', 'T', 'T', 'H'), ('T', 'H', 'T', 'T', 'T'), ('T', 'T', 'H', 'H', 'H'), ('T', 'T', 'H', 'H', 'T'), ('T', 'T', 'H', 'T', 'H'), ('T', 'T', 'H', 'T', 'T'), ('T', 'T', 'T', 'H', 'H'), ('T', 'T', 'T', 'H', 'T')]
    

    So, you get all the combinations, then you iterate over them. Using .groupby() you get items grouped in groups like ['H', 'H', 'H'] and ['T', 'T']. You check if the first one of them is of length <=3. If yes, this is a valid combination form your point of view. Whether you added this combination or not you skip checking this combination to not add it twice or adding it because one group meets your criteria (f.e. 4 Hs didn't pass the if check, but 1 T works fine, so it would be added).

    Since you have only 2 possibilities (H and T) and only 5 repeats, this will work.