import Html exposing (..)
import Html.Attributes exposing (..)
import Html.App as App
import Html.Events exposing (..)
import Random
import Color exposing (..)
import Time exposing (Time, second)
main =
App.program
{ init = (init size)
, view = view
, update = update
, subscriptions = subscriptions
}
size = 36
-- MODEL
type alias State = Maybe Int
type alias Automaton = List (Int, Int)
type alias Model =
{ states : List State
, system : Automaton
}
init : Int -> (Model, Cmd Msg)
init n = (Model (List.map Just [1 .. size]) [], Random.generate Update (genAut n))
-- UPDATE
type Msg
= Step
| Regen
| Update Automaton
| Sort
zip = List.map2 (,)
genAut : Int -> Random.Generator Automaton
genAut n = Random.map (zip [1 .. n]) (Random.list n <| Random.int 1 n)
step : Automaton -> State -> State
step ls s0 = case s0 of
Nothing -> Nothing
Just s -> List.filter (\(a,b) -> a == s) ls |> List.head |> Maybe.map snd
cmp l r = case (l, r) of
(Nothing, Nothing) -> EQ
(Nothing, Just n) -> LT
(Just n, Nothing) -> GT
(Just n, Just m) -> compare n m
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Step -> (Model (List.map (step model.system) model.states) model.system, Cmd.none)
Regen ->
init size
Update newAut ->
(Model model.states newAut, Cmd.none)
Sort ->
(Model (List.sortWith cmp model.states) model.system, Cmd.none)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Time.every (0.1 * second) (\a -> Step)
-- VIEW
(=>) = (,)
state2Color : State -> Color
state2Color s = case s of
Nothing -> Color.black
Just n -> hsl (degrees (toFloat n)*77) 1.0 (0.8 - 0.6 * (toFloat n)/size)
color2String : Color -> String
color2String c = let rgb = toRgb c in "rgb(" ++ toString rgb.red ++ ", " ++ toString rgb.green ++ ", " ++ toString rgb.blue ++ ")"
block : Color -> Html msg
block c = div [style ["background-color" => color2String c, "width" => "100px", "height" => "100px", "display" => "inline-block"]] []
view : Model -> Html Msg
view model =
div []
( button [ onClick Regen ] [ text "Regenerate" ]
:: button [ onClick Sort ] [ text "Sort" ]
:: br [] []
:: List.map (block << state2Color) model.states
)