Last active
March 10, 2023 04:44
-
-
Save Agent-E11/b89154f39c688296482dc56bcae62452 to your computer and use it in GitHub Desktop.
Basic tic tac toe program written in Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::io; | |
use ndarray::{self, arr2, Array2, Array1}; | |
fn main() { | |
let cell_empty: char = '-'; | |
let stdin = io::stdin(); | |
let mut grid = arr2(&[ | |
[cell_empty, cell_empty, cell_empty], | |
[cell_empty, cell_empty, cell_empty], | |
[cell_empty, cell_empty, cell_empty] | |
]); | |
// let mut x_turn: bool = true; | |
let mut playing: bool = true; | |
let mut player = PlayerTurn::X; | |
// Game loop | |
while playing { | |
// Prompt the player | |
player.print_turn(); | |
// Initialize position and input variables | |
let mut input = String::new(); | |
let x_num: usize; | |
let y_num: usize; | |
// Get position | |
// Get x: | |
// Prompt, read line, check for error, set `x_num` | |
println!("Column: "); | |
stdin.read_line(&mut input).expect("Read failed: at x_str"); | |
if let Err(e) = check_parse(input.trim()) { | |
println!("{e}. Try again."); | |
continue; | |
} | |
x_num = input.trim().parse::<usize>().expect("Parse failed: at x_num") - 1; | |
// Clear input | |
input.clear(); | |
// Get y: | |
// Prompt, read line, check for error, set `y_num` | |
println!("Row: "); | |
stdin.read_line(&mut input).expect("Read failed: at y_str"); | |
if let Err(e) = check_parse(input.trim()) { | |
println!("{e}. Try again."); | |
continue; | |
} | |
y_num = input.trim().parse::<usize>().expect("Parse failed: at y_num") - 1; | |
// Check for out of bounds error | |
match check_out_of_bounds(&grid, &y_num, &x_num) { | |
Ok(_) => (), | |
Err(e) => { | |
println!("{e}. Try again."); | |
continue; | |
}, | |
} | |
if grid[(y_num, x_num)] == cell_empty { // If the cell is empty | |
// Place an X or O based on the current player | |
match player { | |
PlayerTurn::X => grid[(y_num, x_num)] = 'X', | |
PlayerTurn::O => grid[(y_num, x_num)] = 'O', | |
} | |
} else { // If the cell is invalid, the grid will not be printed and the turn will not change | |
println!("Invalid location, please try again."); | |
continue; | |
} | |
// Print the grid as a grid | |
for i in 0..3 { | |
for j in 0..3 { | |
print!("{} ", grid[(i, j)]); | |
} | |
print!("\n"); | |
} | |
// Check for a winner | |
match check_win(&grid) { | |
true => { | |
playing = false; | |
println!("Someone has won!"); | |
continue; | |
}, | |
false => () | |
}; | |
// Switch turn | |
player = player.switch(); | |
} | |
} | |
// | |
fn check_win(grid: &Array2<char>) -> bool { | |
// Check columns | |
for col in grid.columns() { | |
if col.iter().all(|n| n == &col[0]) && col[0] != '-' { | |
return true; | |
} | |
} | |
// Check rows | |
for row in grid.rows() { | |
if row.iter().all(|n| n == &row[0]) && row[0] != '-' { | |
return true; | |
} | |
} | |
// Check diagonal | |
if grid.diag().iter().all(|n| n == &grid.diag()[0]) && grid.diag()[0] != '-' { | |
return true; | |
} | |
// Check other diagonal | |
if diag_2(grid).iter().all(|n| n == &diag_2(grid)[0]) && diag_2(grid)[0] != '-' { | |
return true; | |
} | |
// Return false if no one has won | |
false | |
} | |
// Returns an Array1 containing the characters on the 'other diagonal' of the given Array2 | |
fn diag_2(grid: &Array2<char>) -> Array1<char> { | |
// Copy the given array | |
let mut invert = grid.clone(); | |
// Invert the array side-to-side | |
invert.invert_axis(ndarray::Axis(1)); | |
// Return the diagonal of the inverted array | |
invert.diag().to_owned() | |
} | |
fn check_out_of_bounds(grid: &Array2<char>, y: &usize, x: &usize) -> Result<(), String> { | |
match grid.get((*y, *x)) { | |
Some(_) => Ok(()), | |
None => Err(String::from("Invalid index")), | |
} | |
} | |
fn check_parse(str: &str) -> Result<(), std::num::ParseIntError> { | |
match str.parse::<usize>() { | |
Ok(_) => Ok(()), | |
Err(e) => Err(e) | |
} | |
} | |
enum PlayerTurn { | |
X, | |
O, | |
} | |
impl PlayerTurn { | |
fn switch(self) -> PlayerTurn { | |
match self { | |
PlayerTurn::X => PlayerTurn::O, | |
PlayerTurn::O => PlayerTurn::X, | |
} | |
} | |
fn print_turn(&self) { | |
match self { | |
PlayerTurn::X => println!("X's turn"), | |
PlayerTurn::O => println!("O's turn"), | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I use the ndarray crate v0.15.6 (It should be the latest at time of posting)