-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathZenix.hs
199 lines (156 loc) · 6.39 KB
/
Zenix.hs
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
{-{ http://en2.wikipedia.org/wiki/Zenix_(game) }-}
-----------
-- Zenix --
-----------
module Zenix (Zenix, zenix) where
import Game
import Data.Array
import Graphics.UI.WX hiding (border, point)
import Graphics.UI.WXCore hiding (point)
import Tools
data Zenix = Zenix (Array (Int, Int) (Maybe Player)) deriving (Eq, Show)
type ZenixMove = (Int, Int)
zenix :: Zenix
zenix = undefined
instance Game Zenix where
name _ = "zenix"
standard _ = Properties { players = 2, boardsize = 8, human = [True, False, False] }
possible _ = PropertyRange { playersrange = [2, 3], boardsizerange = [4 .. 12] }
new pr = let bsz = boardsize pr
in Zenix $ array ((0, 0), (bsz - 1, bsz - 1)) [((x, y), Nothing) | x <- [0 .. bsz - 1], y <- [0 .. bsz - 1]]
moves pr p (Zenix st) = map (move pr) (allMoves pr p st)
showmove pr p (Zenix s) i = case allMoves pr p s !! i
of (x, y) -> ['a' ..] !! x : show (1 + y)
value pr p (Zenix st)
| null $ allMoves pr p st = let winners = map fst $ filter (\(_i, c) -> c == maximum chains) $ zip [0 ..] chains
in foldr ($) (replicate (players pr) (-1)) $ map (|> 1) winners
| otherwise = map myvalue [0 .. players pr - 1]
where
bsz = boardsize pr
chains :: [Int]
chains = map (\p' -> scan p' bsz []) [0 .. players pr - 1]
myvalue :: Player -> Float
myvalue p' = let t = fromInteger . toInteger $ (players pr) * (chains !! p') - sum chains
n = fromInteger . toInteger $ 2 * bsz
in t / n
scan :: Player -> Int -> [Int] -> Int
scan p' y _ | y >= bsz = scan p' (bsz - 1) [0 .. bsz]
scan _p y [] = bsz - y
scan p' y xs = scan p' (y - 1) $ filter good [0 .. y]
where
good :: Int -> Bool
good x = st ! (x, y) == Just p'
&& (x `elem` xs || (x + 1) `elem` xs)
board p pr vart _ia move' = do
marble <- bitmapCreateLoad "images\\marble.bmp" wxBITMAP_TYPE_ANY
varg <- varCreate $ grate rectZero 0 (0, 0) sizeZero
let
onpaint :: DC () -> Rect -> IO ()
onpaint dc r = do
t <- varGet vart
let Zenix st = state t
bsz = boardsize pr
b <- border dc (bsz, bsz)
let g = grate r b (2 * bsz, bsz) (Size 4 7)
radius = rectWidth (field g (0, 0))
{-
lin' :: Rect -> Rect -> Color -> IO ()
lin' (Rect x1 y1 w1 h1) (Rect x2 y2 w2 h2) c = do
line dc (pt (x1 + w1 `div` 2) (y1 + h1)) (pt (x2 + w2 `div` 2) (y2 + h2)) [penWidth := 4, penColor := c]
lin :: (Int, Int) -> (Int, Int) -> Color -> IO ()
lin p q = lin' (field g $ tograte bsz p) (field g $ tograte bsz q)
-}
varSet varg g
tileBitmap dc r marble
--{ drawGrate dc g [penColor := yellow]
for 0 (bsz - 1) (\i -> do
drawTextRect dc [['A' ..] !! i] $ edge g (2 * i, bsz)
drawTextRect dc (show (i + 1)) $ field g (i - 1, bsz - i - 1)
)
for 0 (bsz - 1) (\i -> for 0 (bsz - 1) (\j ->
when (j - i >= 0) $ drawPiece dc (field g $ tograte bsz (i, j)) radius (st ! (i, j))
))
onclick :: Point -> IO ()
onclick point = do
t <- varGet vart
g <- varGet varg
let Zenix st = state t
bsz = boardsize pr
n = fromgrate bsz $ locate g point
case lookup n $ zip (allMoves pr (player t) st) [0..] of
Nothing -> return ()
Just i -> move' i
set p [ on click := onclick
, on paint := onpaint
, on resize ::= repaint
]
return ()
drawPiece :: DC () -> Rect -> Int -> Maybe Player -> IO ()
drawPiece dc (Rect x y _w h) r mp = do
case mp of Just 0 -> circle dc (pt x (y + h `div` 2)) r [brushKind := BrushSolid, brushColor := blue ]
Just 1 -> circle dc (pt x (y + h `div` 2)) r [brushKind := BrushSolid, brushColor := red ]
Just 2 -> circle dc (pt x (y + h `div` 2)) r [brushKind := BrushSolid, brushColor := green]
Nothing -> circle dc (pt x (y + h `div` 2)) r [brushKind := BrushTransparent]
_ -> error "drawPiece: Unexpected value"
{-
(+-) :: Num a => (a, a) -> (a, a) -> (a, a)
(a, b) +- (c, d) = (a + c, b + d)
-}
allMoves :: Properties -> Player -> Array (Int, Int) (Maybe Player) -> [ZenixMove]
allMoves pr _p st
| otherwise = filter free $ indices st
where
bsz = boardsize pr
free :: ZenixMove -> Bool
free (x, y) = y - x >= 0
&& st ! (x, y) == Nothing
&& (y == bsz - 1 || (st ! (x, y + 1) /= Nothing && st ! (x + 1, y + 1) /= Nothing))
move :: Properties -> ZenixMove -> (Player, Zenix) -> (Player, Zenix)
move pr place (p, Zenix s) = ( (p + 1) `mod` players pr
, Zenix $ s // [(place, Just p)]
)
{-{
win :: Array (Int, Int) (Maybe Player) -> Int -> Player -> Bool
win st bsz 0 = any ((== bsz - 1) . snd) $ floodfill st 0 (zip [0 .. bsz - 1] [-1, -1 ..])
win st bsz 1 = any ((== bsz - 1) . fst) $ floodfill st 1 (zip [-1, -1 ..] [0 .. bsz - 1])
floodfill :: Array (Int, Int) (Maybe Player) -> Player -> [(Int, Int)] -> [(Int, Int)]
floodfill st p togo = floodfill_ p togo []
where
floodfill_ :: Player -> [(Int, Int)] -> [(Int, Int)] -> [(Int, Int)]
floodfill_ p [] known = known
floodfill_ p (f : togo) known = let new = filter (not . flip elem known) $ map (f +-) steps
good = filter (\f -> st ! f == Just p) $ filter (inRange (bounds st)) new
in floodfill_ p (togo ++ good) (known ++ good)
steps :: [(Int, Int)]
steps = [(1, 1), (1, 0), (0, -1), (-1, -1), (-1, 0), (0, 1)]
jumps :: [((Int, Int), [(Int, Int)])]
jumps = [ (( 2, 1), [( 1, 0), ( 1, 1)])
, (( 1, 2), [( 0, 1), ( 1, 1)])
, ((-1, 1), [( 0, 1), (-1, 0)])
, ((-2, -1), [(-1, 0), (-1, -1)])
, ((-1, -2), [( 0, -1), (-1, -1)])
, (( 1, -1), [( 1, 0), ( 0, -1)])
]
}-}
tograte :: Int -> (Int, Int) -> (Int, Int)
tograte bsz (i, j) = (bsz + 2 * i - j, j)
fromgrate :: Int -> (Int, Int) -> (Int, Int)
fromgrate bsz (i, j) = ((i + j - bsz + 1) `div` 2, j)
{-
i = s - 1 + x - y
j = 2s - 2 - x - y
i + j = 3s - 3 - 2y
2y = 3s - 3 - i - j
y = (...) / 2
i - j = -s + 1 + 2x
2x = s - 1 + i - j
-}
{- the zenixboard internally look like this:
0 *
1 * *
2 * * *
3 * * * *
4 * * * * *
5 * * * * * *
0 1 2 3 4 5
-}