RosettaCodeData/Task/Tic-tac-toe/Rust/tic-tac-toe.rust

120 lines
2.9 KiB
Plaintext

use GameState::{ComputerWin, Draw, PlayerWin, Playing};
use rand::prelude::*;
#[derive(PartialEq, Debug)]
enum GameState {
PlayerWin,
ComputerWin,
Draw,
Playing,
}
type Board = [[char; 3]; 3];
fn main() {
let mut rng = StdRng::from_entropy();
let mut board: Board = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']];
draw_board(board);
loop {
player_turn(&mut board);
if check_win(board) != Playing {
break;
}
computer_turn(&mut rng, &mut board);
if check_win(board) != Playing {
break;
}
draw_board(board);
}
draw_board(board);
let announcement = match check_win(board) {
PlayerWin => "The Player has won!",
ComputerWin => "The Computer has won!",
Draw => "Draw!",
Playing => unreachable!(),
};
println!("{}", announcement);
}
fn is_empty(cell: &char) -> bool {
*cell != 'X' && *cell != 'O'
}
fn check_win(board: Board) -> GameState {
// check for win
for (i, row) in board.iter().enumerate() {
if row[0] == row[1] && row[0] == row[2] {
return which_win(row[0]);
} else if board[0][i] == board[1][i] && board[0][i] == board[2][i] {
return which_win(board[0][i]);
}
}
if board[0][0] == board[1][1] && board[0][0] == board[2][2] {
return which_win(board[0][0]);
} else if board[0][2] == board[1][1] && board[0][2] == board[2][0] {
return which_win(board[0][2]);
}
// check if it's not a draw
let is_draw = board.iter().flatten().any(is_empty);
if is_draw {
Playing
} else {
Draw
}
}
fn which_win(s: char) -> GameState {
match s {
'X' => PlayerWin,
'O' => ComputerWin,
_ => unreachable!(),
}
}
fn player_turn(board: &mut Board) {
use std::io;
println!("Player, enter your field of choice!: ");
let mut ln = String::new();
io::stdin()
.read_line(&mut ln)
.expect("Failed to read stdin");
let choice = ln.trim().parse::<usize>().expect("Failed to parse input");
let row = (choice - 1) / 3;
let col = (choice - 1) % 3;
if board[row][col] == 'X' || board[row][col] == 'O' {
println!("Someone already took this field!");
player_turn(board);
} else {
board[row][col] = 'X';
}
}
fn computer_turn<R: Rng>(rng: &mut R, board: &mut Board) {
let possible_choices: Vec<_> = board
.iter()
.flatten()
.enumerate()
.filter(|&(_, c)| is_empty(c))
.map(|(i, _)| i)
.collect();
let choice = possible_choices.choose(rng).unwrap();
println!("Computer chose: {}", choice);
let row = choice / 3;
let col = choice % 3;
board[row][col] = 'O';
}
fn draw_board(board: Board) {
for row in &board {
println!("{} {} {}", row[0], row[1], row[2]);
}
}