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