@@ -787,7 +787,15 @@ impl Board {
787787 zob ^= z_square ( to, piece) ^ z_square ( from, piece) ;
788788
789789 if self . state . ep_square != NO_SQ {
790- zob ^= z_ep ( self . state . ep_square ) ;
790+ // Only XOR out the EP hash if it was included in the zobrist
791+ // (it was included only when an opponent pawn could capture en passant)
792+ let ep_owner = !self . turn ;
793+ if ( pawn_attacks_from ( self . state . ep_square , ep_owner)
794+ & self . piece_bb ( self . turn , PieceType :: P ) )
795+ . is_not_empty ( )
796+ {
797+ zob ^= z_ep ( self . state . ep_square ) ;
798+ }
791799 new_state. ep_square = NO_SQ ;
792800 }
793801
@@ -810,11 +818,14 @@ impl Board {
810818 // Double Push
811819 let poss_ep: u8 = ( to. 0 as i8 - us. pawn_push ( ) ) as u8 ;
812820
813- // Set en-passant square if the moved pawn can be captured
821+ // Always set en-passant square after a double pawn push,
822+ // per the FEN standard
823+ new_state. ep_square = SQ ( poss_ep) ;
824+
825+ // Only include in zobrist hash if the moved pawn can be captured
814826 if ( pawn_attacks_from ( SQ ( poss_ep) , us) & self . piece_bb ( them, PieceType :: P ) )
815827 . is_not_empty ( )
816828 {
817- new_state. ep_square = SQ ( poss_ep) ;
818829 zob ^= z_ep ( new_state. ep_square ) ;
819830 }
820831 } else if bit_move. is_promo ( ) {
@@ -1017,7 +1028,14 @@ impl Board {
10171028 new_state. prev = Some ( Arc :: clone ( & self . state ) ) ;
10181029
10191030 if self . state . ep_square != NO_SQ {
1020- zob ^= z_ep ( self . state . ep_square ) ;
1031+ // Only XOR out the EP hash if it was included in the zobrist
1032+ let ep_owner = !self . turn ;
1033+ if ( pawn_attacks_from ( self . state . ep_square , ep_owner)
1034+ & self . piece_bb ( self . turn , PieceType :: P ) )
1035+ . is_not_empty ( )
1036+ {
1037+ zob ^= z_ep ( self . state . ep_square ) ;
1038+ }
10211039 new_state. ep_square = NO_SQ ;
10221040 }
10231041
0 commit comments