Created
February 9, 2019 06:25
-
-
Save nakanoasaservice/e2b6ceac19e562771e6dfd3351b74dea to your computer and use it in GitHub Desktop.
IBMのRustコーディングガイドにあった3目並べのサンプル
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::io; | |
| use rand; | |
| // StringからEnumにした | |
| type Board = Vec<Vec<Mark>>; | |
| enum Turn { | |
| Player, | |
| Bot, | |
| } | |
| #[derive(PartialEq)] | |
| enum Mark { | |
| Num(i32), | |
| X, | |
| O, | |
| } | |
| pub struct Game { | |
| board: Board, | |
| current_turn: Turn, | |
| } | |
| impl Game { | |
| pub fn new() -> Game { | |
| Game { | |
| board: vec![ | |
| vec![Mark::Num(1), Mark::Num(2), Mark::Num(3)], | |
| vec![Mark::Num(4), Mark::Num(5), Mark::Num(6)], | |
| vec![Mark::Num(7), Mark::Num(8), Mark::Num(9)], | |
| ], | |
| current_turn: Turn::Player, | |
| } | |
| } | |
| pub fn play_game(&mut self) { | |
| let mut finished = false; | |
| while !finished { | |
| self.play_turn(); | |
| if self.game_is_won() { | |
| self.print_board(); | |
| match self.current_turn { | |
| Turn::Player => println!("You won!"), | |
| Turn::Bot => println!("You lost"), | |
| }; | |
| finished = Self::player_is_finished(); | |
| self.reset(); | |
| } | |
| self.current_turn = self.get_next_turn(); | |
| } | |
| } | |
| fn play_turn(&mut self) { | |
| self.print_board(); | |
| let (token, valid_move) = match self.current_turn { | |
| Turn::Player => (Mark::X, self.get_player_move()), | |
| Turn::Bot => (Mark::O, self.get_bot_move()), | |
| }; | |
| let (row, col) = Self::board_location(valid_move); | |
| self.board[row][col] = token; | |
| } | |
| fn print_board(&self) { | |
| let separator = "+---+---+---+"; | |
| println!("\n{}", separator); | |
| for row in &self.board { | |
| let str_row: Vec<String> = row.iter().map(|x| match x { | |
| Mark::Num(num) => num.to_string(), | |
| Mark::X => String::from("X"), | |
| Mark::O => String::from("O"), | |
| }).collect(); | |
| println!("| {} | \n{}", str_row.join(" | "), separator); | |
| } | |
| print!("\n"); | |
| } | |
| fn get_player_move(&self) -> u32 { | |
| loop { | |
| println!("\nPlease enter your move (an integer between 1 and 9): "); | |
| let mut player_input = String::new(); | |
| match io::stdin().read_line(&mut player_input) { | |
| Err(_) => println!("Error reading input, try again!"), | |
| Ok(_) => match self.validate(&player_input) { | |
| Err(err) => println!("{}", err), | |
| Ok(num) => return num, | |
| } | |
| } | |
| } | |
| } | |
| fn validate(&self, input: &str) -> Result<u32, String> { | |
| match input.trim().parse::<u32>() { | |
| Err(_) => Err( | |
| String::from("Please input a valid unsigned integer!") | |
| ), | |
| Ok(number) => { | |
| if self.is_valid_move(number) { | |
| Ok(number) | |
| } else { | |
| Err( | |
| String::from("Please input a number, \ | |
| between 1 and 9, not already chosen!") | |
| ) | |
| } | |
| } | |
| } | |
| } | |
| fn is_valid_move(&self, unchecked_move: u32) -> bool { | |
| match unchecked_move { | |
| 1...9 => { | |
| let (row, col) = Self::board_location(unchecked_move); | |
| match self.board[row][col] { | |
| Mark::X | Mark::O => false, | |
| _ => true, | |
| } | |
| } | |
| _ => false, | |
| } | |
| } | |
| fn board_location(game_move: u32) -> (usize, usize) { | |
| let row = (game_move - 1) / 3; | |
| let col = (game_move - 1) % 3; | |
| (row as usize, col as usize) | |
| } | |
| fn get_bot_move(&self) -> u32 { | |
| let mut bot_move: u32 = rand::random::<u32>() % 9 + 1; | |
| while !self.is_valid_move(bot_move) { | |
| bot_move = rand::random::<u32>() % 9 + 1; | |
| } | |
| println!("Bot played moved at: {}", bot_move); | |
| bot_move | |
| } | |
| fn game_is_won(&self) -> bool { | |
| let mut all_same_row = false; | |
| let mut all_same_col = false; | |
| // |=はor演算子 | |
| for i in 0..3 { | |
| all_same_row |= self.board[i][0] == self.board[i][1] | |
| && self.board[i][1] == self.board[i][2]; | |
| all_same_col |= self.board[0][i] == self.board[1][i] | |
| && self.board[1][i] == self.board[2][i]; | |
| } | |
| let all_same_diag_1 = | |
| self.board[0][0] == self.board[1][1] | |
| && self.board[1][1] == self.board[2][2]; | |
| let all_same_diag_2 = | |
| self.board[0][2] == self.board[1][1] | |
| && self.board[1][1] == self.board[2][0]; | |
| (all_same_row || all_same_col || all_same_diag_1 || all_same_diag_2) | |
| } | |
| fn player_is_finished() -> bool { | |
| let mut player_input = String::new(); | |
| println!("Are you finished playing (y/n)?:"); | |
| match io::stdin().read_line(&mut player_input) { | |
| Ok(_) => { | |
| let temp = player_input.to_lowercase(); | |
| temp.trim() == "y" || temp.trim() == "yes" | |
| } | |
| Err(_) => false, | |
| } | |
| } | |
| fn reset(&mut self) { | |
| self.current_turn = Turn::Player; | |
| self.board = vec![ | |
| vec![Mark::Num(1), Mark::Num(2), Mark::Num(3)], | |
| vec![Mark::Num(4), Mark::Num(5), Mark::Num(6)], | |
| vec![Mark::Num(7), Mark::Num(8), Mark::Num(9)], | |
| ] | |
| } | |
| fn get_next_turn(&self) -> Turn { | |
| match self.current_turn { | |
| Turn::Player => Turn::Bot, | |
| Turn::Bot => Turn::Player | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment