fa0bbcc45fcfe7042204317d9b77c867c16e44c0
1 import { ChessRules
} from "@/base_rules";
2 import { ArrayFun
} from "@/utils/array";
3 import { randInt
} from "@/utils/alea";
5 export class Antiking2Rules
extends ChessRules
{
7 static get ANTIKING() {
12 return ChessRules
.PIECES
.concat([V
.ANTIKING
]);
16 return b
[1] == "a" ? "Antiking/" + b : b
;
19 static IsGoodPosition(position
) {
20 if (!ChessRules
.IsGoodPosition(position
)) return false;
21 const rows
= position
.split("/");
22 // Check that exactly one antiking of each color is there:
23 let antikings
= { 'a': 0, 'A': 0 };
24 for (let row
of rows
) {
25 for (let i
= 0; i
< row
.length
; i
++)
26 if (['A','a'].includes(row
[i
])) antikings
[row
[i
]]++;
28 if (Object
.values(antikings
).some(v
=> v
!= 1)) return false;
32 setOtherVariables(fen
) {
33 super.setOtherVariables(fen
);
34 this.antikingPos
= { w: [-1, -1], b: [-1, -1] };
35 const rows
= V
.ParseFen(fen
).position
.split("/");
36 for (let i
= 0; i
< rows
.length
; i
++) {
38 for (let j
= 0; j
< rows
[i
].length
; j
++) {
39 switch (rows
[i
].charAt(j
)) {
41 this.antikingPos
["b"] = [i
, k
];
44 this.antikingPos
["w"] = [i
, k
];
47 const num
= parseInt(rows
[i
].charAt(j
), 10);
48 if (!isNaN(num
)) k
+= num
- 1;
56 canTake([x1
, y1
], [x2
, y2
]) {
57 const piece1
= this.getPiece(x1
, y1
);
58 const piece2
= this.getPiece(x2
, y2
);
59 const color1
= this.getColor(x1
, y1
);
60 const color2
= this.getColor(x2
, y2
);
64 (piece1
!= "a" && color1
!= color2
) ||
65 (piece1
== "a" && color1
== color2
)
70 getPotentialMovesFrom([x
, y
]) {
71 switch (this.getPiece(x
, y
)) {
73 return this.getPotentialAntikingMoves([x
, y
]);
75 return super.getPotentialMovesFrom([x
, y
]);
79 getPotentialAntikingMoves(sq
) {
80 // The antiking moves like a king (only captured colors differ)
81 return this.getSlideNJumpMoves(
82 sq
, V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1);
85 isAttacked(sq
, color
) {
87 super.isAttacked(sq
, color
) ||
88 this.isAttackedByAntiking(sq
, color
)
92 isAttackedByKing([x
, y
], color
) {
93 // Antiking is not attacked by king:
94 if (this.getPiece(x
, y
) == V
.ANTIKING
) return false;
95 return super.isAttackedByKing([x
, y
], color
);
98 isAttackedByAntiking([x
, y
], color
) {
99 // (Anti)King is not attacked by antiking
100 if ([V
.KING
, V
.ANTIKING
].includes(this.getPiece(x
, y
))) return false;
101 return this.isAttackedBySlideNJump(
102 [x
, y
], color
, V
.ANTIKING
, V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1);
106 const oppCol
= V
.GetOppCol(color
);
108 this.isAttacked(this.kingPos
[color
], oppCol
) ||
109 !this.isAttacked(this.antikingPos
[color
], oppCol
);
114 const color
= this.turn
;
116 const oppCol
= V
.GetOppCol(color
);
117 if (this.isAttacked(this.kingPos
[color
], oppCol
))
118 res
.push(JSON
.parse(JSON
.stringify(this.kingPos
[color
])));
119 if (!this.isAttacked(this.antikingPos
[color
], oppCol
))
120 res
.push(JSON
.parse(JSON
.stringify(this.antikingPos
[color
])));
125 super.postPlay(move);
126 const piece
= move.vanish
[0].p
;
127 const c
= move.vanish
[0].c
;
128 // Update antiking position
129 if (piece
== V
.ANTIKING
) {
130 this.antikingPos
[c
][0] = move.appear
[0].x
;
131 this.antikingPos
[c
][1] = move.appear
[0].y
;
136 super.postUndo(move);
137 const c
= move.vanish
[0].c
;
138 if (move.vanish
[0].p
== V
.ANTIKING
)
139 this.antikingPos
[c
] = [move.start
.x
, move.start
.y
];
142 static get VALUES() {
143 return Object
.assign(
149 static GenRandInitFen(options
) {
150 if (options
.randomness
== 0)
151 return "rnbqkbnr/pppppppp/3A4/8/8/3a4/PPPPPPPP/RNBQKBNR w 0 ahah -";
153 let pieces
= { w: new Array(8), b: new Array(8) };
155 let antikingPos
= { w: -1, b: -1 };
156 for (let c
of ["w", "b"]) {
157 if (c
== 'b' && options
.randomness
== 1) {
158 pieces
['b'] = pieces
['w'];
159 antikingPos
['b'] = antikingPos
['w'];
164 let positions
= ArrayFun
.range(8);
166 // Get random squares for bishops, but avoid corners; because,
167 // if an antiking blocks a cornered bishop, it can never be checkmated
168 let randIndex
= 2 * randInt(1, 4);
169 const bishop1Pos
= positions
[randIndex
];
170 let randIndex_tmp
= 2 * randInt(3) + 1;
171 const bishop2Pos
= positions
[randIndex_tmp
];
172 positions
.splice(Math
.max(randIndex
, randIndex_tmp
), 1);
173 positions
.splice(Math
.min(randIndex
, randIndex_tmp
), 1);
175 randIndex
= randInt(6);
176 const knight1Pos
= positions
[randIndex
];
177 positions
.splice(randIndex
, 1);
178 randIndex
= randInt(5);
179 const knight2Pos
= positions
[randIndex
];
180 positions
.splice(randIndex
, 1);
182 randIndex
= randInt(4);
183 const queenPos
= positions
[randIndex
];
184 positions
.splice(randIndex
, 1);
186 const rook1Pos
= positions
[0];
187 const kingPos
= positions
[1];
188 const rook2Pos
= positions
[2];
190 // Random squares for antikings
191 antikingPos
[c
] = randInt(8);
193 pieces
[c
][rook1Pos
] = "r";
194 pieces
[c
][knight1Pos
] = "n";
195 pieces
[c
][bishop1Pos
] = "b";
196 pieces
[c
][queenPos
] = "q";
197 pieces
[c
][kingPos
] = "k";
198 pieces
[c
][bishop2Pos
] = "b";
199 pieces
[c
][knight2Pos
] = "n";
200 pieces
[c
][rook2Pos
] = "r";
201 flags
+= V
.CoordToColumn(rook1Pos
) + V
.CoordToColumn(rook2Pos
);
203 const ranks23_black
=
205 (antikingPos
["w"] > 0 ? antikingPos
["w"] : "") +
207 (antikingPos
["w"] < 7 ? 7 - antikingPos
["w"] : "");
208 const ranks23_white
=
209 (antikingPos
["b"] > 0 ? antikingPos
["b"] : "") +
211 (antikingPos
["b"] < 7 ? 7 - antikingPos
["b"] : "") +
214 pieces
["b"].join("") +
220 pieces
["w"].join("").toUpperCase() +
221 " w 0 " + flags
+ " -"
225 static get SEARCH_DEPTH() {