Several small improvements + integrate options + first working draft of Cwda
[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 Options() {
7 return null;
8 }
9
10 static get HasFlags() {
11 return false;
12 }
13
14 static get HasEnpassant() {
15 return false;
16 }
17
18 get showFirstTurn() {
19 return true;
20 }
21
22 static get HOLE() {
23 return "xx";
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 hoverHighlight() {
73 return this.movesCount == 0;
74 }
75
76 // Initiate the game by choosing a square for the knight:
77 doClick(square) {
78 if (this.movesCount > 0) return null;
79 return new Move({
80 appear: [
81 new PiPo({ x: square[0], y: square[1], c: 'w', p: V.KNIGHT })
82 ],
83 vanish: [],
84 start: { x: -1, y: -1 }
85 });
86 }
87
88 getAllPotentialMoves() {
89 if (this.movesCount == 0) {
90 return [...Array(64).keys()].map(k => {
91 const i = k % 8;
92 const j = (k - i) / 8;
93 return this.doClick([i, j]);
94 });
95 }
96 for (let i=0; i<8; i++) {
97 for (let j=0; j<8; j++) {
98 if (!([V.EMPTY, V.HOLE].includes(this.board[i][j])))
99 return this.getPotentialKnightMoves([i, j]);
100 }
101 }
102 return [];
103 }
104
105 getPotentialKnightMoves([x, y]) {
106 return (
107 V.steps[V.KNIGHT].filter(
108 s => {
109 const [i, j] = [x + s[0], y + s[1]];
110 return (V.OnBoard(i, j) && this.board[i][j] != V.HOLE);
111 }
112 ).map(s => {
113 return this.getBasicMove([x, y], [x + s[0], y + s[1]]);
114 })
115 );
116 }
117
118 atLeastOneMove() {
119 if (this.movesCount == 0) return true;
120 for (let i=0; i<8; i++) {
121 for (let j=0; j<8; j++) {
122 if (!([V.EMPTY, V.HOLE].includes(this.board[i][j])))
123 return this.getPotentialKnightMoves([i, j]).length > 0;
124 }
125 }
126 return false;
127 }
128
129 filterValid(moves) {
130 return moves;
131 }
132
133 static PlayOnBoard(board, move) {
134 if (move.vanish.length > 0)
135 board[move.vanish[0].x][move.vanish[0].y] = V.HOLE;
136 for (let psq of move.appear) board[psq.x][psq.y] = psq.c + psq.p;
137 }
138
139 postPlay() {}
140 postUndo() {}
141
142 getCheckSquares() {
143 return [];
144 }
145
146 getCurrentScore() {
147 if (this.atLeastOneMove()) return "*";
148 // No valid move: I lose
149 return this.turn == "w" ? "0-1" : "1-0";
150 }
151
152 getComputerMove() {
153 const moves = this.getAllValidMoves();
154 // Just a random mover for now...
155 return moves[randInt(moves.length)];
156 }
157
158 getNotation(move) {
159 if (move.vanish.length > 0) return super.getNotation(move);
160 // First game move:
161 return "N@" + V.CoordsToSquare(move.end);
162 }
163
164 };