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