1 import { ChessRules
} from "@/base_rules";
2 import { Antiking2Rules
} from "@/variants/Antiking2";
4 export class MesmerRules
extends ChessRules
{
6 static IsGoodFen(fen
) {
7 if (!ChessRules
.IsGoodFen(fen
)) return false;
8 const fenParsed
= V
.ParseFen(fen
);
9 // 5) Check arrival of last hypnotizing move (if any)
12 (fenParsed
.hSquare
!= "-" && !fenParsed
.hSquare
.match(/^[a-h][1-8]$/))
19 static get MESMERIST() {
24 return ChessRules
.PIECES
.concat([V
.MESMERIST
]);
28 return (b
.charAt(1) == 'm' ? "Mesmer/" : "") + b
;
31 static ParseFen(fen
) {
32 const fenParts
= fen
.split(" ");
34 { hSquare: fenParts
[5] },
35 ChessRules
.ParseFen(fen
)
39 static GenRandInitFen(options
) {
40 const antikingFen
= Antiking2Rules
.GenRandInitFen(options
);
41 return antikingFen
.replace('a', 'M').replace('A', 'm') + " -";
44 setOtherVariables(fen
) {
45 super.setOtherVariables(fen
);
46 const parsedFen
= V
.ParseFen(fen
);
48 parsedFen
.hSquare
!= "-"
49 ? V
.SquareToCoords(parsedFen
.hSquare
)
56 // Squares of white and black mesmerist:
57 this.mesmerPos
= { w: [-1, -1], b: [-1, -1] };
58 const fenRows
= V
.ParseFen(fen
).position
.split("/");
59 for (let i
= 0; i
< fenRows
.length
; i
++) {
61 for (let j
= 0; j
< fenRows
[i
].length
; j
++) {
62 switch (fenRows
[i
].charAt(j
)) {
64 this.mesmerPos
["b"] = [i
, k
];
67 this.mesmerPos
["w"] = [i
, k
];
70 const num
= parseInt(fenRows
[i
].charAt(j
), 10);
71 if (!isNaN(num
)) k
+= num
- 1;
80 const L
= this.hSquares
.length
;
82 super.getFen() + " " +
83 (!this.hSquares
[L
-1] ? "-" : V
.CoordsToSquare(this.hSquares
[L
-1]))
88 // Wrong, but sufficient approximation let's say
89 return this.turn
== side
;
92 canTake([x1
, y1
], [x2
, y2
]) {
94 const c1
= this.getColor(x1
, y1
);
95 const c2
= this.getColor(x2
, y2
);
96 return (c
== c1
&& c1
!= c2
) || (c
!= c1
&& c1
== c2
);
99 getPotentialMovesFrom([x
, y
]) {
100 const L
= this.hSquares
.length
;
101 const lh
= this.hSquares
[L
-1];
102 if (!!lh
&& lh
.x
== x
&& lh
.y
== y
) return [];
103 const c
= this.getColor(x
, y
);
104 const piece
= this.getPiece(x
, y
);
105 if (c
== this.turn
) {
106 if (piece
== V
.MESMERIST
) return this.getPotentialMesmeristMoves([x
, y
]);
107 return super.getPotentialMovesFrom([x
, y
]);
109 // Playing opponent's pieces: hypnotizing moves. Allowed?
110 if (piece
== V
.MESMERIST
|| !this.isAttackedByMesmerist([x
, y
], this.turn
))
114 // No castling with enemy king (...yes, should eat it but...)
115 ? super.getSlideNJumpMoves(
116 [x
, y
], V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1)
117 : super.getPotentialMovesFrom([x
, y
]);
121 // Moves like a queen without capturing
122 getPotentialMesmeristMoves([x
, y
]) {
123 const steps
= V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]);
125 for (let step
of steps
) {
128 while (V
.OnBoard(i
, j
) && this.board
[i
][j
] == V
.EMPTY
) {
129 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
137 isAttackedByMesmerist(sq
, color
) {
139 super.isAttackedBySlideNJump(
140 sq
, color
, V
.MESMERIST
, V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]))
144 getEnpassantCaptures([x
, y
], shiftX
) {
145 const Lep
= this.epSquares
.length
;
146 const epSquare
= this.epSquares
[Lep
- 1]; //always at least one element
147 let enpassantMove
= null;
148 const c
= this.getColor(x
, y
);
151 epSquare
.x
== x
+ shiftX
&&
152 Math
.abs(epSquare
.y
- y
) == 1 &&
153 // Next conditions to avoid capturing self hypnotized pawns:
154 this.board
[x
][epSquare
.y
] != V
.EMPTY
&&
155 this.getColor(x
, epSquare
.y
) != c
//TODO: probably redundant
157 enpassantMove
= this.getBasicMove([x
, y
], [epSquare
.x
, epSquare
.y
]);
158 enpassantMove
.vanish
.push({
161 p: this.board
[x
][epSquare
.y
].charAt(1),
162 c: this.getColor(x
, epSquare
.y
)
165 return !!enpassantMove
? [enpassantMove
] : [];
168 // TODO: avoid following code duplication, by using getColor()
169 // instead of this.turn at the beginning of 2 next methods
170 addPawnMoves([x1
, y1
], [x2
, y2
], moves
, promotions
) {
171 let finalPieces
= [V
.PAWN
];
172 const color
= this.getColor(x1
, y1
);
173 const lastRank
= (color
== "w" ? 0 : V
.size
.x
- 1);
174 if (x2
== lastRank
) finalPieces
= V
.PawnSpecs
.promotions
;
176 for (let piece
of finalPieces
) {
177 tr
= (piece
!= V
.PAWN
? { c: color
, p: piece
} : null);
178 moves
.push(this.getBasicMove([x1
, y1
], [x2
, y2
], tr
));
182 getPotentialPawnMoves([x
, y
], promotions
) {
183 const color
= this.getColor(x
, y
);
184 const [sizeX
, sizeY
] = [V
.size
.x
, V
.size
.y
];
185 const forward
= (color
== 'w' ? -1 : 1);
188 if (x
+ forward
>= 0 && x
+ forward
< sizeX
) {
189 if (this.board
[x
+ forward
][y
] == V
.EMPTY
) {
190 this.addPawnMoves([x
, y
], [x
+ forward
, y
], moves
, promotions
);
192 ((color
== 'w' && x
== 6) || (color
== 'b' && x
== 1)) &&
193 this.board
[x
+ 2 * forward
][y
] == V
.EMPTY
195 moves
.push(this.getBasicMove([x
, y
], [x
+ 2 * forward
, y
]));
198 for (let shiftY
of [-1, 1]) {
200 y
+ shiftY
>= 0 && y
+ shiftY
< sizeY
&&
201 this.board
[x
+ forward
][y
+ shiftY
] != V
.EMPTY
&&
202 this.canTake([x
, y
], [x
+ forward
, y
+ shiftY
])
205 [x
, y
], [x
+ forward
, y
+ shiftY
],
211 Array
.prototype.push
.apply(moves
,
212 this.getEnpassantCaptures([x
, y
], forward
));
217 super.postPlay(move);
218 if (move.vanish
[0].p
== V
.MESMERIST
)
219 this.mesmerPos
[move.vanish
[0].c
] = [move.appear
[0].x
, move.appear
[0].y
];
220 if (move.vanish
[0].c
== this.turn
)
221 this.hSquares
.push({ x: move.appear
[0].x
, y: move.appear
[0].y
});
222 else this.hSquares
.push(null);
223 if (move.vanish
.length
== 2) {
224 if (move.vanish
[1].p
== V
.KING
)
225 this.kingPos
[move.vanish
[1].c
] = [-1, -1];
226 else if (move.vanish
[1].p
== V
.MESMERIST
)
227 this.mesmerPos
[move.vanish
[1].c
] = [-1, -1]
231 super.postUndo(move);
232 if (move.vanish
[0].p
== V
.MESMERIST
)
233 this.mesmerPos
[move.vanish
[0].c
] = [move.vanish
[0].x
, move.vanish
[0].y
];
235 if (move.vanish
.length
== 2) {
236 const v
= move.vanish
[1];
238 this.kingPos
[v
.c
] = [v
.x
, v
.y
];
239 else if (v
.p
== V
.MESMERIST
)
240 this.mesmerPos
[v
.c
] = [v
.x
, v
.y
];
253 if (this.kingPos
[c
][0] < 0) return (c
== 'w' ? "0-1" : "1-0");
254 if (this.mesmerPos
[c
][0] < 0) return (c
== 'w' ? "0-1" : "1-0");
258 static get SEARCH_DEPTH() {