370c6896bc182dae440569050688a6e42887056e
1 class CheckeredRules
extends ChessRules
5 return b
[0]=='c' ? "Checkered/"+b : b
;
9 const checkered_codes
= {
17 return checkered_codes
[b
[1]];
18 return ChessRules
.board2fen(b
);
22 // Tolerate upper-case versions of checkered pieces (why not?)
23 const checkered_pieces
= {
35 if (Object
.keys(checkered_pieces
).includes(f
))
36 return 'c'+checkered_pieces
[f
];
37 return ChessRules
.fen2board(f
);
41 return ChessRules
.PIECES
.concat(['s','t','u','c','o']);
44 static IsGoodFlags(flags
)
46 // 4 for castle + 16 for pawns
47 return !!flags
.match(/^[01]{20,20}$/);
52 super.setFlags(fenflags
); //castleFlags
55 "w": _
.map(_
.range(8), i
=> true), //pawns can move 2 squares?
56 "b": _
.map(_
.range(8), i
=> true)
60 const flags
= fenflags
.substr(4); //skip first 4 digits, for castle
61 for (let c
of ['w','b'])
63 for (let i
=0; i
<8; i
++)
64 this.pawnFlags
[c
][i
] = (flags
.charAt((c
=='w'?0:8)+i
) == '1');
68 // Aggregates flags into one object
70 return [this.castleFlags
, this.pawnFlags
];
76 this.castleFlags
= flags
[0];
77 this.pawnFlags
= flags
[1];
80 canTake([x1
,y1
], [x2
,y2
])
82 const color1
= this.getColor(x1
,y1
);
83 const color2
= this.getColor(x2
,y2
);
84 // Checkered aren't captured
85 return color1
!= color2
&& color2
!= 'c' && (color1
!= 'c' || color2
!= this.turn
);
88 // Post-processing: apply "checkerization" of standard moves
89 getPotentialMovesFrom([x
,y
])
91 let standardMoves
= super.getPotentialMovesFrom([x
,y
]);
92 const lastRank
= this.turn
== "w" ? 0 : 7;
93 if (this.getPiece(x
,y
) == V
.KING
)
94 return standardMoves
; //king has to be treated differently (for castles)
96 standardMoves
.forEach(m
=> {
97 if (m
.vanish
[0].p
== V
.PAWN
)
99 if (Math
.abs(m
.end
.x
-m
.start
.x
)==2 && !this.pawnFlags
[this.turn
][m
.start
.y
])
100 return; //skip forbidden 2-squares jumps
101 if (this.board
[m
.end
.x
][m
.end
.y
] == V
.EMPTY
&& m
.vanish
.length
==2
102 && this.getColor(m
.start
.x
,m
.start
.y
) == 'c')
104 return; //checkered pawns cannot take en-passant
107 if (m
.vanish
.length
== 1)
108 moves
.push(m
); //no capture
111 // A capture occured (m.vanish.length == 2)
114 if (m
.appear
[0].p
!= m
.vanish
[1].p
//avoid promotions (already treated):
115 && (m
.vanish
[0].p
!= V
.PAWN
|| m
.end
.x
!= lastRank
))
117 // Add transformation into captured piece
118 let m2
= JSON
.parse(JSON
.stringify(m
));
119 m2
.appear
[0].p
= m
.vanish
[1].p
;
127 canIplay(side
, [x
,y
])
129 return (side
== this.turn
&& [side
,'c'].includes(this.getColor(x
,y
)));
132 // Does m2 un-do m1 ? (to disallow undoing checkered moves)
133 oppositeMoves(m1
, m2
)
135 return m1
.appear
.length
== 1 && m2
.appear
.length
== 1
136 && m1
.vanish
.length
== 1 && m2
.vanish
.length
== 1
137 && m1
.start
.x
== m2
.end
.x
&& m1
.end
.x
== m2
.start
.x
138 && m1
.start
.y
== m2
.end
.y
&& m1
.end
.y
== m2
.start
.y
139 && m1
.appear
[0].c
== m2
.vanish
[0].c
&& m1
.appear
[0].p
== m2
.vanish
[0].p
140 && m1
.vanish
[0].c
== m2
.appear
[0].c
&& m1
.vanish
[0].p
== m2
.appear
[0].p
;
145 if (moves
.length
== 0)
147 const color
= this.turn
;
148 return moves
.filter(m
=> {
149 const L
= this.moves
.length
;
150 if (L
> 0 && this.oppositeMoves(this.moves
[L
-1], m
))
152 return !this.underCheck(m
);
156 isAttackedByPawn([x
,y
], colors
)
158 for (let c
of colors
)
160 const color
= (c
=="c" ? this.turn : c
);
161 let pawnShift
= (color
=="w" ? 1 : -1);
162 if (x
+pawnShift
>=0 && x
+pawnShift
<8)
164 for (let i
of [-1,1])
166 if (y
+i
>=0 && y
+i
<8 && this.getPiece(x
+pawnShift
,y
+i
)==V
.PAWN
167 && this.getColor(x
+pawnShift
,y
+i
)==c
)
179 const color
= this.turn
;
181 let res
= this.isAttacked(this.kingPos
[color
], [this.getOppCol(color
),'c']);
186 getCheckSquares(move)
189 const color
= this.turn
;
190 this.moves
.push(move); //artifically change turn, for checkered pawns (TODO)
191 const kingAttacked
= this.isAttacked(
192 this.kingPos
[color
], [this.getOppCol(color
),'c']);
193 let res
= kingAttacked
194 ? [ JSON
.parse(JSON
.stringify(this.kingPos
[color
])) ] //need to duplicate!
201 updateVariables(move)
203 super.updateVariables(move);
204 // Does this move turn off a 2-squares pawn flag?
205 const secondRank
= [1,6];
206 if (secondRank
.includes(move.start
.x
) && move.vanish
[0].p
== V
.PAWN
)
207 this.pawnFlags
[move.start
.x
==6 ? "w" : "b"][move.start
.y
] = false;
212 const color
= this.turn
;
213 // Artifically change turn, for checkered pawns
214 this.turn
= this.getOppCol(this.turn
);
215 const res
= this.isAttacked(this.kingPos
[color
], [this.getOppCol(color
),'c'])
216 ? (color
== "w" ? "0-1" : "1-0")
218 this.turn
= this.getOppCol(this.turn
);
225 //Just count material for now, considering checkered neutral (...)
226 for (let i
=0; i
<V
.size
.x
; i
++)
228 for (let j
=0; j
<V
.size
.y
; j
++)
230 if (this.board
[i
][j
] != V
.EMPTY
)
232 const sqColor
= this.getColor(i
,j
);
233 const sign
= sqColor
== "w" ? 1 : (sqColor
=="b" ? -1 : 0);
234 evaluation
+= sign
* V
.VALUES
[this.getPiece(i
,j
)];
241 static GenRandInitFen()
243 const randFen
= ChessRules
.GenRandInitFen();
244 // Add 16 pawns flags:
245 return randFen
.replace(" 1111 w", " 11111111111111111111 w");
250 let fen
= super.getFlagsFen();
252 for (let c
of ['w','b'])
254 for (let i
=0; i
<8; i
++)
255 fen
+= this.pawnFlags
[c
][i
] ? '1' : '0';
262 if (move.appear
.length
== 2)
265 if (move.end
.y
< move.start
.y
)
271 // Translate final square
273 String
.fromCharCode(97 + move.end
.y
) + (V
.size
.x
-move.end
.x
);
275 let piece
= this.getPiece(move.start
.x
, move.start
.y
);
280 if (move.vanish
.length
> 1)
283 let startColumn
= String
.fromCharCode(97 + move.start
.y
);
284 notation
= startColumn
+ "x" + finalSquare
+
285 "=" + move.appear
[0].p
.toUpperCase();
289 notation
= finalSquare
;
290 if (move.appear
.length
> 0 && piece
!= move.appear
[0].p
) //promotion
291 notation
+= "=" + move.appear
[0].p
.toUpperCase();
299 return piece
.toUpperCase() + (move.vanish
.length
> 1 ? "x" : "") + finalSquare
300 + (move.vanish
.length
> 1 ? "=" + move.appear
[0].p
.toUpperCase() : "");