@@ -61,174 +61,6 @@ func (brd *Board) KingSq(c uint8) int {
6161 return furthestForward (c , brd.pieces [c ][KING ])
6262}
6363
64- // Used to verify that a killer or hash move is legal.
65- func (brd * Board ) LegalMove (m Move , inCheck bool ) bool {
66- if inCheck {
67- return brd .EvadesCheck (m )
68- } else {
69- return brd .PseudolegalAvoidsCheck (m )
70- }
71- }
72-
73- // Moves generated while in check should already be legal, since we determine this
74- // as a side-effect of generating evasions.
75- func (brd * Board ) AvoidsCheck (m Move , inCheck bool ) bool {
76- return inCheck || brd .PseudolegalAvoidsCheck (m )
77- }
78-
79- func (brd * Board ) PseudolegalAvoidsCheck (m Move ) bool {
80- switch m .Piece () {
81- case PAWN :
82- if m .CapturedPiece () == PAWN && brd .TypeAt (m .To ()) == EMPTY { // En-passant
83- return pinnedCanMove (brd , m .From (), m .To (), brd .c , brd .Enemy ()) &&
84- isPinned (brd , int (brd .enpTarget ), brd .c , brd .Enemy ())& sqMaskOn [m .To ()] > 0
85- } else {
86- return pinnedCanMove (brd , m .From (), m .To (), brd .c , brd .Enemy ())
87- }
88- case KING :
89- return ! isAttackedBy (brd , brd .AllOccupied (), m .To (), brd .Enemy (), brd .c )
90- default :
91- return pinnedCanMove (brd , m .From (), m .To (), brd .c , brd .Enemy ())
92- }
93- }
94-
95- // Only called when in check
96- func (brd * Board ) EvadesCheck (m Move ) bool {
97- piece , from , to := m .Piece (), m .From (), m .To ()
98- c , e := brd .c , brd .Enemy ()
99-
100- if piece == KING {
101- return ! isAttackedBy (brd , occAfterMove (brd .AllOccupied (), from , to ), to , e , c )
102- } else {
103- occ := brd .AllOccupied ()
104- kingSq := brd .KingSq (c )
105- threats := colorAttackMap (brd , occ , kingSq , e , c )
106-
107- // TODO: EvadesCheck() called from non-check position in rare cases. Examples:
108- // 5r1k/1b3p1p/pp3p1q/3n4/1P2R3/P2B1PP1/7P/6K1 w - - 0 1
109- // 8/PPKR4/1Bn4P/3P3R/8/2p4r/pp4p1/r6k w - - 5 2 (r h3h5 x r)...?
110-
111- if threats == 0 {
112- fmt .Println ("info string EvadesCheck() called from non-check position!" )
113- // m.Print()
114- // brd.PrintDetails()
115- return true // no threats to evade.
116- }
117-
118- if popCount (threats ) > 1 {
119- return false // only king moves can escape from double check.
120- }
121- if (threats | intervening [furthestForward (e , threats )][kingSq ])& sqMaskOn [to ] == 0 {
122- return false // the moving piece must kill or block the attacking piece.
123- }
124- if ! pinnedCanMove (brd , from , to , c , e ) {
125- return false // the moving piece can't be pinned to the king.
126- }
127- if brd .enpTarget != SQ_INVALID && piece == PAWN && m .CapturedPiece () == PAWN && // En-passant
128- brd .TypeAt (to ) == EMPTY {
129- occ = occAfterMove (occ , from , to ) & sqMaskOff [brd .enpTarget ]
130-
131- return colorAttackMap (brd , occ , kingSq , e , c ) == 0
132- // return attacks_after_move(brd, occ, occ&brd.occupied[e], king_sq, e, c) == 0
133- }
134- }
135- return true
136- }
137-
138- func (brd * Board ) ValidMove (m Move , inCheck bool ) bool {
139- if ! m .IsMove () {
140- return false
141- }
142- c , e := brd .c , brd .Enemy ()
143- piece , from , to , capturedPiece := m .Piece (), m .From (), m .To (), m .CapturedPiece ()
144-
145- if brd .TypeAt (from ) != piece || brd.pieces [c ][piece ]& sqMaskOn [from ] == 0 {
146- // fmt.Printf("No piece of this type available at from square!{%s}", m.ToString())
147- return false
148- }
149- if sqMaskOn [to ]& brd .occupied [c ] > 0 {
150- // fmt.Printf("To square occupied by own piece!{%s}", m.ToString())
151- return false
152- }
153- if capturedPiece == KING || brd.pieces [c ][KING ] == 0 {
154- // fmt.Printf("King capture detected!{%s}", m.ToString())
155- return false
156- }
157- switch piece {
158- case PAWN :
159- var diff int
160- if c == WHITE {
161- diff = to - from
162- } else {
163- diff = from - to
164- }
165- if diff < 0 {
166- // fmt.Printf("Invalid pawn movement direction!{%s}", m.ToString())
167- return false
168- } else if diff == 8 {
169- return brd .TypeAt (to ) == EMPTY
170- } else if diff == 16 {
171- return brd .TypeAt (to ) == EMPTY && brd .TypeAt (pawnStopSq [c ][from ]) == EMPTY
172- } else if capturedPiece == EMPTY {
173- // fmt.Printf("Invalid pawn move!{%s}", m.ToString())
174- return false
175- } else {
176- if capturedPiece == PAWN && brd .TypeAt (to ) == EMPTY {
177- if brd .enpTarget != SQ_INVALID && pawnStopSq [e ][to ] == int (brd .enpTarget ) {
178- return true
179- } else {
180- // fmt.Printf("Invalid En-passant move!{%s}", m.ToString())
181- return false
182- }
183- } else {
184- return brd .TypeAt (to ) == capturedPiece
185- }
186- }
187- case KING :
188- if abs (to - from ) == 2 { // validate castle moves
189- occ := brd .AllOccupied ()
190- if c == WHITE && ! inCheck && (brd .castle & 12 ) > 0 {
191- switch to {
192- case C1 :
193- if (brd .castle & C_WQ > uint8 (0 )) && castleQueensideIntervening [WHITE ]& occ == 0 &&
194- ! isAttackedBy (brd , occ , B1 , e , c ) && ! isAttackedBy (brd , occ , C1 , e , c ) &&
195- ! isAttackedBy (brd , occ , D1 , e , c ) {
196- return true
197- }
198- case G1 :
199- if (brd .castle & C_WK > uint8 (0 )) && castleKingsideIntervening [WHITE ]& occ == 0 &&
200- ! isAttackedBy (brd , occ , F1 , e , c ) && ! isAttackedBy (brd , occ , G1 , e , c ) {
201- return true
202- }
203- }
204- } else if c == BLACK && ! inCheck && (brd .castle & 3 ) > 0 {
205- switch to {
206- case C8 :
207- if (brd .castle & C_BQ > uint8 (0 )) && castleQueensideIntervening [BLACK ]& occ == 0 &&
208- ! isAttackedBy (brd , occ , B8 , e , c ) && ! isAttackedBy (brd , occ , C8 , e , c ) &&
209- ! isAttackedBy (brd , occ , D8 , e , c ) {
210- return true
211- }
212- case G8 :
213- if (brd .castle & C_BK > uint8 (0 )) && castleKingsideIntervening [BLACK ]& occ == 0 &&
214- ! isAttackedBy (brd , occ , F8 , e , c ) && ! isAttackedBy (brd , occ , G8 , e , c ) {
215- return true
216- }
217- }
218- }
219- return false
220- }
221- case KNIGHT :
222- // no special treatment needed for knights.
223- default :
224- if slidingAttacks (piece , brd .AllOccupied (), from )& sqMaskOn [to ] == 0 {
225- return false
226- }
227- }
228-
229- return brd .TypeAt (to ) == capturedPiece
230- }
231-
23264func (brd * Board ) MayPromote (m Move ) bool {
23365 if m .Piece () != PAWN {
23466 return false
0 commit comments