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