diff options
author | Kai Stevenson <kai@kaistevenson.com> | 2025-05-07 23:08:15 -0700 |
---|---|---|
committer | Kai Stevenson <kai@kaistevenson.com> | 2025-05-07 23:08:15 -0700 |
commit | af2bc841119a6751c240dec95dd5511d4ee31d36 (patch) | |
tree | 693cb7d3d6d06bb667a89b1d4d8d2bdaee8ab983 /tic_tac_toe/src/main.rs |
init ; most of tic tac toe done
Diffstat (limited to 'tic_tac_toe/src/main.rs')
-rw-r--r-- | tic_tac_toe/src/main.rs | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/tic_tac_toe/src/main.rs b/tic_tac_toe/src/main.rs new file mode 100644 index 0000000..19285a2 --- /dev/null +++ b/tic_tac_toe/src/main.rs @@ -0,0 +1,162 @@ +mod ai; +mod board; +mod console_helpers; + +use ai::get_best_move; +use board::{Board, Coord, GameState, Tile, init_board, parse_coord}; +use console_helpers::{clear_scrn, write_header}; + +use std::io; + +fn render_board(board: &Board) -> () { + println!(" 1 2 3"); + let mut y = 1; + for row_i in 0..3 { + let row: Vec<Tile> = (0..3).map(|col_i| board.state[col_i][row_i]).collect(); + print!("{y} "); + for tile in row { + print!(" {tile} ") + } + println!("\n"); + y += 1; + } +} + +fn get_coord_input() -> Coord { + loop { + let mut entered = String::new(); + match io::stdin().read_line(&mut entered) { + Ok(_) => {} + Err(_) => { + println!("Couldn't read input!"); + continue; + } + }; + + let coord = match parse_coord(&entered) { + Ok(c) => c, + Err(e) => { + println!("Couldn't parse input '{entered}'! ({e})"); + continue; + } + }; + + return coord; + } +} + +fn check_state(board: &Board) -> GameState { + //check row + let mut has_space = false; + for row_i in 0..3 { + let row: Vec<Tile> = (0..3) + .map(|col_i| { + if !has_space && board.state[col_i][row_i] == Tile::Unowned { + has_space = true + } + return board.state[col_i][row_i]; + }) + .collect(); + if row[0] != Tile::Unowned && row[0] == row[1] && row[1] == row[2] { + return match row[0] { + Tile::PlayerOne => GameState::PlayerOneWin, + Tile::PlayerTwo => GameState::PlayerTwoWin, + Tile::Unowned => panic!("Impossible state"), + }; + } + } + + //check draw + if !has_space { + return GameState::Draw; + } + + //check col + for col in board.state { + if col[0] != Tile::Unowned && col[0] == col[1] && col[1] == col[2] { + return match col[0] { + Tile::PlayerOne => GameState::PlayerOneWin, + Tile::PlayerTwo => GameState::PlayerTwoWin, + Tile::Unowned => panic!("Impossible state"), + }; + } + } + + //check diagonal + if board.state[0][0] != Tile::Unowned + && board.state[0][0] == board.state[1][1] + && board.state[1][1] == board.state[2][2] + { + return match board.state[0][0] { + Tile::PlayerOne => GameState::PlayerOneWin, + Tile::PlayerTwo => GameState::PlayerTwoWin, + Tile::Unowned => panic!("Impossible state"), + }; + } + + if board.state[2][0] != Tile::Unowned + && board.state[2][0] == board.state[1][1] + && board.state[1][1] == board.state[0][2] + { + return match board.state[2][0] { + Tile::PlayerOne => GameState::PlayerOneWin, + Tile::PlayerTwo => GameState::PlayerTwoWin, + Tile::Unowned => panic!("Impossible state"), + }; + } + + //no wincon + return GameState::InProgress; +} + +fn main() { + let mut board = init_board(); + loop { + // clear_scrn(); + write_header("Current state"); + render_board(&board); + + println!("Enter a move (e.g., 1,2) >"); + let coord = get_coord_input(); + board.set_at_coord(coord, Tile::PlayerOne); + + match check_state(&board) { + GameState::InProgress => (), + GameState::Draw => { + println!("Draw!"); + break; + } + GameState::PlayerOneWin => { + println!("Player one wins!"); + break; + } + GameState::PlayerTwoWin => { + println!("Player two wins!"); + break; + } + } + + //get AI move + let ai_move = get_best_move(&board, Tile::PlayerTwo, true, 0); + board.set_at_coord(ai_move.coord, Tile::PlayerTwo); + + match check_state(&board) { + GameState::InProgress => (), + GameState::Draw => { + println!("Draw!"); + break; + } + GameState::PlayerOneWin => { + println!("Player one wins!"); + break; + } + GameState::PlayerTwoWin => { + println!("Player two wins!"); + break; + } + } + } + + render_board(&board); + println!("Game over!") +} |