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(randomness
) {
27 return ChessRules
.GenRandInitFen(randomness
) + " -";
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
]), "oneStep")
73 : super.getPotentialMovesFrom([x
, y
]);
77 getEnpassantCaptures([x
, y
], shiftX
) {
78 const Lep
= this.epSquares
.length
;
79 const epSquare
= this.epSquares
[Lep
- 1]; //always at least one element
80 let enpassantMove
= null;
81 const c
= this.getColor(x
, y
);
84 epSquare
.x
== x
+ shiftX
&&
85 Math
.abs(epSquare
.y
- y
) == 1 &&
86 // Next conditions to avoid capturing self hypnotized pawns:
87 this.board
[x
][epSquare
.y
] != V
.EMPTY
&&
88 this.getColor(x
, epSquare
.y
) != c
//TODO: probably redundant
90 enpassantMove
= this.getBasicMove([x
, y
], [epSquare
.x
, epSquare
.y
]);
91 enpassantMove
.vanish
.push({
94 p: this.board
[x
][epSquare
.y
].charAt(1),
95 c: this.getColor(x
, epSquare
.y
)
98 return !!enpassantMove
? [enpassantMove
] : [];
101 // TODO: avoid following code duplication, by using getColor()
102 // instead of this.turn at the beginning of 2 next methods
103 addPawnMoves([x1
, y1
], [x2
, y2
], moves
, promotions
) {
104 let finalPieces
= [V
.PAWN
];
105 const color
= this.getColor(x1
, y1
);
106 const lastRank
= (color
== "w" ? 0 : V
.size
.x
- 1);
107 if (x2
== lastRank
) finalPieces
= V
.PawnSpecs
.promotions
;
109 for (let piece
of finalPieces
) {
110 tr
= (piece
!= V
.PAWN
? { c: color
, p: piece
} : null);
111 moves
.push(this.getBasicMove([x1
, y1
], [x2
, y2
], tr
));
115 getPotentialPawnMoves([x
, y
], promotions
) {
116 const color
= this.getColor(x
, y
);
117 const [sizeX
, sizeY
] = [V
.size
.x
, V
.size
.y
];
118 const forward
= (color
== 'w' ? -1 : 1);
121 if (x
+ forward
>= 0 && x
+ forward
< sizeX
) {
122 if (this.board
[x
+ forward
][y
] == V
.EMPTY
) {
123 this.addPawnMoves([x
, y
], [x
+ forward
, y
], moves
, promotions
);
125 ((color
== 'w' && x
== 6) || (color
== 'b' && x
== 1)) &&
126 this.board
[x
+ 2 * forward
][y
] == V
.EMPTY
128 moves
.push(this.getBasicMove([x
, y
], [x
+ 2 * forward
, y
]));
131 for (let shiftY
of [-1, 1]) {
133 y
+ shiftY
>= 0 && y
+ shiftY
< sizeY
&&
134 this.board
[x
+ forward
][y
+ shiftY
] != V
.EMPTY
&&
135 this.canTake([x
, y
], [x
+ forward
, y
+ shiftY
])
138 [x
, y
], [x
+ forward
, y
+ shiftY
],
144 Array
.prototype.push
.apply(moves
,
145 this.getEnpassantCaptures([x
, y
], forward
));
150 super.postPlay(move);
151 if (move.vanish
[0].c
== this.turn
)
152 this.hSquares
.push({ x: move.appear
[0].x
, y: move.appear
[0].y
});
153 else this.hSquares
.push(null);
154 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
155 this.kingPos
[move.vanish
[1].c
] = [-1, -1];
158 super.postUndo(move);
160 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
161 this.kingPos
[move.vanish
[1].c
] = [move.vanish
[1].x
, move.vanish
[1].y
];
173 if (this.kingPos
[c
][0] < 0) return (c
== 'w' ? "0-1" : "1-0");
177 static get SEARCH_DEPTH() {