1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
2 import { randInt
} from "@/utils/alea";
3 import { ArrayFun
} from "@/utils/array";
5 export class AtarigoRules
extends ChessRules
{
7 static get Monochrome() {
11 static get Notoodark() {
17 // Draw all inter-squares lines, shifted:
18 for (let i
= 0; i
< V
.size
.x
; i
++)
19 lines
.push([[i
+0.5, 0.5], [i
+0.5, V
.size
.y
-0.5]]);
20 for (let j
= 0; j
< V
.size
.y
; j
++)
21 lines
.push([[0.5, j
+0.5], [V
.size
.x
-0.5, j
+0.5]]);
25 static get HasFlags() {
29 static get HasEnpassant() {
33 static get ReverseColors() {
37 static IsGoodPosition(position
) {
38 if (position
.length
== 0) return false;
39 const rows
= position
.split("/");
40 if (rows
.length
!= V
.size
.x
) return false;
41 for (let row
of rows
) {
43 for (let i
= 0; i
< row
.length
; i
++) {
44 if (row
[i
].toLowerCase() == V
.PAWN
) sumElts
++;
46 const num
= parseInt(row
[i
], 10);
47 if (isNaN(num
) || num
<= 0) return false;
51 if (sumElts
!= V
.size
.y
) return false;
56 static IsGoodFen(fen
) {
57 if (!ChessRules
.IsGoodFen(fen
)) return false;
58 const fenParsed
= V
.ParseFen(fen
);
59 // 3) Check capture "flag"
60 if (!fenParsed
.capture
|| !fenParsed
.capture
.match(/^[01]$/))
65 static ParseFen(fen
) {
66 const fenParts
= fen
.split(" ");
68 ChessRules
.ParseFen(fen
),
69 // Capture field allows to compute the score cleanly.
70 { capture: fenParts
[3] }
75 return { x: 12, y: 12 };
78 static GenRandInitFen() {
79 return "93/93/93/93/93/5Pp5/5pP5/93/93/93/93/93 w 0 0";
83 return super.getFen() + " " + (this.capture
? 1 : 0);
86 setOtherVariables(fen
) {
87 this.capture
= parseInt(V
.ParseFen(fen
).capture
, 10);
102 canIplay(side
, [x
, y
]) {
103 return (side
== this.turn
&& this.board
[x
][y
] == V
.EMPTY
);
106 hoverHighlight([x
, y
], side
) {
107 if (!!side
&& side
!= this.turn
) return false;
108 return (this.board
[x
][y
] == V
.EMPTY
);
111 searchForEmptySpace([x
, y
], color
, explored
) {
112 if (explored
[x
][y
]) return false; //didn't find empty space
113 explored
[x
][y
] = true;
115 for (let s
of V
.steps
[V
.ROOK
]) {
116 const [i
, j
] = [x
+ s
[0], y
+ s
[1]];
117 if (V
.OnBoard(i
, j
)) {
118 if (this.board
[i
][j
] == V
.EMPTY
) res
= true;
119 else if (this.getColor(i
, j
) == color
)
120 res
= this.searchForEmptySpace([i
, j
], color
, explored
) || res
;
127 const color
= this.turn
;
128 const oppCol
= V
.GetOppCol(color
);
129 let move = new Move({
131 new PiPo({ x: x
, y: y
, c: color
, p: V
.PAWN
})
134 start: { x: -1, y: -1 }
136 V
.PlayOnBoard(this.board
, move); //put the stone
137 let noSuicide
= false;
139 for (let s
of V
.steps
[V
.ROOK
]) {
140 const [i
, j
] = [x
+ s
[0], y
+ s
[1]];
141 if (V
.OnBoard(i
, j
)) {
142 if (this.board
[i
][j
] == V
.EMPTY
) noSuicide
= true; //clearly
143 else if (this.getColor(i
, j
) == color
) {
144 // Free space for us = not a suicide
146 let explored
= ArrayFun
.init(V
.size
.x
, V
.size
.y
, false);
147 noSuicide
= this.searchForEmptySpace([i
, j
], color
, explored
);
151 // Free space for opponent = not a capture
152 let explored
= ArrayFun
.init(V
.size
.x
, V
.size
.y
, false);
153 const captureSomething
=
154 !this.searchForEmptySpace([i
, j
], oppCol
, explored
);
155 if (captureSomething
) {
156 for (let ii
= 0; ii
< V
.size
.x
; ii
++) {
157 for (let jj
= 0; jj
< V
.size
.y
; jj
++) {
158 if (explored
[ii
][jj
]) {
160 new PiPo({ x: ii
, y: jj
, c: oppCol
, p: V
.PAWN
})
169 V
.UndoOnBoard(this.board
, move); //remove the stone
170 if (!noSuicide
&& captures
.length
== 0) return null;
171 Array
.prototype.push
.apply(move.vanish
, captures
);
175 getPotentialMovesFrom([x
, y
]) {
176 const move = this.doClick([x
, y
]);
177 return (!move ? [] : [move]);
180 getAllPotentialMoves() {
182 for (let i
= 0; i
< V
.size
.x
; i
++) {
183 for (let j
=0; j
< V
.size
.y
; j
++) {
184 if (this.board
[i
][j
] == V
.EMPTY
) {
185 const mv
= this.doClick(i
, j
);
186 if (!!mv
) moves
.push(mv
);
202 if (move.vanish
.length
>= 1) this.capture
= true;
206 this.capture
= false;
210 if (this.capture
) return (this.turn
== 'w' ? "0-1" : "1-0");
215 const moves
= super.getAllValidMoves();
216 if (moves
.length
== 0) return null;
217 // Just random mover for now... writing a good bot is far out of scope
218 return moves
[randInt(moves
.length
)];
222 return V
.CoordsToSquare(move.end
);