|  | @@ -3,6 +3,7 @@ use bitboard::Square;
 | 
	
		
			
				|  |  |  use bitboard::*;
 | 
	
		
			
				|  |  |  use game::Game;
 | 
	
		
			
				|  |  |  use hash::{Cache, EntryType};
 | 
	
		
			
				|  |  | +use std::f32::consts::PI;
 | 
	
		
			
				|  |  |  use std::iter::Iterator;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  use crate::evaluate::evaluate;
 | 
	
	
		
			
				|  | @@ -30,11 +31,14 @@ pub struct SimpleMove {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 | 
	
		
			
				|  |  | +pub struct PieceCaptureType(u8);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 | 
	
		
			
				|  |  |  pub enum Move {
 | 
	
		
			
				|  |  | -    Default { mov: SimpleMove, piece_type: PieceType, captured: Option<PieceType> },
 | 
	
		
			
				|  |  | +    Default { mov: SimpleMove, pc: PieceCaptureType },
 | 
	
		
			
				|  |  |      Castling { side: Side, left: bool },
 | 
	
		
			
				|  |  |      EnPassant { mov: SimpleMove, beaten: Square },
 | 
	
		
			
				|  |  | -    Promotion { mov: SimpleMove, promote_to: PieceType, captured: Option<PieceType> },
 | 
	
		
			
				|  |  | +    Promotion { mov: SimpleMove, pc: PieceCaptureType },
 | 
	
		
			
				|  |  |      Nullmove
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -47,6 +51,38 @@ pub struct MoveUndo {
 | 
	
		
			
				|  |  |      pub mov: Move
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +impl PieceCaptureType {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn new(piece_type: PieceType, capture_type: Option<PieceType>) -> Self {
 | 
	
		
			
				|  |  | +        if piece_type > KING {
 | 
	
		
			
				|  |  | +            panic!("ILLEGAL PIECE");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        let upper = piece_type << 4;
 | 
	
		
			
				|  |  | +        let lower = capture_type.unwrap_or(0xF);
 | 
	
		
			
				|  |  | +        PieceCaptureType(upper | lower)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn piece_type(&self) -> PieceType {
 | 
	
		
			
				|  |  | +        (self.0 >> 4) as PieceType
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn capture_type(&self) -> Option<PieceType> {
 | 
	
		
			
				|  |  | +        let ct = (self.0 & 0xF) as PieceType;
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        if ct == 0xF {
 | 
	
		
			
				|  |  | +            None
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else {
 | 
	
		
			
				|  |  | +            Some(ct)
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn has_capture(&self) -> bool {
 | 
	
		
			
				|  |  | +        let ct = (self.0 >> 4) as PieceType;
 | 
	
		
			
				|  |  | +        ct != 0xF
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  impl Default for Move {
 | 
	
		
			
				|  |  |      fn default() -> Move {
 | 
	
		
			
				|  |  |          Move::Nullmove
 | 
	
	
		
			
				|  | @@ -81,7 +117,7 @@ impl Move {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn to_string(&self) -> String {
 | 
	
		
			
				|  |  |          match self {
 | 
	
		
			
				|  |  | -            Move::Default{ mov, piece_type: _pt, captured: _c } => {
 | 
	
		
			
				|  |  | +            Move::Default{ mov, pc: _} => {
 | 
	
		
			
				|  |  |                  Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  |              Move::Castling{ side, left } => {
 | 
	
	
		
			
				|  | @@ -103,12 +139,13 @@ impl Move {
 | 
	
		
			
				|  |  |              Move::EnPassant{ mov, beaten: _ } => {
 | 
	
		
			
				|  |  |                  Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  | -            Move::Promotion{ mov, promote_to, captured: _c } => {
 | 
	
		
			
				|  |  | +            Move::Promotion{ mov, pc } => {
 | 
	
		
			
				|  |  | +                let promote_to = pc.piece_type();
 | 
	
		
			
				|  |  |                  Self::square_to_string(mov.from) + &Self::square_to_string(mov.to) + 
 | 
	
		
			
				|  |  | -                if *promote_to == QUEEN { "q" }
 | 
	
		
			
				|  |  | -                else if *promote_to == ROOK { "r" }
 | 
	
		
			
				|  |  | -                else if *promote_to == KNIGHT { "n" }
 | 
	
		
			
				|  |  | -                else if *promote_to == BISHOP { "b" }
 | 
	
		
			
				|  |  | +                if promote_to == QUEEN { "q" }
 | 
	
		
			
				|  |  | +                else if promote_to == ROOK { "r" }
 | 
	
		
			
				|  |  | +                else if promote_to == KNIGHT { "n" }
 | 
	
		
			
				|  |  | +                else if promote_to == BISHOP { "b" }
 | 
	
		
			
				|  |  |                  else { "" }
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  |              Move::Nullmove => {
 | 
	
	
		
			
				|  | @@ -119,8 +156,8 @@ impl Move {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn is_capture(&self) -> bool {
 | 
	
		
			
				|  |  |          match self {
 | 
	
		
			
				|  |  | -            Move::Default{ mov: _, piece_type: _, captured: c } => c.is_some(),
 | 
	
		
			
				|  |  | -            Move::Promotion{ mov: _, promote_to: _, captured: c } => c.is_some(),
 | 
	
		
			
				|  |  | +            Move::Default{ mov: _, pc } => pc.capture_type().is_some(),
 | 
	
		
			
				|  |  | +            Move::Promotion{ mov: _, pc } => pc.capture_type().is_some(),
 | 
	
		
			
				|  |  |              Move::EnPassant{ mov: _, beaten: _ } => true,
 | 
	
		
			
				|  |  |              Move::Castling{ side: _, left: _ } => false,
 | 
	
		
			
				|  |  |              Move::Nullmove => false
 | 
	
	
		
			
				|  | @@ -366,8 +403,8 @@ pub fn generate_legal_moves(game: &mut Game, side: Side, captures_only: bool) ->
 | 
	
		
			
				|  |  |      let check_legality = |m: &Move| {
 | 
	
		
			
				|  |  |          if !check {
 | 
	
		
			
				|  |  |              match m {
 | 
	
		
			
				|  |  | -                Move::Default { mov, piece_type: _, captured: _ } |
 | 
	
		
			
				|  |  | -                Move::Promotion { mov, promote_to: _, captured: _ } => {
 | 
	
		
			
				|  |  | +                Move::Default { mov, pc: _ } |
 | 
	
		
			
				|  |  | +                Move::Promotion { mov, pc: _ } => {
 | 
	
		
			
				|  |  |                      let from = from_square(mov.from);
 | 
	
		
			
				|  |  |                      if from & possible_pins == 0 && from != king {
 | 
	
		
			
				|  |  |                          return true;
 | 
	
	
		
			
				|  | @@ -476,13 +513,13 @@ fn mvv_lva_score(mov: &Move) -> i32 {
 | 
	
		
			
				|  |  |      ];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      match mov {
 | 
	
		
			
				|  |  | -        Move::Default { mov: _, piece_type, captured } => {
 | 
	
		
			
				|  |  | -            let attack = PIECE_VALUES[*piece_type as usize];
 | 
	
		
			
				|  |  | -            let victim = captured.map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
 | 
	
		
			
				|  |  | +        Move::Default { mov: _, pc } => {
 | 
	
		
			
				|  |  | +            let attack = PIECE_VALUES[pc.piece_type() as usize];
 | 
	
		
			
				|  |  | +            let victim = pc.capture_type().map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
 | 
	
		
			
				|  |  |              attack - victim * 5
 | 
	
		
			
				|  |  |          },
 | 
	
		
			
				|  |  | -        Move::Promotion { mov: _, promote_to: _, captured } => {
 | 
	
		
			
				|  |  | -            let victim = captured.map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
 | 
	
		
			
				|  |  | +        Move::Promotion { mov: _, pc } => {
 | 
	
		
			
				|  |  | +            let victim = pc.capture_type().map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
 | 
	
		
			
				|  |  |              PIECE_VALUES[PAWN as usize] - victim * 5
 | 
	
		
			
				|  |  |          },
 | 
	
		
			
				|  |  |          _ => 0
 | 
	
	
		
			
				|  | @@ -521,7 +558,7 @@ fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
 | 
	
		
			
				|  |  |              WHITE => south_one(p),
 | 
	
		
			
				|  |  |              BLACK => north_one(p)
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  | -        move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
 | 
	
		
			
				|  |  | +        move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, pc: PieceCaptureType::new(PAWN, None) });
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -544,7 +581,7 @@ fn generate_pawn_doublepushes(game: &Game, side: Side, move_list: &mut Vec<Move>
 | 
	
		
			
				|  |  |              WHITE => south_one(south_one(p)),
 | 
	
		
			
				|  |  |              BLACK => north_one(north_one(p))
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  | -        move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
 | 
	
		
			
				|  |  | +        move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, pc: PieceCaptureType::new(PAWN, None) });
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -570,12 +607,12 @@ fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
 | 
	
		
			
				|  |  |                  let captured = game.find_piece(*cap);
 | 
	
		
			
				|  |  |                  let simple_move = SimpleMove { from: square(pawn), to: square(*cap)};
 | 
	
		
			
				|  |  |                  if cap & promotion_mask != 0 {
 | 
	
		
			
				|  |  | -                    move_list.push(Move::Promotion { mov: simple_move, promote_to: QUEEN, captured: captured });
 | 
	
		
			
				|  |  | -                    move_list.push(Move::Promotion { mov: simple_move, promote_to: ROOK, captured: captured });
 | 
	
		
			
				|  |  | -                    move_list.push(Move::Promotion { mov: simple_move, promote_to: BISHOP, captured: captured });
 | 
	
		
			
				|  |  | -                    move_list.push(Move::Promotion { mov: simple_move, promote_to: KNIGHT, captured: captured });
 | 
	
		
			
				|  |  | +                    move_list.push(Move::Promotion { mov: simple_move, pc: PieceCaptureType::new(QUEEN, captured) });
 | 
	
		
			
				|  |  | +                    move_list.push(Move::Promotion { mov: simple_move, pc: PieceCaptureType::new(KNIGHT, captured) });
 | 
	
		
			
				|  |  | +                    move_list.push(Move::Promotion { mov: simple_move, pc: PieceCaptureType::new(ROOK, captured) });
 | 
	
		
			
				|  |  | +                    move_list.push(Move::Promotion { mov: simple_move, pc: PieceCaptureType::new(BISHOP, captured) });
 | 
	
		
			
				|  |  |                  } else {
 | 
	
		
			
				|  |  | -                    move_list.push(Move::Default { mov: simple_move, piece_type: PAWN, captured: captured });
 | 
	
		
			
				|  |  | +                    move_list.push(Move::Default { mov: simple_move, pc: PieceCaptureType::new(PAWN, captured) });
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -601,10 +638,10 @@ fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          let movement = SimpleMove { from: square(origin), to: square(p) };
 | 
	
		
			
				|  |  |          //move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
 | 
	
		
			
				|  |  | -        move_list.push(Move::Promotion { mov: movement, promote_to: QUEEN, captured: None });
 | 
	
		
			
				|  |  | -        move_list.push(Move::Promotion { mov: movement, promote_to: ROOK, captured: None });
 | 
	
		
			
				|  |  | -        move_list.push(Move::Promotion { mov: movement, promote_to: BISHOP, captured: None });
 | 
	
		
			
				|  |  | -        move_list.push(Move::Promotion { mov: movement, promote_to: KNIGHT, captured: None });
 | 
	
		
			
				|  |  | +        move_list.push(Move::Promotion { mov: movement, pc: PieceCaptureType::new(QUEEN, None) });
 | 
	
		
			
				|  |  | +        move_list.push(Move::Promotion { mov: movement, pc: PieceCaptureType::new(KNIGHT, None) });
 | 
	
		
			
				|  |  | +        move_list.push(Move::Promotion { mov: movement, pc: PieceCaptureType::new(ROOK, None) });
 | 
	
		
			
				|  |  | +        move_list.push(Move::Promotion { mov: movement, pc: PieceCaptureType::new(BISHOP, None) });
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -657,12 +694,12 @@ fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, cap
 | 
	
		
			
				|  |  |          for target in cap_targets {
 | 
	
		
			
				|  |  |              let simple_move = SimpleMove { from: square(k), to: square(target) };
 | 
	
		
			
				|  |  |              let captured = game.find_piece(target);
 | 
	
		
			
				|  |  | -            move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured });
 | 
	
		
			
				|  |  | +            move_list.push(Move::Default{ mov: simple_move, pc: PieceCaptureType::new(KNIGHT, captured) });
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          if !captures_only {
 | 
	
		
			
				|  |  |              for target in nocap_targets {
 | 
	
		
			
				|  |  |                  let simple_move = SimpleMove { from: square(k), to: square(target) };
 | 
	
		
			
				|  |  | -                move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured: None });
 | 
	
		
			
				|  |  | +                move_list.push(Move::Default{ mov: simple_move, pc: PieceCaptureType::new(KNIGHT, None) });
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -740,10 +777,10 @@ fn generate_sliding_moves(game: &Game, friends: Bitboard, others: Bitboard, piec
 | 
	
		
			
				|  |  |          for dest in dest_iter {
 | 
	
		
			
				|  |  |              let smove = SimpleMove{ from: square(piece), to: square(dest) };
 | 
	
		
			
				|  |  |              if dest & others != 0 {
 | 
	
		
			
				|  |  | -                move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: game.find_piece(dest) });
 | 
	
		
			
				|  |  | +                move_list.push(Move::Default { mov: smove, pc: PieceCaptureType::new(piece_type, game.find_piece(dest)) });
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              else {
 | 
	
		
			
				|  |  | -                move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: None });
 | 
	
		
			
				|  |  | +                move_list.push(Move::Default { mov: smove, pc: PieceCaptureType::new(piece_type, None) });
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -818,7 +855,7 @@ fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captu
 | 
	
		
			
				|  |  |      for destination in area_iter {
 | 
	
		
			
				|  |  |          let simple_move = SimpleMove{ from: square(king), to: square(destination) };
 | 
	
		
			
				|  |  |          let captured = game.find_piece(destination);
 | 
	
		
			
				|  |  | -        move_list.push(Move::Default { mov: simple_move, piece_type: KING, captured });
 | 
	
		
			
				|  |  | +        move_list.push(Move::Default { mov: simple_move, pc: PieceCaptureType::new(KING, captured) });
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |