Skip to content

Instantly share code, notes, and snippets.

@kujirahand
Last active June 3, 2025 03:36
Show Gist options
  • Save kujirahand/4cdc61414178d4044cce8cf724f45317 to your computer and use it in GitHub Desktop.
Save kujirahand/4cdc61414178d4044cce8cf724f45317 to your computer and use it in GitHub Desktop.
トランプのババ抜き
// 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