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