-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConnectFour.elm
100 lines (77 loc) · 1.97 KB
/
ConnectFour.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
module ConnectFour where
import Color exposing (..)
import Graphics.Collage exposing (..)
import Graphics.Element exposing (..)
import List exposing (..)
import Mouse
import Signal
-- Model
type Player = A | B
type Slot = Empty | Piece Player
type alias Column = List Slot
type alias Board = List Column
type alias Model =
{ board: Board
, turn : Player
}
maxColumn = 7
maxRow = 6
pieceSize = 90 -- px
emptyBoard =
repeat maxColumn (repeat maxRow Empty)
startModel =
{ board = emptyBoard
, turn = A
}
-- View
view : Model -> Element
view model =
flow right <| map viewColumn model.board
viewColumn column =
flow down <| map viewSlot column
viewSlot slot =
let pieceRadius = (pieceSize - 15) / 2
pieceColor piece =
case slot of
Empty -> white
Piece A -> blue
Piece B -> red
in collage pieceSize pieceSize
[ circle pieceRadius |> filled (pieceColor slot)]
|> color orange
-- Update
update : Int -> Model -> Model
update column model =
{ model |
board = List.indexedMap (updateColumn (model.turn, column)) model.board
, turn = nextPlayer model.turn
}
updateColumn : (Player, Int) -> Int -> Column -> Column
updateColumn (player, inColumn) index column =
if inColumn /= index then
column
else
player `dropIn` column
dropIn : Player -> Column -> Column
dropIn player column =
let (empty, nonEmpty) = List.partition ((==) Empty) column
filled =
case empty of
[] -> nonEmpty
_ -> Piece player :: nonEmpty
empties = repeat (maxRow - (length filled)) Empty
in empties `append` filled
nextPlayer : Player -> Player
nextPlayer turn =
case turn of
A -> B
B -> A
-- Signals
toColumnIndex : Int -> Int
toColumnIndex x =
(x // pieceSize) % maxColumn
dropPieceAt : Signal Int
dropPieceAt =
Signal.sampleOn Mouse.clicks Mouse.x
-- Main
main = Signal.map view <| Signal.foldp update startModel <| Signal.map toColumnIndex dropPieceAt