Add Avalanche, write Avalam rules
[xogo.git] / variants / Avalanche / class.js
1 import ChessRules from "/base_rules.js";
2 import {Random} from "/utils/alea.js";
3 import PiPo from "/utils/PiPo.js";
4 import Move from "/utils/Move.js";
5
6 export default class AvalancheRules extends ChessRules {
7
8 static get Options() {
9 return {
10 select: C.Options.select,
11 styles: [
12 "atomic",
13 "cannibal",
14 "capture",
15 "crazyhouse",
16 "cylinder",
17 "dark",
18 "madrasi",
19 "recycle",
20 "rifle",
21 "teleport",
22 "zen"
23 ]
24 };
25 }
26
27 get hasEnpassant() {
28 return false;
29 }
30
31 getPartFen(o) {
32 return Object.assign(
33 {promotion: o.init ? false : this.promotion},
34 super.getPartFen(o)
35 );
36 }
37
38 setOtherVariables(fenParsed) {
39 super.setOtherVariables(fenParsed);
40 this.promotion = (fenParsed.promotion == '1');
41 this.subTurn = 1 - (this.promotion ? 1 : 0);
42 }
43
44 doClick(coords) {
45 const myLastRank = (this.turn == 'w' ? 0 : this.size.x - 1);
46 if (
47 this.subTurn != 0 ||
48 coords.x != myLastRank ||
49 this.getPiece(coords.x, coords.y) != 'p'
50 ) {
51 return null;
52 }
53 let moves = [];
54 this.pawnPromotions.forEach(pr => {
55 moves.push(
56 new Move({
57 vanish: [new PiPo({x: coords.x, y: coords.y, c: this.turn, p: 'p'})],
58 appear: [new PiPo({x: coords.x, y: coords.y, c: this.turn, p: pr})]
59 })
60 );
61 });
62 super.showChoices(moves);
63 }
64
65 canIplay(x, y) {
66 const pieceColor = this.getColor(x, y);
67 return (
68 this.playerColor == this.turn &&
69 (
70 (this.subTurn <= 1 && pieceColor == this.playerColor) ||
71 (
72 this.subTurn == 2 &&
73 pieceColor != this.playerColor &&
74 this.getPiece(x, y) == 'p'
75 )
76 )
77 );
78 }
79
80 getPotentialMovesFrom([x, y]) {
81 if (this.subTurn == 0)
82 return [];
83 if (this.subTurn == 1)
84 // Usual case:
85 return super.getPotentialMovesFrom([x, y]);
86 // subTurn == 2: only allowed to push an opponent's pawn (if possible)
87 const oppPawnShift = (this.turn == 'w' ? 1 : -1);
88 if (
89 this.onBoard(x + oppPawnShift, y) &&
90 this.board[x + oppPawnShift][y] == ""
91 ) {
92 return [this.getBasicMove([x, y], [x + oppPawnShift, y])];
93 }
94 return [];
95 }
96
97 filterValid(moves) {
98 if (this.subTurn != 1)
99 return moves; //self-checks by pawns are allowed
100 return super.filterValid(moves);
101 }
102
103 atLeastOnePawnPush(color) {
104 const pawnShift = (color == 'w' ? -1 : 1);
105 for (let i = 0; i < 8; i++) {
106 for (let j = 0; j < 8; j++) {
107 if (
108 this.board[i][j] != "" &&
109 this.getColor(i, j) == color &&
110 this.getPiece(i, j) == 'p' &&
111 this.board[i + pawnShift][j] == ""
112 ) {
113 return true;
114 }
115 }
116 }
117 return false;
118 }
119
120 postPlay(move) {
121 const color = this.turn;
122 const oppCol = C.GetOppCol(color);
123 this.promotion = (
124 this.subTurn == 2 &&
125 move.end.x == (oppCol == 'w' ? 0 : this.size.x - 1) &&
126 move.vanish[0].p == 'p'
127 );
128 if (this.subTurn == 0) {
129 this.subTurn++;
130 if (!this.atLeastOneMove(color)) {
131 move.result = "1/2"; //avoid re-computation
132 this.turn = oppCol;
133 }
134 }
135 else if (this.subTurn == 2) {
136 this.turn = oppCol;
137 this.subTurn = this.promotion ? 0 : 1;
138 }
139 else { //subTurn == 1, usual case
140 const kingCapture = this.searchKingPos(oppCol).length == 0;
141 if (kingCapture)
142 move.result = (color == 'w' ? "1-0" : "0-1");
143 if (!kingCapture && this.atLeastOnePawnPush(oppCol))
144 this.subTurn++;
145 else {
146 this.turn = oppCol;
147 this.subTurn = this.promotion ? 0 : 1;
148 }
149 }
150 }
151
152 atLeastOneMove(color, lastMove) {
153 if (this.subTurn == 0)
154 return true;
155 return super.atLeastOneMove(color);
156 }
157
158 };