Skip to content

Instantly share code, notes, and snippets.

@imeckler
Last active December 13, 2015 18:58
Show Gist options
  • Save imeckler/4958771 to your computer and use it in GitHub Desktop.
Save imeckler/4958771 to your computer and use it in GitHub Desktop.
A fast Haskell program to help answer the following question: How long does it take a person randomly walking on a grid to touch every square?
import Prelude hiding (scanl, length, takeWhile, sum, map)
import Data.List.Stream
import System.Random.Mersenne.Pure64
import qualified Data.Set as S
import Data.Word
randUpTo :: Int -> PureMT -> [Int]
randUpTo n gen = unfoldr make gen
where make g = let (k, g') = randomInt g in Just (k `mod` n, g')
randomWalk :: Int -> PureMT -> [(Int, Int)]
randomWalk w g = scanl move (0, 0) $ randUpTo 4 g
where
move :: (Int, Int) -> Int -> (Int, Int)
move (x, y) n = case n of
0 -> (x, (y + 1) `mod` w) -- up
1 -> (x, (y - 1) `mod` w) -- down
2 -> ((x - 1) `mod` w, y) -- left
3 -> ((x + 1) `mod` w, y) -- right
-- length of a run with stdGen seeded with n on a grid of size w
runWalk :: Int -> Word64 -> Int
runWalk w n = length
. takeWhile (not . S.null)
. scanl (flip S.delete) pointSet $ randomWalk w g
where g = pureMT n
pointSet = S.fromDistinctAscList [(i, j) | i <- [0..w - 1], j <- [0..w - 1]]
main = do
print . sum $ map (runWalk 10) [1..10000]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment