Several small improvements + integrate options + first working draft of Cwda
[vchess.git] / client / src / variants / Refusal1.js
CommitLineData
2a0672a9
BA
1import { ChessRules } from "@/base_rules";
2import { randInt } from "@/utils/alea";
3
39867b70
BA
4export class Refusal1Rules extends ChessRules {
5
6 static get HasFlags() {
7 return false;
8 }
2a0672a9
BA
9
10 static IsGoodFen(fen) {
11 if (!ChessRules.IsGoodFen(fen)) return false;
12 if (!V.ParseFen(fen).lastMove) return false;
13 return true;
14 }
15
16 static ParseFen(fen) {
17 return Object.assign(
39867b70 18 { lastMove: fen.split(" ")[4] },
2a0672a9
BA
19 ChessRules.ParseFen(fen)
20 );
21 }
22
23 getFen() {
24 const L = this.lastMove.length;
25 const lm = this.lastMove[L-1];
26 return super.getFen() + " " + JSON.stringify(lm);
27 }
28
29 // NOTE: with this variant's special rule,
30 // some extra repetitions could be detected... TODO (...)
31
4313762d
BA
32 static GenRandInitFen(options) {
33 return ChessRules.GenRandInitFen(options).slice(0, -6) + "- null";
2a0672a9
BA
34 }
35
36 setOtherVariables(fen) {
37 super.setOtherVariables(fen);
38 this.lastMove = [JSON.parse(V.ParseFen(fen).lastMove)]; //may be null
39 }
40
41 canIplay(side, [x, y]) {
42 if (super.canIplay(side, [x, y])) return true;
43 if (this.turn != side) return false;
44 // Check if playing last move, reversed:
45 const L = this.lastMove.length;
46 const lm = this.lastMove[L-1];
47 return (!!lm && !lm.noRef && x == lm.end.x && y == lm.end.y);
48 }
49
50 getPotentialMovesFrom([x, y]) {
51 if (this.getColor(x, y) != this.turn) {
52 const L = this.lastMove.length;
53 const lm = this.lastMove[L-1];
2da551a3
BA
54 const beforeLastRank = (this.turn == 'w' ? 1 : 6);
55 if (
56 !!lm && !lm.noRef && x == lm.end.x && y == lm.end.y &&
57 (this.getPiece(x, y) != V.PAWN || x != beforeLastRank)
58 ) {
2a0672a9
BA
59 let revLm = JSON.parse(JSON.stringify(lm));
60 let tmp = revLm.appear;
61 revLm.appear = revLm.vanish;
62 revLm.vanish = tmp;
63 tmp = revLm.start;
64 revLm.start = revLm.end;
65 revLm.end = tmp;
66 return [revLm];
67 }
68 return [];
69 }
70 return super.getPotentialMovesFrom([x, y]);
71 }
72
2a0672a9
BA
73 filterValid(moves) {
74 if (moves.length == 0) return [];
75 const color = this.turn;
76 const L = this.lastMove.length;
77 const lm = this.lastMove[L-1];
78 return moves.filter(m => {
79 if (
80 !!lm && !!lm.refusal &&
81 m.start.x == lm.end.x && m.start.y == lm.end.y &&
2da551a3
BA
82 m.end.x == lm.start.x && m.end.y == lm.start.y &&
83 (m.vanish[0].p != V.PAWN || m.appear[0].p == lm.vanish[0].p)
2a0672a9
BA
84 ) {
85 return false;
86 }
87 // NOTE: not using this.play()/undo() ==> infinite loop
88 V.PlayOnBoard(this.board, m);
89 if (m.appear[0].p == V.KING)
90 this.kingPos[m.appear[0].c] = [m.appear[0].x, m.appear[0].y];
91 const res = !this.underCheck(color);
92 V.UndoOnBoard(this.board, m);
93 if (m.vanish[0].p == V.KING)
94 this.kingPos[m.vanish[0].c] = [m.vanish[0].x, m.vanish[0].y];
95 return res;
96 });
97 }
98
99 prePlay(move) {
100 const L = this.lastMove.length;
101 const lm = this.lastMove[L-1];
2a0672a9
BA
102 // NOTE: refusal could be recomputed, but, it's easier like this
103 if (move.vanish[0].c != this.turn) move.refusal = true;
39867b70
BA
104 move.noRef = (
105 !!move.refusal ||
106 // My previous move was already refused?
107 !!lm && this.getColor(lm.end.x, lm.end.y) == this.turn
108 );
2a0672a9
BA
109 }
110
111 getEpSquare(move) {
112 if (!move.refusal) return super.getEpSquare(move);
113 return null; //move refusal
114 }
115
116 postPlay(move) {
117 if (!move.refusal) super.postPlay(move);
118 else {
119 const L = this.lastMove.length;
120 const lm = this.lastMove[L-1];
39867b70
BA
121 if (move.appear[0].p == V.KING)
122 this.kingPos[move.appear[0].c] = [move.end.x, move.end.y];
2a0672a9
BA
123 }
124 // NOTE: explicitely give fields, because some are assigned in BaseGame
125 let mvInLm = {
126 start: move.start,
127 end: move.end,
128 appear: move.appear,
129 vanish: move.vanish,
2a0672a9
BA
130 };
131 if (!!move.noRef) mvInLm.noRef = true;
132 if (!!move.refusal) mvInLm.refusal = true;
133 this.lastMove.push(mvInLm);
134 }
135
136 postUndo(move) {
137 if (!move.refusal) super.postUndo(move);
39867b70
BA
138 else {
139 if (move.appear[0].p == V.KING)
140 this.kingPos[move.appear[0].c] = [move.start.x, move.start.y];
141 }
2a0672a9
BA
142 this.lastMove.pop();
143 }
144
145 getAllPotentialMoves() {
146 const color = this.turn;
147 const L = this.lastMove.length;
148 const lm = this.lastMove[L-1];
149 let potentialMoves = [];
39867b70
BA
150 if (!!lm && !lm.noRef)
151 // Add refusal move:
152 potentialMoves = this.getPotentialMovesFrom([lm.end.x, lm.end.y]);
2a0672a9
BA
153 for (let i = 0; i < V.size.x; i++) {
154 for (let j = 0; j < V.size.y; j++) {
39867b70 155 if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) {
2a0672a9
BA
156 Array.prototype.push.apply(
157 potentialMoves,
158 this.getPotentialMovesFrom([i, j])
159 );
160 }
161 }
162 }
163 return potentialMoves;
164 }
165
39867b70
BA
166 atLeastOneMove() {
167 const L = this.lastMove.length;
168 const lm = this.lastMove[L-1];
169 if (!!lm && !lm.noRef) return true;
170 return super.atLeastOneMove();
171 }
172
2a0672a9
BA
173 getComputerMove() {
174 // Just play at random for now... (TODO?)
175 // Refuse last move with odds 1/3.
176 const moves = this.getAllValidMoves();
177 const refusal = moves.find(m => m.vanish[0].c != this.turn);
178 if (!!refusal) {
39867b70 179 if (moves.length == 1 || Math.random() <= 0.33) return refusal;
2a0672a9
BA
180 const others = moves.filter(m => m.vanish[0].c == this.turn);
181 return others[randInt(others.length)];
182 }
183 else return moves[randInt(moves.length)];
184 }
185
186 getNotation(move) {
187 if (move.vanish[0].c != this.turn) return "Refuse";
188 return super.getNotation(move);
189 }
190
191};