Last active
April 1, 2019 07:59
-
-
Save Xetera/03837ce02614f0502f59a26c8851031c to your computer and use it in GitHub Desktop.
A haskell simulation implementing Optimal Stopping Theory for the math game, game of googol.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {- | |
| Using Optimal Stopping for finding the highest number in a list | |
| 1. Generate an integer list of N size | |
| 2. Reveal the numbers of the first N/e elements | |
| 3. Keep revealing numbers until you find one bigger than the biggest revealed number | |
| 4. The chances of the first matching number being the highest number in the list will consistently be 1/e | |
| -} | |
| -- Games played: 1000 | |
| -- Games Won: 358 | |
| -- Games Lost: 642 | |
| -- Win Ratio: 35.8% | |
| {-# LANGUAGE NumericUnderscores #-} | |
| module Lib | |
| ( someFunc | |
| ) where | |
| import System.Random (randomRIO) | |
| import Text.Read (readMaybe) | |
| import Data.List | |
| import Data.Maybe | |
| import System.Environment | |
| import Control.Monad | |
| import Data.Bifunctor (bimap) | |
| import Control.Concurrent.Async | |
| e :: Float | |
| e = 2.7182818284590452353602874713527 | |
| genRand :: (Int, Int) -> IO Int | |
| genRand = randomRIO | |
| randomNums :: Int -> Int -> IO [Int] | |
| randomNums arrLength maxNum = | |
| let randomNum = genRand (1, maxNum) | |
| in traverse (const randomNum) [1..arrLength] | |
| ratio :: Int -> Int | |
| ratio nums = round $ fromIntegral (nums) / e | |
| grabE :: [Int] -> [Int] | |
| grabE nums = | |
| let amount = ratio (length nums) | |
| in take amount nums | |
| -- Plays a game and returns the winning outcome | |
| game :: IO Bool | |
| game = do | |
| total <-randomNums 1000 1000 | |
| let eNums = grabE total | |
| let maxNum = maximum eNums | |
| let totalMax = maximum total | |
| let iterNums = drop (ratio (length total)) total | |
| let nextBiggest = find (>maxNum) iterNums | |
| let out = fromMaybe (-1) nextBiggest | |
| return $ out == totalMax | |
| mapTuple :: (a -> b) -> (a, a) -> (b, b) | |
| mapTuple = join bimap | |
| getStats :: Int -> Int -> Float | |
| getStats first second = (fromIntegral first / fromIntegral (first + second)) * 100 | |
| extractCount :: [String] -> Either String Int | |
| extractCount [] = Left "Must enter the number of simulations!" | |
| extractCount (count:_) = | |
| case readMaybe count of | |
| Just num -> Right num | |
| Nothing -> Left $ "invalid input: " <> count | |
| getResults :: (Int, Int) -> String | |
| getResults (passing, nonPassing) = | |
| "Games played: " <> show (passing + nonPassing) <> "\n" | |
| <> "Games Won: " <> show passing <> "\n" | |
| <> "Games Lost: " <> show nonPassing <> "\n" | |
| <> "Win Ratio: " <> show (getStats passing nonPassing) <> "%" | |
| someFunc :: IO () | |
| someFunc = getArgs | |
| >>= either return process . extractCount | |
| >>= putStrLn | |
| where | |
| process count = getResults . mapTuple length . partition (==True) <$> replicateM count game |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment