more tests
This commit is contained in:
parent
a4cbde9713
commit
aa562d4ab6
2 changed files with 69 additions and 12 deletions
71
src/ai.rs
71
src/ai.rs
|
|
@ -245,9 +245,8 @@ fn alphabeta_with_printing_inner(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::board::view::View;
|
||||
use crate::board::{BitBoard, Board, Score};
|
||||
use crate::game::Game;
|
||||
use crate::game::{Game, Team};
|
||||
|
||||
use rand::prelude::IndexedRandom;
|
||||
use rand::rngs::StdRng;
|
||||
|
|
@ -259,25 +258,72 @@ mod tests {
|
|||
*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]
|
||||
// just a sanity check to ensure that my AI performs up to snuff with another popular engine
|
||||
fn opening() {
|
||||
let mut game = Game::default();
|
||||
|
||||
println!("{}", game.board().render(View::RankAsc, vec![]));
|
||||
game.play(D3);
|
||||
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);
|
||||
}
|
||||
|
||||
#[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
|
||||
// compete with itself very well. I'm honestly not quite sure why that is.
|
||||
#[test]
|
||||
|
|
@ -310,6 +356,7 @@ mod tests {
|
|||
} else {
|
||||
random_move(&game, &mut rng)
|
||||
};
|
||||
assert_eq!(mv & game.available(), mv, "AI generated an illegal move");
|
||||
game.play(mv);
|
||||
}
|
||||
|
||||
|
|
|
|||
10
src/game.rs
10
src/game.rs
|
|
@ -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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue