Add code
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
/.idea/
|
||||
/*.iml
|
||||
6
Cargo.lock
generated
Normal file
6
Cargo.lock
generated
Normal file
@@ -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"
|
||||
|
||||
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "tictactoe"
|
||||
version = "0.1.0"
|
||||
authors = ["t"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
21
src/main.rs
Normal file
21
src/main.rs
Normal file
@@ -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());
|
||||
|
||||
}
|
||||
171
src/tictactoe.rs
Normal file
171
src/tictactoe.rs
Normal file
@@ -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<Vec<Player>>,
|
||||
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<Player> {
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user