Commit | Line | Data |
---|---|---|
1af36beb BA |
1 | class MagneticRules |
2 | { | |
3 | getEpSquare(move) | |
4 | { | |
5 | return undefined; //no en-passant | |
6 | } | |
7 | ||
8 | // Complete a move with magnetic actions | |
9 | applyMagneticLaws([x,y], move) | |
10 | { | |
11 | // TODO | |
12 | } | |
13 | ||
14 | getBasicMove([sx,sy], [ex,ey], tr) | |
15 | { | |
16 | var mv = new Move({ | |
17 | appear: [ | |
18 | new PiPo({ | |
19 | x: ex, | |
20 | y: ey, | |
21 | c: !!tr ? tr.c : this.getColor(sx,sy), | |
22 | p: !!tr ? tr.p : this.getPiece(sx,sy) | |
23 | }) | |
24 | ], | |
25 | vanish: [ | |
26 | new PiPo({ | |
27 | x: sx, | |
28 | y: sy, | |
29 | c: this.getColor(sx,sy), | |
30 | p: this.getPiece(sx,sy) | |
31 | }) | |
32 | ] | |
33 | }); | |
34 | ||
35 | if (this.board[ex][ey] != VariantRules.EMPTY) | |
36 | { | |
37 | mv.vanish.push( | |
38 | new PiPo({ | |
39 | x: ex, | |
40 | y: ey, | |
41 | c: this.getColor(ex,ey), | |
42 | p: this.getPiece(ex,ey) | |
43 | }) | |
44 | ); | |
45 | } | |
46 | this.applyMagneticLaws([ex,ey], mv); | |
47 | return mv; | |
48 | } | |
49 | ||
50 | getCastleMoves([x,y]) | |
51 | { | |
52 | const c = this.getColor(x,y); | |
53 | if (x != (c=="w" ? 7 : 0) || y != this.INIT_COL_KING[c]) | |
54 | return []; //x isn't first rank, or king has moved (shortcut) | |
55 | ||
56 | const V = VariantRules; | |
57 | ||
58 | // Castling ? | |
59 | const oppCol = this.getOppCol(c); | |
60 | let moves = []; | |
61 | let i = 0; | |
62 | const finalSquares = [ [2,3], [6,5] ]; //king, then rook | |
63 | castlingCheck: | |
64 | for (let castleSide=0; castleSide < 2; castleSide++) //large, then small | |
65 | { | |
66 | if (!this.flags[c][castleSide]) | |
67 | continue; | |
68 | // If this code is reached, rooks and king are on initial position | |
69 | ||
70 | // Nothing on the path of the king (and no checks; OK also if y==finalSquare)? | |
71 | let step = finalSquares[castleSide][0] < y ? -1 : 1; | |
72 | for (i=y; i!=finalSquares[castleSide][0]; i+=step) | |
73 | { | |
74 | if (this.isAttacked([x,i], oppCol) || (this.board[x][i] != V.EMPTY && | |
75 | // NOTE: next check is enough, because of chessboard constraints | |
76 | (this.getColor(x,i) != c || ![V.KING,V.ROOK].includes(this.getPiece(x,i))))) | |
77 | { | |
78 | continue castlingCheck; | |
79 | } | |
80 | } | |
81 | ||
82 | // Nothing on the path to the rook? | |
83 | step = castleSide == 0 ? -1 : 1; | |
84 | for (i = y + step; i != this.INIT_COL_ROOK[c][castleSide]; i += step) | |
85 | { | |
86 | if (this.board[x][i] != V.EMPTY) | |
87 | continue castlingCheck; | |
88 | } | |
89 | const rookPos = this.INIT_COL_ROOK[c][castleSide]; | |
90 | ||
91 | // Nothing on final squares, except maybe king and castling rook? | |
92 | for (i=0; i<2; i++) | |
93 | { | |
94 | if (this.board[x][finalSquares[castleSide][i]] != V.EMPTY && | |
95 | this.getPiece(x,finalSquares[castleSide][i]) != V.KING && | |
96 | finalSquares[castleSide][i] != rookPos) | |
97 | { | |
98 | continue castlingCheck; | |
99 | } | |
100 | } | |
101 | ||
102 | // If this code is reached, castle is valid | |
103 | let cmove = new Move({ | |
104 | appear: [ | |
105 | new PiPo({x:x,y:finalSquares[castleSide][0],p:V.KING,c:c}), | |
106 | new PiPo({x:x,y:finalSquares[castleSide][1],p:V.ROOK,c:c})], | |
107 | vanish: [ | |
108 | new PiPo({x:x,y:y,p:V.KING,c:c}), | |
109 | new PiPo({x:x,y:rookPos,p:V.ROOK,c:c})], | |
110 | end: Math.abs(y - rookPos) <= 2 | |
111 | ? {x:x, y:rookPos} | |
112 | : {x:x, y:y + 2 * (castleSide==0 ? -1 : 1)} | |
113 | }); | |
114 | this.applyMagneticLaws([x,finalSquares[castleSide][1]], cmove); | |
115 | moves.push(cmove); | |
116 | } | |
117 | ||
118 | return moves; | |
119 | } | |
120 | ||
121 | // TODO: verify this assertion | |
122 | // atLeastOneMove() | |
123 | // { | |
124 | // return true; //always at least one possible move | |
125 | // } | |
126 | ||
127 | underCheck(move) | |
128 | { | |
129 | return false; //there is no check | |
130 | } | |
131 | ||
132 | getCheckSquares(move) | |
133 | { | |
134 | const c = this.getOppCol(this.turn); //opponent | |
135 | const saveKingPos = this.kingPos[c]; //king might be taken | |
136 | this.play(move); | |
137 | // The only way to be "under check" is to have lost the king (thus game over) | |
138 | let res = this.kingPos[c][0] < 0; | |
139 | ? [ JSON.parse(JSON.stringify(saveKingPos)) ] | |
140 | : [ ]; | |
141 | this.undo(move); | |
142 | return res; | |
143 | } | |
144 | ||
145 | updateVariables(move) | |
146 | { | |
147 | super.updateVariables(move); | |
148 | const c = this.getColor(move.start.x,move.start.y); | |
149 | if (c != this.getColor(move.end.x,move.end.y) | |
150 | && this.board[move.end.x][move.end.y] != VariantRules.EMPTY | |
151 | && this.getPiece(move.end.x,move.end.y) == VariantRules.KING) | |
152 | { | |
153 | // We took opponent king ! | |
154 | const oppCol = this.getOppCol(c); | |
155 | this.kingPos[oppCol] = [-1,-1]; | |
156 | this.flags[oppCol] = [false,false]; | |
157 | } | |
158 | } | |
159 | ||
160 | unupdateVariables(move) | |
161 | { | |
162 | super.unupdateVariables(move); | |
163 | const c = this.getColor(move.start.x,move.start.y); | |
164 | const oppCol = this.getOppCol(c); | |
165 | if (this.kingPos[oppCol][0] < 0) | |
166 | { | |
167 | // Last move took opponent's king | |
168 | for (let psq of move.vanish) | |
169 | { | |
170 | if (psq.p == 'k') | |
171 | { | |
172 | this.kingPos[oppCol] = [psq.x, psq.y]; | |
173 | break; | |
174 | } | |
175 | } | |
176 | } | |
177 | } | |
178 | ||
179 | checkGameOver() | |
180 | { | |
181 | if (this.checkRepetition()) | |
182 | return "1/2"; | |
183 | ||
184 | const color = this.turn; | |
185 | // TODO: do we need "atLeastOneMove()"? | |
186 | if (this.atLeastOneMove() && this.kingPos[color][0] >= 0) | |
187 | return "*"; | |
188 | ||
189 | return this.checkGameEnd(); | |
190 | } | |
191 | ||
192 | checkGameEnd() | |
193 | { | |
194 | // No valid move: our king disappeared | |
195 | return this.turn == "w" ? "0-1" : "1-0"; | |
196 | } | |
197 | } |