Last active
June 3, 2025 03:36
-
-
Save kujirahand/4cdc61414178d4044cce8cf724f45317 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
// file: src/main.rs | |
use std::io; | |
use lazyrand::{shuffle, randint}; | |
const JOKER: u8 = 52; // ジョーカーは52番 | |
const CARD_SUIT: [&str; 5] = ["♠", "♥", "♣", "♦", ""]; // カードのマーク | |
const CARD_NUMS: [&str; 14] = [ // カードの数字ラベル | |
"Jok", "A", "2", "3", "4", "5", "6", | |
"7", "8", "9", "10", "J", "Q", "K"]; | |
// カード番号を与えてカードの数字を取得する | |
fn get_card_num(cno: u8) -> u8 { | |
if cno == JOKER { 0 } else { cno % 13 + 1 } | |
} | |
// カード番号を与えてカードのラベルを取得する | |
fn get_card_label(cno: u8) -> String { | |
format!("[{}{:>2}]", | |
CARD_SUIT[(cno / 13) as usize], | |
CARD_NUMS[get_card_num(cno) as usize]) | |
} | |
// ペアがあれば削除して捨てた組数を返す | |
fn remove_pair(cards: &mut Vec<u8>) -> usize { | |
let mut remove_cards = vec![]; // 削除用にカード番号を記録 | |
let mut exists_nums = [-1; 14]; // 存在する数字を記録(-1は未発見) | |
// すべてのカードを調べてペアを探す | |
for i in 0..cards.len() { | |
let num = get_card_num(cards[i]); | |
if exists_nums[num as usize] < 0 { | |
exists_nums[num as usize] = i as isize; | |
continue; | |
} | |
// すでに同じ数字のカードが存在する場合は削除マーク | |
remove_cards.push(i); | |
remove_cards.push(exists_nums[num as usize] as usize); | |
exists_nums[num as usize] = -1; // 同じ数字のカードは削除済み | |
} | |
let remove_count = remove_cards.len(); | |
// 削除マークのカードを削除 | |
remove_cards.sort(); | |
for &i in remove_cards.iter().rev() { | |
cards.remove(i); | |
} | |
lazyrand::shuffle(cards); // 削除後にシャッフル | |
return remove_count / 2; | |
} | |
// ユーザーに入力を促す | |
fn input(prompt: &str) -> String { | |
println!("{}:", prompt); | |
let mut input = String::new(); | |
io::stdin().read_line(&mut input).expect("入力エラー"); | |
input.trim().to_string() | |
} | |
// ユーザーが1以上max以下の数字を入力するまで繰り返す | |
fn input_number(prompt: &str, max: usize) -> usize { | |
loop { | |
let msg = format!("{}(1-{})", prompt, max); | |
match input(&msg).parse::<usize>() { | |
Ok(num) if num > 0 && num <= max => return num, | |
_ => println!("無効な値です。もう一度入力してください。"), | |
} | |
} | |
} | |
// 手札を表示する | |
fn get_card_labels(cards: &[u8], is_user: bool) -> String { | |
cards.iter().map(|&card| { | |
if is_user { | |
get_card_label(card) | |
} else { | |
"[???]".to_string() | |
} | |
}).collect::<Vec<String>>().join("") | |
} | |
// 手札の情報を表示して勝敗判定する | |
fn check(user_hands: &[u8], com_hands: &[u8]) -> bool { | |
println!("-------------------------"); | |
println!("- 貴方の手札({:2}枚): {}", user_hands.len(), | |
get_card_labels(user_hands, true)); | |
println!("- 相手の手札({:2}枚): {}", com_hands.len(), | |
get_card_labels(com_hands, false)); | |
if user_hands.is_empty() { | |
println!(">>> 貴方の勝ちです!"); | |
return true; | |
} | |
if com_hands.is_empty() { | |
println!("<<< 相手の勝ちです。"); | |
return true; | |
} | |
false | |
} | |
fn main() { | |
// ジョーカーを加えたカード(53枚)を作成してシャッフル | |
let mut cards = (0..53).collect::<Vec<u8>>(); | |
shuffle(&mut cards); | |
// 手札を作成 | |
let mut user_hands = cards[0..26].to_vec(); | |
let mut com_hands = cards[26..].to_vec(); | |
print!("\x1b[2J\x1b[H"); // 画面をクリア | |
// それぞれの手札からペアを削除 | |
println!("貴方は{}組のカードを捨てました。", remove_pair(&mut user_hands)); | |
println!("相手は{}組のカードを捨てました。", remove_pair(&mut com_hands)); | |
// どちらかの手札が0になるまで繰り返す | |
loop { | |
if check(&user_hands, &com_hands) { break; } | |
// ユーザーの入力を取得 | |
let index = input_number( | |
">>> 何枚目を引きますか", com_hands.len()); | |
// ユーザーの手札にカードを追加 | |
let card = com_hands.remove(index - 1); | |
user_hands.push(card); | |
println!(">>> 貴方は{}を引きました", get_card_label(card)); | |
if check(&user_hands, &com_hands) { break; } | |
if remove_pair(&mut user_hands) > 0 { | |
println!(">>> 成功!! 貴方はカードを捨てました。"); | |
if check(&user_hands, &com_hands) { break; } | |
} | |
input(">>> [Enter]を押してください"); | |
// コンピューターの番 | |
let card = user_hands.remove(randint(0, user_hands.len() as i64 - 1) as usize); | |
com_hands.push(card); | |
println!("<<< 相手が貴方のカード{}を引きました。", get_card_label(card)); | |
if check(&user_hands, &com_hands) { break; } | |
if remove_pair(&mut com_hands) > 0 { | |
println!("<<< 残念.. 相手はカードを捨てました。"); | |
if check(&user_hands, &com_hands) { break; } | |
} | |
} | |
println!("ゲーム終了です。"); | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn test_get_card_label() { | |
assert_eq!(get_card_label(52), "[Jok]"); | |
assert_eq!(get_card_label(0), "[♠ A]"); | |
assert_eq!(get_card_label(12), "[♠ K]"); | |
assert_eq!(get_card_label(13), "[♥ A]"); | |
} | |
#[test] | |
fn test_remove_pair() { | |
let mut cards = vec![0, 1, 2]; | |
assert_eq!(remove_pair(&mut cards), 0); | |
assert_eq!(cards.len(), 3); | |
cards.push(13*2+0); // Aを追加 | |
assert_eq!(remove_pair(&mut cards), 1); | |
assert_eq!(cards.len(), 2); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment