-
Notifications
You must be signed in to change notification settings - Fork 0
/
Board.elm
157 lines (124 loc) · 3.61 KB
/
Board.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
module Board exposing (Board, Plays, Position, initialBoard, MoveResult(..), move, winPlay, drawableBoard)
import Player exposing (..)
import Dict exposing (Dict)
type alias Board =
{ dimensions : ( Int, Int )
, plays : Plays
}
type alias Plays =
Dict Position Player
type alias Position =
( Int, Int )
initialBoard : Board
initialBoard =
{ dimensions = ( 7, 7 )
, plays = Dict.empty
}
type MoveResult
= Ok Board Position
| OutOfBoardError
move : Board -> Int -> Player -> MoveResult
move board column player =
let
position =
nextPositionForColumn board column
in
case positionInBoard board position of
True ->
Ok { board | plays = Dict.insert position player board.plays } position
False ->
OutOfBoardError
winPlay : Board -> ( Position, Player ) -> Bool
winPlay board ( position, player ) =
let
results =
linesToCheck position
|> List.map
(\line ->
line
|> List.map (\p -> getPosition board.plays p)
|> List.map
(\pp ->
if pp == Just player then
1
else
0
)
|> checkLine
)
in
results |> List.foldr (||) False
-- private API
drawableBoard : Board -> List (List (Maybe Player))
drawableBoard board =
let
( columns, rows ) =
board.dimensions
in
List.range 1 columns
|> List.map
(\c ->
List.range 1 rows
|> List.reverse
|> List.map
(\y ->
getPosition board.plays ( c, y )
)
)
checkLine : List Int -> Bool
checkLine line =
let
continuousNum =
line
|> List.foldl
(\y x ->
if x == 4 then
4
else
x * y + y
)
0
in
continuousNum == 4
linesToCheck : Position -> List (List Position)
linesToCheck ( x, y ) =
let
directions =
[ ( 0, 1 ) -- |
, ( 1, 0 ) -- -
, ( 1, 1 ) -- /
, ( 1, -1 ) -- \
]
in
directions
|> List.map
(\( a, b ) ->
List.range -3 3
|> List.map
(\mult ->
( a * mult + x, b * mult + y )
)
)
getPosition : Plays -> Position -> Maybe Player
getPosition plays position =
Dict.get position plays
positionInBoard : Board -> Position -> Bool
positionInBoard board position =
let
( x, y ) =
board.dimensions
( a, b ) =
position
in
List.member a (List.range 1 x) && List.member b (List.range 1 y)
nextPositionForColumn : Board -> Int -> Position
nextPositionForColumn board column =
let
nextPosition ( a, b ) =
case getPosition board.plays ( a, b ) of
Nothing ->
( a, b )
_ ->
nextPosition ( a, b + 1 )
in
nextPosition ( column, 1 )