1 import { ChessRules
} from "@/base_rules";
2 import { randInt
} from "@/utils/alea";
4 export class Refusal1Rules
extends ChessRules
{
6 static get HasFlags() {
10 static IsGoodFen(fen
) {
11 if (!ChessRules
.IsGoodFen(fen
)) return false;
12 if (!V
.ParseFen(fen
).lastMove
) return false;
16 static ParseFen(fen
) {
18 { lastMove: fen
.split(" ")[4] },
19 ChessRules
.ParseFen(fen
)
24 const L
= this.lastMove
.length
;
25 const lm
= this.lastMove
[L
-1];
26 return super.getFen() + " " + JSON
.stringify(lm
);
29 // NOTE: with this variant's special rule,
30 // some extra repetitions could be detected... TODO (...)
32 static GenRandInitFen(options
) {
33 return ChessRules
.GenRandInitFen(options
).slice(0, -6) + "- null";
36 setOtherVariables(fen
) {
37 super.setOtherVariables(fen
);
38 this.lastMove
= [JSON
.parse(V
.ParseFen(fen
).lastMove
)]; //may be null
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
);
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];
54 const beforeLastRank
= (this.turn
== 'w' ? 1 : 6);
56 !!lm
&& !lm
.noRef
&& x
== lm
.end
.x
&& y
== lm
.end
.y
&&
57 (this.getPiece(x
, y
) != V
.PAWN
|| x
!= beforeLastRank
)
59 let revLm
= JSON
.parse(JSON
.stringify(lm
));
60 let tmp
= revLm
.appear
;
61 revLm
.appear
= revLm
.vanish
;
64 revLm
.start
= revLm
.end
;
70 return super.getPotentialMovesFrom([x
, y
]);
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
=> {
80 !!lm
&& !!lm
.refusal
&&
81 m
.start
.x
== lm
.end
.x
&& m
.start
.y
== lm
.end
.y
&&
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
)
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
];
100 const L
= this.lastMove
.length
;
101 const lm
= this.lastMove
[L
-1];
102 // NOTE: refusal could be recomputed, but, it's easier like this
103 if (move.vanish
[0].c
!= this.turn
) move.refusal
= true;
106 // My previous move was already refused?
107 !!lm
&& this.getColor(lm
.end
.x
, lm
.end
.y
) == this.turn
112 if (!move.refusal
) return super.getEpSquare(move);
113 return null; //move refusal
117 if (!move.refusal
) super.postPlay(move);
119 const L
= this.lastMove
.length
;
120 const lm
= this.lastMove
[L
-1];
121 if (move.appear
[0].p
== V
.KING
)
122 this.kingPos
[move.appear
[0].c
] = [move.end
.x
, move.end
.y
];
124 // NOTE: explicitely give fields, because some are assigned in BaseGame
131 if (!!move.noRef
) mvInLm
.noRef
= true;
132 if (!!move.refusal
) mvInLm
.refusal
= true;
133 this.lastMove
.push(mvInLm
);
137 if (!move.refusal
) super.postUndo(move);
139 if (move.appear
[0].p
== V
.KING
)
140 this.kingPos
[move.appear
[0].c
] = [move.start
.x
, move.start
.y
];
145 getAllPotentialMoves() {
146 const color
= this.turn
;
147 const L
= this.lastMove
.length
;
148 const lm
= this.lastMove
[L
-1];
149 let potentialMoves
= [];
150 if (!!lm
&& !lm
.noRef
)
152 potentialMoves
= this.getPotentialMovesFrom([lm
.end
.x
, lm
.end
.y
]);
153 for (let i
= 0; i
< V
.size
.x
; i
++) {
154 for (let j
= 0; j
< V
.size
.y
; j
++) {
155 if (this.board
[i
][j
] != V
.EMPTY
&& this.getColor(i
, j
) == color
) {
156 Array
.prototype.push
.apply(
158 this.getPotentialMovesFrom([i
, j
])
163 return potentialMoves
;
167 const L
= this.lastMove
.length
;
168 const lm
= this.lastMove
[L
-1];
169 if (!!lm
&& !lm
.noRef
) return true;
170 return super.atLeastOneMove();
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
);
179 if (moves
.length
== 1 || Math
.random() <= 0.33) return refusal
;
180 const others
= moves
.filter(m
=> m
.vanish
[0].c
== this.turn
);
181 return others
[randInt(others
.length
)];
183 else return moves
[randInt(moves
.length
)];
187 if (move.vanish
[0].c
!= this.turn
) return "Refuse";
188 return super.getNotation(move);