Last active
February 10, 2018 04:46
-
-
Save segfo/88637ab68074526685eeb6c76c06c2de to your computer and use it in GitHub Desktop.
自販機のふるまいを再現してみるプログラム
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::stdin; | |
use std::io::Write; | |
use std::str::FromStr; | |
use std::io::Read; | |
use std::fmt::{Debug, Display}; | |
use std::error::Error; | |
#[derive(Debug)] | |
struct drink<'a>{ | |
price:u32, | |
product_name:&'a str | |
} | |
impl<'a> drink<'a>{ | |
fn new(price:u32,name:&'a str)->drink{ | |
drink{price:price,product_name:name} | |
} | |
} | |
macro_rules! drinks{ | |
($($price:expr,$product:expr),*) => { | |
{ | |
let mut temp_vec=Vec::new(); | |
$( | |
temp_vec.push(drink::new($price,$product)); | |
)* | |
temp_vec | |
} | |
}; | |
} | |
fn read<T: FromStr>() -> Option<T> { | |
let s = stdin(); | |
let mut s = s.lock(); | |
let s = &mut s; | |
let s = s.by_ref().bytes().map(|c| c.unwrap() as char) | |
.skip_while(|c| c.is_whitespace()) | |
.take_while(|c| !c.is_whitespace()) | |
.collect::<String>(); | |
s.parse::<T>().ok() | |
} | |
#[derive(Debug)] | |
struct COIN_KIND{ | |
coin_value:u32, | |
num:u32 | |
} | |
#[derive(Debug)] | |
struct COIN_BOX{ | |
coin_num:Vec<COIN_KIND>, | |
available_coins:Vec<u32>, | |
} | |
#[derive(Debug)] | |
enum COIN_BOX_Error{ | |
InvalidCoin(u32) | |
} | |
impl Display for COIN_BOX_Error{ | |
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
match *self { | |
COIN_BOX_Error::InvalidCoin(ref n)=>{write!(f,"{}",n)}, | |
} | |
} | |
} | |
impl Error for COIN_BOX_Error { | |
fn description(&self)->&str{ | |
match *self { | |
COIN_BOX_Error::InvalidCoin(_)=>{"Invalid coin"}, | |
} | |
} | |
fn cause(&self)->Option<&Error>{None} | |
} | |
impl COIN_BOX{ | |
pub fn new(mut available_coins:Vec<u32>)->Self{ | |
available_coins.sort(); | |
available_coins.reverse(); | |
COIN_BOX{ | |
coin_num:Vec::new(), | |
available_coins:available_coins | |
} | |
} | |
pub fn show_available_coins(&self){ | |
print!("使用可能なコインは次の通りです : "); | |
for i in 0..self.available_coins.len(){ | |
print!("{} ",self.available_coins[i]); | |
} | |
println!(); | |
} | |
fn coin_normalize(&self,money:u32)->Result<Vec<COIN_KIND>,COIN_BOX_Error>{ | |
let mut money=money; | |
let mut coin_num=Vec::new(); | |
for i in 0..self.available_coins.len(){ | |
let coin = self.available_coins[i]; | |
let num=money/coin; | |
if num!=0{coin_num.push(COIN_KIND{coin_value:coin,num});} // 枚数 | |
money%=coin; | |
} | |
// 割り切れてなかったらエラーとする(使用できるコイン一覧に存在しないので) | |
if money>0{ | |
return Err(COIN_BOX_Error::InvalidCoin(money)); | |
} | |
Ok(coin_num) | |
} | |
pub fn insert_coin(&self,amount:u32)->Result<(),COIN_BOX_Error>{ | |
let coins=self.coin_normalize(amount)?; | |
Ok(()) | |
} | |
pub fn eject_coin(&self,charge:u32)->Result<(),COIN_BOX_Error>{ | |
let coins=self.coin_normalize(charge)?; | |
println!(); | |
if coins.len()==0{ | |
println!("おつりはありません。"); | |
}else{ | |
println!("合計{}円のおつりです。",charge); | |
for cc in coins{ | |
println!("{} x{}",cc.coin_value,cc.num); | |
} | |
} | |
Ok(()) | |
} | |
} | |
fn main() { | |
let drink_list=drinks!(0,"買わない",120,"コーラ",100,"オレンジジュース",100,"コーヒー",150,"お茶",220,"エナドリ"); | |
let mut total=0; | |
// お金に関することを管理する | |
let mut coinbox=COIN_BOX::new(vec![10,50,100,500,1000]); | |
// 現在使用可能なコインを表示 | |
coinbox.show_available_coins(); | |
print!("お金を投入してください(例:150) > "); | |
std::io::stdout().flush(); | |
total = read().unwrap(); | |
if let Err(e)=coinbox.insert_coin(total){ | |
println!("使用できない端数のコインが投入されました"); | |
println!("端数のコイン:{}",e); | |
return; | |
} | |
println!("\n[以下の商品が購入可能です]"); | |
println!("商品番号:商品名"); | |
// 購入可能リストの上限値 | |
let mut available_list_max=0; | |
for i in 0..drink_list.len(){ | |
if total>=drink_list[i].price{ | |
println!("{}:{} {}円",i,drink_list[i].product_name,drink_list[i].price); | |
available_list_max+=1; | |
} | |
} | |
print!("商品番号を入力してください > "); | |
std::io::stdout().flush(); | |
let req_product_no:u32 = read().unwrap(); | |
let mut charge=total; | |
if req_product_no<available_list_max{ | |
println!("\n{} を購入しました",drink_list[req_product_no as usize].product_name); | |
charge=total-drink_list[req_product_no as usize].price; | |
} | |
coinbox.eject_coin(charge); | |
println!("またのご利用お待ちしております。"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment