1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
3 export class KonaneRules
extends ChessRules
{
5 static get HasFlags() {
9 static get HasEnpassant() {
13 static get ReverseColors() {
29 static IsGoodPosition(position
) {
30 if (position
.length
== 0) return false;
31 const rows
= position
.split("/");
32 if (rows
.length
!= V
.size
.x
) return false;
33 for (let row
of rows
) {
35 for (let i
= 0; i
< row
.length
; i
++) {
36 if (V
.PIECES
.includes(row
[i
].toLowerCase())) sumElts
++;
38 const num
= parseInt(row
[i
], 10);
39 if (isNaN(num
) || num
<= 0) return false;
43 if (sumElts
!= V
.size
.y
) return false;
48 static GenRandInitFen() {
50 "PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP/" +
51 "PpPpPpPp/pPpPpPpP/PpPpPpPp/pPpPpPpP w 0"
55 setOtherVariables(fen
) {
56 this.captures
= []; //reinit for each move
59 hoverHighlight(x
, y
) {
60 if (this.movesCount
>= 2) return false;
62 if (c
== 'w') return (x
== y
&& [0, 3, 4, 7].includes(x
));
63 // "Black": search for empty square and allow nearby
64 for (let i
of [0, 3, 4, 7]) {
65 if (this.board
[i
][i
] == V
.EMPTY
)
66 return (Math
.abs(x
- i
) + Math
.abs(y
- i
) == 1)
72 this.movesCount
<= 1 ||
73 // TODO: next line theoretically shouldn't be required...
74 (this.movesCount
== 2 && this.getColor(x
, y
) != this.turn
)
79 if (this.movesCount
>= 2) return null;
80 const color
= this.turn
;
82 if (x
!= y
|| ![0, 3, 4, 7].includes(x
)) return null;
85 vanish: [ new PiPo({ x: x
, y: y
, c: color
, p: V
.PAWN
}) ],
89 // "Black": search for empty square and allow nearby
90 for (let i
of [0, 3, 4, 7]) {
91 if (this.board
[i
][i
] == V
.EMPTY
) {
92 if (Math
.abs(x
- i
) + Math
.abs(y
- i
) != 1) return null;
95 vanish: [ new PiPo({ x: x
, y: y
, c: color
, p: V
.PAWN
}) ],
102 getPotentialMovesFrom([x
, y
]) {
103 if (this.movesCount
<= 1) {
104 const mv
= this.doClick([x
, y
]);
105 return (!!mv
? [mv
] : []);
107 const L
= this.captures
.length
;
108 const c
= (L
> 0 ? this.captures
[L
-1] : null);
109 const color
= this.turn
;
110 const oppCol
= V
.GetOppCol(color
);
114 if (x
!= c
.end
.x
|| y
!= c
.end
.y
) return [];
115 step
= [(c
.end
.x
- c
.start
.x
) / 2, (c
.end
.y
- c
.start
.y
) / 2];
116 // Add move to adjacent empty square to mark "end of capture"
121 start: { x: x
, y: y
},
122 end: { x: x
- step
[0], y: y
- step
[1] }
126 // Examine captures from here
127 for (let s
of (!!step
? [step
] : V
.steps
[V
.ROOK
])) {
128 let [i
, j
] = [x
+ 2*s
[0], y
+ 2*s
[1]];
130 !!c
|| //avoid redundant checks if continuation
133 this.board
[i
][j
] == V
.EMPTY
&&
134 this.board
[i
- s
[0]][j
- s
[1]] != V
.EMPTY
&&
135 this.getColor(i
- s
[0], j
- s
[1]) == oppCol
140 new PiPo({ x: i
, y: j
, c: color
, p: V
.PAWN
})
143 new PiPo({ x: x
, y: y
, c: color
, p: V
.PAWN
}),
144 new PiPo({ x: i
- s
[0], y: j
- s
[1], c: oppCol
, p: V
.PAWN
})
147 // Is there another capture possible then?
148 [i
, j
] = [i
+ 2*s
[0], j
+ 2*s
[1]];
151 this.board
[i
][j
] == V
.EMPTY
&&
152 this.board
[i
- s
[0]][j
- s
[1]] != V
.EMPTY
&&
153 this.getColor(i
- s
[0], j
- s
[1]) == oppCol
155 mv
.end
.moreCapture
= true;
172 if (this.atLeastOneMove()) return "*";
173 return (this.turn
== "w" ? "0-1" : "1-0");
177 V
.PlayOnBoard(this.board
, move);
178 if (!move.end
.moreCapture
) {
179 this.turn
= V
.GetOppCol(this.turn
);
187 end: { x: move.end
.x
, y: move.end
.y
}
194 V
.UndoOnBoard(this.board
, move);
195 if (!move.end
.moreCapture
) {
196 this.turn
= V
.GetOppCol(this.turn
);
199 else this.captures
.pop();
202 static get SEARCH_DEPTH() {
207 if (this.movesCount
<= 1) return V
.CoordsToSquare(move.start
) + "X";
208 if (move.vanish
.length
== 0) return "end";
209 return V
.CoordsToSquare(move.start
) + "x" + V
.CoordsToSquare(move.end
);