Complete Day 7

main
Wes Holland 1 year ago
parent b8e82c25be
commit 164127412d

@ -0,0 +1 @@
/target

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "day7"
version = "0.1.0"

@ -0,0 +1,6 @@
[package]
name = "day7"
version = "0.1.0"
edition = "2021"
[dependencies]

@ -0,0 +1,6 @@
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
J2883 666

File diff suppressed because it is too large Load Diff

@ -0,0 +1,59 @@
use std::io::{Lines, StdinLock};
/// A simple, but panic-y reader for stdin
pub fn simple_stdin() -> SimpleStdinLines {
SimpleStdinLines::new()
}
pub struct SimpleStdinLines {
pub inner: Lines<StdinLock<'static>>,
}
impl SimpleStdinLines {
pub fn new() -> Self {
Self { inner: std::io::stdin().lines() }
}
}
impl Iterator for SimpleStdinLines {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().transpose().unwrap()
}
}
/// A simple, but panic-y parser of arguments
pub fn simple_args() -> SimpleArgs {
SimpleArgs::init()
}
pub struct SimpleArgs {
args: Vec<String>,
}
impl SimpleArgs {
pub fn init() -> Self {
Self { args: std::env::args().collect() }
}
pub fn get_flag(&self, name: &str) -> bool {
self.args.iter().any(|x| x == name)
}
pub fn get_value(&self, name: &str, default: &str) -> String {
let pos = self.args.iter().position(|x| x == name);
if let Some(idx) = pos {
if let Some(s) = self.args.iter().nth(idx + 1) {
s.clone()
}
else {
String::from(default)
}
}
else {
String::from(default)
}
}
}

@ -0,0 +1,48 @@
#[derive(Clone, Debug)]
pub enum Token {
Part(String),
}
pub fn tokenize_line(input: &str) -> Vec<Token> {
let mut vals = vec![];
let mut idx = 0;
while idx < input.len() {
let c = input.chars().nth(idx).unwrap();
if is_keyword_char(c) {
let end = match input.chars().skip(idx)
.position(|x| !is_keyword_char(x)) {
Some(pos) => idx + pos,
None => input.len(),
};
vals.push(Token::Part(String::from(&input[idx..end])));
idx = end;
}
else {
idx = idx + 1;
}
}
vals
}
fn is_keyword_char(c: char) -> bool {
match c {
'A'|'K'|'Q'|'J'|'T'|'0'..='9' => true,
_ => false
}
}
pub fn expect_part<'a>(iter: &mut impl Iterator<Item = &'a Token>) -> Option<String> {
if let Some(Token::Part(k)) = iter.next() {
Some(k.clone())
}
else {
None
}
}

@ -0,0 +1,274 @@
mod input_tools;
mod lexer;
use lexer::*;
use input_tools::*;
use std::cmp::Ordering;
#[derive(Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
enum Handtype {
HighCard,
Pair,
TwoPair,
ThreeKind,
FullHouse,
FourKind,
FiveKind,
}
impl Handtype {
pub fn new(cards: &[u32; 5]) -> Self {
let mut counts = [0u32; 14];
for card in cards {
counts[card.saturating_sub(1) as usize] += 1
}
let max = *counts.iter().max().unwrap();
if max == 5 {
Handtype::FiveKind
}
else if max == 4 {
Handtype::FourKind
}
else if max == 3 {
if counts.iter().any(|x| *x == 2 )
{
Handtype::FullHouse
}
else {
Handtype::ThreeKind
}
}
else if max == 2 {
if counts.iter().filter(|x| **x == 2).count() == 2 {
Handtype::TwoPair
}
else {
Handtype::Pair
}
}
else {
Handtype::HighCard
}
}
pub fn new_with_jokers(cards: &[u32; 5]) -> Self {
let mut counts = [0u32; 15];
for card in cards {
counts[*card as usize] += 1
}
let jokers = counts[1];
let max = *counts.iter().skip(2).max().unwrap() + jokers;
if max == 5 {
Handtype::FiveKind
}
else if max == 4 {
Handtype::FourKind
}
else if max == 3 {
let pair_count = counts.iter().skip(2).filter(|x| **x == 2 ).count();
if pair_count == 2
{
// Joker full house
Handtype::FullHouse
}
else if pair_count == 1 && jokers == 0
{
// True full house
Handtype::FullHouse
}
else {
Handtype::ThreeKind
}
}
else if max == 2 {
if counts.iter().skip(2).filter(|x| **x == 2).count() == 2 {
Handtype::TwoPair
}
else {
Handtype::Pair
}
}
else {
Handtype::HighCard
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd)]
struct Hand {
kind: Handtype,
cards: [u32; 5],
bid: u32,
}
impl Hand {
pub fn from_tokens<'a>(toks: &mut impl Iterator<Item = &'a Token>) -> Self {
let hand_desc = expect_part(toks).unwrap();
let bid_desc = expect_part(toks).unwrap();
let mut cards = [0; 5];
for (idx, c) in Iterator::enumerate(hand_desc.chars()) {
let val = match c {
'A' => 14,
'K' => 13,
'Q' => 12,
'J' => 11,
'T' => 10,
'2'..='9' => u32::from_str_radix(&c.to_string(), 10).unwrap(),
_ => 0,
};
cards[idx] = val;
}
let kind = Handtype::new(&cards);
let bid = u32::from_str_radix(&bid_desc, 10).unwrap();
Self { cards, bid, kind }
}
}
impl std::cmp::Ord for Hand {
fn cmp(&self, other: &Self) -> Ordering {
match self.kind.cmp(&other.kind) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => {
self.cards.iter().cmp(other.cards.iter())
}
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd)]
struct HandWithJokers {
kind: Handtype,
cards: [u32; 5],
bid: u32,
}
impl HandWithJokers {
pub fn from_tokens<'a>(toks: &mut impl Iterator<Item = &'a Token>) -> Self {
let hand_desc = expect_part(toks).unwrap();
let bid_desc = expect_part(toks).unwrap();
let mut cards = [0; 5];
for (idx, c) in Iterator::enumerate(hand_desc.chars()) {
let val = match c {
'A' => 14,
'K' => 13,
'Q' => 12,
'J' => 1,
'T' => 10,
'2'..='9' => u32::from_str_radix(&c.to_string(), 10).unwrap(),
_ => 0,
};
cards[idx] = val;
}
let kind = Handtype::new_with_jokers(&cards);
let bid = u32::from_str_radix(&bid_desc, 10).unwrap();
Self { cards, bid, kind }
}
}
impl std::cmp::Ord for HandWithJokers {
fn cmp(&self, other: &Self) -> Ordering {
match self.kind.cmp(&other.kind) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => {
self.cards.iter().cmp(other.cards.iter())
}
}
}
}
fn puzzle1(verbose: bool) {
println!("Part 1");
let mut sum = 0;
let mut hands = vec![];
for line in simple_stdin() {
let tokens = tokenize_line(&line);
let hand = Hand::from_tokens(&mut tokens.iter());
let pos = hands.binary_search(&hand).unwrap_or_else(|e| e);
hands.insert(pos, hand);
if verbose {
println!("{} -> {:?}", line, hand);
}
}
if verbose {
println!("");
}
for (idx, h) in Iterator::enumerate(hands.iter()) {
let rank = idx + 1;
let score = rank as u32 * h.bid;
sum += score;
if verbose {
println!("Score {} * {} = {} => {:?}", h.bid, rank, score, h);
}
}
println!("Sum: {}", sum);
}
fn puzzle2(verbose: bool) {
println!("Part 2");
let mut sum = 0u64;
let mut hands = vec![];
for line in simple_stdin() {
let tokens = tokenize_line(&line);
let hand = HandWithJokers::from_tokens(&mut tokens.iter());
let pos = hands.binary_search(&hand).unwrap_or_else(|e| e);
hands.insert(pos, hand);
if verbose {
println!("{} -> {:?}", line, hand);
}
}
if verbose {
println!("");
}
for (idx, h) in Iterator::enumerate(hands.iter()) {
let rank = idx + 1;
let score = rank as u64 * h.bid as u64;
sum += score;
if verbose {
println!("Score {} * {} = {} => {:?}", h.bid, rank, score, h);
}
}
println!("Sum: {}", sum);
}
fn main() {
let args = simple_args();
let verbose = args.get_flag("-v");
let part = args.get_value("-p", "1");
match part.as_str() {
"1" => puzzle1(verbose),
"2" => puzzle2(verbose),
_ => println!("Nothing to do")
}
}
Loading…
Cancel
Save

Powered by TurnKey Linux.