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
{
7 static get HasFlags() {
11 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
=5; 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 return this.filterValid(moves
);
188 const color
= move.appear
[0].c
;
189 if (this.movesCount
<= 1) {
190 V
.PlayOnBoard(this.board
, move);
191 const piece
= move.appear
[0].p
;
192 this.reserve
[color
][piece
]--;
193 if (piece
== V
.KING
) this.kingPos
[color
] = [move.end
.x
, move.end
.y
];
194 if (this.subTurn
== 16) {
195 // All placement moves are done
197 this.turn
= V
.GetOppCol(color
);
198 if (this.movesCount
== 1) this.subTurn
= 1;
200 // Initial placement is over
201 delete this["reserve"];
202 delete this["subTurn"];
208 if (this.movesCount
== 2) this.re_setEnlightened(false);
214 const color
= move.appear
[0].c
;
215 if (this.movesCount
<= 2) {
216 V
.UndoOnBoard(this.board
, move);
217 const piece
= move.appear
[0].p
;
218 if (piece
== V
.KING
) this.kingPos
[color
] = [-1, -1];
219 if (!this.subTurn
|| this.subTurn
== 1) {
220 // All placement moves are undone (if any)
221 if (!this.subTurn
) this.re_setReserve(16);
222 else this.subTurn
= 16;
224 if (this.movesCount
== 1) this.re_setEnlightened(true);
228 this.reserve
[color
][piece
]++;
230 else super.undo(move);
234 if (this.movesCount
<= 1) return [];
235 return super.getCheckSquares();
239 if (this.movesCount
<= 1) return "*";
240 return super.getCurrentScore();
244 if (this.movesCount
>= 2) return super.getComputerMove();
245 // Play a random "initialization move"
247 for (let i
=0; i
<16; i
++) {
248 const moves
= this.getAllValidMoves();
249 const moveIdx
= randInt(moves
.length
);
250 this.play(moves
[moveIdx
]);
251 res
.push(moves
[moveIdx
]);
253 for (let i
=15; i
>=0; i
--) this.undo(res
[i
]);
258 // Do not note placement moves (complete move would be too long)
259 if (move.vanish
.length
== 0) return "";
260 return super.getNotation(move);