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