Skip to content

Instantly share code, notes, and snippets.

@nakanoasaservice
Created February 9, 2019 06:25
Show Gist options
  • Select an option

  • Save nakanoasaservice/e2b6ceac19e562771e6dfd3351b74dea to your computer and use it in GitHub Desktop.

Select an option

Save nakanoasaservice/e2b6ceac19e562771e6dfd3351b74dea to your computer and use it in GitHub Desktop.
IBMのRustコーディングガイドにあった3目並べのサンプル
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