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