Created
November 8, 2019 08:37
-
-
Save kb10uy/91433bd96a8d800d182638b14359a6de to your computer and use it in GitHub Desktop.
チンイツチェッカー
This file contains 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::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