more tests

This commit is contained in:
jackjohn7 2026-04-15 03:03:56 -05:00
parent a4cbde9713
commit aa562d4ab6
2 changed files with 69 additions and 12 deletions

View file

@ -245,9 +245,8 @@ fn alphabeta_with_printing_inner(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::board::view::View;
use crate::board::{BitBoard, Board, Score}; use crate::board::{BitBoard, Board, Score};
use crate::game::Game; use crate::game::{Game, Team};
use rand::prelude::IndexedRandom; use rand::prelude::IndexedRandom;
use rand::rngs::StdRng; use rand::rngs::StdRng;
@ -259,25 +258,72 @@ mod tests {
*moves.choose(rng).unwrap() *moves.choose(rng).unwrap()
} }
fn game_after(moves: &[Board]) -> Game {
let mut game = Game::default();
for &mv in moves {
game.safe_play(mv).expect("Move should be valid");
}
game
}
fn assert_ai_move_is_legal(game: &Game, depth: u8) -> Board {
let available = game.available();
let best_move = alphabeta(game.clone(), depth, i8::MIN + 1, i8::MAX - 1).0;
assert_ne!(best_move, 0, "AI should return a move when one exists");
assert_eq!(
best_move & available,
best_move,
"AI returned an illegal move"
);
best_move
}
#[test] #[test]
// just a sanity check to ensure that my AI performs up to snuff with another popular engine // just a sanity check to ensure that my AI performs up to snuff with another popular engine
fn opening() { fn opening() {
let mut game = Game::default(); let mut game = Game::default();
println!("{}", game.board().render(View::RankAsc, vec![]));
game.play(D3); game.play(D3);
let (best_move, _) = alphabeta(game.clone(), 12, i8::MIN + 1, i8::MAX - 1); let (best_move, _) = alphabeta(game.clone(), 12, i8::MIN + 1, i8::MAX - 1);
println!(
"dis:\n{}",
BitBoard {
boards: [0, best_move]
}
);
game.play(best_move);
println!("{}", game.board().render(View::RankAsc, vec![]));
assert_eq!(best_move, C3); assert_eq!(best_move, C3);
} }
#[test]
fn ai_returns_legal_moves_across_curated_positions() {
let cases = vec![
(game_after(&[]), 4),
(game_after(&[D3]), 4),
(game_after(&[F5, F6, E6, F4]), 4),
];
for (game, depth) in cases {
let available = game.available();
if available == 0 {
continue;
}
let mv = assert_ai_move_is_legal(&game, depth);
assert_ne!(mv, 0);
}
}
#[test]
fn ai_prefers_forced_corner() {
let board = BitBoard::from_jon("5bw//////").expect("Valid board");
let game = Game::from_parts(Team::Black, board);
assert_eq!(game.available(), H8);
let mv = assert_ai_move_is_legal(&game, 3);
assert_eq!(mv, H8);
}
#[test]
fn ai_passes_when_no_moves_exist() {
let board = BitBoard::from_jon("wwwwwwww/wwwwwwww/////").expect("Valid board");
let game = Game::from_parts(Team::Black, board);
assert_eq!(game.available(), 0);
let (mv, eval) = alphabeta(game.clone(), 4, i8::MIN + 1, i8::MAX - 1);
assert_eq!(mv, 0);
assert_eq!(eval, game.score().diff());
}
// I found that, despite the AI clobbering me, the AI could not // I found that, despite the AI clobbering me, the AI could not
// compete with itself very well. I'm honestly not quite sure why that is. // compete with itself very well. I'm honestly not quite sure why that is.
#[test] #[test]
@ -310,6 +356,7 @@ mod tests {
} else { } else {
random_move(&game, &mut rng) random_move(&game, &mut rng)
}; };
assert_eq!(mv & game.available(), mv, "AI generated an illegal move");
game.play(mv); game.play(mv);
} }

View file

@ -71,6 +71,16 @@ impl Game {
} }
} }
#[cfg(test)]
impl Game {
pub(crate) fn from_parts(current_team: Team, board: BitBoard) -> Self {
Self {
current_team,
board,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;