1 import { ChessRules
} from "@/base_rules";
3 export class Pacifist1Rules
extends ChessRules
{
4 static get PawnSpecs() {
12 static get HasEnpassant() {
16 static IsGoodPosition(position
) {
17 if (position
.length
== 0) return false;
18 const rows
= position
.split("/");
19 if (rows
.length
!= V
.size
.x
) return false;
21 for (let row
of rows
) {
23 for (let i
= 0; i
< row
.length
; i
++) {
24 if (['K','k'].includes(row
[i
])) kingsCount
++;
25 if (V
.PIECES
.includes(row
[i
].toLowerCase())) sumElts
++;
27 const num
= parseInt(row
[i
], 10);
28 if (isNaN(num
)) return false;
32 if (sumElts
!= V
.size
.y
) return false;
34 // Both kings should be on board. May be of the same color.
35 if (kingsCount
!= 2) return false;
40 // Kings may be swapped, so they are not tracked (no kingPos)
41 this.INIT_COL_KING
= { w: -1, b: -1 };
42 const fenRows
= V
.ParseFen(fen
).position
.split("/");
43 const startRow
= { 'w': V
.size
.x
- 1, 'b': 0 };
44 for (let i
= 0; i
< fenRows
.length
; i
++) {
45 let k
= 0; //column index on board
46 for (let j
= 0; j
< fenRows
[i
].length
; j
++) {
47 switch (fenRows
[i
].charAt(j
)) {
49 this.INIT_COL_KING
["b"] = k
;
52 this.INIT_COL_KING
["w"] = k
;
55 const num
= parseInt(fenRows
[i
].charAt(j
), 10);
56 if (!isNaN(num
)) k
+= num
- 1;
64 // Sum white pieces attacking a square, and remove black pieces count.
66 const getSign
= (color
) => {
67 return (color
== 'w' ? 1 : -1);
71 V
.steps
[V
.KNIGHT
].forEach(s
=> {
72 const [i
, j
] = [x
+ s
[0], y
+ s
[1]];
73 if (V
.OnBoard(i
, j
) && this.getPiece(i
, j
) == V
.KNIGHT
)
74 res
+= getSign(this.getColor(i
, j
));
77 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]).forEach(s
=> {
78 const [i
, j
] = [x
+ s
[0], y
+ s
[1]];
79 if (V
.OnBoard(i
, j
) && this.getPiece(i
, j
) == V
.KING
)
80 res
+= getSign(this.getColor(i
, j
));
83 for (let c
of ['w', 'b']) {
84 for (let shift
of [-1, 1]) {
85 const sign
= getSign(c
);
86 const [i
, j
] = [x
+ sign
, y
+ shift
];
89 this.getPiece(i
, j
) == V
.PAWN
&&
90 this.getColor(i
, j
) == c
96 // Other pieces (sliders):
97 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]).forEach(s
=> {
98 let [i
, j
] = [x
+ s
[0], y
+ s
[1]];
99 let compatible
= [V
.QUEEN
];
100 compatible
.push(s
[0] == 0 || s
[1] == 0 ? V
.ROOK : V
.BISHOP
);
101 let firstCol
= undefined;
102 while (V
.OnBoard(i
, j
)) {
103 if (this.board
[i
][j
] != V
.EMPTY
) {
104 if (!(compatible
.includes(this.getPiece(i
, j
)))) break;
105 const colIJ
= this.getColor(i
, j
);
106 if (!firstCol
) firstCol
= colIJ
;
107 if (colIJ
== firstCol
) res
+= getSign(colIJ
);
117 getPotentialMovesFrom([x
, y
]) {
118 let moves
= super.getPotentialMovesFrom([x
, y
]);
119 const color
= this.turn
;
120 const oppCol
= V
.GetOppCol(color
);
121 if (this.getPiece(x
, y
) == V
.PAWN
) {
122 // Pawns cannot move 2 squares if the intermediate is overly persuaded
123 moves
= moves
.filter(m
=> {
124 if (Math
.abs(m
.end
.x
- m
.start
.x
) == 2) {
125 const [i
, j
] = [(m
.start
.x
+ m
.end
.x
) / 2, y
];
126 const persuasion
= this.sumAttacks([i
, j
]);
128 color
== 'w' && persuasion
>= 0 ||
129 color
== 'b' && persuasion
<= 0
135 // Potentially flipped (opp) pieces
137 for (let i
=0; i
<8; i
++) {
138 for (let j
=0; j
<8; j
++) {
139 if (this.board
[i
][j
] != V
.EMPTY
&& this.getColor(i
, j
) == oppCol
)
140 targets
.push([i
, j
]);
144 // Start persuading other pieces: loop until nothing changes
145 V
.PlayOnBoard(this.board
, m
);
148 targets
.forEach(t
=> {
149 if (this.getColor(t
[0], t
[1]) == oppCol
) {
150 const sqAttacks
= this.sumAttacks([t
[0], t
[1]]);
152 (oppCol
== 'w' && sqAttacks
< 0) ||
153 (oppCol
== 'b' && sqAttacks
> 0)
159 if (persuaded
.length
== 0) break;
160 persuaded
.forEach(p
=> {
161 this.board
[p
[0]][p
[1]] = color
+ this.getPiece(p
[0], p
[1]);
164 V
.UndoOnBoard(this.board
, m
);
165 // Reset pieces colors + adjust move (flipped pieces)
166 targets
.forEach(t
=> {
167 if (this.getColor(t
[0], t
[1]) == color
) {
168 const piece
= this.getPiece(t
[0], t
[1]);
169 m
.appear
.push({ x: t
[0], y: t
[1], c: color
, p: piece
});
170 m
.vanish
.push({ x: t
[0], y: t
[1], c: oppCol
, p: piece
});
171 this.board
[t
[0]][t
[1]] = oppCol
+ piece
;
178 getSlideNJumpMoves([x
, y
], steps
, oneStep
) {
180 outerLoop: for (let loop
= 0; loop
< steps
.length
; loop
++) {
181 const step
= steps
[loop
];
184 while (V
.OnBoard(i
, j
) && this.board
[i
][j
] == V
.EMPTY
) {
185 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
186 if (oneStep
) continue outerLoop
;
196 // Find the king(s) and determine if it (both) is persuaded.
197 // If yes, "under check"
199 for (let i
=0; i
<8; i
++) {
200 for (let j
=0; j
<8; j
++) {
201 if (this.getPiece(i
, j
) == V
.KING
&& this.getColor(i
, j
) == color
)
202 kingPos
.push([i
, j
]);
205 return kingPos
.every(kp
=> {
206 const persuasion
= this.sumAttacks(kp
);
208 (color
== 'w' && persuasion
< 0) ||
209 (color
== 'b' && persuasion
> 0)
215 const fmoves
= super.filterValid(moves
);
216 const color
= this.turn
;
217 // If the king isn't here, only moves persuading a king are valid
218 const kingHere
= this.board
.some(b
=>
219 b
.some(cell
=> cell
[0] == color
&& cell
[1] == V
.KING
)
223 fmoves
.filter(m
=> m
.appear
.some(a
=> a
.c
== color
&& a
.p
== V
.KING
))
230 // There are not really "checks": just color change
235 const color
= this.turn
;
236 // TODO: if no king of turn color, and no move to get one, then it's lost
237 // otherwise 1/2 if no moves, or "*"
238 const kingHere
= this.board
.some(b
=>
239 b
.some(cell
=> cell
[0] == color
&& cell
[1] == V
.KING
)
242 if (this.atLeastOneMove()) return "*";
245 // No king was found: try to convert one
246 const moves
= this.getAllValidMoves();
248 moves
.some(m
=> m
.appear
.some(a
=> a
.c
== color
&& a
.p
== V
.KING
))
250 : (color
== 'w' ? "0-1" : "1-0")
255 this.updateCastleFlags(move, move.vanish
[0].p
);
260 static get SEARCH_DEPTH() {