Commit | Line | Data |
---|---|---|
3de62e0a BA |
1 | import { ChessRules } from "@/base_rules"; |
2 | ||
3 | export class Knightmate2Rules extends ChessRules { | |
4 | ||
5 | static get HasFlags() { | |
6 | return false; | |
7 | } | |
8 | ||
9 | static get COMMONER() { | |
10 | return "c"; | |
11 | } | |
12 | ||
13 | static get PIECES() { | |
14 | return ChessRules.PIECES.concat([V.COMMONER]); | |
15 | } | |
16 | ||
17 | getPpath(b) { | |
18 | return ([V.KING, V.COMMONER].includes(b[1]) ? "Knightmate/" : "") + b; | |
19 | } | |
20 | ||
21 | static IsGoodPosition(position) { | |
22 | if (position.length == 0) return false; | |
23 | const rows = position.split("/"); | |
24 | if (rows.length != V.size.x) return false; | |
25 | let kings = { "k": 0, "K": 0 }; | |
26 | for (let row of rows) { | |
27 | let sumElts = 0; | |
28 | for (let i = 0; i < row.length; i++) { | |
29 | if (['K','k'].includes(row[i])) kings[row[i]]++; | |
30 | if (V.PIECES.includes(row[i].toLowerCase())) sumElts++; | |
31 | else { | |
32 | const num = parseInt(row[i], 10); | |
33 | if (isNaN(num) || num <= 0) return false; | |
34 | sumElts += num; | |
35 | } | |
36 | } | |
37 | if (sumElts != V.size.y) return false; | |
38 | } | |
39 | // 1 or 2 kings should be on board. | |
40 | if (Object.values(kings).some(k => ![1, 2].includes(k))) return false; | |
41 | return true; | |
42 | } | |
43 | ||
44 | scanKings() {} | |
45 | ||
46 | static GenRandInitFen(randomness) { | |
47 | return ( | |
48 | ChessRules.GenRandInitFen(randomness) | |
49 | .replace(/k/g, 'c').replace(/K/g, 'C') | |
50 | .replace(/n/g, 'k').replace(/N/g, 'K') | |
51 | ); | |
52 | } | |
53 | ||
54 | getPotentialMovesFrom([x, y]) { | |
55 | switch (this.getPiece(x, y)) { | |
56 | case V.COMMONER: | |
57 | return this.getPotentialCommonerMoves([x, y]); | |
58 | default: | |
59 | return super.getPotentialMovesFrom([x, y]); | |
60 | } | |
61 | } | |
62 | ||
63 | getPotentialCommonerMoves(sq) { | |
64 | return this.getSlideNJumpMoves( | |
65 | sq, | |
66 | V.steps[V.ROOK].concat(V.steps[V.BISHOP]), | |
67 | "oneStep" | |
68 | ); | |
69 | } | |
70 | ||
71 | getPotentialKingMoves(sq) { | |
72 | return super.getPotentialKnightMoves(sq); | |
73 | } | |
74 | ||
75 | isAttacked(sq, color) { | |
76 | return ( | |
77 | this.isAttackedByCommoner(sq, color) || | |
78 | this.isAttackedByPawn(sq, color) || | |
79 | this.isAttackedByRook(sq, color) || | |
80 | this.isAttackedByBishop(sq, color) || | |
81 | this.isAttackedByQueen(sq, color) || | |
82 | this.isAttackedByKing(sq, color) | |
83 | ); | |
84 | } | |
85 | ||
86 | isAttackedByKing(sq, color) { | |
87 | return this.isAttackedBySlideNJump( | |
88 | sq, | |
89 | color, | |
90 | V.KING, | |
91 | V.steps[V.KNIGHT], | |
92 | "oneStep" | |
93 | ); | |
94 | } | |
95 | ||
96 | isAttackedByCommoner(sq, color) { | |
97 | return this.isAttackedBySlideNJump( | |
98 | sq, | |
99 | color, | |
100 | V.COMMONER, | |
101 | V.steps[V.ROOK].concat(V.steps[V.BISHOP]), | |
102 | "oneStep" | |
103 | ); | |
104 | } | |
105 | ||
106 | postPlay() {} | |
107 | postUndo() {} | |
108 | ||
109 | // NOTE: 4 next functions (almost) copy-paste from Spartan Chess | |
110 | getKingsPos(color) { | |
111 | let kings = []; | |
112 | for (let i=0; i<8; i++) { | |
113 | for (let j=0; j<8; j++) { | |
114 | if ( | |
115 | this.board[i][j] != V.EMPTY && | |
116 | this.getColor(i, j) == color && | |
117 | this.getPiece(i, j) == V.KING | |
118 | ) { | |
119 | kings.push({ x: i, y: j }); | |
120 | } | |
121 | } | |
122 | } | |
123 | return kings; | |
124 | } | |
125 | ||
126 | getCheckSquares() { | |
127 | const color = this.turn; | |
128 | const oppCol = V.GetOppCol(color); | |
129 | const kings = this.getKingsPos(color); | |
130 | let res = []; | |
131 | for (let i of [0, 1]) { | |
132 | if ( | |
133 | kings.length >= i+1 && | |
134 | super.isAttacked([kings[i].x, kings[i].y], oppCol) | |
135 | ) { | |
136 | res.push([kings[i].x, kings[i].y]); | |
137 | } | |
138 | } | |
139 | return res; | |
140 | } | |
141 | ||
142 | filterValid(moves) { | |
143 | if (moves.length == 0) return []; | |
144 | const color = moves[0].vanish[0].c; | |
145 | const oppCol = V.GetOppCol(color); | |
146 | // Check if both kings under attack. | |
147 | // If yes, moves must remove at least one attack. | |
148 | const kings = this.getKingsPos(color); | |
149 | return moves.filter(m => { | |
150 | this.play(m); | |
151 | let attacks = 0; | |
152 | for (let k of kings) { | |
153 | const curKingPos = | |
154 | this.board[k.x][k.y] == V.EMPTY | |
155 | ? [m.appear[0].x, m.appear[0].y] //king moved | |
156 | : [k.x, k.y] | |
157 | if (super.isAttacked(curKingPos, oppCol)) attacks++; | |
158 | else break; //no need to check further | |
159 | } | |
160 | this.undo(m); | |
161 | return ( | |
162 | (kings.length == 2 && attacks <= 1) || | |
163 | (kings.length == 1 && attacks == 0) | |
164 | ); | |
165 | }); | |
166 | } | |
167 | ||
168 | getCurrentScore() { | |
169 | if (super.atLeastOneMove()) return "*"; | |
170 | // Count kings on board | |
171 | const color = this.turn; | |
172 | const oppCol = V.GetOppCol(color); | |
173 | const kings = this.getKingsPos(color); | |
174 | if ( | |
175 | super.isAttacked([kings[0].x, kings[0].y], oppCol) || | |
176 | (kings.length == 2 && super.isAttacked([kings[1].x, kings[1].y], oppCol)) | |
177 | ) { | |
178 | return (color == 'w' ? "0-1" : "1-0"); | |
179 | } | |
180 | return "1/2"; //stalemate | |
181 | } | |
182 | ||
183 | static get VALUES() { | |
184 | return { | |
185 | p: 1, | |
186 | r: 5, | |
187 | c: 5, //the commoner is valuable | |
188 | b: 3, | |
189 | q: 9, | |
190 | k: 1000 | |
191 | }; | |
192 | } | |
193 | ||
194 | }; |