1 import { ChessRules
} from "@/base_rules";
3 export class HypnoticRules
extends ChessRules
{
5 static IsGoodFen(fen
) {
6 if (!ChessRules
.IsGoodFen(fen
)) return false;
7 const fenParsed
= V
.ParseFen(fen
);
8 // 5) Check arrival of last hypnotizing move (if any)
11 (fenParsed
.hSquare
!= "-" && !fenParsed
.hSquare
.match(/^[a-h][1-8]$/))
18 static ParseFen(fen
) {
19 const fenParts
= fen
.split(" ");
21 { hSquare: fenParts
[5] },
22 ChessRules
.ParseFen(fen
)
26 static GenRandInitFen(options
) {
27 return ChessRules
.GenRandInitFen(options
) + " -";
30 setOtherVariables(fen
) {
31 super.setOtherVariables(fen
);
32 const parsedFen
= V
.ParseFen(fen
);
34 parsedFen
.hSquare
!= "-"
35 ? V
.SquareToCoords(parsedFen
.hSquare
)
41 const L
= this.hSquares
.length
;
43 super.getFen() + " " +
44 (!this.hSquares
[L
-1] ? "-" : V
.CoordsToSquare(this.hSquares
[L
-1]))
49 // Wrong, but sufficient approximation let's say
50 return this.turn
== side
;
53 canTake([x1
, y1
], [x2
, y2
]) {
55 const c1
= this.getColor(x1
, y1
);
56 const c2
= this.getColor(x2
, y2
);
57 return (c
== c1
&& c1
!= c2
) || (c
!= c1
&& c1
== c2
);
60 getPotentialMovesFrom([x
, y
]) {
61 const L
= this.hSquares
.length
;
62 const lh
= this.hSquares
[L
-1];
63 if (!!lh
&& lh
.x
== x
&& lh
.y
== y
) return [];
64 const c
= this.getColor(x
, y
);
65 if (c
== this.turn
) return super.getPotentialMovesFrom([x
, y
]);
66 // Playing opponent's pieces: hypnotizing moves. Allowed?
67 if (!this.isAttacked([x
, y
], this.turn
)) return [];
69 this.getPiece(x
, y
) == V
.KING
70 // No castling with enemy king (...yes, should eat it but...)
71 ? super.getSlideNJumpMoves(
72 [x
, y
], V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1)
73 : super.getPotentialMovesFrom([x
, y
]);
77 getAllPotentialMoves() {
78 let potentialMoves
= [];
79 for (let i
= 0; i
< V
.size
.x
; i
++) {
80 for (let j
= 0; j
< V
.size
.y
; j
++) {
81 if (this.board
[i
][j
] != V
.EMPTY
) {
82 Array
.prototype.push
.apply(
84 this.getPotentialMovesFrom([i
, j
])
89 return potentialMoves
;
92 getEnpassantCaptures([x
, y
], shiftX
) {
93 const Lep
= this.epSquares
.length
;
94 const epSquare
= this.epSquares
[Lep
- 1]; //always at least one element
95 let enpassantMove
= null;
96 const c
= this.getColor(x
, y
);
99 epSquare
.x
== x
+ shiftX
&&
100 Math
.abs(epSquare
.y
- y
) == 1 &&
101 // Next conditions to avoid capturing self hypnotized pawns:
102 this.board
[x
][epSquare
.y
] != V
.EMPTY
&&
103 this.getColor(x
, epSquare
.y
) != c
//TODO: probably redundant
105 enpassantMove
= this.getBasicMove([x
, y
], [epSquare
.x
, epSquare
.y
]);
106 enpassantMove
.vanish
.push({
109 p: this.board
[x
][epSquare
.y
].charAt(1),
110 c: this.getColor(x
, epSquare
.y
)
113 return !!enpassantMove
? [enpassantMove
] : [];
116 // TODO: avoid following code duplication, by using getColor()
117 // instead of this.turn at the beginning of 2 next methods
118 addPawnMoves([x1
, y1
], [x2
, y2
], moves
, promotions
) {
119 let finalPieces
= [V
.PAWN
];
120 const color
= this.getColor(x1
, y1
);
121 const lastRank
= (color
== "w" ? 0 : V
.size
.x
- 1);
122 if (x2
== lastRank
) finalPieces
= V
.PawnSpecs
.promotions
;
124 for (let piece
of finalPieces
) {
125 tr
= (piece
!= V
.PAWN
? { c: color
, p: piece
} : null);
126 moves
.push(this.getBasicMove([x1
, y1
], [x2
, y2
], tr
));
130 getPotentialPawnMoves([x
, y
], promotions
) {
131 const color
= this.getColor(x
, y
);
132 const [sizeX
, sizeY
] = [V
.size
.x
, V
.size
.y
];
133 const forward
= (color
== 'w' ? -1 : 1);
136 if (x
+ forward
>= 0 && x
+ forward
< sizeX
) {
137 if (this.board
[x
+ forward
][y
] == V
.EMPTY
) {
138 this.addPawnMoves([x
, y
], [x
+ forward
, y
], moves
, promotions
);
140 ((color
== 'w' && x
== 6) || (color
== 'b' && x
== 1)) &&
141 this.board
[x
+ 2 * forward
][y
] == V
.EMPTY
143 moves
.push(this.getBasicMove([x
, y
], [x
+ 2 * forward
, y
]));
146 for (let shiftY
of [-1, 1]) {
148 y
+ shiftY
>= 0 && y
+ shiftY
< sizeY
&&
149 this.board
[x
+ forward
][y
+ shiftY
] != V
.EMPTY
&&
150 this.canTake([x
, y
], [x
+ forward
, y
+ shiftY
])
153 [x
, y
], [x
+ forward
, y
+ shiftY
],
159 Array
.prototype.push
.apply(moves
,
160 this.getEnpassantCaptures([x
, y
], forward
));
165 super.postPlay(move);
166 if (move.vanish
[0].c
== this.turn
)
167 this.hSquares
.push({ x: move.appear
[0].x
, y: move.appear
[0].y
});
168 else this.hSquares
.push(null);
169 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
170 this.kingPos
[move.vanish
[1].c
] = [-1, -1];
173 super.postUndo(move);
175 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
176 this.kingPos
[move.vanish
[1].c
] = [move.vanish
[1].x
, move.vanish
[1].y
];
188 if (this.kingPos
[c
][0] < 0) return (c
== 'w' ? "0-1" : "1-0");
192 static get SEARCH_DEPTH() {