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(options
) {
28 if (options
.randomness
== 0)
29 return "lhaykahl/8/pppppppp/8/8/8/PPPPPPPP/RNBQKBNR w 0 ah -";
31 // Mapping kingdom --> horde:
40 const baseFen
= ChessRules
.GenRandInitFen(options
);
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 // TODO: merge this extension into base_rules.js
93 getSlideNJumpMoves([x
, y
], steps
, oneStep
, options
) {
94 options
= options
|| {};
96 outerLoop: for (let step
of steps
) {
99 while (V
.OnBoard(i
, j
) && this.board
[i
][j
] == V
.EMPTY
) {
100 if (!options
.onlyTake
) moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
101 if (oneStep
) continue outerLoop
;
105 if (V
.OnBoard(i
, j
) && this.canTake([x
, y
], [i
, j
]) && !options
.onlyMove
)
106 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
111 getPotentialLancerMoves(sq
) {
112 const onlyMoves
= this.getSlideNJumpMoves(
113 sq
, V
.steps
[V
.KNIGHT
], "oneStep", { onlyMove: true });
114 const onlyTakes
= this.getSlideNJumpMoves(
115 sq
, V
.steps
[V
.ROOK
], null, { onlyTake: true });
116 return onlyMoves
.concat(onlyTakes
);
119 getPotentialArcherMoves(sq
) {
120 const onlyMoves
= this.getSlideNJumpMoves(
121 sq
, V
.steps
[V
.KNIGHT
], "oneStep", { onlyMove: true });
122 const onlyTakes
= this.getSlideNJumpMoves(
123 sq
, V
.steps
[V
.BISHOP
], null, { onlyTake: true });
124 return onlyMoves
.concat(onlyTakes
);
127 getPotentialKheshigMoves(sq
) {
129 V
.steps
[V
.KNIGHT
].concat(V
.steps
[V
.ROOK
]).concat(V
.steps
[V
.BISHOP
]);
130 return super.getSlideNJumpMoves(sq
, steps
, 1);
133 getPotentialYurtMoves(sq
) {
134 return super.getSlideNJumpMoves(
135 sq
, V
.steps
[V
.BISHOP
].concat([ [1, 0] ]), 1);
138 getPotentialKingMoves([x
, y
]) {
139 if (this.getColor(x
, y
) == 'w') return super.getPotentialKingMoves([x
, y
]);
140 // Horde doesn't castle:
141 return super.getSlideNJumpMoves(
142 [x
, y
], V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1);
145 isAttacked(sq
, color
) {
148 super.isAttacked(sq
, color
) ||
149 this.isAttackedByKheshig(sq
, color
)
152 // Horde: only pawn, king and queen (if promotions) in common:
154 super.isAttackedByPawn(sq
, color
) ||
155 this.isAttackedByLancer(sq
, color
) ||
156 this.isAttackedByKheshig(sq
, color
) ||
157 this.isAttackedByArcher(sq
, color
) ||
158 this.isAttackedByYurt(sq
, color
) ||
159 super.isAttackedByKing(sq
, color
) ||
160 super.isAttackedByQueen(sq
, color
)
164 isAttackedByLancer(sq
, color
) {
165 return this.isAttackedBySlideNJump(sq
, color
, V
.LANCER
, V
.steps
[V
.ROOK
]);
168 isAttackedByArcher(sq
, color
) {
169 return this.isAttackedBySlideNJump(sq
, color
, V
.ARCHER
, V
.steps
[V
.BISHOP
]);
172 isAttackedByKheshig(sq
, color
) {
174 V
.steps
[V
.KNIGHT
].concat(V
.steps
[V
.ROOK
]).concat(V
.steps
[V
.BISHOP
]);
175 return super.isAttackedBySlideNJump(sq
, color
, V
.KHESHIG
, steps
, 1);
178 isAttackedByYurt(sq
, color
) {
179 return super.isAttackedBySlideNJump(
180 sq
, color
, V
.YURT
, V
.steps
[V
.BISHOP
].concat([ [1, 0] ]), 1);
183 updateCastleFlags(move, piece
) {
184 // Only white can castle:
186 if (piece
== V
.KING
&& move.appear
[0].c
== 'w')
187 this.castleFlags
['w'] = [8, 8];
189 move.start
.x
== firstRank
&&
190 this.castleFlags
['w'].includes(move.start
.y
)
192 const flagIdx
= (move.start
.y
== this.castleFlags
['w'][0] ? 0 : 1);
193 this.castleFlags
['w'][flagIdx
] = 8;
196 move.end
.x
== firstRank
&&
197 this.castleFlags
['w'].includes(move.end
.y
)
199 const flagIdx
= (move.end
.y
== this.castleFlags
['w'][0] ? 0 : 1);
200 this.castleFlags
['w'][flagIdx
] = 8;
206 const color
= V
.GetOppCol(this.turn
);
207 const lastRank
= (color
== 'w' ? 0 : 7);
208 if (this.kingPos
[color
][0] == lastRank
)
209 // The opposing edge is reached!
210 return color
== "w" ? "1-0" : "0-1";
211 if (this.atLeastOneMove()) return "*";
213 const oppCol
= this.turn
;
214 if (!this.underCheck(oppCol
)) return "1/2";
215 return (oppCol
== "w" ? "0-1" : "1-0");
218 static get VALUES() {
219 return Object
.assign(