├── .gitignore ├── README.md ├── data ├── country_names_2017.txt └── state_names.txt └── scripts ├── all_aboard.py ├── average_number_of_matches.py ├── bags_of_marbles.py ├── bold_play_vs_cautious_play.py ├── broken_bar.py ├── carnival_barker.py ├── catching_the_cautious_counterfeiter.py ├── chance_of_dying.py ├── chuck_a_luck.py ├── clumsy_chemist.py ├── coin_flip_sequences.py ├── collecting_coupons.py ├── craps.py ├── curing_the_compulsive_gambler.py ├── dicey_question.py ├── draw_two.py ├── even_split.py ├── exceed_1.py ├── first_ace.py ├── flippant_juror.py ├── flipping_n_coins.py ├── four_flips.py ├── gamblers_ruin.py ├── gummy_bears.py ├── hit_and_run.py ├── hurried_duelers.py ├── infinite_monkeys.py ├── length_of_random_chords.py ├── little_end_of_the_stick.py ├── lonely_card_game.py ├── lunch_in_the_park.py ├── minority_selection.py ├── missiles.py ├── newton_helps_pepys.py ├── painting_puzzle.py ├── petersburg_paradox.py ├── quiz_answers.py ├── second_best.py ├── specific_shuffling_problem.py ├── state_names.py ├── successive_wins.py ├── theater_row.py ├── theater_seats.py ├── three_flips.py ├── trials_until_success.py ├── twin_knights.py └── yahtzee.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | bin/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Installer logs 26 | pip-log.txt 27 | pip-delete-this-directory.txt 28 | 29 | # Unit test / coverage reports 30 | htmlcov/ 31 | .tox/ 32 | .coverage 33 | .cache 34 | nosetests.xml 35 | coverage.xml 36 | 37 | # Translations 38 | *.mo 39 | 40 | # Mr Developer 41 | .mr.developer.cfg 42 | .project 43 | .pydevproject 44 | 45 | # Rope 46 | .ropeproject 47 | 48 | # Django stuff: 49 | *.log 50 | *.pot 51 | 52 | # Sphinx documentation 53 | docs/_build/ 54 | 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Probability 2 | =========== 3 | 4 | Programming solutions to problems in probability. 5 | 6 | The following problems come from [Fifty Challenging Problems in Probability](http://www.amazon.com/gp/product/B00A3M0VV8) by Frederick Mosteller. 7 | 8 | * [Successive Wins](scripts/successive_wins.py) - Which of two series offers a better probability of a win? 9 | * [The Flippant Juror](scripts/flippant_juror.py) - Which jury has a better probability of making the correct decision? 10 | * [Trials Until First Success](scripts/trials_until_success.py) - On average, how many times must a die be thrown until one rolls a six? 11 | * [Chuck-a-Luck](scripts/chuck_a_luck.py) - What is the player's expected loss per unit stake in chuck-a-luck? 12 | * [Curing the Compulsive Gambler](scripts/curing_the_compulsive_gambler.py) - Will a player be behind after 36 plays of one number in roulette? 13 | * [Craps](scripts/craps.py) - What is the player's chance to win at craps? 14 | * [Collecting Coupons](scripts/collecting_coupons.py) - How many coupons do you have to collect to compete a set of 5? 15 | * [The Theater Row](scripts/theater_row.py) - How many matches in a random assortment of 15? 16 | * [Will Second-Best Be Runner-Up?](scripts/second_best.py) - What is the probability that the 2nd-best player will be runner-up in a randomly seeded tournament? 17 | * [Twin Knights](scripts/twin_knights.py) - What are the odds that twins will meet in a tournament? 18 | * [An Even Split at Coin Tossing](scripts/even_split.py) - When 100 coins are tossed, what is the probability that exactly 50 are heads? 19 | * [Isaac Newton Helps Samuel Pepys](scripts/newton_helps_pepys.py) - Which of three events is more likely when throwing dice? 20 | * [Lengths of Random Chords](scripts/length_of_random_chords.py) - If a chord is selected at random on a fixed circle, what is the probability that its length exceeds the radius of the circle? 21 | * [The Hurried Duelers](scripts/hurried_duelers.py) - If duelists arrive at random times, what fraction of duels lead to violence? 22 | * [Catching the Cautious Counterfeiter](scripts/catching_the_cautious_counterfeiter.py) - What is the probability of catching a counterfeiter? 23 | * [Gambler's Ruin](scripts/gamblers_ruin.py) - Under given conditions, what is the probability of player N winning? 24 | * [Bold Play vs. Cautious Play](scripts/bold_play_vs_cautious_play.py) - Compare the merits of two gambling strategies. 25 | * [The Clumsy Chemist](scripts/clumsy_chemist.py) - What is the average length of randomly broken glass rods? 26 | * [The First Ace](scripts/first_ace.py) - How many cards are dealt from a shuffled deck before the first ace appears? 27 | * [The Little End of the Stick](scripts/little_end_of_the_stick.py) - What is the average length of the smaller piece of a randomly broken stick? 28 | * [The Broken Bar](scripts/broken_bar.py) - What are the average sizes of all pieces of a bar randomly broken in three pieces? 29 | * [Average Number of Matches](scripts/average_number_of_matches.py) - What is the average number of matches between two decks of shuffled cards? 30 | 31 | **Miscellaneous** 32 | 33 | The following problems come from various other sources. 34 | 35 | * [All Aboard](scripts/all_aboard.py) (From [Futility Closet](https://www.futilitycloset.com/2012/02/29/all-aboard-5/)) - What’s the probability that the 100th passenger on an airlplane finds his seat occupied? 36 | * [Hit and Run](scripts/hit_and_run.py) (From [Randomness](https://www.amazon.com/Randomness-Deborah-J-Bennett/dp/0674107462/ref=asap_bc?ie=UTF8) by Deborah J. Bennet) - What is the probability that a cab involved in an accident was Blue rather than Green? 37 | * [Exceed 1](scripts/exceed_1.py) (From [Mathematics Stack Exchange](http://math.stackexchange.com/questions/111314/choose-a-random-number-between-0-and-1-and-record-its-value-keep-doing-it-until)) - What's the expected value of the number of random numbers needed to exceed 1? 38 | * [Coin Flip Sequences](scripts/coin_flip_sequences.py) - Which sequence will take longer on average when flipping a fair coin, HTH or HTT? 39 | * [Minority Selection](scripts/minority_selection.py) - What is the probability that no member of a minority party will be selected out of N slots? 40 | * [The Petersburg Paradox](scripts/petersburg_paradox.py) - What would be a fair price to pay the casino for entering the game? 41 | * [Gummy Bears](scripts/gummy_bears.py) (From [Data Science Renee on Twitter](https://twitter.com/BecomingDataSci/status/826635249341911044)) - What is the probability of selecting 5 different flavors? 42 | * [Missiles](scripts/missiles.py) - What is the probability that a target will be hit by any of four missiles? 43 | * [Quiz Answers](scripts/quiz_answers.py) - Generate a strategy for a quiz game. 44 | * [Infinite Monkeys](scripts/infinite_monkeys.py) - If infinite monkeys struck each of the 26 letters of a typewriter once, what is the probability that either name 'IAGO' or 'LEAR' would appear? 45 | * [Yahtzee](scripts/yahtzee.py) - What is the probability of rolling five of a kind when rolling five six-sided dice three times? 46 | * [Lunch in the Park](scripts/lunch_in_the_park.py) (From [FiveThirtyEight](https://fivethirtyeight.com/features/what-are-the-chances-well-meet-for-lunch/)) - What is the probability that two friends will meet for lunch? 47 | * [A Painting Puzzle](scripts/painting_puzzle.py) (From [FiveThirtyEight](https://fivethirtyeight.com/features/can-you-solve-these-colorful-puzzles/)) - What is the expected number of turns to finish a game? 48 | * [A Dicey Question](scripts/dicey_question.py) (From [Mental Gymnastics: Recreational Mathematics Puzzles](https://www.amazon.com/Mental-Gymnastics-Recreational-Mathematics-Puzzles/dp/0486480542/ref=asap_bc?ie=UTF8) by Dick Hess) - Which is greater when rolling five dice, the probability of rolling exactly one six, or the probabilit of rolling no sixes? 49 | * [Bags of Marbles](scripts/bags_of_marbles.py) - In the specified game, what is the probability that a second marble is white? 50 | * [Theater Seats](scripts/theater_seats.py) (From [7 friends are going to the cinema...](https://math.stackexchange.com/q/2332589/271304)) - Out of seven movie-goers, what is the probability that two friends won't sit together? 51 | * [Draw Two](scripts/draw_two.py) (From [Patrick Honner on Twitter](https://twitter.com/MrHonner/status/917546796322377728)) - Two numbers are drawn from the integers 1-10. What's the expected value of their sum? 52 | 53 | -------------------------------------------------------------------------------- /data/country_names_2017.txt: -------------------------------------------------------------------------------- 1 | Afghanistan 2 | Albania 3 | Algeria 4 | Andorra 5 | Angola 6 | Antigua and Barbuda 7 | Argentina 8 | Armenia 9 | Aruba 10 | Australia 11 | Austria 12 | Azerbaijan 13 | Bahamas, The 14 | Bahrain 15 | Bangladesh 16 | Barbados 17 | Belarus 18 | Belgium 19 | Belize 20 | Benin 21 | Bhutan 22 | Bolivia 23 | Bosnia and Herzegovina 24 | Botswana 25 | Brazil 26 | Brunei 27 | Bulgaria 28 | Burkina Faso 29 | Burma 30 | Burundi 31 | Cambodia 32 | Cameroon 33 | Canada 34 | Cabo Verde 35 | Central African Republic 36 | Chad 37 | Chile 38 | China 39 | Colombia 40 | Comoros 41 | Congo, Democratic Republic of the 42 | Congo, Republic of the 43 | Costa Rica 44 | Cote d'Ivoire 45 | Croatia 46 | Cuba 47 | Curacao 48 | Cyprus 49 | Czechia 50 | Denmark 51 | Djibouti 52 | Dominica 53 | Dominican Republic 54 | East Timor (see Timor-Leste) 55 | Ecuador 56 | Egypt 57 | El Salvador 58 | Equatorial Guinea 59 | Eritrea 60 | Estonia 61 | Ethiopia 62 | Fiji 63 | Finland 64 | France 65 | Gabon 66 | Gambia, The 67 | Georgia 68 | Germany 69 | Ghana 70 | Greece 71 | Grenada 72 | Guatemala 73 | Guinea 74 | Guinea-Bissau 75 | Guyana 76 | Haiti 77 | Holy See 78 | Honduras 79 | Hong Kong 80 | Hungary 81 | Iceland 82 | India 83 | Indonesia 84 | Iran 85 | Iraq 86 | Ireland 87 | Israel 88 | Italy 89 | Jamaica 90 | Japan 91 | Jordan 92 | Kazakhstan 93 | Kenya 94 | Kiribati 95 | Korea, North 96 | Korea, South 97 | Kosovo 98 | Kuwait 99 | Kyrgyzstan 100 | Laos 101 | Latvia 102 | Lebanon 103 | Lesotho 104 | Liberia 105 | Libya 106 | Liechtenstein 107 | Lithuania 108 | Luxembourg 109 | Macau 110 | Macedonia 111 | Madagascar 112 | Malawi 113 | Malaysia 114 | Maldives 115 | Mali 116 | Malta 117 | Marshall Islands 118 | Mauritania 119 | Mauritius 120 | Mexico 121 | Micronesia 122 | Moldova 123 | Monaco 124 | Mongolia 125 | Montenegro 126 | Morocco 127 | Mozambique 128 | Namibia 129 | Nauru 130 | Nepal 131 | Netherlands 132 | New Zealand 133 | Nicaragua 134 | Niger 135 | Nigeria 136 | North Korea 137 | Norway 138 | Oman 139 | Pakistan 140 | Palau 141 | Palestinian Territories 142 | Panama 143 | Papua New Guinea 144 | Paraguay 145 | Peru 146 | Philippines 147 | Poland 148 | Portugal 149 | Qatar 150 | Romania 151 | Russia 152 | Rwanda 153 | Saint Kitts and Nevis 154 | Saint Lucia 155 | Saint Vincent and the Grenadines 156 | Samoa 157 | San Marino 158 | Sao Tome and Principe 159 | Saudi Arabia 160 | Senegal 161 | Serbia 162 | Seychelles 163 | Sierra Leone 164 | Singapore 165 | Sint Maarten 166 | Slovakia 167 | Slovenia 168 | Solomon Islands 169 | Somalia 170 | South Africa 171 | South Korea 172 | South Sudan 173 | Spain 174 | Sri Lanka 175 | Sudan 176 | Suriname 177 | Swaziland 178 | Sweden 179 | Switzerland 180 | Syria 181 | Taiwan 182 | Tajikistan 183 | Tanzania 184 | Thailand 185 | Timor-Leste 186 | Togo 187 | Tonga 188 | Trinidad and Tobago 189 | Tunisia 190 | Turkey 191 | Turkmenistan 192 | Tuvalu 193 | Uganda 194 | Ukraine 195 | United Arab Emirates 196 | United Kingdom 197 | Uruguay 198 | Uzbekistan 199 | Vanuatu 200 | Venezuela 201 | Vietnam 202 | Yemen 203 | Zambia 204 | Zimbabwe -------------------------------------------------------------------------------- /data/state_names.txt: -------------------------------------------------------------------------------- 1 | Alabama 2 | Alaska 3 | Arizona 4 | Arkansas 5 | California 6 | Colorado 7 | Connecticut 8 | Delaware 9 | Florida 10 | Georgia 11 | Hawaii 12 | Idaho 13 | Illinois 14 | Indiana 15 | Iowa 16 | Kansas 17 | Kentucky 18 | Louisiana 19 | Maine 20 | Maryland 21 | Massachusetts 22 | Michigan 23 | Minnesota 24 | Mississippi 25 | Missouri 26 | Montana 27 | Nebraska 28 | Nevada 29 | New Hampshire 30 | New Jersey 31 | New Mexico 32 | New York 33 | North Carolina 34 | North Dakota 35 | Ohio 36 | Oklahoma 37 | Oregon 38 | Pennsylvania 39 | Rhode Island 40 | South Carolina 41 | South Dakota 42 | Tennessee 43 | Texas 44 | Utah 45 | Vermont 46 | Virginia 47 | Washington 48 | West Virginia 49 | Wisconsin 50 | Wyoming 51 | -------------------------------------------------------------------------------- /scripts/all_aboard.py: -------------------------------------------------------------------------------- 1 | # All Aboard 2 | # 3 | # One hundred people board a 100-seat airplane. The first one has lost 4 | # his boarding pass, so he sits in a random seat. Each subsequent 5 | # passenger sits in his own seat if it’s available or takes a random 6 | # unoccupied seat if it’s not. 7 | # What’s the probability that the 100th passenger finds his seat occupied? 8 | # 9 | # From: Futility Closet 10 | # http://www.futilitycloset.com/2012/02/29/all-aboard-5/ 11 | 12 | import random 13 | 14 | def all_aboard(): 15 | samples = 10000 16 | total = 0 17 | num_passengers = 100 18 | 19 | for i in range(samples): 20 | seats = [s for s in range(num_passengers)] 21 | passengers = [p for p in range(num_passengers)] 22 | random.shuffle(passengers) 23 | 24 | # pop the first passenger, but have them occupy a random seat 25 | passengers.pop() 26 | seat = random.randint(0, num_passengers-1) 27 | seats.remove(seat) 28 | 29 | # seat the next 98 passengers 30 | for j in range(len(passengers) - 1): 31 | if passengers[j] in seats: 32 | seats.remove(passengers[j]) 33 | else: 34 | seats.pop(random.randint(0, len(seats)-1)) 35 | 36 | # is the last passenger's seat available? 37 | if passengers[len(passengers)-1] != seats[0]: 38 | total += 1 39 | 40 | average = total / samples 41 | print("Probability that the 100th passenger finds his seat occupied:", average) 42 | 43 | 44 | if __name__ == '__main__': 45 | all_aboard() 46 | -------------------------------------------------------------------------------- /scripts/average_number_of_matches.py: -------------------------------------------------------------------------------- 1 | # Average Number of Matches 2 | # From a shuffled deck, cards are laid out on a table one at a time, 3 | # face up from left to right, and then another deck is laid out so 4 | # that each of its cards is beneath a card of the first deck. 5 | # What is the average number of matches of the card above and 6 | # the card below in repetitions of this experiment? 7 | # 8 | # From: Fifty Challenging Problems in Probability 9 | # by Frederick Mosteller 10 | # Problem 45 11 | 12 | import random 13 | 14 | def number_of_matches(): 15 | samples = 10000 16 | total = 0 17 | 18 | for i in range(samples): 19 | deck1 = [x for x in range(52)] 20 | random.shuffle(deck1) 21 | deck2 = [x for x in range(52)] 22 | random.shuffle(deck2) 23 | 24 | matches = 0 25 | zipped = zip(deck1, deck2) 26 | 27 | for pairs in zipped: 28 | if pairs[0] == pairs[1]: 29 | matches += 1 30 | 31 | total += matches 32 | 33 | average = total / samples 34 | print("Average number of matches:", average) 35 | 36 | 37 | if __name__ == '__main__': 38 | number_of_matches() 39 | -------------------------------------------------------------------------------- /scripts/bags_of_marbles.py: -------------------------------------------------------------------------------- 1 | # Bags of Marbles 2 | # You have three identical bags, each containing two marbles. 3 | # Bag A contains two white marbles, bag B contains two black marbles, 4 | # and Bag C contains one white and one black marble. 5 | # You pick a bag at random and draw out one marble. If the marble is white, 6 | # what is the probability that the other marble in the same bag 7 | # is also white? 8 | 9 | from __future__ import division 10 | import random 11 | 12 | def bags_of_marbles(): 13 | samples = 10000 14 | white_1 = 0 15 | white_2 = 0 16 | 17 | for i in range(samples): 18 | bag_a = [ "white", "white" ] 19 | bag_b = [ "black", "black" ] 20 | bag_c = [ "white", "black" ] 21 | 22 | # select a bag at random 23 | b = random.randint(1, 3) 24 | if b == 1: 25 | bag = bag_a 26 | elif b == 2: 27 | bag = bag_b 28 | else: 29 | bag = bag_c 30 | 31 | # pick a marble from the bag 32 | marble_1 = bag.pop(random.randint(0, 1)) 33 | if marble_1 == "white": 34 | white_1 += 1 35 | # look at the other marble 36 | marble_2 = bag.pop() 37 | if marble_2 == "white": 38 | white_2 += 1 39 | 40 | print("First marble was white", white_1, "times.") 41 | print("Second marble was white", white_2, "times.") 42 | print("Probability that 2nd marble was white when 1st marble was white:", white_2 / white_1) 43 | 44 | 45 | 46 | if __name__ == '__main__': 47 | bags_of_marbles() 48 | -------------------------------------------------------------------------------- /scripts/bold_play_vs_cautious_play.py: -------------------------------------------------------------------------------- 1 | # Bold Play vs. Cautious Play 2 | # At Las Vegas, a man with $20 needs $40, but he is too embarrassed to 3 | # wire his wife for more money. He decides to invest in roulette (which 4 | # he doesn't enjoy playing) and is considering two strategies: bet the 5 | # $20 on "evens" all at once and quit if he wins or loses, or bet on 6 | # "evens" one dollar at a time until he has won or lost $20. 7 | # Compare the merits of the strategies. 8 | # 9 | # From: Fifty Challenging Problems in Probability 10 | # by Frederick Mosteller 11 | # Problem 37 12 | 13 | import random 14 | 15 | def bold_play_vs_cautious_play(): 16 | samples = 10000 17 | wins = 0 18 | 19 | for i in range(samples): 20 | bank = 20 21 | while bank > 0 and bank < 40: 22 | spin = random.randint(0, 37) 23 | if spin > 0 and (spin % 2 == 0): 24 | bank += 1 25 | else: 26 | bank -= 1 27 | if bank == 40: 28 | wins += 1 29 | 30 | average = wins / samples 31 | print("Odds of winning $20, $1 at a time at roulette:", average) 32 | 33 | 34 | 35 | if __name__ == '__main__': 36 | bold_play_vs_cautious_play() 37 | -------------------------------------------------------------------------------- /scripts/broken_bar.py: -------------------------------------------------------------------------------- 1 | # The Broken Bar 2 | # A bar is broken at random in two places. Find the average size of the 3 | # smallest, the middle-sized, and the largest pieces. 4 | # 5 | # From: Fifty Challenging Problems in Probability 6 | # by Frederick Mosteller 7 | # Problem 43 8 | 9 | import random 10 | 11 | def broken_bar(): 12 | samples = 10000 13 | shortest = 0.0 14 | middle = 0.0 15 | longest = 0.0 16 | 17 | for i in range(samples): 18 | # simulate breaking the bar in two spots 19 | breaks = [] 20 | breaks.append(random.random()) 21 | breaks.append(random.random()) 22 | breaks.sort() 23 | 24 | # find the lengths of the pieces 25 | pieces = [] 26 | pieces.append(breaks[0]) 27 | pieces.append(breaks[1] - breaks[0]) 28 | pieces.append(1.0 - breaks[1]) 29 | 30 | pieces.sort() 31 | shortest += pieces[0] 32 | middle += pieces[1] 33 | longest += pieces[2] 34 | 35 | print("Average length of the smallest piece:", shortest / samples) 36 | print("Average length of the middle piece:", middle / samples) 37 | print("Average length of the largest piece:", longest / samples) 38 | 39 | 40 | 41 | if __name__ == '__main__': 42 | broken_bar() 43 | -------------------------------------------------------------------------------- /scripts/carnival_barker.py: -------------------------------------------------------------------------------- 1 | # Carnival barker asks you to pick a # from 1 to 6. 2 | # Then he rolls 3 dice. If your number comes up all 3 times, 3 | # you win $30, if twice $20, if once $10, if 0 times, you lose $10. 4 | # What is expected value of your winnings. 5 | 6 | # From John Allen Paulos 7 | # https://twitter.com/JohnAllenPaulos/status/1050387226499133445 8 | 9 | import random 10 | 11 | def carnival_barker(): 12 | samples = 1000000 13 | winnings = 0.00 14 | 15 | for i in range(samples): 16 | my_number = random.randint(1, 6) 17 | 18 | die_1 = random.randint(1, 6) 19 | die_2 = random.randint(1, 6) 20 | die_3 = random.randint(1, 6) 21 | 22 | if die_1 == my_number: 23 | winnings += 10.00 24 | if die_2 == my_number: 25 | winnings += 10.00 26 | if die_3 == my_number: 27 | winnings += 10.00 28 | if not my_number in (die_1, die_2, die_3): 29 | winnings -= 10.00 30 | 31 | avg_winnings = winnings / samples 32 | print("Total winnings:", winnings) 33 | print("Expected winnings per game:", avg_winnings) 34 | 35 | 36 | if __name__ == '__main__': 37 | carnival_barker() 38 | -------------------------------------------------------------------------------- /scripts/catching_the_cautious_counterfeiter.py: -------------------------------------------------------------------------------- 1 | # Catching the Cautious Counterfeiter 2 | # (a) The king's minter boxes his coins 100 to a box. In each box 3 | # he puts 1 false coin. The king suspects the minter and from each 4 | # of 100 boxes draws a random coin and has it tested. What is the 5 | # chance the minter's peculations go undetected? 6 | # (b) What if both 100s are replaced by n? 7 | # 8 | # From: Fifty Challenging Problems in Probability 9 | # by Frederick Mosteller 10 | # Problem 27 11 | 12 | import random 13 | 14 | def catching_the_cautious_counterfeiter(): 15 | samples = 10000 16 | total = 0 17 | # change values for coins and boxes to answer (b) 18 | coins = 100 19 | boxes = 100 20 | 21 | for i in range(samples): 22 | caught = False 23 | for j in range(boxes): 24 | fake = random.randint(1, coins) 25 | test = random.randint(1, coins) 26 | 27 | if fake == test: 28 | caught = True 29 | 30 | if caught: 31 | total += 1 32 | 33 | 34 | average = total / samples 35 | print("Chance of going undetected:", 1.0 - average) 36 | 37 | 38 | 39 | if __name__ == '__main__': 40 | catching_the_cautious_counterfeiter() 41 | -------------------------------------------------------------------------------- /scripts/chance_of_dying.py: -------------------------------------------------------------------------------- 1 | # Chances of dying 2 | # Given 19 6-sided dice, what are the chances of rolling a sum of 57 or greater? 3 | 4 | import random 5 | 6 | def chance_of_dying(): 7 | samples = 10000 8 | dice = 19 9 | sides = 6 10 | threshhold = dice * (sides / 2) 11 | 12 | exceeds_or_meets = 0 13 | for i in range(samples): 14 | total = 0 15 | for j in range(dice): 16 | total += random.randint(1, 6) 17 | if total >= threshhold: 18 | exceeds_or_meets += 1 19 | 20 | chances = exceeds_or_meets / samples 21 | print("Chance of dying:", chances) 22 | 23 | if __name__ == '__main__': 24 | chance_of_dying() 25 | -------------------------------------------------------------------------------- /scripts/chuck_a_luck.py: -------------------------------------------------------------------------------- 1 | # Chuck-a-Luck 2 | # Chuck-a-Luck is a gambling game often played at carnivals and gambling houses. 3 | # A player may bet on any one of the numbers 1, 2, 3, 4, 5, 6. Three dice 4 | # are rolled. If the player's number appears on one, two, or three of the dice, 5 | # he receives respectively one, two, or three times his original stake, plus 6 | # his own money back; otherwise he loses his stake. What is the player's 7 | # expected loss per unit stake? (Actually, the player may distribute stakes on 8 | # several numbers, but each such stake can be regarded as a separate bet.) 9 | # 10 | # From: Fifty Challenging Problems in Probability 11 | # by Frederick Mosteller 12 | # Problem 6 13 | 14 | import random 15 | 16 | def chuck_a_luck(): 17 | samples = 10000 18 | bank = 10000 19 | 20 | for i in range(samples): 21 | dice = [random.randint(1, 6) for x in range(3)] 22 | #assume the player always bets on 1 23 | wins = dice.count(1) 24 | 25 | if wins > 0: 26 | bank += wins 27 | else: 28 | bank -= 1 29 | 30 | loss = (10000 - bank) / 10000 31 | print("Expected loss:", loss) 32 | 33 | 34 | if __name__ == '__main__': 35 | chuck_a_luck() 36 | -------------------------------------------------------------------------------- /scripts/clumsy_chemist.py: -------------------------------------------------------------------------------- 1 | # The Clumsy Chemist 2 | # In a laboratory, each of a handful of thin 9-inch glass rods had one tip 3 | # marked with a blue dot and the other with a red. When the laboratory 4 | # assistant tripped and dropped them onto the concrete floor, many broke 5 | # into three pieces. For these, what was the average length of the 6 | # fragment with the blue dot? 7 | # 8 | # From: Fifty Challenging Problems in Probability 9 | # by Frederick Mosteller 10 | # Problem 39 11 | 12 | import random 13 | 14 | def clumsy_chemist(): 15 | samples = 10000 16 | total = 0.0 17 | 18 | for i in range(samples): 19 | break1 = random.random() 20 | break2 = random.random() 21 | 22 | blue = break1 if (break1 < break2) else break2 23 | total += blue 24 | 25 | average = (total / samples) * 9 26 | print("Average length of fragment with blue dot:", average) 27 | 28 | 29 | if __name__ == '__main__': 30 | clumsy_chemist() 31 | -------------------------------------------------------------------------------- /scripts/coin_flip_sequences.py: -------------------------------------------------------------------------------- 1 | # Coin Flip Sequences 2 | # When flipping a fair coin until either HTH or HTT is first reached, 3 | # which sequence will take longer on average? 4 | 5 | import random 6 | 7 | def coin_flip_sequences(): 8 | samples = 10000 9 | 10 | # HTH - Assume True = H 11 | total_flips = 0 12 | for i in range(samples): 13 | prev1 = None 14 | prev2 = None 15 | current = None 16 | flips = 0 17 | while True: 18 | prev1 = prev2 19 | prev2 = current 20 | current = random.random() < 0.5 21 | flips += 1 22 | if prev1 == True and prev2 == False and current == True: 23 | total_flips += flips 24 | break 25 | 26 | average = total_flips / samples 27 | print("Average number of flips before HHT:", average) 28 | 29 | # HTT - Assume True = H 30 | total_flips = 0 31 | for i in range(samples): 32 | flips = 0 33 | prev1 = None 34 | prev2 = None 35 | current = None 36 | while True: 37 | prev1 = prev2 38 | prev2 = current 39 | current = random.random() < 0.5 40 | flips += 1 41 | if prev1 == True and prev2 == False and current == False: 42 | total_flips += flips 43 | break 44 | 45 | average = total_flips / samples 46 | print("Average number of flips before HTT:", average) 47 | 48 | 49 | if __name__ == '__main__': 50 | coin_flip_sequences() 51 | -------------------------------------------------------------------------------- /scripts/collecting_coupons.py: -------------------------------------------------------------------------------- 1 | # Collecting coupons 2 | # Coupons in cereal boxes are numbered 1 to 5, and a set of one 3 | # of each is required for a prize. With one coupon per box, how 4 | # many boxes on average are required to make a compete set? 5 | # From: Fifty Challenging Problems in Probability 6 | # by Frederick Mosteller 7 | # Problem 14 8 | 9 | import random 10 | 11 | def collecting_coupons(): 12 | samples = 10000 13 | total = 0 14 | 15 | for i in range(samples): 16 | coupons = [False] * 5 17 | count = 0 18 | 19 | while(not all(coupons)): 20 | r = random.randint(0, 4) 21 | coupons[r] = True 22 | count += 1 23 | 24 | total += count 25 | 26 | average = total / samples 27 | print("Average number of boxes to collect all 5:", average) 28 | 29 | 30 | if __name__ == '__main__': 31 | collecting_coupons() 32 | -------------------------------------------------------------------------------- /scripts/craps.py: -------------------------------------------------------------------------------- 1 | # Craps 2 | # The game of craps, played with two dice, is one of America's fastest 3 | # and most popular gambling games. Calculating the odds associated with 4 | # it is an instructive exercise. 5 | # The rules are these. Only totals for the two dice count. The player 6 | # throws the dice and wins at once if the total for the first throw is 7 | # 7 or 11, loses at once if it is 2, 3, or 12. Any other throw is called 8 | # his "point." If the first throw is a point, the player throws the dice 9 | # repeatedly, until he either wins by throwing his point again or loses 10 | # by throwing 7. What is the player's chance to win? 11 | # 12 | # From: Fifty Challenging Problems in Probability 13 | # by Frederick Mosteller 14 | # Problem 9 15 | 16 | import random 17 | 18 | def craps(): 19 | samples = 10000 20 | wins = 0 21 | losses = 0 22 | 23 | for i in range(samples): 24 | total = roll() 25 | 26 | if total == 7 or total == 11: 27 | wins += 1 28 | elif total == 2 or total == 3 or total == 12: 29 | losses += 1 30 | else: 31 | point = total 32 | loop = True 33 | while loop: 34 | total = roll() 35 | if total == 7: 36 | losses += 1 37 | loop = False 38 | elif total == point: 39 | wins += 1 40 | loop = False 41 | # else: keep rolling 42 | 43 | average = wins / samples 44 | print("Player's chance to win at craps:", average) 45 | 46 | def roll(): 47 | d1 = random.randint(1, 6) 48 | d2 = random.randint(1, 6) 49 | return (d1 + d2) 50 | 51 | 52 | if __name__ == '__main__': 53 | craps() 54 | -------------------------------------------------------------------------------- /scripts/curing_the_compulsive_gambler.py: -------------------------------------------------------------------------------- 1 | # Curing the Compulsive Gambler 2 | # Mr. Brown always bets a dollar on the number 13 at roulette against 3 | # the advice of Kind Friend. To help cure Mr. Brown of playing roulette, 4 | # Kind Friend always bets Brown $20 at even money that Brown will be 5 | # behind at the end of 36 plays. How is the cure working? 6 | # (Most American roulette wheels have 38 equally likely numbers. 7 | # If the player's number comes up, he is paid 35 times his stake and 8 | # gets his original stake back; otherwise he loses his stake.) 9 | # 10 | # From: Fifty Challenging Problems in Probability 11 | # by Frederick Mosteller 12 | # Problem 7 13 | 14 | import random 15 | 16 | def curing_the_compulsive_gambler(): 17 | samples = 10000 18 | total = 0 19 | 20 | for i in range(samples): 21 | bank = 0 22 | for j in range(36): 23 | spin = random.randint(1, 38) 24 | if spin == 13: 25 | bank += 35 26 | else: 27 | bank -= 1 28 | 29 | if bank >= 0: 30 | bank += 20 31 | else: 32 | bank -= 20 33 | 34 | total += bank 35 | 36 | average = total / samples 37 | print("Average winnings after 36 spins:", average) 38 | 39 | 40 | if __name__ == '__main__': 41 | curing_the_compulsive_gambler() 42 | -------------------------------------------------------------------------------- /scripts/dicey_question.py: -------------------------------------------------------------------------------- 1 | # Dicey Question 2 | # You are about to roll five regular dice. You win if you roll exactly 3 | # one six. You lose if you roll no sixes. Are you more likely to win 4 | # than lose, or are you less likely to win than lose? 5 | 6 | import random 7 | 8 | def dicey_question(): 9 | samples = 10000 10 | wins = 0 11 | losses = 0 12 | 13 | for i in range(samples): 14 | sixes = 0 15 | for j in range(5): 16 | d = random.randint(1, 6) 17 | if d == 6: 18 | sixes += 1 19 | 20 | 21 | if sixes == 1: 22 | wins += 1 23 | 24 | if sixes == 0: 25 | losses += 1 26 | 27 | 28 | avg_wins = wins / samples 29 | avg_loss = losses / samples 30 | print("Chance of winning:", avg_wins) 31 | print("Chance of losing:", avg_loss) 32 | 33 | 34 | 35 | if __name__ == '__main__': 36 | dicey_question() 37 | -------------------------------------------------------------------------------- /scripts/draw_two.py: -------------------------------------------------------------------------------- 1 | # Draw Two 2 | # Two numbers are drawn from the integers 1-10. 3 | # What's the expected value of their sum? 4 | # (With and without replacement.) 5 | # Based on https://twitter.com/MrHonner/status/917546796322377728 6 | 7 | import random 8 | 9 | def with_replacement(samples): 10 | total = 0 11 | 12 | for i in range(samples): 13 | a = random.randint(1, 10) 14 | b = random.randint(1, 10) 15 | c = a + b 16 | total += c 17 | 18 | avg = total / samples 19 | return avg 20 | 21 | 22 | def without_replacement(samples): 23 | total = 0 24 | 25 | for i in range(samples): 26 | values = list(range(1, 11)) # range stop value is not inclusive 27 | random.shuffle(values) 28 | a = values.pop() 29 | b = values.pop() 30 | c = a + b 31 | total += c 32 | 33 | avg = total / samples 34 | return avg 35 | 36 | 37 | def draw_two(): 38 | samples = 10000 39 | with_rep = with_replacement(samples) 40 | without_rep = without_replacement(samples) 41 | print("Expected value with replacement:", with_rep) 42 | print("Expected value without replacement:", without_rep) 43 | 44 | if __name__ == '__main__': 45 | draw_two() 46 | -------------------------------------------------------------------------------- /scripts/even_split.py: -------------------------------------------------------------------------------- 1 | # An Even Split at Coin Tossing 2 | # When 100 coins are tossed, what is the 3 | # probability that exactly 50 are heads? 4 | # 5 | # From: Fifty Challenging Problems in Probability 6 | # by Frederick Mosteller 7 | # Problem 18 8 | 9 | import random 10 | 11 | def even_split(): 12 | samples = 10000 13 | total = 0 14 | 15 | for i in range(samples): 16 | heads = 0 17 | for j in range(100): 18 | if(random.random() < 0.5): 19 | heads +=1 20 | 21 | if(heads == 50): 22 | total += 1 23 | 24 | average = total / samples 25 | print("Probability of exactly 50 heads:", average) 26 | 27 | 28 | 29 | if __name__ == '__main__': 30 | even_split() 31 | -------------------------------------------------------------------------------- /scripts/exceed_1.py: -------------------------------------------------------------------------------- 1 | # Exceed 1 2 | # Choose a random number between 0 and 1 and record its value. 3 | # Do this again and add the second number to the first number. 4 | # Keep doing this until the sum of the numbers exceeds 1. 5 | # What's the expected value of the number of random numbers 6 | # needed to accomplish this? 7 | 8 | # http://math.stackexchange.com/questions/111314/choose-a-random-number-between-0-and-1-and-record-its-value-keep-doing-it-until 9 | 10 | import random 11 | 12 | def exceed_1(): 13 | samples = 100000 14 | total = 0 15 | 16 | for i in range(samples): 17 | draws = 0 18 | draw_sum = 0.0 19 | while draw_sum <= 1.0: 20 | draw_sum += random.random() 21 | draws += 1 22 | total += draws 23 | 24 | average = total / samples 25 | print("Expected number of draws to exceed 1:", average) 26 | 27 | if __name__ == '__main__': 28 | exceed_1() 29 | -------------------------------------------------------------------------------- /scripts/first_ace.py: -------------------------------------------------------------------------------- 1 | # The First Ace 2 | # Shuffle an ordinary deck of 52 playing cards containing four aces. 3 | # Then turn up cards from the top until the first ace appears. 4 | # On the average, how many cards are required until the first ace appears? 5 | # 6 | # From: Fifty Challenging Problems in Probability 7 | # by Frederick Mosteller 8 | # Problem 40 9 | 10 | import random 11 | 12 | def first_ace(): 13 | samples = 10000 14 | total = 0 15 | 16 | for i in range(samples): 17 | deck = [x for x in range(52)] 18 | random.shuffle(deck) 19 | 20 | count = 1 21 | for card in deck: 22 | if card < 4: 23 | break 24 | else: 25 | count += 1 26 | total += count 27 | 28 | average = total / samples 29 | print("Average number of cards until the first ace:", average) 30 | 31 | 32 | if __name__ == '__main__': 33 | first_ace() 34 | -------------------------------------------------------------------------------- /scripts/flippant_juror.py: -------------------------------------------------------------------------------- 1 | # The Flippant Juror 2 | # A three-man jury has two members each of whom independently has 3 | # probability p of making the correct decision and a third member 4 | # who flips a coin for each decision (majority rules). A one-man 5 | # jury has probability p of making the correct decision. Which jury 6 | # has the better probability of making the correct decision? 7 | # 8 | # From: Fifty Challenging Problems in Probability 9 | # by Frederick Mosteller 10 | # Problem 3 11 | 12 | import random 13 | 14 | def flippant_juror(): 15 | samples = 10000 16 | correct = 0 17 | 18 | for i in range(samples): 19 | juror1 = random.random() < 0.8 20 | juror2 = random.random() < 0.8 21 | juror3 = random.random() < 0.5 22 | 23 | # check to see if two out of three jurors came 24 | # up with the "correct" decision (True). 25 | decision = juror1 if (juror1 == juror2) else juror3 26 | if decision: 27 | correct += 1 28 | 29 | average = correct / samples 30 | print("Probability of correct decision:", average) 31 | 32 | 33 | if __name__ == '__main__': 34 | flippant_juror() 35 | -------------------------------------------------------------------------------- /scripts/flipping_n_coins.py: -------------------------------------------------------------------------------- 1 | # Flipping n coins 2 | # You have 100 coins and you flip them all at the same time. 3 | # Any that come up tails you set aside. The ones that come up 4 | # heads you flip again. How many rounds do you expect to play 5 | # before only one coin remains? 6 | # What if you start with 1000 coins? 7 | 8 | import random 9 | 10 | def flipping_n_coins(): 11 | samples = 10000 12 | rounds = 0 13 | 14 | for i in range(samples): 15 | coins = 100 16 | while coins > 1: 17 | heads = 0 18 | for i in range(coins): 19 | if random.random() <= 0.5: 20 | heads += 1 21 | rounds += 1 22 | coins = heads 23 | 24 | average = rounds / samples 25 | print("Average number of rounds:", average) 26 | 27 | 28 | if __name__ == '__main__': 29 | flipping_n_coins() 30 | -------------------------------------------------------------------------------- /scripts/four_flips.py: -------------------------------------------------------------------------------- 1 | # Four flips 2 | # You are to flip a fair coin four times. 3 | # If heads and tails each appear twice in four flips, 4 | # he will pay you $11. If they don't, you must pay $10. 5 | # Do you take the bet? 6 | 7 | import random 8 | 9 | def four_flips(): 10 | samples = 10000 11 | wins = 0 12 | 13 | for i in range(samples): 14 | heads = 0 15 | for j in range(4): 16 | if random.random() < 0.5: 17 | heads += 1 18 | if heads == 2: 19 | wins += 1 20 | 21 | average = wins / samples 22 | print("Total wins:", wins) 23 | print("Winning probability:", average) 24 | 25 | 26 | if __name__ == '__main__': 27 | four_flips() 28 | -------------------------------------------------------------------------------- /scripts/gamblers_ruin.py: -------------------------------------------------------------------------------- 1 | # Gambler's Ruin 2 | # Player M has $1, and Player N has $2. Each play gives one of the 3 | # players $1 from the other. Player M is enough better than Player N 4 | # that he wins 2/3 of the plays. They play until one is bankrupt. 5 | # What is the chance that Player M wins? 6 | # 7 | # From: Fifty Challenging Problems in Probability 8 | # by Frederick Mosteller 9 | # Problem 36 10 | 11 | import random 12 | 13 | def gamblers_ruin(): 14 | samples = 10000 15 | m_wins = 0 16 | odds = 2 / 3 17 | 18 | for i in range(samples): 19 | m = 1 20 | n = 2 21 | 22 | while m > 0 and n > 0: 23 | if random.random() < odds: 24 | m += 1 25 | n -= 1 26 | else: 27 | m -= 1 28 | n += 1 29 | 30 | if m > 0: 31 | m_wins += 1 32 | 33 | average = m_wins / samples 34 | print("Chance that Player M wins:", average) 35 | 36 | 37 | 38 | if __name__ == '__main__': 39 | gamblers_ruin() 40 | -------------------------------------------------------------------------------- /scripts/gummy_bears.py: -------------------------------------------------------------------------------- 1 | # Gummy Bears 2 | # 3 | # There are 12 flavors of gummy bears. Assume evenly represented. 4 | # If I have a bag of 120 gummy bears, what are the chances that if 5 | # I select 5 random ones, each of the 5 will be different flavors? 6 | # 7 | # From: https://twitter.com/BecomingDataSci/status/826635249341911044 8 | 9 | import random 10 | 11 | def gummy_bears(): 12 | samples = 10000 13 | wins = 0 14 | 15 | # simulate a bag with 120 items and 12 different flavors 16 | bag = [(x % 12) for x in range(120)] 17 | 18 | for i in range(samples): 19 | random.shuffle(bag) 20 | 21 | # Are the first 5 flavors unique? 22 | if(len(set(bag[0:5])) == 5): 23 | wins += 1 24 | 25 | average = wins / samples 26 | print("Probability of 5 different flavors:", average) 27 | 28 | 29 | 30 | if __name__ == '__main__': 31 | gummy_bears() 32 | -------------------------------------------------------------------------------- /scripts/hit_and_run.py: -------------------------------------------------------------------------------- 1 | # Hit and Run 2 | # A cab was involved in a hit and run accident at night. Two cab companies, 3 | # the Green and the Blue, operate in the city. 4 | # You are given the following data: 5 | # (a) 85% of the cabs in the city are Green and 15% are Blue. 6 | # (b) A witness identified the cab as Blue. The court tested the reliability 7 | # of the witness under the same circumstances that existed on the night 8 | # of the accident and concluded that the witness correctly identified 9 | # each one of the two colors 80% of the time and failed 20% of the time. 10 | # What is the probability that the cab involved in the accident was 11 | # Blue rather than Green? 12 | # 13 | # From: Randomness 14 | # by Deborah J. Bennett 15 | # page 2 16 | 17 | import random 18 | 19 | def hit_and_run(): 20 | samples = 10000 21 | id_blue = 0 22 | both_blue = 0 23 | 24 | for i in range(samples): 25 | cab_blue = (random.random() < 0.15) 26 | witness_correct = (random.random() < 0.80) 27 | 28 | if cab_blue and witness_correct: 29 | both_blue += 1 30 | id_blue += 1 31 | 32 | if (not cab_blue) and (not witness_correct): 33 | id_blue += 1 34 | 35 | average = both_blue / id_blue 36 | print("Probability that the cab was Blue:", average) 37 | 38 | 39 | if __name__ == '__main__': 40 | hit_and_run() 41 | -------------------------------------------------------------------------------- /scripts/hurried_duelers.py: -------------------------------------------------------------------------------- 1 | # The Hurried Duelers 2 | # Duels in the town of Discretion are rarely fatal. There, each contestant 3 | # comes at a random moment between 5 AM and 6 AM on the appointed day and 4 | # leaves exactly 5 minutes later, honor served, unless his opponent arrives 5 | # within the time interval and then they fight. 6 | # What fraction of duels lead to violence? 7 | # 8 | # From: Fifty Challenging Problems in Probability 9 | # by Frederick Mosteller 10 | # Problem 26 11 | 12 | import random 13 | 14 | def hurried_duelers(): 15 | samples = 10000 16 | total = 0 17 | 18 | for i in range(samples): 19 | d1 = random.randint(1, 3600) 20 | d2 = random.randint(1, 3600) 21 | 22 | if abs(d1 - d2) < 300: 23 | total += 1 24 | 25 | average = total / samples 26 | print("Fraction of duels that lead to violence:", average) 27 | 28 | 29 | if __name__ == '__main__': 30 | hurried_duelers() 31 | -------------------------------------------------------------------------------- /scripts/infinite_monkeys.py: -------------------------------------------------------------------------------- 1 | # Infinite Monkeys 2 | # 3 | # If infinite monkeys struck each of the 26 letters of a typewriter once, 4 | # what is the probability that either name 'IAGO' or 'LEAR' would appear? 5 | 6 | import random 7 | 8 | def infinite_monkeys(): 9 | samples = 100000 10 | iagos = 0 11 | lears = 0 12 | 13 | alphabet = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ') 14 | 15 | for i in range(samples): 16 | random.shuffle(alphabet) 17 | output = ''.join(alphabet) 18 | 19 | if "IAGO" in output: 20 | iagos += 1 21 | 22 | if "LEAR" in output: 23 | lears += 1 24 | 25 | 26 | average = (iagos + lears) / samples 27 | print("Probability that 'IAGO' or 'LEAR' appears:", average) 28 | 29 | 30 | 31 | if __name__ == '__main__': 32 | infinite_monkeys() 33 | -------------------------------------------------------------------------------- /scripts/length_of_random_chords.py: -------------------------------------------------------------------------------- 1 | # Lengths of Random Chords 2 | # If a chord is selected at random on a fixed circle, what is the probability 3 | # that its length exceeds the radius of the circle? 4 | # 5 | # From: Fifty Challenging Problems in Probability 6 | # by Frederick Mosteller 7 | # Problem 25 8 | 9 | import random 10 | import math 11 | 12 | def length_of_random_chords(): 13 | samples = 10000 14 | positive = 0 15 | radius = 0.5 # assume a unit circle 16 | 17 | for i in range(samples): 18 | angle = random.random() * 2 * math.pi 19 | p1 = calc_point(angle, radius) 20 | 21 | angle = random.random() * 2 * math.pi 22 | p2 = calc_point(angle, radius) 23 | 24 | if distance(p1, p2) > 0.5: 25 | positive += 1 26 | 27 | average = positive / samples 28 | print("Probability that a random chord exceeds the radius:", average) 29 | 30 | 31 | # calculate a point on a circle given 32 | # an angle in radians and its radius 33 | def calc_point(angle, radius): 34 | x = math.cos(angle) * radius 35 | y = math.sin(angle) * radius 36 | return (x, y) 37 | 38 | 39 | # calculate the distance between two points 40 | def distance(p1, p2): 41 | return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) 42 | 43 | 44 | if __name__ == '__main__': 45 | length_of_random_chords() 46 | -------------------------------------------------------------------------------- /scripts/little_end_of_the_stick.py: -------------------------------------------------------------------------------- 1 | # The Little End of the Stick 2 | # (a) if a stick is broken in two at random, what is the average length 3 | # of the smaller piece? 4 | # (b) (For calculus students.) What is the average ratio of the smaller 5 | # length to the larger? 6 | # 7 | # From: Fifty Challenging Problems in Probability 8 | # by Frederick Mosteller 9 | # Problem 42 10 | 11 | import random 12 | 13 | def little_end_of_the_stick(): 14 | samples = 10000 15 | total_len = 0.0 16 | total_ratio = 0.0 17 | 18 | for i in range(samples): 19 | # assume a stick of unit length 20 | s1 = random.random() 21 | s2 = 1.0 - s1 22 | 23 | if s1 < s2: 24 | total_len += s1 25 | total_ratio += (s1 / s2) 26 | else: 27 | total_len += s2 28 | total_ratio += (s2 / s1) 29 | 30 | average_len = total_len / samples 31 | print("Average length of the smaller piece:", average_len) 32 | average_ratio = total_ratio / samples 33 | print("Average ratio of smaller to larger:", average_ratio) 34 | 35 | 36 | if __name__ == '__main__': 37 | little_end_of_the_stick() 38 | -------------------------------------------------------------------------------- /scripts/lonely_card_game.py: -------------------------------------------------------------------------------- 1 | # Lonely Card Game 2 | # 3 | # On snowy afternoons, you like to play a solitaire “game” with a standard, 4 | # randomly shuffled deck of 52 cards. You start dealing cards face up, one 5 | # at a time, into a pile. As you deal each card, you also speak aloud, 6 | # in order, the 13 card faces in a standard deck: ace, two, three, etc. 7 | # (When you get to king, you start over at ace.) You keep doing this 8 | # until the rank of the card you deal matches the rank you speak aloud, 9 | # in which case you lose. You win if you reach the end of the deck 10 | # without any matches. 11 | # 12 | # What is the probability that you win? 13 | # 14 | # From: Can You Deal With These Card Game Puzzles? 15 | # http://fivethirtyeight.com/features/can-you-deal-with-these-card-game-puzzles/ 16 | 17 | import random 18 | 19 | def lonely_card_game(): 20 | samples = 10000 21 | wins = 0 22 | 23 | deck1 = [(x % 13) for x in range(52)] 24 | 25 | for i in range(samples): 26 | deck2 = deck1[:] 27 | random.shuffle(deck2) 28 | 29 | matches = 0 30 | zipped = zip(deck1, deck2) 31 | 32 | for pairs in zipped: 33 | if pairs[0] == pairs[1]: 34 | matches += 1 35 | 36 | if matches == 0: 37 | wins += 1 38 | 39 | average = wins / samples 40 | print("Probability of winning:", average) 41 | 42 | 43 | 44 | 45 | if __name__ == '__main__': 46 | lonely_card_game() 47 | -------------------------------------------------------------------------------- /scripts/lunch_in_the_park.py: -------------------------------------------------------------------------------- 1 | # Lunch in the Park 2 | # 3 | # On a lovely spring day, you and I agree to meet for a lunch 4 | # picnic at the fountain in the center of our favorite park. 5 | # We agree that we’ll each arrive sometime from noon and 1 p.m., 6 | # and that whoever arrives first will wait up to 15 minutes for 7 | # the other. If the other person doesn’t show by then, the first 8 | # person will abandon the plans and spend the day with a more 9 | # punctual friend. If we both arrive at the fountain at an 10 | # independently random time between noon and 1, what are the 11 | # chances our picnic actually happens? 12 | # 13 | # From "What Are The Chances We’ll Meet For Lunch?" 14 | # https://fivethirtyeight.com/features/what-are-the-chances-well-meet-for-lunch/ 15 | 16 | import random 17 | 18 | def lunch_in_the_park(): 19 | samples = 10000 20 | lunches = 0 21 | 22 | for i in range(samples): 23 | time1 = random.randint(0, 59) 24 | time2 = random.randint(0, 59) 25 | 26 | if abs(time1 - time2) <= 15: 27 | lunches += 1 28 | 29 | average = lunches / samples 30 | print("Chances the picnic will actually happen:", average) 31 | 32 | 33 | 34 | if __name__ == '__main__': 35 | lunch_in_the_park() 36 | -------------------------------------------------------------------------------- /scripts/minority_selection.py: -------------------------------------------------------------------------------- 1 | # Minority Selection 2 | # What is the probability that no member of a minority party 3 | # will be selected out of N slots? 4 | # Example: A certain minority party is 10% of a population. In a 5 | # random drawing of 10 nominees, what are the odds that no 6 | # member of the minority party is selected? 7 | 8 | import random 9 | 10 | def selection(): 11 | trials = 10000 12 | represented = 0 13 | 14 | for i in range(trials): 15 | rep = False 16 | for i in range(10): 17 | d = random.randint(1, 10) 18 | if d == 10: 19 | rep = True 20 | 21 | if(rep): 22 | represented += 1 23 | 24 | average = represented / trials 25 | print("Minority odds of being represented:", average) 26 | 27 | 28 | if __name__ == '__main__': 29 | selection() 30 | -------------------------------------------------------------------------------- /scripts/missiles.py: -------------------------------------------------------------------------------- 1 | # Missiles 2 | # If a certain missile will hit its target one out of four times, 3 | # and four such missiles are fired at the same target, what is the 4 | # probability that the target will be hit? 5 | 6 | import random 7 | 8 | def missiles(): 9 | samples = 10000 10 | hits = 0 11 | 12 | for i in range(samples): 13 | hit = False 14 | for j in range(4): 15 | if random.random() < 0.25: 16 | hit = True 17 | if hit: 18 | hits += 1 19 | 20 | average = hits / samples 21 | print("Probability that the target will be hit:", average) 22 | 23 | if __name__ == '__main__': 24 | missiles() 25 | -------------------------------------------------------------------------------- /scripts/newton_helps_pepys.py: -------------------------------------------------------------------------------- 1 | # Isaac Newton Helps Samuel Pepys 2 | # Pepys wrote Newton to ask which of three events is more likely: 3 | # that a person get (a) at least 1 six when 6 dice are rolled, 4 | # (b) at least 2 sixes when 12 dice are rolled, or (c) at least 3 5 | # sixes when 18 dice are rolled. What is the answer? 6 | # 7 | # From: Fifty Challenging Problems in Probability 8 | # by Frederick Mosteller 9 | # Problem 19 10 | 11 | import random 12 | 13 | def newton_helps_pepys(): 14 | samples = 10000 15 | totals = [ 0, 0, 0 ] 16 | 17 | for i in range(samples): 18 | # roll 6 dice 19 | sixes = 0 20 | for j in range(6): 21 | if(random.randint(1, 6) == 6): 22 | sixes += 1 23 | if(sixes >= 1): 24 | totals[0] += 1 25 | 26 | # roll 12 dice 27 | sixes = 0 28 | for j in range(12): 29 | if(random.randint(1, 6) == 6): 30 | sixes += 1 31 | if(sixes >= 2): 32 | totals[1] += 1 33 | 34 | # roll 18 dice 35 | sixes = 0 36 | for j in range(18): 37 | if(random.randint(1, 6) == 6): 38 | sixes += 1 39 | if(sixes >= 3): 40 | totals[2] += 1 41 | 42 | averages = [x / samples for x in totals] 43 | 44 | 45 | print("Probability of at least 1 six when 6 dice are rolled:", averages[0]) 46 | print("Probability of at least 2 sixes when 12 dice are rolled:", averages[1]) 47 | print("Probability of at least 3 sixes when 18 dice are rolled:", averages[2]) 48 | 49 | 50 | if __name__ == '__main__': 51 | newton_helps_pepys() 52 | -------------------------------------------------------------------------------- /scripts/painting_puzzle.py: -------------------------------------------------------------------------------- 1 | # Painting Puzzle 2 | # You play a game with four balls: One ball is red, one is blue, 3 | # one is green and one is yellow. They are placed in a box. 4 | # You draw a ball out of the box at random and note its color. 5 | # Without replacing the first ball, you draw a second ball and 6 | # then paint it to match the color of the first. Replace both balls, 7 | # and repeat the process. The game ends when all four balls have 8 | # become the same color. What is the expected number of turns to 9 | # finish the game? 10 | # From: https://fivethirtyeight.com/features/can-you-solve-these-colorful-puzzles/ 11 | 12 | import random 13 | 14 | def painting_puzzle(): 15 | samples = 10000 16 | turns = 0 17 | 18 | for i in range(samples): 19 | colors = ["red", "blue", "green", "yellow"] 20 | 21 | while not all_the_same(colors): 22 | i = random.randint(0, 3) 23 | colors.remove(colors[i]) 24 | 25 | j = random.randint(0, 2) 26 | color = colors[j] 27 | colors.append(color) 28 | 29 | turns += 1 30 | 31 | average = turns / samples 32 | print("Expected number of turns:", average) 33 | 34 | 35 | def all_the_same(colors): 36 | if ((colors[0] == colors[1]) and 37 | (colors[0] == colors[2]) and 38 | (colors[0] == colors[3])): 39 | return True 40 | else: 41 | return False 42 | 43 | 44 | if __name__ == '__main__': 45 | painting_puzzle() 46 | -------------------------------------------------------------------------------- /scripts/petersburg_paradox.py: -------------------------------------------------------------------------------- 1 | # The Petersburg Paradox 2 | # http://en.wikipedia.org/wiki/St._Petersburg_paradox 3 | # A casino offers a game of chance for a single player in which a fair coin is 4 | # tossed at each stage. The pot starts at 2 dollars and is doubled every time 5 | # a head appears. The first time a tail appears, the game ends and the player 6 | # wins whatever is in the pot. Thus the player wins 2 dollars if a tail appears 7 | # on the first toss, 4 dollars if a head appears on the first toss and a tail on 8 | # the second, 8 dollars if a head appears on the first two tosses and a tail on 9 | # the third, 16 dollars if a head appears on the first three tosses and a tail on 10 | # the fourth, and so on. In short, the player wins 2k dollars, where k equals number 11 | # of tosses. What would be a fair price to pay the casino for entering the game? 12 | 13 | from random import random 14 | 15 | samples = 10000 16 | winnings = 0.0 17 | 18 | for i in range(samples): 19 | pot = 2 20 | keep_playing = True 21 | 22 | while(keep_playing): 23 | if random() < 0.5: # call this heads 24 | pot *= 2 25 | else: 26 | winnings += pot 27 | keep_playing = False 28 | 29 | expected_winnings = winnings / samples 30 | print("Fair price to pay to enter the game: %.2f" % expected_winnings) -------------------------------------------------------------------------------- /scripts/quiz_answers.py: -------------------------------------------------------------------------------- 1 | # Quiz Answers 2 | # Say you're writing a math quiz game, and for each question, 3 | # you want to present three possible answers. A naive approach to 4 | # generating the possible answers would be to calculate the correct 5 | # answer, then adding/subtracting a random amount to that for the 6 | # wrong answers. Even the most inattentive players would eventually 7 | # learn to just pick the middle answer. 8 | # Create a strategy for automatically generating answers so that 9 | # the correct answer is the lowest choice 1/3 of the time, the middle 10 | # choice 1/3 of the time, and the highest choice 1/3 of the time. 11 | 12 | import random 13 | 14 | def quiz_answers(): 15 | samples = 10000 16 | lowest = 0 17 | middle = 0 18 | highest = 0 19 | 20 | for i in range(samples): 21 | x = random.randint(1, 10) 22 | y = random.randint(1, 10) 23 | 24 | correctAns = x + y 25 | 26 | # strategy for generating wrong answers 27 | prob = random.random() 28 | if prob < 0.3333: 29 | wrongAns1 = correctAns + random.randint(1, 5) 30 | wrongAns2 = correctAns + random.randint(1, 5) 31 | elif prob < 0.6666: 32 | wrongAns1 = correctAns + random.randint(1, 5) 33 | wrongAns2 = correctAns - random.randint(1, 5) 34 | else: 35 | wrongAns1 = correctAns - random.randint(1, 5) 36 | wrongAns2 = correctAns - random.randint(1, 5) 37 | 38 | 39 | if correctAns < wrongAns1 and correctAns < wrongAns2: 40 | lowest += 1 41 | elif correctAns > wrongAns1 and correctAns > wrongAns2: 42 | highest += 1 43 | else: 44 | middle += 1 45 | 46 | print("Correct answer is lowest:", lowest/samples) 47 | print("Correct answer is middle:", middle/samples) 48 | print("Correct answer is highest:", highest/samples) 49 | 50 | 51 | if __name__ == '__main__': 52 | quiz_answers() 53 | -------------------------------------------------------------------------------- /scripts/second_best.py: -------------------------------------------------------------------------------- 1 | # Will Second-Best Be Runner-Up? 2 | # A tennis tournament has 8 players. The number a player draws from a 3 | # hat decides his first-round run in the tournament ladder. 4 | # Suppose that the best player always defeats the next best and that 5 | # the latter always defeats all the rest. The loser of the finals gets 6 | # the runner-up cup. What is the chance that the second-best player 7 | # wins the runner-up cup? 8 | # 9 | # From: Fifty Challenging Problems in Probability 10 | # by Frederick Mosteller 11 | # Problem 16 12 | 13 | import random 14 | 15 | def second_best(): 16 | samples = 10000 17 | total = 0 18 | 19 | for i in range(samples): 20 | ladder = [x for x in range(8)] 21 | random.shuffle(ladder) 22 | 23 | second_place = runner_up(ladder) 24 | if(second_place == 1): 25 | total += 1 26 | 27 | average = total / samples 28 | print("Chance that the second-best player wins the runner-up cup:", average) 29 | 30 | # find out which player was the runner-up in the given ladder arrangement 31 | def runner_up(ladder): 32 | if(len(ladder) == 2): 33 | return max(ladder) 34 | else: 35 | next_round_ladder = [] 36 | for j, k in zip(ladder[0::2], ladder[1::2]): 37 | next_round_ladder.append(min(j, k)) 38 | return runner_up(next_round_ladder) 39 | 40 | 41 | if __name__ == '__main__': 42 | second_best() 43 | 44 | -------------------------------------------------------------------------------- /scripts/specific_shuffling_problem.py: -------------------------------------------------------------------------------- 1 | # A specific shuffling problem: 2 | # Suppose you have a shuffled deck containing 13 cards. Each card has a number 3 | # from 1 to 13 and each number appears on exactly one card. You look at the 4 | # number on the first card — suppose it’s k — and then you reverse the order 5 | # of the first k cards. You continue this procedure — reading the first card’s 6 | # number and then reversing the order of the corresponding number of cards — until 7 | # the first card reads 1. Clearly, the number of reversals depends on the initial 8 | # order of the cards. What is the largest number of reversals that you might have to do? 9 | # What order are the cards in before you start shuffling the maximum-reversal deck? 10 | # Extra credit: What if the deck contains 53 cards? 11 | 12 | # From https://fivethirtyeight.com/features/how-long-will-you-shuffle-this-damn-deck-of-cards/ 13 | 14 | import random 15 | 16 | def specific_shuffle(): 17 | samples = 100000 18 | deck = [ 1, 2, 3, 4, 5, 6, 7 ] 19 | reversals = 0 20 | 21 | for i in range(samples): 22 | random.shuffle(deck) 23 | orig_deck = deck[:] 24 | rev = 0 25 | while deck[0] != 1: 26 | k = deck[0] 27 | deck[0:k] = reversed(deck[0:k]) 28 | rev += 1 29 | if rev > reversals: 30 | reversals = rev 31 | print(rev, orig_deck) 32 | 33 | print("Maximum number of reversals:", reversals) 34 | 35 | 36 | 37 | 38 | 39 | if __name__ == '__main__': 40 | specific_shuffle() 41 | -------------------------------------------------------------------------------- /scripts/state_names.py: -------------------------------------------------------------------------------- 1 | # State names letter frequency 2 | 3 | def state_names(): 4 | # load names from file 5 | with open("../data/state_names.txt", "r") as file: 6 | lines = file.readlines() 7 | 8 | # convert to lower case and strip \n 9 | lines = [x.lower().strip() for x in lines] 10 | print(lines) 11 | 12 | # initialize a frequency list 13 | alpha = "abcdefghijklmnopqrstuvwxyz " 14 | freq = dict() 15 | for c in alpha: 16 | freq[c] = 0 17 | 18 | # count letter frequency 19 | for word in lines: 20 | for char in word: 21 | freq[char] += 1 22 | 23 | # sort letters by frequency 24 | s_freq = sorted(freq.items(), key=lambda x: x[1]) 25 | print(s_freq) 26 | 27 | 28 | if __name__ == '__main__': 29 | state_names() 30 | -------------------------------------------------------------------------------- /scripts/successive_wins.py: -------------------------------------------------------------------------------- 1 | # Successive Wins 2 | # To encourage Elmer's promising tennis career, his father offers him a 3 | # prize if he wins (at least) two tennis sets in a row in a three-set 4 | # series to be played with his father and the club champion alternately: 5 | # father-champion-father or champion-father-champion, according to 6 | # Elmer's choice. The champion is a better player than Elmer's father. 7 | # Which series should Elmer choose? 8 | # 9 | # From: Fifty Challenging Problems in Probability 10 | # by Frederick Mosteller 11 | # Problem 2 12 | 13 | import random 14 | 15 | def successive_wins(): 16 | samples = 10000 17 | fcf_wins = 0 18 | cfc_wins = 0 19 | 20 | # assume Elmer has an 80% chance of winning against his father 21 | # and only a 40% chance of winning agains the club champion. 22 | 23 | for i in range(samples): 24 | # father-champion-father series 25 | set1 = random.random() < 0.8 26 | set2 = random.random() < 0.4 27 | set3 = random.random() < 0.8 28 | 29 | if (set1 and set2) or (set2 and set3): 30 | fcf_wins += 1 31 | 32 | # champion-father-champion series 33 | set1 = random.random() < 0.4 34 | set2 = random.random() < 0.8 35 | set3 = random.random() < 0.4 36 | 37 | if (set1 and set2) or (set2 and set3): 38 | cfc_wins += 1 39 | 40 | fcf_avg = fcf_wins / samples 41 | cfc_avg = cfc_wins / samples 42 | 43 | print("Elmer's win percent in father-champion-father series:", fcf_avg) 44 | print("Elmer's win percent in champion-father-champion series:", cfc_avg) 45 | 46 | 47 | 48 | if __name__ == '__main__': 49 | successive_wins() 50 | -------------------------------------------------------------------------------- /scripts/theater_row.py: -------------------------------------------------------------------------------- 1 | # The Theater Row 2 | # Eight eligible bachelors and seven beautiful models 3 | # happen randomly to have purchased single seats in a 4 | # 15-seat row of a theater. On the average, how many pairs 5 | # of adjacent seats are ticketed for marriageable couples? 6 | # 7 | # From: Fifty Challenging Problems in Probability 8 | # by Frederick Mosteller 9 | # Problem 15 10 | 11 | import random 12 | 13 | def theater_row(): 14 | samples = 10000 15 | total = 0 16 | 17 | brides = [False] * 7 18 | grooms = [True] * 8 19 | row = brides + grooms 20 | 21 | for i in range(samples): 22 | random.shuffle(row) 23 | total += couples(row) 24 | 25 | average = total / samples 26 | print("Average number of couples in the row:", average) 27 | 28 | # find how many couples there are in the row 29 | def couples(row): 30 | a = 0 31 | b = 1 32 | count = 0 33 | 34 | while(b < len(row)): 35 | if(row[a] != row[b]): 36 | count += 1 37 | a += 1 38 | b += 1 39 | 40 | return count 41 | 42 | 43 | 44 | if __name__ == '__main__': 45 | theater_row() 46 | -------------------------------------------------------------------------------- /scripts/theater_seats.py: -------------------------------------------------------------------------------- 1 | # Theater Seats 2 | # To watch a movie, John, Mary and 5 friends will sit randomly in 3 | # a row with 7 seats. What is the probability John and Mary won't 4 | # sit together? 5 | 6 | from __future__ import division 7 | import random 8 | 9 | def theater_seats(): 10 | samples = 10000 11 | friends = [ "Alice", "Bob", "Carol", "Dave", "Eve", "John", "Mary" ] 12 | john_mary = 0 13 | mary_john = 0 14 | 15 | for i in range(samples): 16 | random.shuffle(friends) 17 | seating = ",".join(friends) 18 | if "John,Mary" in seating: 19 | john_mary += 1 20 | if "Mary,John" in seating: 21 | mary_john += 1 22 | 23 | average = (john_mary + mary_john) / samples; 24 | print("Mary sat next to John", john_mary + mary_john, "times.") 25 | print("The probability Mary won't sit next to John is", 1.0 - average) 26 | 27 | 28 | if __name__ == '__main__': 29 | theater_seats() 30 | -------------------------------------------------------------------------------- /scripts/three_flips.py: -------------------------------------------------------------------------------- 1 | # Three flips 2 | # The following game has a $10 entry fee. 3 | # You are to flip a fair coin three times. 4 | # The first time it comes up heads you are paid $5. 5 | # The second time it comes up heads you're paid an additional $7. 6 | # The third time it comes up heads you're paid $9 more, 7 | # for a possible maximum prize of $21. 8 | # Would you pay the $10 entry fee to play? 9 | 10 | import random 11 | 12 | def three_flips(): 13 | samples = 10000 14 | winnings = 0 15 | prizes = (5, 7, 9) 16 | 17 | for i in range(samples): 18 | heads = 0 19 | for j in range(3): 20 | if random.random() < 0.5: 21 | winnings += prizes[heads] 22 | heads += 1 23 | 24 | winnings = winnings - (10 * samples) # subtract entry fees 25 | average = winnings / samples 26 | print("Total winnings:", winnings) 27 | print("Average winnings:", average) 28 | 29 | 30 | 31 | if __name__ == '__main__': 32 | three_flips() 33 | -------------------------------------------------------------------------------- /scripts/trials_until_success.py: -------------------------------------------------------------------------------- 1 | # Trials until success 2 | # On average, how many times must a die be thrown until one rolls a six? 3 | # From: Fifty Challenging Problems in Probability 4 | # by Frederick Mosteller 5 | # Problem 4 6 | 7 | import random 8 | 9 | def trials_until_success(): 10 | samples = 10000 11 | total = 0; 12 | 13 | for i in range(samples): 14 | throws = 1 15 | die = random.randint(1, 6) 16 | 17 | while(die != 6): 18 | die = random.randint(1, 6) 19 | throws += 1 20 | 21 | total += throws 22 | 23 | average = total / samples 24 | print("Average number of throws until the first 6: ", average) 25 | 26 | if __name__ == '__main__': 27 | trials_until_success() 28 | -------------------------------------------------------------------------------- /scripts/twin_knights.py: -------------------------------------------------------------------------------- 1 | # Twin Knights 2 | # (a) Suppose King Arthur holds a jousting tournament where the jousts are 3 | # in pairs as in a tennis tournament. The 8 knights in the tournament are 4 | # evenly matched, and they include the twin knights Balin and Balan. 5 | # What is the chance that the twins meet in a match during the tournament? 6 | # (b) Replace 8 by 2^n in the above problem. Now what is the chance they meet? 7 | # 8 | # From: Fifty Challenging Problems in Probability 9 | # by Frederick Mosteller 10 | # Problem 17 11 | 12 | import random 13 | 14 | def twin_knights(): 15 | samples = 10000 16 | total = 0 17 | 18 | for i in range(samples): 19 | ladder = [x for x in range(8)] 20 | random.shuffle(ladder) 21 | if twins_meet(ladder): 22 | total += 1 23 | 24 | average = total / samples 25 | print("Chance that the twins meet in a match:", average) 26 | 27 | 28 | # Check to see if the "twins" (0 and 1) meet 29 | # in a given shuffled tournament ladder. 30 | def twins_meet(ladder): 31 | if(len(ladder) == 2): 32 | if all(x < 2 for x in ladder): 33 | return True 34 | else: 35 | return False 36 | else: 37 | next_round_ladder = [] 38 | for j, k in zip(ladder[0::2], ladder[1::2]): 39 | if j < 2 and k < 2: 40 | return True 41 | winner = j if (random.random() < 0.5) else k 42 | next_round_ladder.append(winner) 43 | return twins_meet(next_round_ladder) 44 | 45 | 46 | if __name__ == '__main__': 47 | twin_knights() 48 | -------------------------------------------------------------------------------- /scripts/yahtzee.py: -------------------------------------------------------------------------------- 1 | # Yahtzee! 2 | # What is the probability of rolling five of a kind when rolling 3 | # five six-sided dice three times? 4 | 5 | import random 6 | 7 | def yahtzee(): 8 | samples = 100000 9 | successes = 0 10 | 11 | for i in range(samples): 12 | for j in range(3): # roll the dice 3 times 13 | dice = [] 14 | for k in range(5): # roll 5 dice 15 | dice.append(random.randint(1, 6)) 16 | 17 | if all(die == dice[0] for die in dice): 18 | successes += 1 19 | 20 | average = successes / samples 21 | print("Probability of rolling 5 of a kind:", average) 22 | 23 | 24 | 25 | if __name__ == '__main__': 26 | yahtzee() 27 | --------------------------------------------------------------------------------