Skip to content

Instantly share code, notes, and snippets.

@pkoch
Created July 20, 2022 23:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pkoch/d811da236dd91e137e94d3385270fd6a to your computer and use it in GitHub Desktop.
Save pkoch/d811da236dd91e137e94d3385270fd6a to your computer and use it in GitHub Desktop.
// I wish I could use creates. :(
use std::collections::HashSet;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct DecodeError(String);
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
enum Rank {
Two = 2,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Jack,
Queen,
King,
Ace,
}
impl TryFrom<char> for Rank {
type Error = DecodeError;
fn try_from(s: char) -> Result<Self, Self::Error> {
match s {
'2' => Ok(Rank::Two),
'3' => Ok(Rank::Three),
'4' => Ok(Rank::Four),
'5' => Ok(Rank::Five),
'6' => Ok(Rank::Six),
'7' => Ok(Rank::Seven),
'8' => Ok(Rank::Eight),
'9' => Ok(Rank::Nine),
'J' => Ok(Rank::Jack),
'Q' => Ok(Rank::Queen),
'K' => Ok(Rank::King),
'A' => Ok(Rank::Ace),
_ => Err(DecodeError(format!("`{:?}`: not a Rank", s))),
}
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum Suit {
Diamonds,
Hearts,
Clubs,
Spades,
}
impl TryFrom<char> for Suit {
type Error = DecodeError;
fn try_from(s: char) -> Result<Self, Self::Error> {
match s {
'D' => Ok(Suit::Diamonds),
'H' => Ok(Suit::Hearts),
'C' => Ok(Suit::Clubs),
'S' => Ok(Suit::Spades),
_ => Err(DecodeError(format!("`{:?}`: not a Suit", s))),
}
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct Card {
rank: Rank,
suit: Suit,
}
impl TryFrom<&str> for Card {
type Error = DecodeError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
let chrs = s.chars().collect::<Vec<_>>();
if chrs.len() != 2 {
return Err(DecodeError(format!("`{:?}`: expected to be two chars", s)));
};
Ok(Card {
rank: Rank::try_from(chrs[0])?,
suit: Suit::try_from(chrs[1])?,
})
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct Hand([Card; 5]);
impl TryFrom<&str> for Hand {
type Error = DecodeError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
let hnds = s.split_ascii_whitespace().collect::<Vec<_>>();
if hnds.len() != 5 {
return Err(DecodeError(format!(
"`{:?}`: expected to be 5 char pairs",
s
)));
};
Ok(Hand(
hnds.iter()
.map(|s| (*s).try_into())
.collect::<Result<Vec<Card>, _>>()?
.try_into()
.unwrap(),
))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum HandScore {
StraightFlush {
top_rank: Rank,
},
FourOfAKind {
top_rank: Rank,
bottom_rank: Rank,
},
FullHouse {
top_rank: Rank,
bottom_rank: Rank,
},
Flush {
ranks: Vec<Rank>,
},
Straight {
top_rank: Rank,
},
ThreeOfAKind {
top_rank: Rank,
other_ranks: Vec<Rank>,
},
TwoPair {
top_rank: Rank,
second_rank: Rank,
bottom_rank: Rank,
},
OnePair {
top_rank: Rank,
other_ranks: Vec<Rank>,
},
HighCard {
top_rank: Rank,
other_ranks: Vec<Rank>,
},
}
fn consecutive(cards: &[Card]) -> bool {
if cards.len() < 2 {
return true;
}
let ranks = cards
.iter()
.map(|Card { rank, suit: _ }| *rank as u8)
.collect::<Vec<_>>();
if HashSet::<_>::from_iter(ranks.iter()).len() != cards.len() {
return false;
}
let mut possibilities = vec![ranks];
let ranks_ = possibilities.first().unwrap();
let ace_u8 = Rank::Ace as u8;
if ranks_.contains(&ace_u8) {
let mut alt = ranks_.clone();
alt.retain(|e| *e != ace_u8);
alt.push(1);
possibilities.push(alt);
}
possibilities.iter().any(|p| {
p.windows(2)
.all(|w| if let [a, b] = w { *a + 1 == *b } else { false })
})
}
fn same_suit(cards: &[Card]) -> bool {
cards
.iter()
.map(|Card { rank: _, suit }| suit)
.collect::<HashSet<_>>()
.len()
== 1
}
fn same_rank(cards: &[Card]) -> bool {
cards
.iter()
.map(|Card { rank, suit: _ }| rank)
.collect::<HashSet<_>>()
.len()
== 1
}
impl From<Hand> for HandScore {
fn from(h: Hand) -> Self {
let mut cards = h.0;
if consecutive(&cards) && same_suit(&cards) {
cards.sort();
return HandScore::StraightFlush {
top_rank: cards.last().unwrap().rank,
};
};
todo!()
}
}
impl From<&str> for HandScore {
fn from(s: &str) -> Self {
HandScore::from(Hand::try_from(s).unwrap_or_else(|v| panic!("{:?}", v)))
}
}
pub fn winning_hands<'a>(hands: &[&'a str]) -> Vec<&'a str> {
let mut hs: Vec<&'a str> = hands.into();
hs.sort_by_key(|v| HandScore::from(*v));
hs
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment