From 133cfeff653ef40305b7dde71005b8d1fa004096 Mon Sep 17 00:00:00 2001 From: tilman Date: Wed, 11 Sep 2019 17:11:44 +0200 Subject: [PATCH] Add code --- .gitignore | 4 ++ Cargo.lock | 6 ++ Cargo.toml | 7 ++ src/main.rs | 21 ++++++ src/tictactoe.rs | 171 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 209 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs create mode 100644 src/tictactoe.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..833e1da --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +**/*.rs.bk +/.idea/ +/*.iml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1987e34 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "tictactoe" +version = "0.1.0" + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..04bdd64 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "tictactoe" +version = "0.1.0" +authors = ["t"] +edition = "2018" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3f2705c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,21 @@ +mod tictactoe; + +use crate::tictactoe::*; + +fn main() { + let mut field = Field::new(3, 3); + //.mark(0, 0, Player::X) + //.mark(0, 1, Player::O); + field.print(); + println!("----------------"); + let mut player = Player::X; + while field.get_winner().is_none() { + let (x, y) = get_best_turn(&field, player); + field = field.mark(x, y, player); + field.print(); + player = player.change(); + println!("----------------"); + } + println!("{:?}", field.get_winner()); + +} diff --git a/src/tictactoe.rs b/src/tictactoe.rs new file mode 100644 index 0000000..f7c2003 --- /dev/null +++ b/src/tictactoe.rs @@ -0,0 +1,171 @@ +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Player { + X, O, NONE +} + +impl Player { + + pub fn change(&self) -> Self { + match self { + &Player::X => Player::O, + &Player::O => Player::X, + x => *x + } + } + +} + +pub struct Field { + fields: Vec>, + width: usize, + height: usize +} + +impl Field { + + pub fn new(width: usize, height: usize) -> Self { + Field { fields: vec![vec![Player::NONE; height]; width], width, height } + } + + pub fn print(&self) { + for j in 0 .. self.height { + for i in 0 .. self.width { + match self.fields[i][j] { + Player::X => print!("X"), + Player::O => print!("O"), + Player::NONE => print!(" ") + } + } + println!() + } + } + + pub fn mark(&self, x: usize, y: usize, player: Player) -> Self { + let mut fields = Vec::with_capacity(self.width); + for i in 0 .. self.width { + let mut column = Vec::with_capacity(self.height); + for j in 0 .. self.height { + if i == x && j == y { + column.push(player); + } else { + column.push(self.fields[i][j]); + } + } + fields.push(column); + } + Field { fields, width: self.width, height: self.height } + } + + pub fn is_winner(&self, player: Player) -> bool { + assert_eq!(self.width, self.height); + for i in 0 .. self.width { // check columns + let mut winner = true; + for j in 0 .. self.height { + if self.fields[i][j] != player { + winner = false; + break; + } + } + if winner { + return true; + } + } + for j in 0 .. self.height { // check rows + let mut winner = true; + for i in 0 .. self.width { + if self.fields[i][j] != player { + winner = false; + break; + } + } + if winner { + return true; + } + } + { // check top-left bottom-right diagonal + let mut winner = true; + for i in 0 .. self.width { + if self.fields[i][i] != player { + winner = false; + break; + } + } + if winner { + return true; + } + } + { // check bottom-left top-right diagonal + let mut winner = true; + for i in 0 .. self.width { + if self.fields[i][self.height - i - 1] != player { + winner = false; + break; + } + } + if winner { + return true; + } + } + return false; + } + + pub fn get_winner(&self) -> Option { + if self.is_winner(Player::X) { + Some(Player::X) + } else if self.is_winner(Player::O) { + Some(Player::O) + } else { + let mut full = true; + for i in 0 .. self.width { + for j in 0 .. self.height { + if self.fields[i][j] == Player::NONE { + full = false; + } + } + } + if full { + Some(Player::NONE) + } else { + None + } + } + } + +} + +pub fn get_best_turn(field: &Field, player: Player) -> (usize, usize) { + let (x, y, _) = search_best_turn(field, player); + (x, y) +} + +fn search_best_turn(field: &Field, player: Player) -> (usize, usize, i8) { + let mut max_turn = (0, 0); + let mut max_value = -2; + for i in 0 .. field.width { + for j in 0 .. field.height { + if field.fields[i][j] == Player::NONE { + let played = field.mark(i, j, player); + let value = match played.get_winner() { + Some(p) => { + if p == player { + 1 + } else if p == Player::NONE { + 0 + } else { // loose + -1 + } + }, + None => { + let (_, _, sub_value) = search_best_turn(&played, player.change()); + -sub_value + } + }; + if value > max_value { + max_turn = (i, j); + max_value = value; + } + } + } + } + (max_turn.0, max_turn.1, max_value) +}