1e7bfabb8fd0d09d77eb05c388835a8f6c1726ca
[vchess.git] / client / src / variants / Knightrelay1.js
1 import { ChessRules } from "@/base_rules";
2
3 export class Knightrelay1Rules extends ChessRules {
4
5 static get HasEnpassant() {
6 return false;
7 }
8
9 // TODO: IsGoodPosition to check that 2 knights are on the board...
10
11 getPotentialMovesFrom([x, y]) {
12 let moves = super.getPotentialMovesFrom([x, y]);
13
14 // Expand possible moves if guarded by a knight, and is not a king:
15 const piece = this.getPiece(x,y);
16 if (![V.KNIGHT,V.KING].includes(piece)) {
17 const color = this.turn;
18 let guardedByKnight = false;
19 for (const step of V.steps[V.KNIGHT]) {
20 if (
21 V.OnBoard(x+step[0],y+step[1]) &&
22 this.getPiece(x+step[0],y+step[1]) == V.KNIGHT &&
23 this.getColor(x+step[0],y+step[1]) == color
24 ) {
25 guardedByKnight = true;
26 break;
27 }
28 }
29 if (guardedByKnight) {
30 const lastRank = (color == "w" ? 0 : V.size.x - 1);
31 for (const step of V.steps[V.KNIGHT]) {
32 if (
33 V.OnBoard(x+step[0],y+step[1]) &&
34 this.getColor(x+step[0],y+step[1]) != color &&
35 // Pawns cannot promote by knight-relay
36 (piece != V.PAWN || x+step[0] != lastRank)
37 ) {
38 moves.push(this.getBasicMove([x,y], [x+step[0],y+step[1]]));
39 }
40 }
41 }
42 }
43
44 // Forbid captures of knights (invincible in this variant)
45 return moves.filter(m => {
46 return (
47 m.vanish.length == 1 ||
48 m.appear.length == 2 ||
49 m.vanish[1].p != V.KNIGHT
50 );
51 });
52 }
53
54 getPotentialKnightMoves(sq) {
55 // Knights don't capture:
56 return super.getPotentialKnightMoves(sq).filter(m => m.vanish.length == 1);
57 }
58
59 isAttacked(sq, color) {
60 if (super.isAttacked(sq, color)) return true;
61
62 // Check if a (non-knight) piece at knight distance
63 // is guarded by a knight (and thus attacking)
64 // --> Except for pawns targetting last rank.
65 const x = sq[0],
66 y = sq[1];
67 // Last rank for me, that is to say oppCol of color:
68 const lastRank = (color == 'w' ? V.size.x - 1 : 0);
69 for (const step of V.steps[V.KNIGHT]) {
70 if (
71 V.OnBoard(x+step[0],y+step[1]) &&
72 this.getColor(x+step[0],y+step[1]) == color
73 ) {
74 const piece = this.getPiece(x+step[0],y+step[1]);
75 if (piece != V.KNIGHT && (piece != V.PAWN || x != lastRank)) {
76 for (const step2 of V.steps[V.KNIGHT]) {
77 const xx = x+step[0]+step2[0],
78 yy = y+step[1]+step2[1];
79 if (
80 V.OnBoard(xx,yy) &&
81 this.getColor(xx,yy) == color &&
82 this.getPiece(xx,yy) == V.KNIGHT
83 ) {
84 return true;
85 }
86 }
87 }
88 }
89 }
90
91 return false;
92 }
93
94 isAttackedByKnight(sq, color) {
95 // Knights don't attack
96 return false;
97 }
98
99 static get VALUES() {
100 return {
101 p: 1,
102 r: 5,
103 n: 0, //the knight isn't captured - value doesn't matter
104 b: 3,
105 q: 9,
106 k: 1000
107 };
108 }
109
110 static get SEARCH_DEPTH() {
111 return 2;
112 }
113
114 getNotation(move) {
115 if (move.appear.length == 2 && move.appear[0].p == V.KING)
116 // Castle
117 return move.end.y < move.start.y ? "0-0-0" : "0-0";
118
119 // Translate final and initial square
120 const initSquare = V.CoordsToSquare(move.start);
121 const finalSquare = V.CoordsToSquare(move.end);
122 const piece = this.getPiece(move.start.x, move.start.y);
123
124 // Since pieces and pawns could move like knight,
125 // indicate start and end squares
126 let notation =
127 piece.toUpperCase() +
128 initSquare +
129 (move.vanish.length > move.appear.length ? "x" : "") +
130 finalSquare
131
132 if (
133 piece == V.PAWN &&
134 move.appear.length > 0 &&
135 move.appear[0].p != V.PAWN
136 ) {
137 // Promotion
138 notation += "=" + move.appear[0].p.toUpperCase();
139 }
140
141 return notation;
142 }
143
144 };