Fix Omega promotions
[vchess.git] / client / src / variants / Minishogi.js
1 import { ChessRules, PiPo, Move } from "@/base_rules";
2 import { ShogiRules } from "@/variants/Shogi";
3
4 export class MinishogiRules extends ShogiRules {
5 static IsGoodFen(fen) {
6 if (!ChessRules.IsGoodFen(fen)) return false;
7 const fenParsed = V.ParseFen(fen);
8 // 3) Check reserves
9 if (!fenParsed.reserve || !fenParsed.reserve.match(/^[0-9]{10,10}$/))
10 return false;
11 return true;
12 }
13
14 // No knight or lance
15 static get PIECES() {
16 return [
17 ChessRules.PAWN,
18 ChessRules.ROOK,
19 ChessRules.BISHOP,
20 ChessRules.KING,
21 V.GOLD_G,
22 V.SILVER_G,
23 V.P_PAWN,
24 V.P_SILVER,
25 V.P_ROOK,
26 V.P_BISHOP
27 ];
28 }
29
30 static GenRandInitFen() {
31 return "rbsgk/4p/5/P4/KGSBR w 0 0000000000";
32 }
33
34 getReserveFen() {
35 let counts = new Array(10);
36 for (let i = 0; i < V.RESERVE_PIECES.length; i++) {
37 counts[i] = this.reserve["w"][V.RESERVE_PIECES[i]];
38 counts[5 + i] = this.reserve["b"][V.RESERVE_PIECES[i]];
39 }
40 return counts.join("");
41 }
42
43 setOtherVariables(fen) {
44 super.setOtherVariables(fen);
45 // Also init reserves (used by the interface to show landable pieces)
46 const reserve =
47 V.ParseFen(fen).reserve.split("").map(x => parseInt(x, 10));
48 this.reserve = {
49 w: {
50 [V.PAWN]: reserve[0],
51 [V.ROOK]: reserve[1],
52 [V.BISHOP]: reserve[2],
53 [V.GOLD_G]: reserve[3],
54 [V.SILVER_G]: reserve[4]
55 },
56 b: {
57 [V.PAWN]: reserve[5],
58 [V.ROOK]: reserve[6],
59 [V.BISHOP]: reserve[7],
60 [V.GOLD_G]: reserve[8],
61 [V.SILVER_G]: reserve[9]
62 }
63 };
64 }
65
66 static get size() {
67 return { x: 5, y: 5 };
68 }
69
70 static get RESERVE_PIECES() {
71 return (
72 [V.PAWN, V.ROOK, V.BISHOP, V.GOLD_G, V.SILVER_G]
73 );
74 }
75
76 getReserveMoves([x, y]) {
77 const color = this.turn;
78 const p = V.RESERVE_PIECES[y];
79 if (p == V.PAWN) {
80 var oppCol = V.GetOppCol(color);
81 var allowedFiles =
82 [...Array(5).keys()].filter(j =>
83 [...Array(5).keys()].every(i => {
84 return (
85 this.board[i][j] == V.EMPTY ||
86 this.getColor(i, j) != color ||
87 this.getPiece(i, j) != V.PAWN
88 );
89 })
90 )
91 }
92 if (this.reserve[color][p] == 0) return [];
93 let moves = [];
94 const forward = color == 'w' ? -1 : 1;
95 const lastRank = color == 'w' ? 0 : 4;
96 for (let i = 0; i < V.size.x; i++) {
97 if (p == V.PAWN && i == lastRank) continue;
98 for (let j = 0; j < V.size.y; j++) {
99 if (
100 this.board[i][j] == V.EMPTY &&
101 (p != V.PAWN || allowedFiles.includes(j))
102 ) {
103 let mv = new Move({
104 appear: [
105 new PiPo({
106 x: i,
107 y: j,
108 c: color,
109 p: p
110 })
111 ],
112 vanish: [],
113 start: { x: x, y: y }, //a bit artificial...
114 end: { x: i, y: j }
115 });
116 if (p == V.PAWN) {
117 // Do not drop on checkmate:
118 this.play(mv);
119 const res = (this.underCheck(oppCol) && !this.atLeastOneMove());
120 this.undo(mv);
121 if (res) continue;
122 }
123 moves.push(mv);
124 }
125 }
126 }
127 return moves;
128 }
129
130 getSlideNJumpMoves([x, y], steps, options) {
131 options = options || {};
132 const color = this.turn;
133 const oneStep = options.oneStep;
134 const forcePromoteOnLastRank = options.force;
135 const promoteInto = options.promote;
136 const lastRank = (color == 'w' ? 0 : 4);
137 let moves = [];
138 outerLoop: for (let step of steps) {
139 let i = x + step[0];
140 let j = y + step[1];
141 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
142 if (i != lastRank || !forcePromoteOnLastRank)
143 moves.push(this.getBasicMove([x, y], [i, j]));
144 if (i == lastRank && !!promoteInto) {
145 moves.push(
146 this.getBasicMove(
147 [x, y], [i, j], { c: color, p: promoteInto })
148 );
149 }
150 if (oneStep) continue outerLoop;
151 i += step[0];
152 j += step[1];
153 }
154 if (V.OnBoard(i, j) && this.canTake([x, y], [i, j])) {
155 if (i != lastRank || !forcePromoteOnLastRank)
156 moves.push(this.getBasicMove([x, y], [i, j]));
157 if (i == lastRank && !!promoteInto) {
158 moves.push(
159 this.getBasicMove(
160 [x, y], [i, j], { c: color, p: promoteInto })
161 );
162 }
163 }
164 }
165 return moves;
166 }
167
168 static get SEARCH_DEPTH() {
169 return 3;
170 }
171 };