Start working on Convert variant
[xogo.git] / variants / Alice / class.js
1 import ChessRules from "/base_rules.js";
2 import {ArrayFun} from "/utils/array.js";
3
4 export default class AliceRules extends ChessRules {
5
6 static get Options() {
7 return {
8 select: C.Options.select,
9 input: C.Options.input,
10 styles: [
11 "balance",
12 "capture",
13 "cylinder",
14 "dark",
15 "doublemove",
16 "progressive",
17 "zen"
18 ]
19 };
20 }
21
22 // To the other side of the mirror and back...
23 static get ALICE_PIECES() {
24 return {
25 s: "p",
26 u: "r",
27 o: "n",
28 c: "b",
29 t: "q",
30 l: "k"
31 };
32 }
33 static get ALICE_CODES() {
34 return {
35 p: "s",
36 r: "u",
37 n: "o",
38 b: "c",
39 q: "t",
40 k: "l"
41 };
42 }
43
44 isKing(x, y, p) {
45 if (!p)
46 p = this.getPiece(x, y);
47 return ['k', 'l'].includes(p);
48 }
49
50 pieces(color, x, y) {
51 let alices = {
52 's': {"class": "alice-pawn", moveas: 'p'},
53 'u': {"class": "alice-rook", moveas: 'r'},
54 'o': {"class": "alice-knight", moveas: 'n'},
55 'c': {"class": "alice-bishop", moveas: 'b'},
56 't': {"class": "alice-queen", moveas: 'q'},
57 'l': {"class": "alice-king", moveas: 'k'}
58 };
59 return Object.assign(alices, super.pieces(color, x, y));
60 }
61
62 fromSameWorld(p1, p2) {
63 return (
64 (V.ALICE_PIECES[p1] && V.ALICE_PIECES[p2]) ||
65 (V.ALICE_CODES[p1] && V.ALICE_CODES[p2])
66 );
67 }
68
69 // Step of p over i,j ?
70 canStepOver(i, j, p) {
71 return (
72 this.board[i][j] == "" || !this.fromSameWorld(this.getPiece(i, j), p));
73 }
74
75 getPotentialMovesFrom([x, y]) {
76 return super.getPotentialMovesFrom([x, y]).filter(m => {
77 // Remove moves landing on occupied square on other board
78 return (
79 this.board[m.end.x][m.end.y] == "" ||
80 this.fromSameWorld(m.vanish[0].p, m.vanish[1].p)
81 );
82 }).map(m => {
83 // Apply Alice rule: go to the other side of the mirror
84 if (Object.keys(V.ALICE_CODES).includes(m.vanish[0].p))
85 // Board 1
86 m.appear.forEach(a => a.p = V.ALICE_CODES[a.p])
87 else
88 // Board 2
89 m.appear.forEach(a => a.p = V.ALICE_PIECES[a.p])
90 return m;
91 });
92 }
93
94 // helper for filterValid
95 toggleWorld(x, y) {
96 const piece = this.getPiece(x, y);
97 if (V.ALICE_PIECES[piece])
98 // From the other side of the mirror
99 this.board[x][y] = this.getColor(x, y) + V.ALICE_PIECES[piece];
100 else
101 // From the other other side :)
102 this.board[x][y] = this.getColor(x, y) + V.ALICE_CODES[piece];
103 }
104
105 filterValid(moves) {
106 const color = this.turn;
107 const oppCol = C.GetOppTurn(color);
108 const kingPos = this.searchKingPos(color)[0];
109 const kingPiece = this.getPiece(kingPos[0], kingPos[1]);
110 return super.filterValid(moves).filter(m => {
111 // A move must also be legal on the board it is played:
112 // Shortcut if the moving piece and king are on different sides
113 if (
114 !this.isKing(0, 0, m.vanish[0].p) &&
115 !this.fromSameWorld(kingPiece, m.vanish[0].p)
116 ) {
117 return true;
118 }
119 this.playOnBoard(m);
120 m.appear.forEach(a => this.toggleWorld(a.x, a.y));
121 const kingAppear = m.appear.find(a => this.isKing(0, 0, a.p));
122 const target = [kingAppear ? [kingAppear.x, kingAppear.y] : kingPos];
123 const res = this.underCheck(target, oppCol);
124 m.appear.forEach(a => this.toggleWorld(a.x, a.y));
125 this.undoOnBoard(m);
126 return !res;
127 });
128 }
129
130 };