/// /// Simulates a 3x3 game of /// calculating cultivators /// /// Output is /// 1. left starting position /// 2. right starting position /// 3. outcome class of the game /// #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] struct Pos { row: i8, col: i8, } impl Pos { fn new(row: i8, col: i8) -> Option { if row < 0 || row >= 3 || col < 0 || col >= 3 { None } else { Some(Self { row, col }) } } fn index(&self) -> usize { (self.row * 3 + self.col) as usize } fn step(&self, d_row: i8, d_col: i8) -> Option { Self::new(self.row + d_row, self.col + d_col) } fn from_index(index: usize) -> Self { let row = (index as i8) / 3; let col = (index as i8) % 3; Self { row, col } } fn as_str(&self) -> &'static str { let i = self.index(); match i { 0 => "A1", 1 => "A2", 2 => "A3", 3 => "B1", 4 => "B2", 5 => "B3", 6 => "C1", 7 => "C2", _ => "C3", } } } #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] struct Game { left: Pos, right: Pos, board: [bool; 9] } impl Game { fn moves_in_dir(&self, moves: &mut Vec, mut plr: Pos, d_row: i8, d_col: i8) { loop { let Some(new_pos) = plr.step(d_row, d_col) else { break; }; let index = new_pos.index(); if self.left == new_pos || self.right == new_pos || self.board[index] { break; } moves.push(new_pos); plr = new_pos; } } fn moves_left(&self) -> Vec { let mut moves = vec![]; self.moves_in_dir(&mut moves, self.left, -1, 0); self.moves_in_dir(&mut moves, self.left, 1, 0); self.moves_in_dir(&mut moves, self.left, 0, -1); self.moves_in_dir(&mut moves, self.left, 0, 1); return moves; } fn moves_right(&self) -> Vec { let mut moves = vec![]; self.moves_in_dir(&mut moves, self.left, -1, -1); self.moves_in_dir(&mut moves, self.left, -1, 1); self.moves_in_dir(&mut moves, self.left, 1, -1); self.moves_in_dir(&mut moves, self.left, 1, 1); return moves; } fn game_class(&self) -> char { let left_moves = self.moves_left(); let right_moves = self.moves_right(); if left_moves.is_empty() && right_moves.is_empty() { return 'p'; } let mut left_win = false; let mut right_win = false; for mov in left_moves { let mut game = *self; game.board[game.left.index()] = true; game.left = mov; let class = game.game_class(); if class == 'p' || class == 'l' { left_win = true; break; } } for mov in right_moves { let mut game = *self; game.board[game.right.index()] = true; game.right = mov; let class = game.game_class(); if class == 'p' || class == 'r' { right_win = true; break; } } if left_win && right_win { return 'n'; } if left_win { return 'l'; } if right_win { return 'r'; } return 'p'; } } fn main() { for i in 0..9 { for j in 0..9 { if i == j { continue; } let mut game = Game::default(); game.left = Pos::from_index(i); game.right = Pos::from_index(j); let class = game.game_class(); println!("{} {} {}", game.left.as_str(), game.right.as_str(), class.to_uppercase()); } } }