Last active
September 6, 2020 14:30
-
-
Save typebird/3159c961f0e8ccb43b83fe28a36f693f to your computer and use it in GitHub Desktop.
簡單的猜數字遊戲。
This file contains 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
mod numbers; | |
mod process; | |
use process::GameProcess; | |
fn main() { | |
println!("請輸入你猜測的數字,或者輸入 exit 以退出:"); | |
GameProcess::execute(); | |
} |
This file contains 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 rand::{thread_rng, Rng}; | |
#[derive(Debug)] | |
pub struct Answer { | |
vals: [u32; 4], | |
} | |
impl Answer { | |
/// 隨機產生器 | |
fn generator() -> [u32; 4] { | |
let mut rng = thread_rng(); | |
let mut arr = [0; 4]; | |
for idx in 0..4 { | |
loop { | |
let val: u32 = rng.gen_range(0, 10); | |
if !arr.contains(&val) { | |
arr[idx] = val; | |
break; | |
} | |
} | |
} | |
arr | |
} | |
/// 建立 | |
pub fn new() -> Answer { | |
Answer { | |
vals: Answer::generator(), | |
} | |
} | |
/// 取值 | |
pub fn get_values(&self) -> [u32; 4] { | |
self.vals | |
} | |
} | |
#[derive(Debug)] | |
pub struct Guess { | |
vals: [u32; 4], | |
} | |
impl Guess { | |
/// 檢查長度 | |
fn check_len(len: usize) -> Result<(), String> { | |
if len == 4 { | |
return Ok(()); | |
} | |
Err(String::from("輸入的參數僅能有四字元。")) | |
} | |
/// 檢查值 | |
fn check_val(arr: [u32; 4], idx: usize, val: u32) -> Result<(), String> { | |
if arr.contains(&val) { | |
let pos = arr.iter().position(|&v| v == val).unwrap(); | |
let msg = format!( | |
"第 {} 位的 {} 與第 {} 位數字重覆了。", | |
idx + 1, | |
val, | |
pos + 1 | |
); | |
return Err(msg); | |
} | |
Ok(()) | |
} | |
/// 建立結構 | |
pub fn new(val: &str) -> Result<Guess, String> { | |
Guess::check_len(val.len())?; | |
let mut arr = [10; 4]; | |
for (idx, num) in val.chars().enumerate() { | |
match num.to_digit(10) { | |
Some(v) => { | |
Guess::check_val(arr, idx, v)?; | |
arr[idx] = v; | |
} | |
None => { | |
let msg = format!("第 {} 個字不是數字,而是 {}。", idx + 1, num); | |
return Err(msg); | |
} | |
} | |
} | |
Ok(Guess { vals: arr }) | |
} | |
/// 初始化 | |
pub fn init() -> Guess { | |
Guess { vals: [10; 4] } | |
} | |
/// 轉為迭代器 | |
pub fn iter(&self) -> std::slice::Iter<'_, u32> { | |
self.vals.iter() | |
} | |
/// 取得值 | |
pub fn get_values(&self) -> [u32; 4] { | |
self.vals | |
} | |
} |
This file contains 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 crate::numbers::{Answer, Guess}; | |
use std::io::{self, prelude::*}; | |
#[derive(Debug)] | |
struct A(u32); | |
#[derive(Debug)] | |
struct B(u32); | |
#[derive(Debug)] | |
enum GuessResult { | |
Rrite, | |
Wrong(A, B), | |
Start, | |
} | |
impl GuessResult { | |
/// 初始化 | |
fn init() -> GuessResult { | |
GuessResult::Start | |
} | |
/// 建立 | |
fn new(a: u32, b: u32) -> GuessResult { | |
match (a, b) { | |
(4, _) => GuessResult::Rrite, | |
(a, b) => GuessResult::Wrong(A(a), B(b)), | |
} | |
} | |
/// 轉為字串 | |
fn to_string(&self) -> String { | |
match self { | |
GuessResult::Rrite => String::from("4 A, 0 B"), | |
GuessResult::Start => String::from("0 A, 0 B"), | |
GuessResult::Wrong(A(a), B(b)) => String::from(format!("{} A, {} B", a, b)), | |
} | |
} | |
} | |
#[derive(Debug)] | |
/// 記錄數據,執行邏輯 | |
pub struct GameProcess { | |
guess: Guess, | |
answer: Answer, | |
result: GuessResult, | |
} | |
impl GameProcess { | |
/// 初始化 | |
fn new() -> GameProcess { | |
GameProcess { | |
result: GuessResult::init(), | |
answer: Answer::new(), | |
guess: Guess::init(), | |
} | |
} | |
/// 取得使用者輸入值 | |
fn get_input(pros: GameProcess) -> Option<GameProcess> { | |
let stdin = io::stdin(); | |
for line in stdin.lock().lines() { | |
let input = line.unwrap(); | |
if input == "exit" { | |
println!("-| 再見~"); | |
break; | |
} | |
match Guess::new(&input) { | |
Err(e) => println!(" | {}\n | 請重新輸入,或者輸入 exit 以退出。", e), | |
Ok(v) => { | |
return Some(GameProcess { | |
result: pros.result, | |
answer: pros.answer, | |
guess: v, | |
}); | |
} | |
} | |
} | |
None | |
} | |
/// 確認結果 | |
fn check_res(pros: GameProcess) -> GameProcess { | |
if let GuessResult::Rrite = pros.result { | |
return pros; | |
} | |
let answer = pros.answer.get_values(); | |
let (a, b) = pros | |
.guess | |
.iter() | |
.enumerate() | |
.fold((0, 0), |res, (idx, val)| { | |
if let Some(ans) = answer.get(idx) { | |
match (ans == val, answer.contains(val)) { | |
(true, _) => return (res.0 + 1, res.1), | |
(_, true) => return (res.0, res.1 + 1), | |
(_, _) => return res, | |
} | |
} | |
res | |
}); | |
GameProcess { | |
result: GuessResult::new(a, b), | |
answer: pros.answer, | |
guess: pros.guess, | |
} | |
} | |
/// 執行遊戲 | |
pub fn execute() -> Option<GameProcess> { | |
let mut pros = GameProcess::new(); | |
let mut turn = 0; | |
// println!("0| 答案:{:?}", pros.answer.get_values()); | |
loop { | |
let step = GameProcess::get_input(pros).map(GameProcess::check_res); | |
if let Some(val) = step { | |
turn += 1; | |
println!( | |
"{}| 猜測:{:?}\t結果:{}", | |
turn, | |
val.guess.get_values(), | |
val.result.to_string() | |
); | |
if let GuessResult::Rrite = val.result { | |
println!(" | 猜對了,恭喜~"); | |
break; | |
} | |
pros = val; | |
} else { | |
break; | |
} | |
} | |
None | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment