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() {
16 return this.movesCount
>= 2;
19 get someHiddenMoves() {
20 return this.movesCount
<= 1;
23 static GenRandInitFen() {
25 return "8/8/8/8/8/8/8/8 w 0";
28 re_setReserve(subTurn
) {
29 const mc
= this.movesCount
;
30 const wc
= (mc
== 0 ? 1 : 0);
31 const bc
= (mc
<= 1 ? 1 : 0);
50 this.subTurn
= subTurn
|| 1;
53 re_setEnlightened(onOff
) {
54 if (!onOff
) delete this["enlightened"];
58 'w': ArrayFun
.init(8, 8, false),
59 'b': ArrayFun
.init(8, 8, false)
61 for (let i
=0; i
<4; i
++) {
62 for (let j
=0; j
<8; j
++) this.enlightened
['b'][i
][j
] = true;
64 for (let i
=4; i
<8; i
++) {
65 for (let j
=0; j
<8; j
++) this.enlightened
['w'][i
][j
] = true;
70 setOtherVariables(fen
) {
71 super.setOtherVariables(fen
);
72 if (this.movesCount
<= 1) {
74 this.re_setEnlightened(true);
79 if (i
>= V
.size
.x
) return i
== V
.size
.x
? "w" : "b";
80 return this.board
[i
][j
].charAt(0);
84 if (i
>= V
.size
.x
) return V
.RESERVE_PIECES
[j
];
85 return this.board
[i
][j
].charAt(1);
88 getReservePpath(index
, color
) {
89 return color
+ V
.RESERVE_PIECES
[index
];
92 static get RESERVE_PIECES() {
93 return [V
.PAWN
, V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
, V
.KING
];
96 getPotentialMovesFrom([x
, y
]) {
97 if (this.movesCount
>= 2) return super.getPotentialMovesFrom([x
, y
]);
98 // Only reserve moves are allowed for now:
99 if (V
.OnBoard(x
, y
)) return [];
100 const color
= this.turn
;
101 const p
= V
.RESERVE_PIECES
[y
];
102 if (this.reserve
[color
][p
] == 0) return [];
103 const shift
= (p
== V
.PAWN
? 1 : 0);
104 let iBound
= (color
== 'w' ? [4, 7 - shift
] : [shift
, 3]);
107 // Pawns cannot stack on files, one bishop per color
108 let forbiddenFiles
= [];
110 const colorShift
= (color
== 'w' ? 4 : 1);
112 ArrayFun
.range(8).filter(jj
=> {
113 return ArrayFun
.range(3).some(ii
=> {
115 this.board
[colorShift
+ ii
][jj
] != V
.EMPTY
&&
116 this.getPiece(colorShift
+ ii
, jj
) == V
.PAWN
121 let forbiddenColor
= -1;
123 const colorShift
= (color
== 'w' ? 4 : 0);
124 outerLoop: for (let ii
= colorShift
; ii
< colorShift
+ 4; ii
++) {
125 for (let jj
= 0; jj
< 8; jj
++) {
127 this.board
[ii
][jj
] != V
.EMPTY
&&
128 this.getPiece(ii
, jj
) == V
.BISHOP
130 forbiddenColor
= (ii
+ jj
) % 2;
137 for (let i
= iBound
[0]; i
<= iBound
[1]; i
++) {
138 for (let j
= 0; j
< 8; j
++) {
140 this.board
[i
][j
] == V
.EMPTY
&&
141 (p
!= V
.PAWN
|| !forbiddenFiles
.includes(j
)) &&
142 (p
!= V
.BISHOP
|| (i
+ j
) % 2 != forbiddenColor
)
144 // Ok, move is valid:
155 start: { x: x
, y: y
},
162 moves
.forEach(m
=> { m
.end
.noHighlight
= true; });
167 if (this.movesCount
<= 1) return false;
168 return super.underCheck(color
);
172 if (this.movesCount
>= 2) return super.getAllValidMoves();
173 const color
= this.turn
;
175 for (let i
= 0; i
< V
.RESERVE_PIECES
.length
; i
++) {
176 moves
= moves
.concat(
177 this.getPotentialMovesFrom([V
.size
.x
+ (color
== "w" ? 0 : 1), i
])
180 return this.filterValid(moves
);
184 const color
= move.appear
[0].c
;
185 if (this.movesCount
<= 1) {
186 V
.PlayOnBoard(this.board
, move);
187 const piece
= move.appear
[0].p
;
188 this.reserve
[color
][piece
]--;
189 if (piece
== V
.KING
) this.kingPos
[color
] = [move.end
.x
, move.end
.y
];
190 if (this.subTurn
== 16) {
191 // All placement moves are done
193 this.turn
= V
.GetOppCol(color
);
194 if (this.movesCount
== 1) this.subTurn
= 1;
196 // Initial placement is over
197 delete this["reserve"];
198 delete this["subTurn"];
204 if (this.movesCount
== 2) this.re_setEnlightened(false);
210 const color
= move.appear
[0].c
;
211 if (this.movesCount
<= 2) {
212 V
.UndoOnBoard(this.board
, move);
213 const piece
= move.appear
[0].p
;
214 if (piece
== V
.KING
) this.kingPos
[color
] = [-1, -1];
215 if (!this.subTurn
|| this.subTurn
== 1) {
216 // All placement moves are undone (if any)
217 if (!this.subTurn
) this.re_setReserve(16);
218 else this.subTurn
= 16;
220 if (this.movesCount
== 1) this.re_setEnlightened(true);
224 this.reserve
[color
][piece
]++;
226 else super.undo(move);
230 if (this.movesCount
<= 1) return [];
231 return super.getCheckSquares();
235 if (this.movesCount
<= 1) return "*";
236 return super.getCurrentScore();
240 if (this.movesCount
>= 2) return super.getComputerMove();
241 // Play a random "initialization move"
243 for (let i
=0; i
<16; i
++) {
244 const moves
= this.getAllValidMoves();
245 const moveIdx
= randInt(moves
.length
);
246 this.play(moves
[moveIdx
]);
247 res
.push(moves
[moveIdx
]);
249 for (let i
=15; i
>=0; i
--) this.undo(res
[i
]);
254 // Do not note placement moves (complete move would be too long)
255 if (move.vanish
.length
== 0) return "";
256 return super.getNotation(move);