1 import { ChessRules
} from "@/base_rules";
2 import { ArrayFun
} from "@/utils/array";
3 import { randInt
} from "@/utils/alea";
5 export class OrdaRules
extends ChessRules
{
7 static get PawnSpecs() {
11 { promotions: [V
.QUEEN
, V
.KHESHIG
] }
15 static IsGoodFlags(flags
) {
16 // Only white can castle
17 return !!flags
.match(/^[a-z]{2,2}$/);
21 if (b
[0] == 'b' || b
[1] == 'h')
22 // Horde piece or white promoted pawn in kheshig
27 static GenRandInitFen(randomness
) {
29 return "lhaykahl/8/pppppppp/8/8/8/PPPPPPPP/RNBQKBNR w 0 ah -";
31 // Mapping kingdom --> horde:
40 const baseFen
= ChessRules
.GenRandInitFen(randomness
);
42 baseFen
.substr(0, 8).split('').map(p
=> piecesMap
[p
]).join('') +
43 // Skip 3 first rows + black castle flags
44 "/8/pppppppp" + baseFen
.substr(19, 31) + " -"
49 return this.castleFlags
['w'].map(V
.CoordToColumn
).join("");
53 this.castleFlags
= { 'w': [-1, -1] };
54 for (let i
= 0; i
< 2; i
++)
55 this.castleFlags
['w'][i
] = V
.ColumnToCoord(fenflags
.charAt(i
));
64 static get KHESHIG() {
70 // Khan is technically a King, so let's keep things simple.
73 return ChessRules
.PIECES
.concat([V
.LANCER
, V
.ARCHER
, V
.KHESHIG
, V
.YURT
]);
76 getPotentialMovesFrom([x
, y
]) {
77 switch (this.getPiece(x
, y
)) {
79 return this.getPotentialLancerMoves([x
, y
]);
81 return this.getPotentialArcherMoves([x
, y
]);
83 return this.getPotentialKheshigMoves([x
, y
]);
85 return this.getPotentialYurtMoves([x
, y
]);
87 return super.getPotentialMovesFrom([x
, y
]);
92 getSlideNJumpMoves([x
, y
], steps
, oneStep
, options
) {
93 options
= options
|| {};
95 outerLoop: for (let step
of steps
) {
98 while (V
.OnBoard(i
, j
) && this.board
[i
][j
] == V
.EMPTY
) {
99 if (!options
.onlyTake
) moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
100 if (!!oneStep
) continue outerLoop
;
104 if (V
.OnBoard(i
, j
) && this.canTake([x
, y
], [i
, j
]) && !options
.onlyMove
)
105 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
110 getPotentialLancerMoves(sq
) {
111 const onlyMoves
= this.getSlideNJumpMoves(
117 const onlyTakes
= this.getSlideNJumpMoves(
123 return onlyMoves
.concat(onlyTakes
);
126 getPotentialArcherMoves(sq
) {
127 const onlyMoves
= this.getSlideNJumpMoves(
133 const onlyTakes
= this.getSlideNJumpMoves(
139 return onlyMoves
.concat(onlyTakes
);
142 getPotentialKheshigMoves(sq
) {
143 return super.getSlideNJumpMoves(
145 V
.steps
[V
.KNIGHT
].concat(V
.steps
[V
.ROOK
]).concat(V
.steps
[V
.BISHOP
]),
150 getPotentialYurtMoves(sq
) {
151 return super.getSlideNJumpMoves(
153 V
.steps
[V
.BISHOP
].concat([ [1, 0] ]),
158 getPotentialKingMoves([x
, y
]) {
159 if (this.getColor(x
, y
) == 'w') return super.getPotentialKingMoves([x
, y
]);
160 // Horde doesn't castle:
161 return super.getSlideNJumpMoves(
163 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]),
168 isAttacked(sq
, color
) {
171 super.isAttacked(sq
, color
) ||
172 this.isAttackedByKheshig(sq
, color
)
175 // Horde: only pawn, king and queen (if promotions) in common:
177 super.isAttackedByPawn(sq
, color
) ||
178 this.isAttackedByLancer(sq
, color
) ||
179 this.isAttackedByKheshig(sq
, color
) ||
180 this.isAttackedByArcher(sq
, color
) ||
181 this.isAttackedByYurt(sq
, color
) ||
182 super.isAttackedByKing(sq
, color
) ||
183 super.isAttackedByQueen(sq
, color
)
187 isAttackedByLancer(sq
, color
) {
188 return this.isAttackedBySlideNJump(sq
, color
, V
.LANCER
, V
.steps
[V
.ROOK
]);
191 isAttackedByArcher(sq
, color
) {
192 return this.isAttackedBySlideNJump(sq
, color
, V
.ARCHER
, V
.steps
[V
.BISHOP
]);
195 isAttackedByKheshig(sq
, color
) {
196 return super.isAttackedBySlideNJump(
200 V
.steps
[V
.KNIGHT
].concat(V
.steps
[V
.ROOK
]).concat(V
.steps
[V
.BISHOP
]),
205 isAttackedByYurt(sq
, color
) {
206 return super.isAttackedBySlideNJump(
210 V
.steps
[V
.BISHOP
].concat([ [1, 0] ]),
215 updateCastleFlags(move, piece
) {
216 // Only white can castle:
218 if (piece
== V
.KING
&& move.appear
[0].c
== 'w')
219 this.castleFlags
['w'] = [8, 8];
221 move.start
.x
== firstRank
&&
222 this.castleFlags
['w'].includes(move.start
.y
)
224 const flagIdx
= (move.start
.y
== this.castleFlags
['w'][0] ? 0 : 1);
225 this.castleFlags
['w'][flagIdx
] = 8;
228 move.end
.x
== firstRank
&&
229 this.castleFlags
['w'].includes(move.end
.y
)
231 const flagIdx
= (move.end
.y
== this.castleFlags
['w'][0] ? 0 : 1);
232 this.castleFlags
['w'][flagIdx
] = 8;
238 const color
= V
.GetOppCol(this.turn
);
239 const lastRank
= (color
== 'w' ? 0 : 7);
240 if (this.kingPos
[color
][0] == lastRank
)
241 // The opposing edge is reached!
242 return color
== "w" ? "1-0" : "0-1";
243 if (this.atLeastOneMove()) return "*";
245 const oppCol
= this.turn
;
246 if (!this.underCheck(oppCol
)) return "1/2";
247 return (oppCol
== "w" ? "0-1" : "1-0");
250 static get VALUES() {
251 return Object
.assign(