Pandemonium 1 & 2, Stealthbomb 1 & 2
[vchess.git] / client / src / variants / Konane.js
1 import { ChessRules, Move, PiPo } from "@/base_rules";
2 import { randInt } from "@/utils/alea";
3
4 export class KonaneRules extends ChessRules {
5
6 static get HasFlags() {
7 return false;
8 }
9
10 static get HasEnpassant() {
11 return false;
12 }
13
14 static get ReverseColors() {
15 return true;
16 }
17
18 getPiece() {
19 return V.PAWN;
20 }
21
22 getPpath(b) {
23 return "Konane/" + b;
24 }
25
26 static IsGoodPosition(position) {
27 if (position.length == 0) return false;
28 const rows = position.split("/");
29 if (rows.length != V.size.x) return false;
30 for (let row of rows) {
31 let sumElts = 0;
32 for (let i = 0; i < row.length; i++) {
33 if (row[i].toLowerCase() == V.PAWN) sumElts++;
34 else {
35 const num = parseInt(row[i], 10);
36 if (isNaN(num) || num <= 0) return false;
37 sumElts += num;
38 }
39 }
40 if (sumElts != V.size.y) return false;
41 }
42 return true;
43 }
44
45 static GenRandInitFen() {
46 return (
47 "PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/" +
48 "PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP w 0"
49 );
50 }
51
52 hoverHighlight([x, y], side) {
53 const c = this.turn;
54 if (this.movesCount >= 2 || (!!side && side != c)) return false;
55 if (c == 'w') return (x == y && [0, 3, 4, 7].includes(x));
56 // "Black": search for empty square and allow nearby
57 for (let i of [0, 3, 4, 7]) {
58 if (this.board[i][i] == V.EMPTY)
59 return (Math.abs(x - i) + Math.abs(y - i) == 1)
60 }
61 }
62
63 onlyClick([x, y]) {
64 return (
65 this.movesCount <= 1 ||
66 // TODO: next line theoretically shouldn't be required...
67 (this.movesCount == 2 && this.getColor(x, y) != this.turn)
68 );
69 }
70
71 doClick([x, y]) {
72 if (this.movesCount >= 2) return null;
73 const color = this.turn;
74 if (color == 'w') {
75 if (x != y || ![0, 3, 4, 7].includes(x)) return null;
76 return new Move({
77 appear: [],
78 vanish: [ new PiPo({ x: x, y: y, c: color, p: V.PAWN }) ],
79 end: { x: x, y: y }
80 });
81 }
82 // "Black": search for empty square and allow nearby
83 for (let i of [0, 3, 4, 7]) {
84 if (this.board[i][i] == V.EMPTY) {
85 if (Math.abs(x - i) + Math.abs(y - i) != 1) return null;
86 return new Move({
87 appear: [],
88 vanish: [ new PiPo({ x: x, y: y, c: color, p: V.PAWN }) ],
89 end: { x: x, y: y }
90 });
91 }
92 }
93 }
94
95 getPotentialMovesFrom([x, y]) {
96 if (this.movesCount <= 1) {
97 const mv = this.doClick([x, y]);
98 return (!!mv ? [mv] : []);
99 }
100 const color = this.turn;
101 const oppCol = V.GetOppCol(color);
102 let moves = [];
103 for (let s of V.steps[V.ROOK]) {
104 let curmv = new Move({
105 appear: [ new PiPo({ x: -1, y: -1, c: color, p: V.PAWN }) ],
106 vanish: [ new PiPo({ x: x, y: y, c: color, p: V.PAWN }) ]
107 });
108 for (let mult = 2; ; mult += 2) {
109 let [i, j] = [x + mult * s[0], y + mult * s[1]];
110 if (
111 V.OnBoard(i, j) &&
112 this.board[i][j] == V.EMPTY &&
113 this.board[i - s[0]][j - s[1]] != V.EMPTY &&
114 this.getColor(i - s[0], j - s[1]) == oppCol
115 ) {
116 curmv.vanish.push(
117 new PiPo({ x: i - s[0], y: j - s[1], c: oppCol, p: V.PAWN }));
118 let mv = JSON.parse(JSON.stringify(curmv));
119 mv.appear[0].x = i;
120 mv.appear[0].y = j;
121 mv.end = { x: i, y: j };
122 moves.push(mv);
123 }
124 else break;
125 }
126 }
127 return moves;
128 }
129
130 filterValid(moves) {
131 return moves;
132 }
133
134 getCheckSquares() {
135 return [];
136 }
137
138 getCurrentScore() {
139 if (this.atLeastOneMove()) return "*";
140 return (this.turn == "w" ? "0-1" : "1-0");
141 }
142
143 static get SEARCH_DEPTH() {
144 return 4;
145 }
146
147 getNotation(move) {
148 if (this.movesCount <= 1) return V.CoordsToSquare(move.start) + "X";
149 if (move.vanish.length == 0) return "end";
150 return V.CoordsToSquare(move.start) + V.CoordsToSquare(move.end);
151 }
152
153 };