Add Freecapture + advance on Koopa Chess
[vchess.git] / client / src / variants / Koopa.js
1 import { ChessRulesi, PiPo } from "@/base_rules";
2
3 export class KoopaRules extends ChessRules {
4 static get HasEnpassant() {
5 return false;
6 }
7
8 // Between stun time and stun + 1 move
9 static get STUNNED_1() {
10 return ['s', 'u', 'o', 'c', 't', 'l'];
11 }
12
13 // Between stun + 1 move and stun + 2 moves
14 static get STUNNED_2() {
15 return ['v', 'x', 'a', 'd', 'w', 'm'];
16 }
17
18 static get PIECES() {
19 return ChessRules.PIECES.concat(V.STUNNED_1).concat(V.STUNNED_2);
20 }
21
22 getNormalizedStep(step) {
23 const [deltaX, deltaY] = [Math.abs(step[0]), Math.abs(step[1])];
24 if (deltaX == 0 || deltaY == 0 || deltaX == deltaY)
25 return [step[0] / deltaX || 0, step[1] / deltaY || 0];
26 // Knight:
27 const divisor = Math.min(deltaX, deltaY)
28 return [step[0] / divisor, step[1] / divisor];
29 }
30
31 getPotentialMovesFrom([x, y]) {
32 let moves = super.getPotentialMovesFrom([x, y]);
33 // Complete moves: stuns & kicks
34 const stun = V.STUNNED_1.concat(V.STUNNED_2);
35 moves.forEach(m => {
36 if (m.vanish.length == 2 && m.appear.length == 1) {
37 const step =
38 this.getNormalizedStep([m.end.x - m.start.x, m.end.y - m.start.y]);
39 // "Capture" something: is target stunned?
40 if (stun.includes(m.vanish[1].p)) {
41 // Kick it: continue movement in the same direction,
42 // destroying all on its path.
43 let [i, j] = [m.end.x + step[0], m.end.y + step[1]];
44 while (V.OnBoard(i, j)) {
45 if (this.board[i][j] != V.EMPTY) {
46 m.vanish.push(
47 new PiPo({
48 x: i,
49 y: j,
50 c: this.getColor(i, j),
51 p: this.getPiece(i, j)
52 })
53 );
54 }
55 i += step[0];
56 j += step[1];
57 }
58 }
59 else {
60 // The piece is now stunned
61 m.appear.push(m.vanish.pop());
62 const pIdx = ChessRules.PIECES.findIndex(p => p == m.appear[1].p);
63 m.appear[1].p = V.STUNNED_1[pIdx];
64 // And the capturer continue in the same direction until an empty
65 // square or the edge of the board, maybe stunning other pieces.
66 let [i, j] = [m.end.x + step[0], m.end.y + step[1]];
67 while (V.OnBoard(i, j) && this.board[i][j] != V.EMPTY) {
68 const colIJ = this.getColor(i, j);
69 const pieceIJ = this.getPiece(i, j);
70 m.vanish.push(
71 new PiPo({
72 x: i,
73 y: j,
74 c: colIJ,
75 p: pieceIJ
76 })
77 );
78 const pIdx = ChessRules.PIECES.findIndex(p => p == pieceIJ);
79 m.appear.push(
80 new PiPo({
81 x: i,
82 y: j,
83 c: colIJ,
84 p: V.STUNNED_1[pIdx]
85 })
86 );
87 i += step[0];
88 j += step[1];
89 }
90 if (V.OnBoard(i, j)) {
91 m.appear[0].x = i;
92 m.appear[0].y = j;
93 // Is it a pawn on last rank?
94 }
95 else {
96 // The piece is out
97 m.appear.shift();
98 }
99 }
100 }
101 });
102 return moves;
103 }
104
105 static GenRandInitFen(randomness) {
106 // No en-passant:
107 return ChessRules.GenRandInitFen(randomness).slice(0, -2);
108 }
109
110 filterValid(moves) {
111 // Forbid kicking own king out
112 const color = this.turn;
113 return moves.filter(m => {
114 return m.vanish.every(v => v.c != color || !(['l','m'].includes(v.p)));
115 });
116 }
117
118 getCheckSquares() {
119 return [];
120 }
121
122 getCurrentScore() {
123 if (this.kingPos['w'][0] < 0) return "0-1";
124 if (this.kingPos['b'][0] < 0) return "1-0";
125 if (!this.atLeastOneMove()) return "1/2";
126 return "*";
127 }
128
129 postPlay(move) {
130 // TODO: toutes les pièces "stunned" by me (turn) avancent d'un niveau
131 // --> alter board
132 move.wasStunned = array of stunned stage 2 pieces (just back to normal then)
133 }
134
135 postUndo(move) {
136 if (wasStunned
137 STUNNED_2
138 }
139 };