From a49108dc249e53c7b0e4d03190074d7066c8b0f1 Mon Sep 17 00:00:00 2001 From: elarroba Date: Thu, 22 Apr 2021 19:20:01 -0400 Subject: [PATCH] Initial Commit --- .gitignore | 2 + Cargo.lock | 5 ++ Cargo.toml | 9 +++ src/board.rs | 206 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 62 +++++++++++++++ src/players.rs | 35 +++++++++ 6 files changed, 319 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/board.rs create mode 100644 src/main.rs create mode 100644 src/players.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2a0038a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +.idea \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..fe26f3c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "rust-tic-tac-toe" +version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..44605b6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust-tic-tac-toe" +version = "1.0.0" +authors = ["elarroba "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/board.rs b/src/board.rs new file mode 100644 index 0000000..3ec9250 --- /dev/null +++ b/src/board.rs @@ -0,0 +1,206 @@ +use core::fmt; +use std::fmt::{Display, Formatter}; + +use crate::players::Player; + +#[derive(PartialEq, Eq)] +pub enum CellValue { + Blank, + X, + O, +} + +impl Display for CellValue { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let tick = match self { + CellValue::Blank => { " " } + CellValue::X => { "X" } + CellValue::O => { "O" } + }; + write!(f, "{}", tick) + } +} + +pub struct TicTacToeBoard<'b> { + a1: &'b CellValue, + a2: &'b CellValue, + a3: &'b CellValue, + + b1: &'b CellValue, + b2: &'b CellValue, + b3: &'b CellValue, + + c1: &'b CellValue, + c2: &'b CellValue, + c3: &'b CellValue, +} + +impl<'c> TicTacToeBoard<'c> { + pub fn new() -> TicTacToeBoard<'c> { + TicTacToeBoard { + a1: &CellValue::Blank, + a2: &CellValue::Blank, + a3: &CellValue::Blank, + b1: &CellValue::Blank, + b2: &CellValue::Blank, + b3: &CellValue::Blank, + c1: &CellValue::Blank, + c2: &CellValue::Blank, + c3: &CellValue::Blank, + } + } + + pub fn get_display_value(cell: &CellValue) -> &'static str { + match cell { + CellValue::Blank => { " " } + CellValue::X => { "X" } + CellValue::O => { "O" } + } + } + + + pub fn add_move(&mut self, position: &str, player: &'c Player) -> bool { + return match position { + "a1" => { + if self.a1 == &CellValue::Blank { + self.a1 = player.tick; + true + } else { false } + } + + "a2" => { + if self.a2 == &CellValue::Blank { + self.a2 = player.tick; + true + } else { false } + } + "a3" => { + if self.a3 == &CellValue::Blank { + self.a3 = player.tick; + true + } else { false } + } + "b1" => { + if self.b1 == &CellValue::Blank { + self.b1 = player.tick; + true + } else { false } + } + "b2" => { + if self.b2 == &CellValue::Blank { + self.b2 = player.tick; + true + } else { false } + } + "b3" => { + if self.b3 == &CellValue::Blank { + self.b3 = player.tick; + true + } else { false } + } + "c1" => { + if self.c1 == &CellValue::Blank { + self.c1 = player.tick; + true + } else { false } + } + "c2" => { + if self.c2 == &CellValue::Blank { + self.c2 = player.tick; + true + } else { false } + } + "c3" => { + if self.c3 == &CellValue::Blank { + self.c3 = player.tick; + true + } else { false } + } + _ => { false } + }; + } + + + pub fn player_wins(&self, player: &'c Player) -> Option<&'c Player> { + let board_array: [&CellValue; 9] = [ + self.a1, + self.a2, + self.a3, + self.b1, + self.b2, + self.b3, + self.c1, + self.c2, + self.c3, + ]; + + + println!("Player tick: {:?}", player.get_tick()); + + for n in 0..3 { + let mut r1 = board_array[n]; + let mut r2 = board_array[n + 3]; + let mut r3 = board_array[n + 6]; + + + if r1 == r2 && r2 == r3 && !(r3 == &CellValue::Blank) { + return Some(&player); + } else { + r1 = board_array[n]; + r2 = board_array[n + 1]; + r3 = board_array[n + 2]; + + // Checking for line win... + if r1 == r2 && r2 == r3 && !(r3 == &CellValue::Blank) { + return Some(&player); + } + } + } + + let mut r1 = board_array[0]; + let mut r2 = board_array[4]; + let mut r3 = board_array[8]; + if r1 == r2 && r2 == r3 && !(r3 == &CellValue::Blank) { + return Some(&player); + } + + + r1 = board_array[2]; + r2 = board_array[4]; + r3 = board_array[5]; + if r1 == r2 && r2 == r3 && !(r3 == &CellValue::Blank) { + return Some(&player); + } + None + } + + pub fn print_board(&self) { + let head = " 1 2 3 \n"; + let div = " _______\n"; + let ln1 = format!("a |{}|{}|{}|\n", + TicTacToeBoard::get_display_value(&self.a1), + TicTacToeBoard::get_display_value(&self.a2), + TicTacToeBoard::get_display_value(&self.a3)); + let ln2 = format!("b |{}|{}|{}|\n", + TicTacToeBoard::get_display_value(&self.b1), + TicTacToeBoard::get_display_value(&self.b2), + TicTacToeBoard::get_display_value(&self.b3)); + let ln3 = format!("c |{}|{}|{}|\n", + TicTacToeBoard::get_display_value(&self.c1), + TicTacToeBoard::get_display_value(&self.c2), + TicTacToeBoard::get_display_value(&self.c3)); + + let mut board: String = String::new(); + + board.push_str(head); + board.push_str(div); + board.push_str(ln1.as_str()); + board.push_str(div); + board.push_str(ln2.as_str()); + board.push_str(div); + board.push_str(ln3.as_str()); + board.push_str(div); + + println!("{}", board); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6a66d3d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,62 @@ +use std::io::stdin; + +use board::TicTacToeBoard; +use players::Player; + +use crate::board::CellValue; + +mod players; +mod board; + + +fn main() { + let player1 = Player::new("Miguel", "Sanda", 38, &CellValue::X); + let player2 = Player::new("Dayana", "Alonso", 36, &CellValue::O); + + let players: [&Player; 2] = [&player1, &player2]; + + let mut game_board: TicTacToeBoard = TicTacToeBoard::new(); + game_board.print_board(); + let mut game_over = false; + + for i in players.iter().cycle().enumerate() { + let p = i.1; + p.say_hello(); + + println!("Now is {}'s Turn!", p.full_name()); + + // read user input .... + loop { + let mut txt_in = String::new(); + match stdin().read_line(&mut txt_in) { + Ok(..) => { + txt_in.pop(); + let success_move = game_board.add_move(&txt_in, p); + if success_move { + let winner = game_board.player_wins(p); + match winner { + None => {} + Some(w) => { + game_over = true; + println!("Player {} Wins!", w.full_name()); + break; + } + } + game_board.print_board(); + break; + } else { + println!("Uhm... You cannot do that!..."); + game_board.print_board(); + } + } + + Err(error) => println!("error: {}", error), + } + } + + if game_over { + println!("Game Over!"); + break; + } + } +} diff --git a/src/players.rs b/src/players.rs new file mode 100644 index 0000000..0d200b7 --- /dev/null +++ b/src/players.rs @@ -0,0 +1,35 @@ +use crate::board::{CellValue}; + +pub struct Player<'b> { + first_name: String, + last_name: String, + age: i8, + pub tick: &'b CellValue, +} + +impl<'b> Player<'b> { + pub fn new(first_name: &'static str, last_name: &'static str, age: i8, tick: &'b CellValue) -> Player<'b> { + Player { + first_name: first_name.to_string(), + last_name: last_name.to_string(), + age, + tick, + } + } + + pub fn full_name(&self) -> String { + format!("{} {}", self.first_name, self.last_name) + } + + pub fn get_tick(&self) -> char { + match self.tick { + CellValue::X => { 'X' } + CellValue::O => { 'O' } + _ => { ' ' } + } + } + + pub fn say_hello(&self) { + println!("Hello, I'm {} and I'm {}. My tick is {}. Let's play!", self.full_name(), self.age, self.get_tick()) + } +} \ No newline at end of file