Fix Arena diag
[vchess.git] / client / src / variants / Cylinder.js
1 import { ChessRules, PiPo, Move } from "@/base_rules";
2 import { ArrayFun } from "@/utils/array";
3 import { randInt, shuffle } from "@/utils/alea";
4
5 export class CylinderRules extends ChessRules {
6
7 // Output basically x % 8 (circular board)
8 static ComputeY(y) {
9 let res = y % V.size.y;
10 if (res < 0)
11 res += V.size.y;
12 return res;
13 }
14
15 getSlideNJumpMoves([x, y], steps, oneStep) {
16 let moves = [];
17 // Don't add move twice when running on an infinite rank:
18 let infiniteSteps = {};
19 outerLoop: for (let step of steps) {
20 if (!!infiniteSteps[(-step[0]) + "." + (-step[1])]) continue;
21 let i = x + step[0];
22 let j = V.ComputeY(y + step[1]);
23 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
24 moves.push(this.getBasicMove([x, y], [i, j]));
25 if (oneStep) continue outerLoop;
26 i += step[0];
27 j = V.ComputeY(j + step[1]);
28 }
29 if (V.OnBoard(i, j)) {
30 if (i == x && j == y)
31 // Looped back onto initial square
32 infiniteSteps[step[0] + "." + step[1]] = true;
33 else if (this.canTake([x, y], [i, j]))
34 moves.push(this.getBasicMove([x, y], [i, j]));
35 }
36 }
37 return moves;
38 }
39
40 getPotentialPawnMoves([x, y]) {
41 const color = this.turn;
42 let moves = [];
43 const [sizeX, sizeY] = [V.size.x, V.size.y];
44 const shiftX = color == "w" ? -1 : 1;
45 const startRank = color == "w" ? sizeX - 2 : 1;
46 const lastRank = color == "w" ? 0 : sizeX - 1;
47
48 const finalPieces =
49 x + shiftX == lastRank
50 ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]
51 : [V.PAWN];
52 if (this.board[x + shiftX][y] == V.EMPTY) {
53 // One square forward
54 for (let piece of finalPieces) {
55 moves.push(
56 this.getBasicMove([x, y], [x + shiftX, y], {
57 c: color,
58 p: piece
59 })
60 );
61 }
62 if (
63 x == startRank &&
64 this.board[x + 2 * shiftX][y] == V.EMPTY
65 ) {
66 // Two squares jump
67 moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
68 }
69 }
70 // Captures
71 for (let shiftY of [-1, 1]) {
72 const nextFile = V.ComputeY(y + shiftY);
73 if (
74 this.board[x + shiftX][nextFile] != V.EMPTY &&
75 this.canTake([x, y], [x + shiftX, nextFile])
76 ) {
77 for (let piece of finalPieces) {
78 moves.push(
79 this.getBasicMove([x, y], [x + shiftX, nextFile], {
80 c: color,
81 p: piece
82 })
83 );
84 }
85 }
86 }
87
88 // En passant
89 const Lep = this.epSquares.length;
90 const epSquare = this.epSquares[Lep - 1]; //always at least one element
91 if (
92 !!epSquare &&
93 epSquare.x == x + shiftX &&
94 Math.abs( (epSquare.y - y) % V.size.y ) == 1
95 ) {
96 let enpassantMove = this.getBasicMove([x, y], [epSquare.x, epSquare.y]);
97 enpassantMove.vanish.push({
98 x: x,
99 y: epSquare.y,
100 p: "p",
101 c: this.getColor(x, epSquare.y)
102 });
103 moves.push(enpassantMove);
104 }
105
106 return moves;
107 }
108
109 isAttackedByPawn([x, y], color) {
110 let pawnShift = (color == "w" ? 1 : -1);
111 if (x + pawnShift >= 0 && x + pawnShift < V.size.x) {
112 for (let i of [-1, 1]) {
113 const nextFile = V.ComputeY(y + i);
114 if (
115 this.getPiece(x + pawnShift, nextFile) == V.PAWN &&
116 this.getColor(x + pawnShift, nextFile) == color
117 ) {
118 return true;
119 }
120 }
121 }
122 return false;
123 }
124
125 isAttackedBySlideNJump([x, y], color, piece, steps, oneStep) {
126 for (let step of steps) {
127 let rx = x + step[0],
128 ry = V.ComputeY(y + step[1]);
129 while (V.OnBoard(rx, ry) && this.board[rx][ry] == V.EMPTY && !oneStep) {
130 rx += step[0];
131 ry = V.ComputeY(ry + step[1]);
132 }
133 if (
134 V.OnBoard(rx, ry) &&
135 this.getPiece(rx, ry) == piece &&
136 this.getColor(rx, ry) == color
137 ) {
138 return true;
139 }
140 }
141 return false;
142 }
143
144 static get SEARCH_DEPTH() {
145 return 2;
146 }
147
148 static get VALUES() {
149 return {
150 p: 1,
151 r: 5,
152 n: 3,
153 b: 4,
154 q: 10,
155 k: 1000
156 };
157 }
158
159 };