Last active
March 29, 2016 07:44
-
-
Save beckyconning/adef8f3e88da4d1d20e9 to your computer and use it in GitHub Desktop.
Bingo card generator app in both Elm 0.16.0 and Purescript v0.7.6.1 for comparison. The apps are almost identical except that the Elm version uses a random seed and the Purescript version includes a "FREE SPACE" in the middle. Elm version by Charlotte Tortorella, Purescript version by Becky Conning.
This file contains 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
import Signal | |
import Graphics.Element exposing (..) | |
import Graphics.Input exposing (button) | |
import Graphics.Collage exposing (collage, toForm) | |
import List exposing (..) | |
import Color | |
import Text | |
import Random | |
import Random.Array | |
import Window | |
import Task exposing (Task) | |
import Array exposing (Array) | |
type alias Model = | |
{ seed : Random.Seed | |
, bingoTiles : List String | |
, generator : Random.Generator (List String) | |
} | |
type Action = NoOp | |
| Shuffle | |
randomGenerator : Random.Generator (List String) | |
randomGenerator = | |
initialNumbers | |
|> Random.Array.shuffle << Array.fromList | |
|> Random.map Array.toList | |
initialNumbers : List String | |
initialNumbers = | |
[ "1" | |
, "2" | |
, "3" | |
, "4" | |
, "5" | |
, "6" | |
, "7" | |
, "8" | |
, "9" | |
, "10" | |
, "11" | |
, "12" | |
, "13" | |
, "14" | |
, "15" | |
, "16" | |
, "17" | |
, "18" | |
, "19" | |
, "20" | |
, "21" | |
, "22" | |
, "23" | |
, "24" | |
, "25" | |
] | |
main = | |
Signal.map2 view model Window.dimensions | |
update : Action -> Model -> Model | |
update action model = | |
case action of | |
NoOp -> | |
model | |
Shuffle -> | |
let (tiles, newSeed) = Random.generate model.generator model.seed | |
in | |
{ model | |
| bingoTiles = tiles | |
, seed = newSeed | |
} | |
initialModel : Model | |
initialModel = | |
{ seed = Random.initialSeed 42 | |
, bingoTiles = initialNumbers | |
, generator = randomGenerator | |
} | |
model : Signal Model | |
model = | |
Signal.foldp update initialModel actions.signal | |
slice : List a -> Int -> Int -> List a | |
slice xs s e = take (e - s + 1) <| drop (s - 1) xs | |
view : Model -> (Int, Int) -> Element | |
view model (windowWidth, windowHeight) = | |
let boxSize = (min windowWidth windowHeight) |> toFloat |> flip (/) 6 |> round | |
boxSpacing = 2 | |
boxSpacer = spacer boxSpacing boxSpacing | |
shuffleButton = button (Signal.message actions.address Shuffle) "Shuffle" | |
sliceTilesAsText start end = | |
slice model.bingoTiles start end | |
|> map (centered << Text.height 10 << Text.fromString) | |
|> map (container boxSize boxSize middle) | |
|> map (color Color.lightGrey) | |
|> intersperse boxSpacer | |
|> flow right | |
middleAtY = middleAt (relative 0.5) | |
bingoTiles = | |
[ sliceTilesAsText 1 5 | |
, sliceTilesAsText 6 10 | |
, sliceTilesAsText 11 15 | |
, sliceTilesAsText 16 20 | |
, sliceTilesAsText 21 25 | |
] | |
|> intersperse boxSpacer | |
|> flow down | |
in | |
collage windowWidth windowHeight | |
<| map toForm | |
[ container ((widthOf bingoTiles) + boxSpacing * 2) ((heightOf bingoTiles) + boxSpacing * 2) middle bingoTiles | |
|> color Color.black | |
|> below (container ((widthOf bingoTiles) + boxSpacing * 2) ((heightOf shuffleButton) * 2) middle shuffleButton) | |
] | |
actions : Signal.Mailbox Action | |
actions = | |
Signal.mailbox NoOp |
This file contains 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
module Main where | |
import Control.Bind ((=<<)) | |
import Control.Monad.Aff (Aff(), runAff, later') | |
import Control.Monad.Eff (Eff()) | |
import Control.Monad.Eff.Exception (throwException) | |
import Control.Monad.List.Trans as ListT | |
import Control.Monad.Trampoline (Trampoline, runTrampoline) | |
import Data.Array (slice, insertAt, head, singleton) | |
import Data.Functor ((<$)) | |
import Data.Lazy (Lazy, force) | |
import Data.Maybe (Maybe(Just), maybe) | |
import Data.Tuple (Tuple, fst, snd) | |
import Halogen | |
import Halogen.HTML.Events.Indexed as E | |
import Halogen.HTML.Indexed as H | |
import Halogen.HTML.Properties.Indexed as P | |
import Halogen.Util (appendToBody, onLoad) | |
import Prelude | |
import Test.StrongCheck.Gen (Gen, GenState(..), runGen, shuffleArray, infinite, toLazyList) | |
data BingoQuery a = Shuffle a | |
type Numbers = Array String | |
type Permutations = ListT.ListT Lazy (Array String) | |
type BingoState = { numbers :: Maybe Numbers, permutations :: Permutations } | |
initialNumbers :: Array String | |
initialNumbers = | |
[ "1" | |
, "2" | |
, "3" | |
, "4" | |
, "5" | |
, "6" | |
, "7" | |
, "8" | |
, "9" | |
, "10" | |
, "11" | |
, "12" | |
, "13" | |
, "14" | |
, "15" | |
, "16" | |
, "17" | |
, "18" | |
, "19" | |
, "20" | |
, "21" | |
, "22" | |
, "23" | |
, "24" | |
] | |
initialGenState :: GenState | |
initialGenState = GenState { size: 1, seed: 454645874.0 } | |
initialPermutations :: Permutations | |
initialPermutations = toLazyList (infinite $ shuffleArray initialNumbers) initialGenState | |
initialState :: BingoState | |
initialState = { numbers: Just initialNumbers, permutations: initialPermutations } | |
nextPermutation :: BingoState -> BingoState | |
nextPermutation state = | |
{ numbers: force $ ListT.head $ state.permutations, permutations: ListT.drop 1 state.permutations } | |
insertFreeSpace :: Array String -> Maybe (Array String) | |
insertFreeSpace = insertAt 12 "FREE SPACE" | |
rows :: forall a. Array a -> Array (Array a) | |
rows xs = [slice 0 5 xs, slice 5 10 xs, slice 10 15 xs, slice 15 20 xs, slice 20 25 xs] | |
ui :: forall g. (Functor g) => Component BingoState BingoQuery g | |
ui = component render eval | |
where | |
render :: BingoState -> ComponentHTML BingoQuery | |
render state = | |
H.div_ | |
[ maybe renderGenError renderTableIfThereAreEnoughNumbers $ state.numbers | |
, H.button [ E.onClick $ E.input_ Shuffle ] [ H.text "Shuffle" ] | |
] | |
renderTableIfThereAreEnoughNumbers :: Array String -> ComponentHTML BingoQuery | |
renderTableIfThereAreEnoughNumbers = | |
maybe renderNotEnoughNumbersError renderTable <<< insertFreeSpace | |
renderNotEnoughNumbersError :: ComponentHTML BingoQuery | |
renderNotEnoughNumbersError = H.text "Needed at least 12 numbers" | |
renderGenError :: ComponentHTML BingoQuery | |
renderGenError = H.text "Generator didn't produce a sample" | |
renderTable :: Array String -> ComponentHTML BingoQuery | |
renderTable = H.table_ <<< map renderRow <<< rows | |
renderRow :: Array String -> ComponentHTML BingoQuery | |
renderRow = H.tr_ <<< map renderCell | |
renderCell :: String -> ComponentHTML BingoQuery | |
renderCell = H.td_ <<< singleton <<< H.text | |
eval :: Natural BingoQuery (ComponentDSL BingoState BingoQuery g) | |
eval (Shuffle next) = next <$ modify nextPermutation | |
main :: Eff (HalogenEffects ()) Unit | |
main = runAff throwException (const (pure unit)) initialiseAndAppendNode | |
where | |
initialiseAndAppendNode = | |
onLoad <<< appendToBody <<< _.node =<< (runUI ui $ nextPermutation initialState) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment