Add Yote
[vchess.git] / client / src / variants / Konane.js
1 import { ChessRules, Move, PiPo } from "@/base_rules";
2
3 export class KonaneRules extends ChessRules {
4
5 static get HasFlags() {
6 return false;
7 }
8
9 static get HasEnpassant() {
10 return false;
11 }
12
13 static get ReverseColors() {
14 return true;
15 }
16
17 static get PIECES() {
18 return V.PAWN;
19 }
20
21 getPiece() {
22 return V.PAWN;
23 }
24
25 getPpath(b) {
26 return "Konane/" + b;
27 }
28
29 static IsGoodPosition(position) {
30 if (position.length == 0) return false;
31 const rows = position.split("/");
32 if (rows.length != V.size.x) return false;
33 for (let row of rows) {
34 let sumElts = 0;
35 for (let i = 0; i < row.length; i++) {
36 if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
37 else {
38 const num = parseInt(row[i], 10);
39 if (isNaN(num) || num <= 0) return false;
40 sumElts += num;
41 }
42 }
43 if (sumElts != V.size.y) return false;
44 }
45 return true;
46 }
47
48 static GenRandInitFen() {
49 return (
50 "PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/" +
51 "PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP w 0"
52 );
53 }
54
55 setOtherVariables(fen) {
56 this.captures = []; //reinit for each move
57 }
58
59 hoverHighlight(x, y) {
60 if (this.movesCount >= 2) return false;
61 const c = this.turn;
62 if (c == 'w') return (x == y && [0, 3, 4, 7].includes(x));
63 // "Black": search for empty square and allow nearby
64 for (let i of [0, 3, 4, 7]) {
65 if (this.board[i][i] == V.EMPTY)
66 return (Math.abs(x - i) + Math.abs(y - i) == 1)
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
78 doClick([x, y]) {
79 if (this.movesCount >= 2) return null;
80 const color = this.turn;
81 if (color == 'w') {
82 if (x != y || ![0, 3, 4, 7].includes(x)) return null;
83 return new Move({
84 appear: [],
85 vanish: [ new PiPo({ x: x, y: y, c: color, p: V.PAWN }) ],
86 end: { x: x, y: y }
87 });
88 }
89 // "Black": search for empty square and allow nearby
90 for (let i of [0, 3, 4, 7]) {
91 if (this.board[i][i] == V.EMPTY) {
92 if (Math.abs(x - i) + Math.abs(y - i) != 1) return null;
93 return new Move({
94 appear: [],
95 vanish: [ new PiPo({ x: x, y: y, c: color, p: V.PAWN }) ],
96 end: { x: x, y: y }
97 });
98 }
99 }
100 }
101
102 getPotentialMovesFrom([x, y]) {
103 if (this.movesCount <= 1) {
104 const mv = this.doClick([x, y]);
105 return (!!mv ? [mv] : []);
106 }
107 const L = this.captures.length;
108 const c = (L > 0 ? this.captures[L-1] : null);
109 const color = this.turn;
110 const oppCol = V.GetOppCol(color);
111 let step = null;
112 let moves = [];
113 if (!!c) {
114 if (x != c.end.x || y != c.end.y) return [];
115 step = [(c.end.x - c.start.x) / 2, (c.end.y - c.start.y) / 2];
116 // Add move to adjacent empty square to mark "end of capture"
117 moves.push(
118 new Move({
119 appear: [],
120 vanish: [],
121 start: { x: x, y: y },
122 end: { x: x - step[0], y: y - step[1] }
123 })
124 );
125 }
126 // Examine captures from here
127 for (let s of (!!step ? [step] : V.steps[V.ROOK])) {
128 let [i, j] = [x + 2*s[0], y + 2*s[1]];
129 if (
130 !!c || //avoid redundant checks if continuation
131 (
132 V.OnBoard(i, j) &&
133 this.board[i][j] == V.EMPTY &&
134 this.board[i - s[0]][j - s[1]] != V.EMPTY &&
135 this.getColor(i - s[0], j - s[1]) == oppCol
136 )
137 ) {
138 let mv = new Move({
139 appear: [
140 new PiPo({ x: i, y: j, c: color, p: V.PAWN })
141 ],
142 vanish: [
143 new PiPo({ x: x, y: y, c: color, p: V.PAWN }),
144 new PiPo({ x: i - s[0], y: j - s[1], c: oppCol, p: V.PAWN })
145 ]
146 });
147 // Is there another capture possible then?
148 [i, j] = [i + 2*s[0], j + 2*s[1]];
149 if (
150 V.OnBoard(i, j) &&
151 this.board[i][j] == V.EMPTY &&
152 this.board[i - s[0]][j - s[1]] != V.EMPTY &&
153 this.getColor(i - s[0], j - s[1]) == oppCol
154 ) {
155 mv.end.moreCapture = true;
156 }
157 moves.push(mv);
158 }
159 }
160 return moves;
161 }
162
163 filterValid(moves) {
164 return moves;
165 }
166
167 getCheckSquares() {
168 return [];
169 }
170
171 getCurrentScore() {
172 if (this.atLeastOneMove()) return "*";
173 return (this.turn == "w" ? "0-1" : "1-0");
174 }
175
176 play(move) {
177 V.PlayOnBoard(this.board, move);
178 if (!move.end.moreCapture) {
179 this.turn = V.GetOppCol(this.turn);
180 this.movesCount++;
181 this.captures = [];
182 }
183 else {
184 this.captures.push(
185 {
186 start: move.start,
187 end: { x: move.end.x, y: move.end.y }
188 }
189 );
190 }
191 }
192
193 undo(move) {
194 V.UndoOnBoard(this.board, move);
195 if (!move.end.moreCapture) {
196 this.turn = V.GetOppCol(this.turn);
197 this.movesCount--;
198 }
199 else this.captures.pop();
200 }
201
202 static get SEARCH_DEPTH() {
203 return 4;
204 }
205
206 getNotation(move) {
207 if (this.movesCount <= 1) return V.CoordsToSquare(move.start) + "X";
208 if (move.vanish.length == 0) return "end";
209 return V.CoordsToSquare(move.start) + "x" + V.CoordsToSquare(move.end);
210 }
211
212 };