|  | @@ -23,7 +23,7 @@ enum MoveUndo {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  pub struct SearchControl<'a> {
 |  |  pub struct SearchControl<'a> {
 | 
											
												
													
														|  |      pub nodes: usize,
 |  |      pub nodes: usize,
 | 
											
												
													
														|  | -    pub check: &'a dyn Fn() -> bool,
 |  | 
 | 
											
												
													
														|  | 
 |  | +    pub check: &'a mut dyn FnMut() -> bool,
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -56,10 +56,17 @@ pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> Move {
 | 
											
												
													
														|  |      // determine possibly multiple good moves
 |  |      // determine possibly multiple good moves
 | 
											
												
													
														|  |      const ALPHA_OFFSET: i32 = 50;
 |  |      const ALPHA_OFFSET: i32 = 50;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    let mut valued_moves = moves.iter().map(|mov| {
 |  | 
 | 
											
												
													
														|  | -        let new_game = apply_move(game, *mov);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    let mut valued_moves: Vec<(Move, i32)> = Vec::with_capacity(moves.len());
 | 
											
												
													
														|  | 
 |  | +    for mov in moves {
 | 
											
												
													
														|  | 
 |  | +        let new_game = apply_move(game, mov);
 | 
											
												
													
														|  |          //info!("searching {}", mov.to_string());
 |  |          //info!("searching {}", mov.to_string());
 | 
											
												
													
														|  | -        let val = -negamax(&new_game, sc, -beta, -alpha, depth - 1);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        let (mut val, ret) = negamax(&new_game, sc, -beta, -alpha, depth - 1);
 | 
											
												
													
														|  | 
 |  | +        val = -val;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        if ret {
 | 
											
												
													
														|  | 
 |  | +            return Move::default();
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |          info!("searched {} -> {}", mov.to_string(), val);
 |  |          info!("searched {} -> {}", mov.to_string(), val);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          if val > alpha {
 |  |          if val > alpha {
 | 
											
										
											
												
													
														|  | @@ -67,8 +74,9 @@ pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> Move {
 | 
											
												
													
														|  |              //info!("updated alpha to {}", alpha);
 |  |              //info!("updated alpha to {}", alpha);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -        (*mov, -val)
 |  | 
 | 
											
												
													
														|  | -    }).collect::<Vec<(Move, i32)>>();
 |  | 
 | 
											
												
													
														|  | 
 |  | +        valued_moves.push((mov, -val));
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |      //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);
 | 
											
										
											
												
													
														|  | @@ -87,43 +95,54 @@ pub fn search(game: &Game, sc: &mut SearchControl, depth: i32) -> Move {
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -fn negamax(game: &Game, sc: &mut SearchControl, mut alpha: i32, beta: i32, depth: i32) -> i32 {
 |  | 
 | 
											
												
													
														|  | 
 |  | +fn negamax(game: &Game, sc: &mut SearchControl, mut alpha: i32, beta: i32, depth: i32) -> (i32, bool) {
 | 
											
												
													
														|  |      if depth == 0 {
 |  |      if depth == 0 {
 | 
											
												
													
														|  | -        return quiescence_search(game, sc, alpha, beta, 7);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        return (quiescence_search(game, sc, alpha, beta, 7), false);
 | 
											
												
													
														|  |          let eval = evaluate(game);
 |  |          let eval = evaluate(game);
 | 
											
												
													
														|  |          if eval != 0 {
 |  |          if eval != 0 {
 | 
											
												
													
														|  |              //info!("eval: {}", eval);
 |  |              //info!("eval: {}", eval);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  | -        return eval;
 |  | 
 | 
											
												
													
														|  | 
 |  | +        //return eval;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      const MIN_VALUE: i32 = i32::min_value() + 1;
 |  |      const MIN_VALUE: i32 = i32::min_value() + 1;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      sc.nodes += 1;
 |  |      sc.nodes += 1;
 | 
											
												
													
														|  | 
 |  | +    if sc.nodes % 128 == 0 {
 | 
											
												
													
														|  | 
 |  | +        if (sc.check)() {
 | 
											
												
													
														|  | 
 |  | +            return (0, true);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      let mut best = MIN_VALUE;
 |  |      let mut best = MIN_VALUE;
 | 
											
												
													
														|  |      //let mut best_move = Move::default();
 |  |      //let mut best_move = Move::default();
 | 
											
												
													
														|  |      //info!(" -> generate_legal_moves");
 |  |      //info!(" -> generate_legal_moves");
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    if game.get_piece(KING, game.turn) == 0 { return MIN_VALUE; }
 |  | 
 | 
											
												
													
														|  | 
 |  | +    if game.get_piece(KING, game.turn) == 0 { return (MIN_VALUE, false); }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      let moves = generate_legal_moves(game, game.turn);
 |  |      let moves = generate_legal_moves(game, game.turn);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      if moves.len() == 0 {
 |  |      if moves.len() == 0 {
 | 
											
												
													
														|  |          if is_check(game, game.turn) {
 |  |          if is_check(game, game.turn) {
 | 
											
												
													
														|  |              // mate
 |  |              // mate
 | 
											
												
													
														|  | -            return MIN_VALUE;
 |  | 
 | 
											
												
													
														|  | 
 |  | +            return (MIN_VALUE, false);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          else {
 |  |          else {
 | 
											
												
													
														|  |              // stalemate
 |  |              // stalemate
 | 
											
												
													
														|  | -            return 0;
 |  | 
 | 
											
												
													
														|  | 
 |  | +            return (0, false);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      for mov in moves {
 |  |      for mov in moves {
 | 
											
												
													
														|  |          let new_game = apply_move(game, mov);
 |  |          let new_game = apply_move(game, mov);
 | 
											
												
													
														|  | -        let val = -negamax(&new_game, sc, -beta, -alpha, depth - 1);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        let (mut val, ret) = negamax(&new_game, sc, -beta, -alpha, depth - 1);
 | 
											
												
													
														|  | 
 |  | +        val = -val;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        if ret {
 | 
											
												
													
														|  | 
 |  | +            return (alpha, ret)
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |          if val >= beta {
 |  |          if val >= beta {
 | 
											
												
													
														|  | -            return beta;
 |  | 
 | 
											
												
													
														|  | 
 |  | +            return (beta, false);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          if val > alpha {
 |  |          if val > alpha {
 | 
											
												
													
														|  |              alpha = (val as f64 * 0.95) as i32;
 |  |              alpha = (val as f64 * 0.95) as i32;
 | 
											
										
											
												
													
														|  | @@ -136,7 +155,7 @@ 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;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    return ((best as f64 * 0.99) as i32, false);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  fn quiescence_search(game: &Game, si: &mut SearchControl, mut alpha: i32, beta: i32, depth: i32) -> i32 {
 |  |  fn quiescence_search(game: &Game, si: &mut SearchControl, mut alpha: i32, beta: i32, depth: i32) -> i32 {
 |