Commit | Line | Data |
---|---|---|
fbc3e6f9 BA |
1 | import { ChessRules, Move, PiPo } from "@/base_rules"; |
2 | ||
278a28a1 | 3 | export class Stealthbomb1Rules extends ChessRules { |
fbc3e6f9 BA |
4 | |
5 | static get CanAnalyze() { | |
6 | return false; | |
7 | } | |
8 | ||
9 | static get SomeHiddenMoves() { | |
10 | return true; | |
11 | } | |
12 | ||
13 | static get BOMB_DECODE() { | |
14 | return { | |
15 | s: "p", | |
16 | t: "q", | |
17 | u: "r", | |
18 | c: "b", | |
19 | o: "n", | |
20 | l: "k" | |
21 | }; | |
22 | } | |
23 | static get BOMB_CODE() { | |
24 | return { | |
25 | p: "s", | |
26 | q: "t", | |
27 | r: "u", | |
28 | b: "c", | |
29 | n: "o", | |
30 | k: "l" | |
31 | }; | |
32 | } | |
33 | ||
34 | static get PIECES() { | |
35 | return ChessRules.PIECES.concat(Object.keys(V.BOMB_DECODE)); | |
36 | } | |
37 | ||
38 | getPiece(i, j) { | |
39 | const piece = this.board[i][j].charAt(1); | |
40 | if ( | |
41 | ChessRules.PIECES.includes(piece) || | |
42 | // 'side' is used to determine what I see: normal or "loaded" piece? | |
43 | this.getColor(i, j) == this.side | |
44 | ) { | |
45 | return piece; | |
46 | } | |
47 | // Loaded piece, but no right to view it | |
48 | return V.BOMB_DECODE[piece]; | |
49 | } | |
50 | ||
51 | getPpath(b, color, score) { | |
52 | if (Object.keys(V.BOMB_DECODE).includes(b[1])) { | |
53 | // Supposed to be hidden. | |
54 | if (score == "*" && (!color || color != b[0])) | |
55 | return b[0] + V.BOMB_DECODE[b[1]]; | |
56 | return "Stealthbomb/" + b; | |
57 | } | |
58 | return b; | |
59 | } | |
60 | ||
61 | hoverHighlight([x, y]) { | |
62 | const c = this.turn; | |
63 | return ( | |
64 | this.movesCount <= 1 && | |
65 | ( | |
66 | (c == 'w' && x >= 6) || | |
67 | (c == 'b' && x <= 1) | |
68 | ) | |
69 | ); | |
70 | } | |
71 | ||
72 | onlyClick([x, y]) { | |
73 | return ( | |
74 | this.movesCount <= 1 || | |
75 | // TODO: next line theoretically shouldn't be required... | |
76 | (this.movesCount == 2 && this.getColor(x, y) != this.turn) | |
77 | ); | |
78 | } | |
79 | ||
80 | // Initiate the game by choosing a square for the bomb: | |
81 | doClick(square) { | |
82 | const c = this.turn; | |
83 | if ( | |
84 | this.movesCount >= 2 || | |
85 | ( | |
86 | (c == 'w' && square[0] < 6) || | |
278a28a1 | 87 | (c == 'b' && square[0] > 1) |
fbc3e6f9 BA |
88 | ) |
89 | ) { | |
90 | return null; | |
91 | } | |
92 | const [x, y] = square; | |
93 | const piece = super.getPiece(x, y); | |
94 | return new Move({ | |
95 | appear: [ new PiPo({ x: x, y: y, c: c, p: V.BOMB_CODE[piece] }) ], | |
96 | vanish: [ new PiPo({ x: x, y: y, c: c, p: piece }) ], | |
278a28a1 BA |
97 | start: { x: -1, y: -1 }, |
98 | end: { x: x, y: y, noHighlight: true } | |
fbc3e6f9 BA |
99 | }); |
100 | } | |
101 | ||
102 | getPotentialMovesFrom([x, y]) { | |
103 | if (this.movesCount <= 1) { | |
104 | const setup = this.doClick([x, y]); | |
105 | return (!setup ? [] : [setup]); | |
106 | } | |
107 | let moves = super.getPotentialMovesFrom([x, y]); | |
108 | const c = this.turn; | |
109 | // Add bomb explosion | |
110 | if (Object.keys(V.BOMB_DECODE).includes(this.board[x][y][1])) { | |
111 | let mv = new Move({ | |
112 | appear: [ ], | |
113 | vanish: [ new PiPo({ x: x, y: y, c: c, p: this.board[x][y][1] }) ], | |
114 | end: { x: this.kingPos[c][0], y: this.kingPos[c][1] } | |
115 | }); | |
116 | for (let s of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) { | |
117 | let [i, j] = [x + s[0], y + s[1]]; | |
118 | if (V.OnBoard(i, j) && this.board[i][j] != V.EMPTY) { | |
119 | mv.vanish.push( | |
120 | new PiPo({ | |
121 | x: i, | |
122 | y: j, | |
123 | c: this.getColor(i, j), | |
124 | p: this.board[i][j][1] | |
125 | }) | |
126 | ); | |
127 | } | |
128 | } | |
129 | moves.push(mv); | |
130 | } | |
131 | return moves; | |
132 | } | |
133 | ||
134 | // NOTE: a lot of copy-paste from Atomic from here. | |
135 | postPlay(move) { | |
136 | if (this.movesCount >= 3) { | |
137 | super.postPlay(move); | |
138 | if (move.appear.length == 0) { | |
139 | // Explosion | |
140 | const firstRank = { w: 7, b: 0 }; | |
141 | for (let c of ["w", "b"]) { | |
142 | // Did we explode king of color c ? | |
143 | if ( | |
144 | Math.abs(this.kingPos[c][0] - move.start.x) <= 1 && | |
145 | Math.abs(this.kingPos[c][1] - move.start.y) <= 1 | |
146 | ) { | |
147 | this.kingPos[c] = [-1, -1]; | |
148 | this.castleFlags[c] = [8, 8]; | |
149 | } | |
150 | else { | |
151 | // Now check if init rook(s) exploded | |
152 | if (Math.abs(move.start.x - firstRank[c]) <= 1) { | |
153 | if (Math.abs(move.start.y - this.castleFlags[c][0]) <= 1) | |
154 | this.castleFlags[c][0] = 8; | |
155 | if (Math.abs(move.start.y - this.castleFlags[c][1]) <= 1) | |
156 | this.castleFlags[c][1] = 8; | |
157 | } | |
158 | } | |
159 | } | |
160 | } | |
161 | } | |
162 | } | |
163 | ||
164 | postUndo(move) { | |
165 | if (this.movesCount >= 2) { | |
166 | super.postUndo(move); | |
167 | const c = this.turn; | |
168 | const oppCol = V.GetOppCol(c); | |
169 | if ([this.kingPos[c][0], this.kingPos[oppCol][0]].some(e => e < 0)) { | |
170 | // Last move exploded some king.. | |
171 | for (let psq of move.vanish) { | |
172 | if (psq.p == "k") | |
173 | this.kingPos[psq.c == c ? c : oppCol] = [psq.x, psq.y]; | |
174 | } | |
175 | } | |
176 | } | |
177 | } | |
178 | ||
179 | underCheck(color) { | |
180 | const oppCol = V.GetOppCol(color); | |
181 | let res = undefined; | |
182 | // If our king disappeared, move is not valid | |
183 | if (this.kingPos[color][0] < 0) res = true; | |
184 | // If opponent king disappeared, move is valid | |
185 | else if (this.kingPos[oppCol][0] < 0) res = false; | |
186 | // Otherwise, if we remain under check, move is not valid | |
187 | else res = this.isAttacked(this.kingPos[color], oppCol); | |
188 | return res; | |
189 | } | |
190 | ||
191 | getCheckSquares() { | |
192 | const color = this.turn; | |
193 | let res = []; | |
194 | if ( | |
195 | this.kingPos[color][0] >= 0 && //king might have exploded | |
196 | this.isAttacked(this.kingPos[color], V.GetOppCol(color)) | |
197 | ) { | |
198 | res = [JSON.parse(JSON.stringify(this.kingPos[color]))]; | |
199 | } | |
200 | return res; | |
201 | } | |
202 | ||
203 | getCurrentScore() { | |
204 | const color = this.turn; | |
205 | const kp = this.kingPos[color]; | |
206 | if (kp[0] < 0) | |
207 | // King disappeared | |
208 | return color == "w" ? "0-1" : "1-0"; | |
209 | if (this.atLeastOneMove()) return "*"; | |
210 | if (!this.isAttacked(kp, V.GetOppCol(color))) return "1/2"; | |
211 | return color == "w" ? "0-1" : "1-0"; //checkmate | |
212 | } | |
213 | ||
214 | getNotation(move) { | |
215 | if (this.movesCount <= 1) return "Bomb?"; | |
216 | const c = this.turn; | |
217 | if (move.end.x == this.kingPos[c][0] && move.end.y == this.kingPos[c][1]) | |
218 | return V.CoordsToSquare(move.start) + "~X"; | |
219 | if (Object.keys(V.BOMB_DECODE).includes(move.vanish[0].p)) { | |
220 | let cpMove = JSON.parse(JSON.stringify(move)); | |
221 | cpMove.vanish[0].p = V.BOMB_DECODE[move.vanish[0].p]; | |
222 | if (Object.keys(V.BOMB_DECODE).includes(move.appear[0].p)) | |
223 | cpMove.appear[0].p = V.BOMB_DECODE[move.appear[0].p]; | |
224 | return super.getNotation(cpMove); | |
225 | } | |
226 | return super.getNotation(move); | |
227 | } | |
228 | ||
229 | }; |