Skip to content

Instantly share code, notes, and snippets.

@segfo
Last active February 10, 2018 04:46
Show Gist options
  • Save segfo/88637ab68074526685eeb6c76c06c2de to your computer and use it in GitHub Desktop.
Save segfo/88637ab68074526685eeb6c76c06c2de to your computer and use it in GitHub Desktop.
自販機のふるまいを再現してみるプログラム
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