Skip to content

Instantly share code, notes, and snippets.

@vhalli
Created November 17, 2019 09:18
Show Gist options
  • Save vhalli/b74edf65a8805f7200fc9683a4fa3266 to your computer and use it in GitHub Desktop.
Save vhalli/b74edf65a8805f7200fc9683a4fa3266 to your computer and use it in GitHub Desktop.
Conway's Game of Life in Elm (For GDCR 2019 at Helpshift)
module Conway exposing (..)
import Set exposing (Set)
type alias Cell =
( Int, Int )
newCell : Int -> Int -> Cell
newCell x y =
Tuple.pair x y
vicinity_of : Cell -> Set Cell
vicinity_of cell =
Set.fromList
[ newCell (Tuple.first cell - 1) (Tuple.second cell - 1)
, newCell (Tuple.first cell) (Tuple.second cell - 1)
, newCell (Tuple.first cell + 1) (Tuple.second cell - 1)
, newCell (Tuple.first cell - 1) (Tuple.second cell)
, newCell (Tuple.first cell + 1) (Tuple.second cell)
, newCell (Tuple.first cell - 1) (Tuple.second cell + 1)
, newCell (Tuple.first cell) (Tuple.second cell + 1)
, newCell (Tuple.first cell + 1) (Tuple.second cell + 1)
]
neighbours_of : Set Cell -> Cell -> Set Cell
neighbours_of alive cell =
cell
|> vicinity_of
|> Set.intersect alive
survives : Set Cell -> Cell -> Bool
survives alive cell =
cell
|> neighbours_of alive
|> Set.size
|> (\x -> x == 2 || x == 3)
regenerates : Set Cell -> Cell -> Bool
regenerates alive dead_cell =
dead_cell
|> neighbours_of alive
|> Set.size
|> (==) 3
tick : Set Cell -> Set Cell
tick env =
let
neighbours =
Set.foldl (\c s -> Set.union s (vicinity_of c)) Set.empty env
dead_cells =
Set.diff neighbours env
survivors =
Set.filter (\c -> survives env c) env
second_chance =
Set.filter (\c -> regenerates env c) dead_cells
in
Set.union survivors second_chance
module ConwayTest exposing (..)
import Conway
import Expect exposing (..)
import Set exposing (Set)
import Test exposing (..)
suite : Test
suite =
describe "Conway's Game of Life"
[ describe "A Cell"
(let
cell =
Conway.newCell 5 5
alive : Set Conway.Cell
alive =
Set.fromList
[ Conway.newCell 3 6
, Conway.newCell 4 4
, Conway.newCell 6 6
, Conway.newCell 9 9
]
in
[ test "has a vicinity" <|
let
expected_vicinity =
Set.fromList
[ ( 4, 4 )
, ( 5, 4 )
, ( 6, 4 )
, ( 4, 5 )
, ( 6, 5 )
, ( 4, 6 )
, ( 5, 6 )
, ( 6, 6 )
]
in
\_ -> Expect.equalSets expected_vicinity (Conway.vicinity_of cell)
, test "may have neighbours in its vicinity" <|
let
expected_neighbours =
Set.fromList [ Conway.newCell 4 4, Conway.newCell 6 6 ]
in
\_ -> Expect.equalSets expected_neighbours (Conway.neighbours_of alive cell)
, test "with two or three live neighbours, survives" <|
\_ -> Expect.true "Expected cell to survive" (Conway.survives alive cell)
, test "with no neighbours, to die" <|
\_ -> Expect.false "Expected cell to die" (Conway.survives alive (Conway.newCell 0 0))
, test "with more than three neighbours, to die" <|
let
too_much_bheed =
alive
|> Set.insert (Conway.newCell 4 6)
|> Set.insert (Conway.newCell 5 6)
in
\_ -> Expect.false "Expected cell to die" (Conway.survives too_much_bheed cell)
, test "with three live neighbours, becomes alive" <|
let
three_neighbours =
Set.insert (Conway.newCell 4 6) alive
in
\_ -> Expect.true "Expected cell to regenerate" (Conway.regenerates three_neighbours cell)
]
)
, describe "After each tick, a set"
[ test "with no cells remains unchanged" <|
\_ -> Expect.equalSets Set.empty (Conway.tick Set.empty)
, test "with a single cell becomes empty" <|
let
current_state =
Set.singleton (Conway.newCell 1 1)
in
\_ -> Expect.equalSets Set.empty (Conway.tick current_state)
, test "with multiple cells follows the rules of the game :)" <|
let
current_state =
Set.fromList
[ Conway.newCell 5 5
, Conway.newCell 5 6
, Conway.newCell 5 7
]
next_state =
Set.fromList
[ Conway.newCell 4 6
, Conway.newCell 5 6
, Conway.newCell 6 6
]
in
\_ -> Expect.equalSets next_state (Conway.tick current_state)
]
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment