Skip to content

Instantly share code, notes, and snippets.

@kb10uy kb10uy/chincheck.rs
Created Nov 8, 2019

Embed
What would you like to do?
チンイツチェッカー
use std::cmp::Ordering;
use std::collections::{BTreeSet, VecDeque};
use std::env::args;
use std::error::Error;
use std::fmt::{Display, Error as FormatError, Formatter};
/// 面子
#[derive(Clone, Copy, PartialEq, Eq)]
enum Meld {
Pong(u8),
Chow(u8),
Eye(u8),
}
impl PartialOrd for Meld {
fn partial_cmp(&self, rhs: &Meld) -> Option<Ordering> {
match (self, rhs) {
(Meld::Pong(l), Meld::Pong(r)) => l.partial_cmp(r),
(Meld::Pong(l), Meld::Chow(r)) => match l.cmp(&(r + 2)) {
Ordering::Equal => Some(Ordering::Less),
otherwise => Some(otherwise),
},
(Meld::Pong(_), Meld::Eye(_)) => Some(Ordering::Less),
(Meld::Chow(l), Meld::Pong(r)) => match (l + 2).cmp(r) {
Ordering::Equal => Some(Ordering::Greater),
otherwise => Some(otherwise),
},
(Meld::Chow(l), Meld::Chow(r)) => l.partial_cmp(r),
(Meld::Chow(_), Meld::Eye(_)) => Some(Ordering::Less),
(Meld::Eye(_), Meld::Pong(_)) => Some(Ordering::Greater),
(Meld::Eye(_), Meld::Chow(_)) => Some(Ordering::Greater),
(Meld::Eye(l), Meld::Eye(r)) => l.partial_cmp(r),
}
}
}
impl Ord for Meld {
fn cmp(&self, rhs: &Meld) -> Ordering {
self.partial_cmp(rhs).unwrap()
}
}
impl Display for Meld {
fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
match self {
Meld::Pong(n) => write!(f, "{0}{0}{0}", n),
Meld::Chow(n) => write!(f, "{}{}{}", n, n + 1, n + 2),
Meld::Eye(n) => write!(f, "{0}{0}", n),
}
}
}
/// 探索状態
#[derive(Clone)]
struct State {
waiting: u8,
melds: Vec<Meld>,
rest_tiles: [u8; 9],
}
fn main() -> Result<(), Box<dyn Error>> {
let args: Vec<_> = args().collect();
let hand_string = args.get(1).expect("Hand string must be given");
if hand_string.len() != 13 {
return Err("Too many or short tiles".into());
}
let mut hand = [0u8; 9];
for n in hand_string.chars() {
match n {
'1'..='9' => {
let index = n.to_digit(10).expect("Should be parsed") as usize;
hand[index - 1] += 1;
}
_ => return Err("Fuck".into()),
}
}
let mut complete_hands = BTreeSet::new();
for additional in 1..=9 {
let mut queue = VecDeque::new();
let mut complete_hand = hand;
complete_hand[additional - 1] += 1;
queue.push_back(State {
waiting: additional as u8,
melds: vec![],
rest_tiles: complete_hand,
});
while !queue.is_empty() {
let state = queue.pop_front().expect("Must not be empty");
// 牌を使いきった
if &state.rest_tiles.iter().sum::<u8>() == &0u8 {
let melds = &state.melds;
let eyes = melds
.iter()
.filter(|m| match m {
Meld::Eye(_) => true,
_ => false,
})
.count();
// 和了形でもチートイでもない場合は不正なので飛ばす
if eyes != 1 && eyes != 7 {
continue;
}
let mut sorted = state.melds.clone();
sorted.sort();
complete_hands.insert((state.waiting, sorted));
continue;
}
// 刻子
for p in 1..=9 {
if state.rest_tiles[p - 1] >= 3 {
let mut next = state.clone();
next.rest_tiles[p - 1] -= 3;
next.melds.push(Meld::Pong(p as u8));
queue.push_back(next);
}
}
// 順子
for p in 1..=7 {
if state.rest_tiles[p - 1] >= 1
&& state.rest_tiles[p] >= 1
&& state.rest_tiles[p + 1] >= 1
{
let mut next = state.clone();
next.rest_tiles[p - 1] -= 1;
next.rest_tiles[p] -= 1;
next.rest_tiles[p + 1] -= 1;
next.melds.push(Meld::Chow(p as u8));
queue.push_back(next);
}
}
// 対子
for p in 1..=9 {
if state.rest_tiles[p - 1] >= 2 {
let mut next = state.clone();
next.rest_tiles[p - 1] -= 2;
next.melds.push(Meld::Eye(p as u8));
queue.push_back(next);
}
}
}
}
for (waiting, melds) in &complete_hands {
print!("待ち: {}, 面子: ", waiting);
for meld in melds {
print!("{} ", meld);
}
println!();
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.