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