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