1 import ChessRules
from "/base_rules.js";
2 import {ArrayFun
} from "/utils/array.js";
4 export class ApocalypseRules
extends ChessRules
{
10 get pawnPromotions() {
18 setOtherVariables(fenParsed
) {
19 super.setOtherVariables(fenParsed
);
20 this.whiteMove
= fenParsed
.whiteMove
!= "-"
21 ? JSON
.parse(fenParsed
.whiteMove
)
25 genRandInitBaseFen() {
27 fen: "npppn/p3p/5/P3P/NPPPN w 0",
33 let parts
= super.getPartFen(o
);
34 parts
["whiteMove"] = this.whiteMove
|| "-";
39 return Object
.values(this.penaltyFlags
).join("");
43 this.penaltyFlags
= ArrayFun
.toObject(
44 ['w', 'b'], [0, 1].map(i
=> parseInt(fenflags
.charAt(i
), 10)));
48 return !this.whiteMove
? "-" : JSON
.stringify(this.whiteMove
);
51 // Allow pawns to move diagonally and capture vertically,
52 // because some of these moves might be valid a posteriori.
53 // They will be flagged as 'illegal' in a first time, however.
55 const pawnShift
= (color
== "w" ? -1 : 1);
61 steps: [[pawnShift
, 0], [pawnShift
, -1], [pawnShift
, 1]],
66 'n': super.pieces(color
, x
, y
)['n']
70 // Allow self-captures, because they might be valid
71 // if opponent takes on the same square (luck...)
76 getPotentialMovesFrom([x
, y
]) {
78 if (this.subTurn
== 2) {
79 const start
= this.moveStack
[0].end
;
80 if (x
== start
.x
&& y
== start
.y
) {
81 // Move the pawn to any empty square not on last rank (== x)
82 for (let i
=0; i
<this.size
.x
; i
++) {
85 for (let j
=0; j
<this.size
.y
; j
++) {
86 if (this.board
[i
][j
] == "")
87 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
93 moves
= super.getPotentialMovesFrom([x
, y
])
94 // Flag a priori illegal moves
98 (m
.vanish
.length
== 2 && m
.vanish
[1].c
== m
.vanish
[0].c
) ||
99 // Pawn going diagonaly to empty square, or vertically to occupied
101 m
.vanish
[0].p
== 'p' &&
103 (m
.end
.y
== m
.start
.y
&& m
.vanish
.length
== 2) ||
104 (m
.end
.y
!= m
.start
.y
&& m
.vanish
.length
== 1)
123 // White and black (partial) moves were played: merge
124 // + animate both at the same time !
125 resolveSynchroneMove(move) {
130 if (this.subTurn
...) //TODO: detect (mark?) if pawn move arriving on last rank (=> subTurn++)
131 this.turn
= V
.GetOppCol(this.turn
);
137 if (pawn promotion into pawn
) {
138 this.curMove
move; //TODO: animate both move at same time + effects AFTER !
141 else if (this.turn
== 'b')
142 // NOTE: whiteMove is used read-only, so no need to copy
143 this.whiteMove
= move;
146 // A full turn just ended:
147 const [wMove
, bMove
] = this.resolveSynchroneMove(move);
148 V
.PlayOnBoard(this.board
, smove
); //----> ici : animate both !
149 this.whiteMove
= null;
156 atLeastOneLegalMove(color
) {
157 for (let i
=0; i
<this.size
.x
; i
++) {
158 for (let j
=0; j
<this.size
.y
; j
++) {
160 this.board
[i
][j
] != "" &&
161 this.getColor(i
, j
) == color
&&
162 this.getPotentialMoves([i
, j
]).some(m
=> !m
.illegal
)
172 if (this.turn
== 'b') {
173 // Turn (white + black) not over yet.
174 // Could be stalemate if black cannot move (legally):
175 if (!this.atLeastOneLegalMove('b'))
179 // Count footmen: if a side has none, it loses
180 let fmCount
= { 'w': 0, 'b': 0 };
181 for (let i
=0; i
<5; i
++) {
182 for (let j
=0; j
<5; j
++) {
183 if (this.board
[i
][j
] != V
.EMPTY
&& this.getPiece(i
, j
) == V
.PAWN
)
184 fmCount
[this.getColor(i
, j
)]++;
187 if (Object
.values(fmCount
).some(v
=> v
== 0)) {
188 if (fmCount
['w'] == 0 && fmCount
['b'] == 0)
191 if (fmCount
['w'] == 0) return "0-1";
192 return "1-0"; //fmCount['b'] == 0
194 // Check penaltyFlags: if a side has 2 or more, it loses
195 if (Object
.values(this.penaltyFlags
).every(v
=> v
== 2)) return "1/2";
196 if (this.penaltyFlags
['w'] == 2) return "0-1";
197 if (this.penaltyFlags
['b'] == 2) return "1-0";
198 if (!this.atLeastOneLegalMove('w') || !this.atLeastOneLegalMove('b'))
199 // Stalemate (should be very rare)