2cd9ca67cadcf4ce33439619ddef2a83d1958e6d
[xogo.git] / variants / Refusal / class.js
1 import ChessRules from "/base_rules.js";
2
3 export default class RefusalRules extends ChessRules {
4
5 static get Options() {
6 return {
7 select: C.Options.select,
8 input: [
9 {
10 label: "Refuse any",
11 variable: "refuseany",
12 type: "checkbox",
13 defaut: true
14 }
15 ],
16 styles: ["cylinder"]
17 };
18 }
19
20 get hasFlags() {
21 return false;
22 }
23
24 genRandInitFen(seed) {
25 return super.genRandInitFen(seed).slice(0, -1) + ',"lastmove":"null"}';
26 }
27
28 getFen() {
29 return (
30 super.getFen().slice(0, -1) + ',"lastmove":"' +
31 JSON.stringify(this.lastMove) + '"}');
32 }
33
34 setOtherVariables(fenParsed) {
35 super.setOtherVariables(fenParsed);
36 this.lastMove = JSON.parse(fenParsed.lastmove);
37 if (!this.lastMove) {
38 // Fill with empty values to avoid checking lastMove != null
39 this.lastMove = {
40 start: {x: -1, y: -1}, end: {x: -1, y: -1}, vanish: [{c: ''}]
41 };
42 }
43 }
44
45 canIplay(x, y) {
46 if (super.canIplay(x, y))
47 return true;
48 // Check if playing last move, reversed:
49 const lm = this.lastMove;
50 return (!lm.noRef && x == lm.end.x && y == lm.end.y);
51 }
52
53 getPotentialMovesFrom([x, y]) {
54 const moveColor = this.getColor(x, y);
55 if (moveColor != this.turn) {
56 let revLm = JSON.parse(JSON.stringify(this.lastMove));
57 [revLm.appear, revLm.vanish] = [revLm.vanish, revLm.appear];
58 [revLm.start, revLm.end] = [revLm.end, revLm.start];
59 if (!this.options["refuseany"]) {
60 // After refusing this move, can my opponent play a different move?
61 this.playOnBoard(revLm);
62 let totOppMoves = 0;
63 outerLoop: for (let i=0; i<this.size.x; i++) {
64 for (let j=0; j<this.size.y; j++) {
65 if (this.getColor(i, j) == moveColor) {
66 const potentialOppMoves = super.getPotentialMovesFrom([i, j]);
67 totOppMoves +=
68 super.filterValid(potentialOppMoves, moveColor).length;
69 if (totOppMoves >= 2)
70 break outerLoop;
71 }
72 }
73 }
74 this.undoOnBoard(revLm);
75 if (totOppMoves <= 1)
76 return [];
77 }
78 // Also reverse segments in Cylinder mode:
79 if (this.options["cylinder"])
80 revLm.segments = revLm.segments.map(seg => [seg[1], seg[0]]);
81 else
82 delete revLm["segments"];
83 revLm.refusal = true;
84 revLm.noRef = true; //cannot refuse a refusal move :)
85 return [revLm];
86 }
87 return super.getPotentialMovesFrom([x, y]);
88 }
89
90 getEpSquare(move) {
91 if (!move.refusal)
92 return super.getEpSquare(move);
93 return null;
94 }
95
96 filterValid(moves) {
97 const color = this.turn;
98 const lm = this.lastMove;
99 let rMoves = moves.filter(m => {
100 return (
101 !lm.refusal || //it's my first move attempt on this turn
102 m.start.x != lm.end.x || m.start.y != lm.end.y ||
103 m.end.x != lm.start.x || m.end.y != lm.start.y ||
104 // Doing the same move again: maybe pawn promotion?
105 (m.vanish[0].p == 'p' && m.appear[0].p != lm.appear[0].p)
106 );
107 });
108 return super.filterValid(rMoves);
109 }
110
111 prePlay(move) {
112 if (!move.noRef)
113 // My previous move was already refused?
114 move.noRef = this.lastMove.vanish[0].c == this.turn;
115 }
116
117 postPlay(move) {
118 this.lastMove = move;
119 super.postPlay(move);
120 }
121
122 atLeastOneMove() {
123 if (!this.lastMove.noRef)
124 return true;
125 return super.atLeastOneMove();
126 }
127
128 };