Joshua Moerman
8 years ago
commit
a71928382b
5 changed files with 310 additions and 0 deletions
@ -0,0 +1,62 @@ |
|||
module Grid exposing (..) |
|||
|
|||
import RingList exposing (..) |
|||
|
|||
type alias Grid a = RingList (RingList a) |
|||
|
|||
{- Basic conversion -} |
|||
generate : Int -> Int -> (Int -> Int -> a) -> Grid a |
|||
generate width height gen = let |
|||
row = RingList.fromList 1 [2..width] |
|||
cols = RingList.fromList 1 [2..height] |
|||
grid = RingList.map (\y -> RingList.map (\x -> (x, y)) row) cols |
|||
in map (uncurry gen) grid |
|||
|
|||
toList : Grid a -> List (List a) |
|||
toList grid = RingList.toList <| RingList.map RingList.toList <| grid |
|||
|
|||
{- Functor like functions -} |
|||
map : (a -> b) -> Grid a -> Grid b |
|||
map f grid = RingList.map (RingList.map f) grid |
|||
|
|||
edit : (a -> a) -> Grid a -> Grid a |
|||
edit f grid = RingList.edit (RingList.edit f) grid |
|||
|
|||
{- Comonad functions -} |
|||
extract : Grid a -> a |
|||
extract grid = grid.focus.focus |
|||
|
|||
-- It was quite difficult to define duplicate. A simple RL.map RL.dup >> RL.dup |
|||
-- is not the right definition (this would be too simple). With the transpose |
|||
-- trick it is quite ok to reason about (draw the diagrams yourself!) |
|||
duplicate : Grid a -> Grid (Grid a) |
|||
duplicate grid = grid |> RingList.map RingList.duplicate |> transpose |> RingList.map RingList.duplicate |> transpose |
|||
|
|||
extend : (Grid a -> b) -> Grid a -> Grid b |
|||
extend f w = map f (duplicate w) |
|||
|
|||
(=>>) : Grid a -> (Grid a -> b) -> Grid b |
|||
(=>>) = flip extend |
|||
|
|||
{- Domain functions -} |
|||
shiftLeft : Grid a -> Grid a |
|||
shiftLeft grid = RingList.map RingList.shiftLeft grid |
|||
|
|||
shiftRight : Grid a -> Grid a |
|||
shiftRight grid = RingList.map RingList.shiftRight grid |
|||
|
|||
shiftUp : Grid a -> Grid a |
|||
shiftUp grid = RingList.shiftLeft grid |
|||
|
|||
shiftDown : Grid a -> Grid a |
|||
shiftDown grid = RingList.shiftRight grid |
|||
|
|||
transpose : Grid a -> Grid a |
|||
transpose grid = let |
|||
newBefore grid = List.map RingList.extract grid.before |
|||
newAfter grid = List.map RingList.extract grid.after |
|||
newFocus rl = RingList (newBefore rl) (extract rl) (newAfter rl) |
|||
nb = List.map newFocus <| RingList.iterate1N (List.length grid.focus.before) shiftRight grid |
|||
nf = newFocus grid |
|||
na = List.map newFocus <| RingList.iterate1N (List.length grid.focus.after) shiftLeft grid |
|||
in RingList nb nf na |
@ -0,0 +1,67 @@ |
|||
import Grid exposing (..) |
|||
import RingList exposing (..) |
|||
|
|||
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 |
|||
, view = view |
|||
, update = update |
|||
, subscriptions = subscriptions |
|||
} |
|||
|
|||
width = 21 |
|||
height = 16 |
|||
|
|||
-- MODEL |
|||
|
|||
type alias World = Grid (Int, Float) |
|||
type alias Model = |
|||
{ grid : World |
|||
, history : List (Int, Float) |
|||
} |
|||
|
|||
init : (Model, Cmd Msg) |
|||
init = (Model (Grid.generate width height (\x y -> (x, toFloat y))) [], Cmd.none) |
|||
|
|||
|
|||
-- UPDATE |
|||
|
|||
type Msg |
|||
= Update World |
|||
|
|||
succ (n, m) = (n + 1, m * 2) |
|||
|
|||
update : Msg -> Model -> (Model, Cmd Msg) |
|||
update msg model = |
|||
case msg of |
|||
Update grid -> (Model grid (Grid.extract grid :: model.history), Cmd.none) |
|||
|
|||
|
|||
-- SUBSCRIPTIONS |
|||
|
|||
subscriptions : Model -> Sub Msg |
|||
subscriptions model = Sub.none |
|||
|
|||
|
|||
-- VIEW |
|||
|
|||
butt : World -> Html Msg |
|||
--butt rl = button [ onClick (Update (RingList.edit succ rl)) ] [ RingList.extract rl |> toString |> text ] |
|||
butt grid = button [ onClick (Update (Grid.edit succ grid)) ] [ Grid.extract grid |> toString |> text ] |
|||
|
|||
view : Model -> Html Msg |
|||
view model = let |
|||
dupmodel = Grid.duplicate model.grid |
|||
butts = Grid.map butt dupmodel |
|||
listm = Grid.toList butts |
|||
viewm = List.map (\row -> div [] (br [] [] :: row)) listm |
|||
in div [] <| viewm ++ [div [] [model.history |> toString |> text]] |
@ -0,0 +1,108 @@ |
|||
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 |
|||
) |
|||
|
|||
|
|||
|
@ -0,0 +1,58 @@ |
|||
module RingList exposing (..) |
|||
|
|||
type alias RingList a = |
|||
{ before : List a |
|||
, focus : a |
|||
, after : List a |
|||
} |
|||
|
|||
{- Basic conversion -} |
|||
fromList : a -> List a -> RingList a |
|||
fromList a l = RingList [] a l |
|||
|
|||
toList : RingList a -> List a |
|||
toList rl = List.reverse rl.before ++ [rl.focus] ++ rl.after |
|||
|
|||
{- Functor like things -} |
|||
map : (a -> b) -> RingList a -> RingList b |
|||
map f rl = RingList (List.map f rl.before) (f rl.focus) (List.map f rl.after) |
|||
|
|||
edit : (a -> a) -> RingList a -> RingList a |
|||
edit f rl = RingList rl.before (rl.focus |> f) rl.after |
|||
|
|||
{- Comonad functions -} |
|||
extract : RingList a -> a |
|||
extract rl = rl.focus |
|||
|
|||
duplicate : RingList a -> RingList (RingList a) |
|||
duplicate rl = let |
|||
lefts = iterate1N (List.length rl.before) shiftRight rl |
|||
rights = iterate1N (List.length rl.after) shiftLeft rl |
|||
in RingList lefts rl rights |
|||
|
|||
extend : (RingList a -> b) -> RingList a -> RingList b |
|||
extend f w = map f (duplicate w) |
|||
|
|||
(=>>) : RingList a -> (RingList a -> b) -> RingList b |
|||
(=>>) = flip extend |
|||
|
|||
{- Domain functions -} |
|||
shiftLeft : RingList a -> RingList a |
|||
shiftLeft rl = case rl.after of |
|||
[] -> case List.reverse rl.before of |
|||
[] -> RingList [] rl.focus [] |
|||
x::xs -> RingList [rl.focus] x xs |
|||
x::xs -> RingList (rl.focus :: rl.before) x xs |
|||
|
|||
shiftRight : RingList a -> RingList a |
|||
shiftRight rl = case rl.before of |
|||
[] -> case List.reverse rl.after of |
|||
[] -> RingList [] rl.focus [] |
|||
x::xs -> RingList xs x [rl.focus] |
|||
x::xs -> RingList xs x (rl.focus :: rl.after) |
|||
|
|||
{- From here we have private functions -} |
|||
iterate1N : Int -> (a -> a) -> a -> List a |
|||
iterate1N n f a = case n of |
|||
0 -> [] |
|||
m -> f a :: List.map f (iterate1N (m - 1) f a) |
@ -0,0 +1,15 @@ |
|||
{ |
|||
"version": "1.0.0", |
|||
"summary": "helpful summary of your project, less than 80 characters", |
|||
"repository": "https://github.com/user/project.git", |
|||
"license": "BSD3", |
|||
"source-directories": [ |
|||
"." |
|||
], |
|||
"exposed-modules": [], |
|||
"dependencies": { |
|||
"elm-lang/core": "4.0.5 <= v < 5.0.0", |
|||
"elm-lang/html": "1.1.0 <= v < 2.0.0" |
|||
}, |
|||
"elm-version": "0.17.1 <= v < 0.18.0" |
|||
} |
Reference in new issue