|  | @@ -26,11 +26,21 @@ pub struct SearchControl<'a> {
 | 
											
												
													
														|  |      pub check: &'a mut dyn FnMut() -> bool,
 |  |      pub check: &'a mut dyn FnMut() -> bool,
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +pub enum SearchResult {
 | 
											
												
													
														|  | 
 |  | +    Finished(Move, PosValue),
 | 
											
												
													
														|  | 
 |  | +    Mate(Move, i32),
 | 
											
												
													
														|  | 
 |  | +    Cancelled(Option<(Move, PosValue)>),
 | 
											
												
													
														|  | 
 |  | +    Invalid
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> Move {
 |  | 
 | 
											
												
													
														|  | 
 |  | +/**
 | 
											
												
													
														|  | 
 |  | + * searches for moves and returns the best move found plus its value
 | 
											
												
													
														|  | 
 |  | + */
 | 
											
												
													
														|  | 
 |  | +pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> SearchResult {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      if depth == 0 {
 |  |      if depth == 0 {
 | 
											
												
													
														|  | -        return Move::default();
 |  | 
 | 
											
												
													
														|  | 
 |  | +        return SearchResult::Invalid;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      let mut moves = generate_legal_moves(game, game.turn);
 |  |      let mut moves = generate_legal_moves(game, game.turn);
 | 
											
										
											
												
													
														|  | @@ -49,14 +59,15 @@ pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> Move {
 | 
											
												
													
														|  |      
 |  |      
 | 
											
												
													
														|  |      info!("moves: {:?}", moves.iter().map(|mv| mv.to_string()).collect::<Vec<String>>());
 |  |      info!("moves: {:?}", moves.iter().map(|mv| mv.to_string()).collect::<Vec<String>>());
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    let mut alpha = i32::min_value() + 1;
 |  | 
 | 
											
												
													
														|  | -    let mut beta = i32::max_value();
 |  | 
 | 
											
												
													
														|  | 
 |  | +    let mut alpha: PosValue = MIN_VALUE;
 | 
											
												
													
														|  | 
 |  | +    let mut beta: PosValue = MAX_VALUE;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      // use a slight offset for the alpha value in the root node in order to
 |  |      // use a slight offset for the alpha value in the root node in order to
 | 
											
												
													
														|  |      // determine possibly multiple good moves
 |  |      // determine possibly multiple good moves
 | 
											
												
													
														|  | -    const ALPHA_OFFSET: i32 = 50;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    const ALPHA_OFFSET: PosValue = 50 as _;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    let mut valued_moves: Vec<(Move, i32)> = Vec::with_capacity(moves.len());
 |  | 
 | 
											
												
													
														|  | 
 |  | +    let mut valued_moves: Vec<(Move, PosValue)> = Vec::with_capacity(moves.len());
 | 
											
												
													
														|  | 
 |  | +    let mut cancelled = false;
 | 
											
												
													
														|  |      for mov in moves {
 |  |      for mov in moves {
 | 
											
												
													
														|  |          let new_game = apply_move(game, mov);
 |  |          let new_game = apply_move(game, mov);
 | 
											
												
													
														|  |          //info!("searching {}", mov.to_string());
 |  |          //info!("searching {}", mov.to_string());
 | 
											
										
											
												
													
														|  | @@ -64,10 +75,18 @@ pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> Move {
 | 
											
												
													
														|  |          val = -val;
 |  |          val = -val;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          if ret {
 |  |          if ret {
 | 
											
												
													
														|  | -            return Move::default();
 |  | 
 | 
											
												
													
														|  | 
 |  | +            //return (Move::default(), 0);
 | 
											
												
													
														|  | 
 |  | +            cancelled = true;
 | 
											
												
													
														|  | 
 |  | +            break;
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -        info!("searched {} -> {}", mov.to_string(), val);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        if val >= MAX_VALUE {
 | 
											
												
													
														|  | 
 |  | +            // mate in 1
 | 
											
												
													
														|  | 
 |  | +            info!("yay mate!");
 | 
											
												
													
														|  | 
 |  | +            return SearchResult::Mate(mov, 1);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        //info!("searched {} -> {}", mov.to_string(), val);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          if val > alpha {
 |  |          if val > alpha {
 | 
											
												
													
														|  |              alpha = val - ALPHA_OFFSET;
 |  |              alpha = val - ALPHA_OFFSET;
 | 
											
										
											
												
													
														|  | @@ -79,38 +98,42 @@ pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> Move {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      //info!("movvalues: {:?}", valued_moves.iter().map(|mv| mv.0.to_string() + " - " + &mv.1.to_string()).collect::<Vec<String>>());
 |  |      //info!("movvalues: {:?}", valued_moves.iter().map(|mv| mv.0.to_string() + " - " + &mv.1.to_string()).collect::<Vec<String>>());
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    valued_moves.sort_by_key(|mv| mv.1);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    valued_moves.sort_by_key(|mv| (mv.1 * 1000.0f32) as i64);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      //info!("best movvalues: {:?}", valued_moves.iter().map(|mv| mv.0.to_string() + " - " + &mv.1.to_string()).collect::<Vec<String>>());
 |  |      //info!("best movvalues: {:?}", valued_moves.iter().map(|mv| mv.0.to_string() + " - " + &mv.1.to_string()).collect::<Vec<String>>());
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      if valued_moves.len() > 0 {
 |  |      if valued_moves.len() > 0 {
 | 
											
												
													
														|  |          let min_val = valued_moves[0].1;
 |  |          let min_val = valued_moves[0].1;
 | 
											
												
													
														|  | -        let best_moves = valued_moves.iter().filter(|mv| mv.1 == min_val).map(|(mov, _)| *mov).collect::<Vec<Move>>();
 |  | 
 | 
											
												
													
														|  | 
 |  | +        let best_moves = valued_moves.iter().filter(|mv| mv.1 == min_val).collect::<Vec<&(Move, PosValue)>>();
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          //info!("bestmove value {}", -min_val);
 |  |          //info!("bestmove value {}", -min_val);
 | 
											
												
													
														|  | -        return best_moves[(rng.next_u64() % best_moves.len() as u64) as usize];
 |  | 
 | 
											
												
													
														|  | 
 |  | +        let chosen_mov = best_moves[(rng.next_u64() % best_moves.len() as u64) as usize];
 | 
											
												
													
														|  | 
 |  | +        if cancelled {
 | 
											
												
													
														|  | 
 |  | +            return SearchResult::Cancelled(Some((chosen_mov.0, chosen_mov.1)));
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        else {
 | 
											
												
													
														|  | 
 |  | +            return SearchResult::Finished(chosen_mov.0, chosen_mov.1);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      else {
 |  |      else {
 | 
											
												
													
														|  | -        return Move::Default{ mov: SimpleMove{ from: 0, to: 0 }, piece_type: PAWN };
 |  | 
 | 
											
												
													
														|  | 
 |  | +        return SearchResult::Invalid;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -fn negamax(game: &Game, sc: &mut SearchControl, mut alpha: i32, beta: i32, depth: i32) -> (i32, bool) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +fn negamax(game: &Game, sc: &mut SearchControl, mut alpha: PosValue, beta: PosValue, depth: i32) -> (PosValue, bool) {
 | 
											
												
													
														|  |      if depth == 0 {
 |  |      if depth == 0 {
 | 
											
												
													
														|  |          return (quiescence_search(game, sc, alpha, beta, 7), false);
 |  |          return (quiescence_search(game, sc, alpha, beta, 7), false);
 | 
											
												
													
														|  |          let eval = evaluate(game);
 |  |          let eval = evaluate(game);
 | 
											
												
													
														|  | -        if eval != 0 {
 |  | 
 | 
											
												
													
														|  | 
 |  | +        if eval != 0.0f32 {
 | 
											
												
													
														|  |              //info!("eval: {}", eval);
 |  |              //info!("eval: {}", eval);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          //return eval;
 |  |          //return eval;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    const MIN_VALUE: i32 = i32::min_value() + 1;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |      sc.nodes += 1;
 |  |      sc.nodes += 1;
 | 
											
												
													
														|  |      if sc.nodes % 128 == 0 {
 |  |      if sc.nodes % 128 == 0 {
 | 
											
												
													
														|  |          if (sc.check)() {
 |  |          if (sc.check)() {
 | 
											
												
													
														|  | -            return (0, true);
 |  | 
 | 
											
												
													
														|  | 
 |  | +            return (0 as _, true);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -129,7 +152,7 @@ fn negamax(game: &Game, sc: &mut SearchControl, mut alpha: i32, beta: i32, depth
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          else {
 |  |          else {
 | 
											
												
													
														|  |              // stalemate
 |  |              // stalemate
 | 
											
												
													
														|  | -            return (0, false);
 |  | 
 | 
											
												
													
														|  | 
 |  | +            return (0 as _, false);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      for mov in moves {
 |  |      for mov in moves {
 | 
											
										
											
												
													
														|  | @@ -145,7 +168,7 @@ fn negamax(game: &Game, sc: &mut SearchControl, mut alpha: i32, beta: i32, depth
 | 
											
												
													
														|  |              return (beta, false);
 |  |              return (beta, false);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          if val > alpha {
 |  |          if val > alpha {
 | 
											
												
													
														|  | -            alpha = (val as f64 * 0.95) as i32;
 |  | 
 | 
											
												
													
														|  | 
 |  | +            alpha = (val as f64 * 0.95) as _;
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          //info!(" -> negamaxed {} -> {}", mov.to_string(), depth - 1);
 |  |          //info!(" -> negamaxed {} -> {}", mov.to_string(), depth - 1);
 | 
											
												
													
														|  |          if val > best {
 |  |          if val > best {
 | 
											
										
											
												
													
														|  | @@ -155,12 +178,10 @@ fn negamax(game: &Game, sc: &mut SearchControl, mut alpha: i32, beta: i32, depth
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      //info!("best alpha {}", best);
 |  |      //info!("best alpha {}", best);
 | 
											
												
													
														|  | -    return ((best as f64 * 0.99) as i32, false);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    return ((best as f64 * 0.99) as _, false);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -fn quiescence_search(game: &Game, si: &mut SearchControl, mut alpha: i32, beta: i32, depth: i32) -> i32 {
 |  | 
 | 
											
												
													
														|  | -    const MIN_VALUE: i32 = i32::min_value() + 1;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | 
 |  | +fn quiescence_search(game: &Game, si: &mut SearchControl, mut alpha: PosValue, beta: PosValue, depth: i32) -> PosValue {
 | 
											
												
													
														|  |      let val = evaluate(game);
 |  |      let val = evaluate(game);
 | 
											
												
													
														|  |      si.nodes += 1;
 |  |      si.nodes += 1;
 | 
											
												
													
														|  |  
 |  |  
 |