summaryrefslogtreecommitdiff
path: root/tic_tac_toe/src/main.rs
diff options
context:
space:
mode:
authorKai Stevenson <kai@kaistevenson.com>2025-05-07 23:08:15 -0700
committerKai Stevenson <kai@kaistevenson.com>2025-05-07 23:08:15 -0700
commitaf2bc841119a6751c240dec95dd5511d4ee31d36 (patch)
tree693cb7d3d6d06bb667a89b1d4d8d2bdaee8ab983 /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.rs162
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!")
+}