-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMerlin.elm
103 lines (81 loc) · 3.24 KB
/
Merlin.elm
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
module Merlin where
import Text exposing (..)
import Graphics.Input exposing (..)
import Graphics.Element exposing (..)
import Graphics.Collage exposing (..)
import Color exposing (..)
import List
import Mouse
import Window
import Signal
import Signal.Extra
import Debug
-- Model
size = 5
start u =
case u of
Viewport (w,h) -> {
view={w=w,h=h},
states=List.map (always True) [1..size^2]
}
gridSize (w,h) = (min w h)*2/3
divide n side =
let n' = toFloat n
in (side-4-((n'-1)*2))/n'
-- Update
type Update = Viewport (Int, Int) | Click (Float,Float)
update u world =
case u of
Viewport vp -> updateViewport vp world
Click square -> updateClick square world
updateClick (row,col) world =
let which (row,col) = ((row-1)*size)+col-1
ok n = n >= 1 && n <= size
allOffsets = List.map (\(x,y) -> (row+x,col+y)) [(0,1),(-1,0),(0,0),(0,-1),(1,0)]
coordOffsets = List.filter (\ (x,y) -> ok x && ok y) allOffsets
offsets = List.map which coordOffsets
toggle which states =
let before = List.take which states
(first :: rest) = List.drop which states
in before ++ (not first :: rest)
in {world | states <- List.foldl toggle world.states offsets}
updateViewport (w,h) world =
let view = world.view
view' = {view | w<-w,h<-h}
in {world | view <- view'}
-- Display
displaySquare row col world =
let side = gridSize (toFloat world.view.w,toFloat world.view.h)
small = divide size side
frnd = toFloat << round
(state :: rest) = List.drop ((((floor row)-1)*size)+(floor col)-1) world.states
style = if state then filled green else outlined (solid white)
disp = collage (floor small) (floor small) <| [style (rect small small)]
in clickable (Signal.message clicks.address (row,col)) disp
rowOfSquares world row =
let squares = List.map (\col -> displaySquare row col world) [1..size]
between = spacer 2 2
in flow right (List.intersperse between squares)
makeSquares world =
let rows = List.map (rowOfSquares world) [1..size]
between = spacer 2 2
in flow down (List.intersperse between rows)
winStyle = { typeface = [], height = Just 24, color = white, bold = True, italic = False, line = Nothing}
win world =
if List.all (not) world.states then [container world.view.w world.view.h middle <| centered <| style winStyle <| fromString "You Win!"]
else []
display world =
let backdrop = filled black <| rect (toFloat world.view.w) (toFloat world.view.h)
side = gridSize (toFloat world.view.w,toFloat world.view.h)
grid = outlined (solid white) (rect side side)
table = collage world.view.w world.view.h [backdrop,grid]
squares = List.concatMap (\row -> List.map (\col -> displaySquare row col world) [1..size]) [1..size]
in layers <| [table, container world.view.w world.view.h middle (makeSquares world)] ++ win world
-- Signals
clicks = Signal.mailbox (0.0,0.0)
squareClicks = Signal.map Click clicks.signal
dimensions = Signal.map Viewport (Window.dimensions)
inputs = Signal.mergeMany [dimensions,squareClicks]
main =
let states = Signal.Extra.foldp' update start inputs
in Signal.map display states