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