Skip to content

Instantly share code, notes, and snippets.

@eamonburns
Last active March 10, 2023 04:44
Show Gist options
  • Select an option

  • Save eamonburns/b89154f39c688296482dc56bcae62452 to your computer and use it in GitHub Desktop.

Select an option

Save eamonburns/b89154f39c688296482dc56bcae62452 to your computer and use it in GitHub Desktop.
Basic tic tac toe program written in Rust
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"),
}
}
}
@eamonburns
Copy link
Author

eamonburns commented Mar 9, 2023

I use the ndarray crate v0.15.6 (It should be the latest at time of posting)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment