board_game/heuristic/
ataxx.rs

1use std::cmp::{max, Ordering};
2
3use crate::ai::minimax::Heuristic;
4use crate::ai::solver::SolverHeuristic;
5use crate::board::Board;
6use crate::games::ataxx::AtaxxBoard;
7use crate::util::bitboard::BitBoard8;
8
9#[derive(Debug)]
10pub struct AtaxxTileHeuristic {
11    pub tile_factor: i32,
12    pub surface_factor: i32,
13}
14
15impl AtaxxTileHeuristic {
16    pub fn new(tile_factor: i32, surface_factor: i32) -> Self {
17        AtaxxTileHeuristic {
18            tile_factor,
19            surface_factor,
20        }
21    }
22
23    pub fn greedy() -> Self {
24        AtaxxTileHeuristic {
25            tile_factor: 1,
26            surface_factor: 0,
27        }
28    }
29}
30
31impl Default for AtaxxTileHeuristic {
32    fn default() -> Self {
33        AtaxxTileHeuristic {
34            tile_factor: 100,
35            surface_factor: 10,
36        }
37    }
38}
39
40impl AtaxxTileHeuristic {
41    fn player_score(&self, board: &AtaxxBoard, tiles: BitBoard8) -> i32 {
42        let tile_count = tiles.count() as i32;
43        let surface_area = (tiles.adjacent() & board.free_tiles()).count() as i32;
44
45        self.tile_factor * tile_count + self.surface_factor * surface_area
46    }
47}
48
49impl Heuristic<AtaxxBoard> for AtaxxTileHeuristic {
50    type V = i32;
51
52    fn value(&self, board: &AtaxxBoard, length: u32) -> Self::V {
53        if board.is_done() {
54            // return near-max values for wins/draws/losses
55            SolverHeuristic.value(board, length).to_i32()
56        } else {
57            let (next, other) = board.tiles_pov();
58            self.player_score(board, next) - self.player_score(board, other)
59        }
60    }
61
62    fn merge(old: Self::V, new: Self::V) -> (Self::V, Ordering) {
63        (max(old, new), new.cmp(&old))
64    }
65}