1 import { ChessRules
} from "@/base_rules";
2 import { randInt
} from "@/utils/alea";
4 export class RefusalRules
extends ChessRules
{
6 static IsGoodFen(fen
) {
7 if (!ChessRules
.IsGoodFen(fen
)) return false;
8 if (!V
.ParseFen(fen
).lastMove
) return false;
12 static ParseFen(fen
) {
14 { lastMove: fen
.split(" ")[5] },
15 ChessRules
.ParseFen(fen
)
20 const L
= this.lastMove
.length
;
21 const lm
= this.lastMove
[L
-1];
22 return super.getFen() + " " + JSON
.stringify(lm
);
25 // NOTE: with this variant's special rule,
26 // some extra repetitions could be detected... TODO (...)
28 static GenRandInitFen(randomness
) {
29 return ChessRules
.GenRandInitFen(randomness
) + " null";
32 setOtherVariables(fen
) {
33 super.setOtherVariables(fen
);
34 this.lastMove
= [JSON
.parse(V
.ParseFen(fen
).lastMove
)]; //may be null
37 canIplay(side
, [x
, y
]) {
38 if (super.canIplay(side
, [x
, y
])) return true;
39 if (this.turn
!= side
) return false;
40 // Check if playing last move, reversed:
41 const L
= this.lastMove
.length
;
42 const lm
= this.lastMove
[L
-1];
43 return (!!lm
&& !lm
.noRef
&& x
== lm
.end
.x
&& y
== lm
.end
.y
);
46 getPotentialMovesFrom([x
, y
]) {
47 if (this.getColor(x
, y
) != this.turn
) {
48 const L
= this.lastMove
.length
;
49 const lm
= this.lastMove
[L
-1];
50 const beforeLastRank
= (this.turn
== 'w' ? 1 : 6);
52 !!lm
&& !lm
.noRef
&& x
== lm
.end
.x
&& y
== lm
.end
.y
&&
53 (this.getPiece(x
, y
) != V
.PAWN
|| x
!= beforeLastRank
)
55 let revLm
= JSON
.parse(JSON
.stringify(lm
));
56 let tmp
= revLm
.appear
;
57 revLm
.appear
= revLm
.vanish
;
60 revLm
.start
= revLm
.end
;
66 return super.getPotentialMovesFrom([x
, y
]);
69 // NOTE: do not take refusal move into account here (two own moves)
72 const color
= this.turn
;
73 for (let i
= 0; i
< V
.size
.x
; i
++) {
74 for (let j
= 0; j
< V
.size
.y
; j
++) {
75 if (this.board
[i
][j
] != V
.EMPTY
&& this.getColor(i
, j
) == color
) {
76 const moves
= this.getPotentialMovesFrom([i
, j
]);
77 for (let m
of moves
) {
78 if (m
.vanish
[0].c
== color
&& this.filterValid([m
]).length
> 0) {
80 if (movesCounter
>= 2) return true;
90 if (moves
.length
== 0) return [];
91 const color
= this.turn
;
92 const L
= this.lastMove
.length
;
93 const lm
= this.lastMove
[L
-1];
94 return moves
.filter(m
=> {
96 !!lm
&& !!lm
.refusal
&&
97 m
.start
.x
== lm
.end
.x
&& m
.start
.y
== lm
.end
.y
&&
98 m
.end
.x
== lm
.start
.x
&& m
.end
.y
== lm
.start
.y
&&
99 (m
.vanish
[0].p
!= V
.PAWN
|| m
.appear
[0].p
== lm
.vanish
[0].p
)
103 // NOTE: not using this.play()/undo() ==> infinite loop
104 V
.PlayOnBoard(this.board
, m
);
105 if (m
.appear
[0].p
== V
.KING
)
106 this.kingPos
[m
.appear
[0].c
] = [m
.appear
[0].x
, m
.appear
[0].y
];
107 const res
= !this.underCheck(color
);
108 V
.UndoOnBoard(this.board
, m
);
109 if (m
.vanish
[0].p
== V
.KING
)
110 this.kingPos
[m
.vanish
[0].c
] = [m
.vanish
[0].x
, m
.vanish
[0].y
];
116 const L
= this.lastMove
.length
;
117 const lm
= this.lastMove
[L
-1];
119 // My previous move was already refused?
120 (!!lm
&& this.getColor(lm
.end
.x
, lm
.end
.y
) == this.turn
) ||
121 // I've only one move available?
122 !this.atLeastTwoMoves()
126 // NOTE: refusal could be recomputed, but, it's easier like this
127 if (move.vanish
[0].c
!= this.turn
) move.refusal
= true;
131 if (!move.refusal
) return super.getEpSquare(move);
132 return null; //move refusal
136 if (!move.refusal
) super.postPlay(move);
138 const L
= this.lastMove
.length
;
139 const lm
= this.lastMove
[L
-1];
140 this.disaggregateFlags(JSON
.parse(lm
.flags
));
142 // NOTE: explicitely give fields, because some are assigned in BaseGame
150 if (!!move.noRef
) mvInLm
.noRef
= true;
151 if (!!move.refusal
) mvInLm
.refusal
= true;
152 this.lastMove
.push(mvInLm
);
156 if (!move.refusal
) super.postUndo(move);
160 getAllPotentialMoves() {
161 const color
= this.turn
;
162 const L
= this.lastMove
.length
;
163 const lm
= this.lastMove
[L
-1];
164 let potentialMoves
= [];
165 for (let i
= 0; i
< V
.size
.x
; i
++) {
166 for (let j
= 0; j
< V
.size
.y
; j
++) {
168 this.board
[i
][j
] != V
.EMPTY
&&
170 this.getColor(i
, j
) == color
||
172 (!!lm
&& lm
.end
.x
== i
&& lm
.end
.y
== j
)
175 Array
.prototype.push
.apply(
177 this.getPotentialMovesFrom([i
, j
])
182 return potentialMoves
;
186 // Just play at random for now... (TODO?)
187 // Refuse last move with odds 1/3.
188 const moves
= this.getAllValidMoves();
189 const refusal
= moves
.find(m
=> m
.vanish
[0].c
!= this.turn
);
191 if (Math
.random() <= 0.33) return refusal
;
192 const others
= moves
.filter(m
=> m
.vanish
[0].c
== this.turn
);
193 return others
[randInt(others
.length
)];
195 else return moves
[randInt(moves
.length
)];
199 if (move.vanish
[0].c
!= this.turn
) return "Refuse";
200 return super.getNotation(move);