pub const BOARD_SIZE: usize = 36;
pub const NUM_SQUARES: usize = BOARD_SIZE * BOARD_SIZE; pub const BLACK: u8 = 0;
pub const WHITE: u8 = 1;
pub const PROMO_ZONE_DEPTH: usize = 11;
#[inline]
pub fn in_promo_zone(sq: usize, color: u8) -> bool {
let row = sq / BOARD_SIZE;
if color == BLACK { row < PROMO_ZONE_DEPTH } else { row >= BOARD_SIZE - PROMO_ZONE_DEPTH }
}
#[inline]
pub fn is_farthest_rank(sq: usize, color: u8) -> bool {
let row = sq / BOARD_SIZE;
if color == BLACK { row == 0 } else { row == BOARD_SIZE - 1 }
}
pub const N: usize = 0;
pub const NE: usize = 1;
pub const E: usize = 2;
pub const SE: usize = 3;
pub const S: usize = 4;
pub const SW: usize = 5;
pub const W: usize = 6;
pub const NW: usize = 7;
pub const NUM_DIRS: usize = 8;
pub const DIR_DR: [i32; 8] = [-1, -1, 0, 1, 1, 1, 0, -1];
pub const DIR_DC: [i32; 8] = [0, 1, 1, 1, 0, -1, -1, -1];
pub type Cell = u16;
pub const EMPTY_CELL: Cell = 0;
pub const INVALID_SQ: u16 = 0xFFFF;
pub const MAX_PIECES_PER_SIDE: usize = 410;
pub const MAX_ROYALS: usize = 8;
#[inline]
pub fn make_cell(piece_type: u16, color: u8) -> Cell {
(piece_type << 1) | (color as u16)
}
#[inline]
pub fn cell_piece(cell: Cell) -> u16 {
cell >> 1
}
#[inline]
pub fn cell_color(cell: Cell) -> u8 {
(cell & 1) as u8
}
#[inline]
pub fn sq_index(row: usize, col: usize) -> usize {
row * BOARD_SIZE + col
}
#[inline]
pub fn sq_row(sq: usize) -> usize {
sq / BOARD_SIZE
}
#[inline]
pub fn sq_col(sq: usize) -> usize {
sq % BOARD_SIZE
}
#[inline]
pub fn get_deltas(dir: usize, color: u8) -> (i32, i32) {
if color == BLACK {
(DIR_DR[dir], DIR_DC[dir])
} else {
(-DIR_DR[dir], -DIR_DC[dir])
}
}
#[inline]
pub fn step_sq(sq: usize, dir: usize, color: u8) -> Option<usize> {
let (dr, dc) = get_deltas(dir, color);
let r = sq_row(sq) as i32 + dr;
let c = sq_col(sq) as i32 + dc;
if r >= 0 && r < BOARD_SIZE as i32 && c >= 0 && c < BOARD_SIZE as i32 {
Some(r as usize * BOARD_SIZE + c as usize)
} else {
None
}
}
#[derive(Clone, Copy, Debug)]
pub enum GameResult {
BlackWins,
WhiteWins,
Draw,
}
#[derive(Clone, Debug)]
pub struct Movement {
pub slides: Vec<(u8, u8)>, pub jumps: Vec<(i8, i8)>, pub hook: Option<HookType>,
pub area: u8, pub range_capture: Vec<u8>, pub igui: bool,
}
#[derive(Clone, Copy, Debug)]
pub enum HookType {
Orthogonal,
Diagonal,
}
impl Movement {
pub fn empty() -> Self {
Movement {
slides: Vec::new(),
jumps: Vec::new(),
hook: None,
area: 0,
range_capture: Vec::new(),
igui: false,
}
}
}
#[derive(Clone, Debug)]
pub struct Move {
pub from_sq: u16,
pub to_sq: u16,
pub promotion: bool,
pub captured_piece: u16, pub captured_color: u8,
pub is_igui: bool,
pub mid_sq: u16, pub mid_piece: u16,
pub mid_color: u8,
pub range_caps: Option<Vec<(u16, u16, u8)>>, }
impl Move {
pub fn simple(from: u16, to: u16) -> Self {
Move {
from_sq: from, to_sq: to, promotion: false,
captured_piece: 0, captured_color: 0, is_igui: false,
mid_sq: INVALID_SQ, mid_piece: 0, mid_color: 0,
range_caps: None,
}
}
}
pub const RANK_ROYAL: u8 = 0;
pub const RANK_GREAT: u8 = 1;
pub const RANK_VICE: u8 = 2;
pub const RANK_RANGE_CAP: u8 = 3;
pub const RANK_NORMAL: u8 = 4;
#[derive(Clone)]
pub struct UndoInfo {
pub from_sq: u16,
pub to_sq: u16,
pub from_cell: Cell,
pub to_cell: Cell,
pub side: u8,
pub move_number: u32,
pub mid_sq: u16,
pub mid_cell: Cell,
pub range_caps: Option<Vec<(u16, Cell)>>,
}
pub struct RayTable {
offsets: Vec<u32>,
lens: Vec<u8>,
data: Vec<u16>,
}
impl RayTable {
pub fn new() -> Self {
let total = NUM_SQUARES * NUM_DIRS;
let mut offsets = vec![0u32; total];
let mut lens = vec![0u8; total];
let mut data = Vec::with_capacity(total * 18);
for sq in 0..NUM_SQUARES {
let r = sq_row(sq) as i32;
let c = sq_col(sq) as i32;
for dir in 0..NUM_DIRS {
let idx = sq * NUM_DIRS + dir;
offsets[idx] = data.len() as u32;
let dr = DIR_DR[dir];
let dc = DIR_DC[dir];
let mut cr = r + dr;
let mut cc = c + dc;
let mut count = 0u8;
while cr >= 0 && cr < BOARD_SIZE as i32 && cc >= 0 && cc < BOARD_SIZE as i32 {
data.push((cr as usize * BOARD_SIZE + cc as usize) as u16);
count += 1;
cr += dr;
cc += dc;
}
lens[idx] = count;
}
}
RayTable { offsets, lens, data }
}
#[inline]
pub fn ray(&self, sq: usize, dir: usize) -> &[u16] {
let idx = sq * NUM_DIRS + dir;
let start = self.offsets[idx] as usize;
let len = self.lens[idx] as usize;
&self.data[start..start + len]
}
#[inline]
pub fn ray_for_color(&self, sq: usize, dir: usize, color: u8) -> &[u16] {
if color == BLACK {
self.ray(sq, dir)
} else {
self.ray(sq, (dir + 4) % 8)
}
}
}
use std::sync::OnceLock;
static RAY_TABLE: OnceLock<RayTable> = OnceLock::new();
pub fn ray_table() -> &'static RayTable {
RAY_TABLE.get_or_init(RayTable::new)
}