Several small improvements + integrate options + first working draft of Cwda
[vchess.git] / client / src / variants / Grasshopper.js
1 import { ChessRules } from "@/base_rules";
2 import { ArrayFun } from "@/utils/array";
3 import { randInt } from "@/utils/alea";
4
5 export class GrasshopperRules extends ChessRules {
6
7 static get HasEnpassant() {
8 return false;
9 }
10
11 static get PawnSpecs() {
12 return Object.assign(
13 {},
14 ChessRules.PawnSpecs,
15 { promotions: ChessRules.PawnSpecs.promotions.concat([V.GRASSHOPPER]) }
16 );
17 }
18
19 static get GRASSHOPPER() {
20 return "g";
21 }
22
23 static get PIECES() {
24 return ChessRules.PIECES.concat([V.GRASSHOPPER]);
25 }
26
27 getPpath(b) {
28 return (b[1] == V.GRASSHOPPER ? "Grasshopper/" : "") + b;
29 }
30
31 getPotentialMovesFrom([x, y]) {
32 switch (this.getPiece(x, y)) {
33 case V.GRASSHOPPER:
34 return this.getPotentialGrasshopperMoves([x, y]);
35 default:
36 return super.getPotentialMovesFrom([x, y]);
37 }
38 }
39
40 getPotentialGrasshopperMoves([x, y]) {
41 let moves = [];
42 // Look in every direction until an obstacle (to jump) is met
43 for (const step of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) {
44 let i = x + step[0];
45 let j = y + step[1];
46 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
47 i += step[0];
48 j += step[1];
49 }
50 // Move is valid if the next square is empty or occupied by enemy
51 const nextSq = [i+step[0], j+step[1]];
52 if (V.OnBoard(nextSq[0], nextSq[1]) && this.canTake([x, y], nextSq))
53 moves.push(this.getBasicMove([x, y], nextSq));
54 }
55 return moves;
56 }
57
58 isAttacked(sq, color) {
59 return (
60 super.isAttacked(sq, color) ||
61 this.isAttackedByGrasshopper(sq, color)
62 );
63 }
64
65 isAttackedByGrasshopper([x, y], color) {
66 // Reversed process: is there an adjacent obstacle,
67 // and a grasshopper next in the same line?
68 for (const step of V.steps[V.ROOK].concat(V.steps[V.BISHOP])) {
69 const nextSq = [x+step[0], y+step[1]];
70 if (
71 V.OnBoard(nextSq[0], nextSq[1]) &&
72 this.board[nextSq[0]][nextSq[1]] != V.EMPTY
73 ) {
74 let i = nextSq[0] + step[0];
75 let j = nextSq[1] + step[1];
76 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
77 i += step[0];
78 j += step[1];
79 }
80 if (
81 V.OnBoard(i, j) &&
82 this.getPiece(i, j) == V.GRASSHOPPER &&
83 this.getColor(i, j) == color
84 ) {
85 return true;
86 }
87 }
88 }
89 return false;
90 }
91
92 static get VALUES() {
93 return Object.assign(
94 // TODO: grasshoppers power decline with less pieces on board...
95 { g: 2 },
96 ChessRules.VALUES
97 );
98 }
99
100 static get SEARCH_DEPTH() {
101 return 2;
102 }
103
104 static GenRandInitFen(options) {
105 return ChessRules.GenRandInitFen(options)
106 .slice(0, -2)
107 .replace(
108 "/pppppppp/8/8/8/8/PPPPPPPP/",
109 "/gggggggg/pppppppp/8/8/PPPPPPPP/GGGGGGGG/"
110 );
111 }
112
113 };