1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
3 export class SittuyinRules
extends ChessRules
{
4 static get HasFlags() {
8 static get HasEnpassant() {
12 static get PawnSpecs() {
18 // Promotions are handled differently here
24 static GenRandInitFen() {
25 return "8/8/4pppp/pppp4/4PPPP/PPPP4/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);
48 this.subTurn
= subTurn
|| 1;
51 setOtherVariables(fen
) {
52 super.setOtherVariables(fen
);
53 if (this.movesCount
<= 1) this.re_setReserve();
57 return "Sittuyin/" + b
;
61 if (i
>= V
.size
.x
) return i
== V
.size
.x
? "w" : "b";
62 return this.board
[i
][j
].charAt(0);
66 if (i
>= V
.size
.x
) return V
.RESERVE_PIECES
[j
];
67 return this.board
[i
][j
].charAt(1);
70 getReservePpath(index
, color
) {
71 return "Sittuyin/" + color
+ V
.RESERVE_PIECES
[index
];
74 static get RESERVE_PIECES() {
75 return [V
.ROOK
, V
.KNIGHT
, V
.BISHOP
, V
.QUEEN
, V
.KING
];
78 getPotentialMovesFrom([x
, y
]) {
79 if (this.movesCount
<= 1) {
80 const color
= this.turn
;
81 const p
= V
.RESERVE_PIECES
[y
];
82 if (this.reserve
[color
][p
] == 0) return [];
85 ? (color
== 'w' ? [4, 7] : [0, 3])
86 : (color
== 'w' ? [7, 7] : [0, 0]);
87 const jBound
= (i
) => {
88 if (color
== 'w' && i
== 4) return [4, 7];
89 if (color
== 'b' && i
== 3) return [0, 3];
93 for (let i
= iBound
[0]; i
<= iBound
[1]; i
++) {
95 for (let j
= jb
[0]; j
<= jb
[1]; j
++) {
96 if (this.board
[i
][j
] == V
.EMPTY
) {
107 start: { x: x
, y: y
},
116 return super.getPotentialMovesFrom([x
, y
]);
119 getPotentialPawnMoves([x
, y
]) {
120 const color
= this.turn
;
121 const [sizeX
, sizeY
] = [V
.size
.x
, V
.size
.y
];
122 const shiftX
= V
.PawnSpecs
.directions
[color
];
124 // NOTE: next condition is generally true (no pawn on last rank)
125 if (x
+ shiftX
>= 0 && x
+ shiftX
< sizeX
) {
126 if (this.board
[x
+ shiftX
][y
] == V
.EMPTY
) {
127 // One square forward
128 moves
.push(this.getBasicMove([x
, y
], [x
+ shiftX
, y
]));
131 if (V
.PawnSpecs
.canCapture
) {
132 for (let shiftY
of [-1, 1]) {
138 this.board
[x
+ shiftX
][y
+ shiftY
] != V
.EMPTY
&&
139 this.canTake([x
, y
], [x
+ shiftX
, y
+ shiftY
])
141 moves
.push(this.getBasicMove([x
, y
], [x
+ shiftX
, y
+ shiftY
]));
147 let queenOnBoard
= false;
149 outerLoop: for (let i
=0; i
<8; i
++) {
150 for (let j
=0; j
<8; j
++) {
151 if (this.board
[i
][j
] != V
.EMPTY
&& this.getColor(i
, j
) == color
) {
152 const p
= this.getPiece(i
, j
);
157 else if (p
== V
.PAWN
&& pawnsCount
<= 1) pawnsCount
++;
165 (color
== 'w' && ((y
<= 3 && x
== y
) || (y
>= 4 && x
== 7 - y
))) ||
166 (color
== 'b' && ((y
>= 4 && x
== y
) || (y
<= 3 && x
== 7 - y
)))
169 // Add potential promotions
170 const addPromotion
= ([xx
, yy
], moveTo
) => {
175 x: !!moveTo
? xx : x
,
176 y: yy
, //yy == y if !!moveTo
189 start: { x: x
, y: y
},
190 end: { x: xx
, y: yy
}
194 // In-place promotion always possible:
195 addPromotion([x
- shiftX
, y
]);
196 for (let step
of V
.steps
[V
.BISHOP
]) {
197 const [i
, j
] = [x
+ step
[0], y
+ step
[1]];
198 if (V
.OnBoard(i
, j
) && this.board
[i
][j
] != V
.EMPTY
)
199 addPromotion([i
, j
], "moveTo");
205 getPotentialBishopMoves(sq
) {
206 const forward
= (this.turn
== 'w' ? -1 : 1);
207 return this.getSlideNJumpMoves(
209 V
.steps
[V
.BISHOP
].concat([ [forward
, 0] ]),
214 getPotentialQueenMoves(sq
) {
215 return this.getSlideNJumpMoves(
222 isAttackedByBishop(sq
, color
) {
223 const forward
= (this.turn
== 'w' ? 1 : -1);
224 return this.isAttackedBySlideNJump(
228 V
.steps
[V
.BISHOP
].concat([ [forward
, 0] ]),
233 isAttackedByQueen(sq
, color
) {
234 return this.isAttackedBySlideNJump(
244 if (this.movesCount
<= 1) return false;
245 return super.underCheck(color
);
249 const color
= move.appear
[0].c
;
250 if (this.movesCount
<= 1) {
251 V
.PlayOnBoard(this.board
, move);
252 const piece
= move.appear
[0].p
;
253 this.reserve
[color
][piece
]--;
254 if (piece
== V
.KING
) this.kingPos
[color
] = [move.end
.x
, move.end
.y
];
255 if (this.subTurn
== 8) {
256 // All placement moves are done
258 this.turn
= V
.GetOppCol(color
);
259 if (this.movesCount
== 1) this.subTurn
= 1;
261 // Initial placement is over
262 delete this["reserve"];
263 delete this["subTurn"];
268 else super.play(move);
272 const color
= move.appear
[0].c
;
273 if (this.movesCount
<= 2) {
274 V
.UndoOnBoard(this.board
, move);
275 const piece
= move.appear
[0].p
;
276 if (piece
== V
.KING
) this.kingPos
[color
] = [-1, -1];
277 if (!this.subTurn
|| this.subTurn
== 1) {
278 // All placement moves are undone (if any)
279 if (!this.subTurn
) this.re_setReserve(8);
280 else this.subTurn
= 8;
285 this.reserve
[color
][piece
]++;
287 else super.undo(move);
291 if (this.movesCount
<= 1) return [];
292 return super.getCheckSquares();
296 if (this.movesCount
<= 1) return "*";
297 return super.getCurrentScore();
300 static get VALUES() {
312 // Do not note placement moves (complete move would be too long)
313 if (move.vanish
.length
== 0) return "";
314 return super.getNotation(move);