Add temporary patch for preset challenges
[vchess.git] / client / src / variants / Hamilton.js
1 import { ChessRules, Move, PiPo } from "@/base_rules";
2 import { randInt } from "@/utils/alea";
3
4 export class HamiltonRules extends ChessRules {
5
6 static get HasFlags() {
7 return false;
8 }
9
10 static get HasEnpassant() {
11 return false;
12 }
13
14 get showFirstTurn() {
15 return true;
16 }
17
18 static get HOLE() {
19 return "xx";
20 }
21
22 static board2fen(b) {
23 if (b[0] == 'x') return 'x';
24 return ChessRules.board2fen(b);
25 }
26
27 static fen2board(f) {
28 if (f == 'x') return V.HOLE;
29 return ChessRules.fen2board(f);
30 }
31
32 getPpath(b) {
33 if (b[0] == 'x') return "Hamilton/hole";
34 return b;
35 }
36
37 static get PIECES() {
38 return [ChessRules.KNIGHT];
39 }
40
41 static IsGoodPosition(position) {
42 if (position.length == 0) return false;
43 const rows = position.split("/");
44 if (rows.length != V.size.x) return false;
45 for (let row of rows) {
46 let sumElts = 0;
47 for (let i = 0; i < row.length; i++) {
48 if (['x'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
49 else {
50 const num = parseInt(row[i], 10);
51 if (isNaN(num)) return false;
52 sumElts += num;
53 }
54 }
55 if (sumElts != V.size.y) return false;
56 }
57 return true;
58 }
59
60 static GenRandInitFen() {
61 return "8/8/8/8/8/8/8/8 w 0";
62 }
63
64 canIplay(side, [x, y]) {
65 return side == this.turn;
66 }
67
68 hoverHighlight() {
69 return this.movesCount == 0;
70 }
71
72 // Initiate the game by choosing a square for the knight:
73 doClick(square) {
74 if (this.movesCount > 0) return null;
75 return new Move({
76 appear: [
77 new PiPo({ x: square[0], y: square[1], c: 'w', p: V.KNIGHT })
78 ],
79 vanish: [],
80 start: { x: -1, y: -1 }
81 });
82 }
83
84 getAllPotentialMoves() {
85 if (this.movesCount == 0) {
86 return [...Array(64).keys()].map(k => {
87 const i = k % 8;
88 const j = (k - i) / 8;
89 return this.doClick([i, j]);
90 });
91 }
92 for (let i=0; i<8; i++) {
93 for (let j=0; j<8; j++) {
94 if (!([V.EMPTY, V.HOLE].includes(this.board[i][j])))
95 return this.getPotentialKnightMoves([i, j]);
96 }
97 }
98 return [];
99 }
100
101 getPotentialKnightMoves([x, y]) {
102 return (
103 V.steps[V.KNIGHT].filter(
104 s => {
105 const [i, j] = [x + s[0], y + s[1]];
106 return (V.OnBoard(i, j) && this.board[i][j] != V.HOLE);
107 }
108 ).map(s => {
109 return this.getBasicMove([x, y], [x + s[0], y + s[1]]);
110 })
111 );
112 }
113
114 atLeastOneMove() {
115 if (this.movesCount == 0) return true;
116 for (let i=0; i<8; i++) {
117 for (let j=0; j<8; j++) {
118 if (!([V.EMPTY, V.HOLE].includes(this.board[i][j])))
119 return this.getPotentialKnightMoves([i, j]).length > 0;
120 }
121 }
122 return false;
123 }
124
125 filterValid(moves) {
126 return moves;
127 }
128
129 static PlayOnBoard(board, move) {
130 if (move.vanish.length > 0)
131 board[move.vanish[0].x][move.vanish[0].y] = V.HOLE;
132 for (let psq of move.appear) board[psq.x][psq.y] = psq.c + psq.p;
133 }
134
135 postPlay() {}
136 postUndo() {}
137
138 getCheckSquares() {
139 return [];
140 }
141
142 getCurrentScore() {
143 if (this.atLeastOneMove()) return "*";
144 // No valid move: I lose
145 return this.turn == "w" ? "0-1" : "1-0";
146 }
147
148 getComputerMove() {
149 const moves = this.getAllValidMoves();
150 // Just a random mover for now...
151 return moves[randInt(moves.length)];
152 }
153
154 getNotation(move) {
155 if (move.vanish.length > 0) return super.getNotation(move);
156 // First game move:
157 return "N@" + V.CoordsToSquare(move.end);
158 }
159
160 };