78d3d630dbfbc3cc536b5b4f1a1192db6c1c371b
[xogo.git] / variants / Ambiguous / class.js
1 import ChessRules from "/base_rules.js";
2 import { randInt, shuffle } from "@/utils/alea";
3 import { ArrayFun } from "@/utils/array";
4
5 export default class AmbiguousRules extends ChessRules {
6
7 // TODO: options
8
9 get hasFlags() {
10 return false;
11 }
12
13 setOtherVariables(fenParsed) {
14 super.setOtherVariables(fenParsed);
15 if (this.movesCount == 0)
16 this.subTurn = 2;
17 else
18 this.subTurn = 1;
19 }
20
21 genRandInitFen(seed) {
22 const gr = new GiveawayRules(
23 {mode: "suicide", options: this.options, genFenOnly: true});
24 return gr.genRandInitFen(seed);
25 }
26
27 // Subturn 1: play a move for the opponent on the designated square.
28 // Subturn 2: play a move for me (which just indicate a square).
29 getPotentialMovesFrom([x, y]) {
30 const color = this.turn;
31 const oppCol = V.GetOppCol(color);
32 if (this.subTurn == 2) {
33 // Just play a normal move (which in fact only indicate a square)
34 let movesHash = {};
35 return (
36 super.getPotentialMovesFrom([x, y])
37 .filter(m => {
38 // Filter promotions: keep only one, since no choice now.
39 if (m.appear[0].p != m.vanish[0].p) {
40 const hash = V.CoordsToSquare(m.start) + V.CoordsToSquare(m.end);
41 if (!movesHash[hash]) {
42 movesHash[hash] = true;
43 return true;
44 }
45 return false;
46 }
47 return true;
48 })
49 .map(m => {
50 if (m.vanish.length == 1) m.appear[0].p = V.GOAL;
51 else m.appear[0].p = V.TARGET_CODE[m.vanish[1].p];
52 m.appear[0].c = oppCol;
53 m.vanish.shift();
54 return m;
55 })
56 );
57 }
58 // At subTurn == 1, play a targeted move for opponent
59 // Search for target (we could also have it in a stack...)
60 let target = { x: -1, y: -1 };
61 outerLoop: for (let i = 0; i < V.size.x; i++) {
62 for (let j = 0; j < V.size.y; j++) {
63 if (this.board[i][j] != V.EMPTY) {
64 const piece = this.board[i][j][1];
65 if (
66 piece == V.GOAL ||
67 Object.keys(V.TARGET_DECODE).includes(piece)
68 ) {
69 target = { x: i, y: j};
70 break outerLoop;
71 }
72 }
73 }
74 }
75 // TODO: could be more efficient than generating all moves.
76 this.turn = oppCol;
77 const emptyTarget = (this.board[target.x][target.y][1] == V.GOAL);
78 if (emptyTarget) this.board[target.x][target.y] = V.EMPTY;
79 let moves = super.getPotentialMovesFrom([x, y]);
80 if (emptyTarget) {
81 this.board[target.x][target.y] = color + V.GOAL;
82 moves.forEach(m => {
83 m.vanish.push({
84 x: target.x,
85 y: target.y,
86 c: color,
87 p: V.GOAL
88 });
89 });
90 }
91 this.turn = color;
92 return moves.filter(m => m.end.x == target.x && m.end.y == target.y);
93 }
94
95 canIplay(x, y) {
96 const color = this.getColor(x, y);
97 return (
98 (this.subTurn == 1 && ![this.turn, this.playerColor].includes(color)) ||
99 (this.subTurn == 2 && super.canIplay(x, y))
100 );
101 }
102
103 // Code for empty square target
104 static get GOAL() {
105 return 'g';
106 }
107
108 static get TARGET_DECODE() {
109 return {
110 's': 'p',
111 't': 'q',
112 'u': 'r',
113 'o': 'n',
114 'c': 'b',
115 'l': 'k'
116 };
117 }
118
119 static get TARGET_CODE() {
120 return {
121 'p': 's',
122 'q': 't',
123 'r': 'u',
124 'n': 'o',
125 'b': 'c',
126 'k': 'l'
127 };
128 }
129
130 pieces() {
131 // .........
132 }
133
134 atLeastOneMove() {
135 // Since there are no checks this seems true (same as for Magnetic...)
136 return true;
137 }
138
139 filterValid(moves) {
140 return moves;
141 }
142
143 getCurrentScore() {
144 // This function is only called at subTurn 1
145 const color = V.GetOppCol(this.turn);
146 if (this.kingPos[color][0] < 0) return (color == 'w' ? "0-1" : "1-0");
147 return "*";
148 }
149
150 play(move) {
151 let kingCaptured = false;
152 if (this.subTurn == 1) {
153 this.prePlay(move);
154 this.epSquares.push(this.getEpSquare(move));
155 kingCaptured = this.kingPos[this.turn][0] < 0;
156 }
157 if (kingCaptured) move.kingCaptured = true;
158 V.PlayOnBoard(this.board, move);
159 if (this.subTurn == 2 || kingCaptured) {
160 this.turn = V.GetOppCol(this.turn);
161 this.movesCount++;
162 }
163 if (!kingCaptured) this.subTurn = 3 - this.subTurn;
164 }
165
166 };