1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
2 import { randInt
} from "@/utils/alea";
3 import { ArrayFun
} from "@/utils/array";
5 export class ScreenRules
extends ChessRules
{
11 static get HasFlags() {
15 static get HasEnpassant() {
20 return this.movesCount
>= 2;
23 get someHiddenMoves() {
24 return this.movesCount
<= 1;
27 static GenRandInitFen() {
29 return "8/8/8/8/8/8/8/8 w 0";
32 re_setReserve(subTurn
) {
33 const mc
= this.movesCount
;
34 const wc
= (mc
== 0 ? 1 : 0);
35 const bc
= (mc
<= 1 ? 1 : 0);
54 this.subTurn
= subTurn
|| 1;
57 re_setEnlightened(onOff
) {
58 if (!onOff
) delete this["enlightened"];
62 'w': ArrayFun
.init(8, 8, false),
63 'b': ArrayFun
.init(8, 8, false)
65 for (let i
=0; i
<4; i
++) {
66 for (let j
=0; j
<8; j
++) this.enlightened
['b'][i
][j
] = true;
68 for (let i
=4; i
<8; i
++) {
69 for (let j
=0; j
<8; j
++) this.enlightened
['w'][i
][j
] = true;
74 setOtherVariables(fen
) {
75 super.setOtherVariables(fen
);
76 if (this.movesCount
<= 1) {
78 this.re_setEnlightened(true);
83 if (i
>= V
.size
.x
) return i
== V
.size
.x
? "w" : "b";
84 return this.board
[i
][j
].charAt(0);
88 if (i
>= V
.size
.x
) return V
.RESERVE_PIECES
[j
];
89 return this.board
[i
][j
].charAt(1);
92 getReservePpath(index
, color
) {
93 return color
+ V
.RESERVE_PIECES
[index
];
96 static get RESERVE_PIECES() {
97 return [V
.PAWN
, V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
, V
.KING
];
100 getPotentialMovesFrom([x
, y
]) {
101 if (this.movesCount
>= 2) return super.getPotentialMovesFrom([x
, y
]);
102 // Only reserve moves are allowed for now:
103 if (V
.OnBoard(x
, y
)) return [];
104 const color
= this.turn
;
105 const p
= V
.RESERVE_PIECES
[y
];
106 if (this.reserve
[color
][p
] == 0) return [];
107 const shift
= (p
== V
.PAWN
? 1 : 0);
108 let iBound
= (color
== 'w' ? [4, 7 - shift
] : [shift
, 3]);
111 // Pawns cannot stack on files, one bishop per color
112 let forbiddenFiles
= [];
114 const colorShift
= (color
== 'w' ? 4 : 1);
116 ArrayFun
.range(8).filter(jj
=> {
117 return ArrayFun
.range(3).some(ii
=> {
119 this.board
[colorShift
+ ii
][jj
] != V
.EMPTY
&&
120 this.getPiece(colorShift
+ ii
, jj
) == V
.PAWN
125 let forbiddenColor
= -1;
127 const colorShift
= (color
== 'w' ? 4 : 0);
128 outerLoop: for (let ii
= colorShift
; ii
< colorShift
+ 4; ii
++) {
129 for (let jj
= 0; jj
< 8; jj
++) {
131 this.board
[ii
][jj
] != V
.EMPTY
&&
132 this.getPiece(ii
, jj
) == V
.BISHOP
134 forbiddenColor
= (ii
+ jj
) % 2;
141 for (let i
= iBound
[0]; i
<= iBound
[1]; i
++) {
142 for (let j
= 0; j
< 8; j
++) {
144 this.board
[i
][j
] == V
.EMPTY
&&
145 (p
!= V
.PAWN
|| !forbiddenFiles
.includes(j
)) &&
146 (p
!= V
.BISHOP
|| (i
+ j
) % 2 != forbiddenColor
)
148 // Ok, move is valid:
159 start: { x: x
, y: y
},
166 moves
.forEach(m
=> { m
.end
.noHighlight
= true; });
171 if (this.movesCount
<= 1) return false;
172 return super.underCheck(color
);
176 if (this.movesCount
>= 2) return super.getAllValidMoves();
177 const color
= this.turn
;
179 for (let i
= 0; i
< V
.RESERVE_PIECES
.length
; i
++) {
180 moves
= moves
.concat(
181 this.getPotentialMovesFrom([V
.size
.x
+ (color
== "w" ? 0 : 1), i
])
184 // Some setup moves may let the king en prise (thus game would be lost)
189 if (this.movesCount
<= 1) return moves
;
190 return super.filterValid(moves
);
194 const color
= move.appear
[0].c
;
195 if (this.movesCount
<= 1) {
196 V
.PlayOnBoard(this.board
, move);
197 const piece
= move.appear
[0].p
;
198 this.reserve
[color
][piece
]--;
199 if (piece
== V
.KING
) this.kingPos
[color
] = [move.end
.x
, move.end
.y
];
200 if (this.subTurn
== 16) {
201 // All placement moves are done
203 this.turn
= V
.GetOppCol(color
);
204 if (this.movesCount
== 1) this.subTurn
= 1;
206 // Initial placement is over
207 delete this["reserve"];
208 delete this["subTurn"];
214 if (this.movesCount
== 2) this.re_setEnlightened(false);
220 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
221 // Only black king could be captured (theoretically...)
222 this.kingPos
['b'] = [-1, -1];
223 super.postPlay(move);
227 const color
= move.appear
[0].c
;
228 if (this.movesCount
<= 2) {
229 V
.UndoOnBoard(this.board
, move);
230 const piece
= move.appear
[0].p
;
231 if (piece
== V
.KING
) this.kingPos
[color
] = [-1, -1];
232 if (!this.subTurn
|| this.subTurn
== 1) {
233 // All placement moves are undone (if any)
234 if (!this.subTurn
) this.re_setReserve(16);
235 else this.subTurn
= 16;
237 if (this.movesCount
== 1) this.re_setEnlightened(true);
241 this.reserve
[color
][piece
]++;
243 else super.undo(move);
247 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
248 this.kingPos
['b'] = [move.vanish
[1].x
, move.vanish
[1].y
];
249 super.postUndo(move);
253 if (this.movesCount
<= 1) return [];
254 return super.getCheckSquares();
258 if (this.movesCount
<= 1) return "*";
259 // Only black king could be eaten on move 2:
260 if (this.kingPos
['b'][0] < 0) return "1-0";
261 return super.getCurrentScore();
265 if (this.movesCount
>= 2) return super.getComputerMove();
266 // Play a random "initialization move"
268 for (let i
=0; i
<16; i
++) {
269 const moves
= this.getAllValidMoves();
270 const moveIdx
= randInt(moves
.length
);
271 this.play(moves
[moveIdx
]);
272 res
.push(moves
[moveIdx
]);
274 for (let i
=15; i
>=0; i
--) this.undo(res
[i
]);
279 // Do not note placement moves (complete move would be too long)
280 if (move.vanish
.length
== 0) return "";
281 return super.getNotation(move);