add 2023/07/2
This commit is contained in:
parent
f04588c2f0
commit
da2401d54a
@ -26,7 +26,7 @@ fn parse_input(raw: &str) -> Parsed {
|
|||||||
(seeds, ranges)
|
(seeds, ranges)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve(start: I, mappings: &Vec<Mapping>) -> I {
|
fn resolve(start: I, mappings: &[Mapping]) -> I {
|
||||||
mappings.iter().fold(start, |i, map| map.iter().find_map(|(range, _, offset)| range.contains(&i).then_some(i + offset)).unwrap_or(i))
|
mappings.iter().fold(start, |i, map| map.iter().find_map(|(range, _, offset)| range.contains(&i).then_some(i + offset)).unwrap_or(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ fn part1((seeds, mappings): &Parsed) -> I {
|
|||||||
seeds.iter().map(|&s| resolve(s, mappings)).min().unwrap()
|
seeds.iter().map(|&s| resolve(s, mappings)).min().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_backwards(start: I, mappings: &Vec<Mapping>) -> I {
|
fn resolve_backwards(start: I, mappings: &[Mapping]) -> I {
|
||||||
mappings.iter().fold(start, |i, map| map.iter().find_map(|(_, range, offset)| range.contains(&i).then_some(i - offset)).unwrap_or(i))
|
mappings.iter().fold(start, |i, map| map.iter().find_map(|(_, range, offset)| range.contains(&i).then_some(i - offset)).unwrap_or(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +77,8 @@ fn part2((seeds, mappings): &Parsed) -> I {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_starting_seed(start: I, offset: i64, seed_ranges: &Vec<Range<I>>, mappings: &Vec<Mapping>) -> bool {
|
fn has_starting_seed(start: I, offset: i64, seed_ranges: &[Range<I>], mappings: &[Mapping]) -> bool {
|
||||||
let seed = resolve_backwards(start - offset, &mappings);
|
let seed = resolve_backwards(start - offset, mappings);
|
||||||
// If seed == s, the entire resolution didn’t hit a single mapping, so we don’t need to check seeds.
|
// If seed == s, the entire resolution didn’t hit a single mapping, so we don’t need to check seeds.
|
||||||
seed != start && seed_ranges.iter().any(|r| r.contains(&seed))
|
seed != start && seed_ranges.iter().any(|r| r.contains(&seed))
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,48 @@
|
|||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use aoc2023::{boilerplate, common::*};
|
use aoc2023::{boilerplate, common::*};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
const DAY: usize = 7;
|
const DAY: usize = 7;
|
||||||
type I = usize;
|
type I = usize;
|
||||||
type Parsed = Vec<([I; 5], I, I)>;
|
type Hand = [u8; 5];
|
||||||
|
type Parsed = Vec<(Hand, I)>;
|
||||||
|
|
||||||
const CARDS: [u8; 13] = [b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'T', b'J', b'Q', b'K', b'A'];
|
const CARDS: [u8; 13] = [b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'T', b'J', b'Q', b'K', b'A'];
|
||||||
|
const CARDS_P2: [u8; 13] = [b'J', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'T', b'Q', b'K', b'A'];
|
||||||
|
|
||||||
|
enum Quality {
|
||||||
|
AllEqual = 1 << 30,
|
||||||
|
Quad = 1 << 29,
|
||||||
|
FullHouse = 1 << 28,
|
||||||
|
Triple = 1 << 27,
|
||||||
|
TwoPair = 1 << 26,
|
||||||
|
Pair = 1 << 25,
|
||||||
|
None = 1 << 24,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Quality {
|
||||||
|
// How adding 1 joker raises the quality of a hand.
|
||||||
|
fn upgrade(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Quality::AllEqual | Quality::Quad => Quality::AllEqual,
|
||||||
|
Quality::Triple | Quality::FullHouse => Quality::Quad,
|
||||||
|
Quality::TwoPair => Quality::FullHouse,
|
||||||
|
Quality::Pair => Quality::Triple,
|
||||||
|
Quality::None => Quality::Pair,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_input(raw: &str) -> Parsed {
|
fn parse_input(raw: &str) -> Parsed {
|
||||||
raw.lines()
|
raw.lines()
|
||||||
.map(|l| l.split_once(' ').unwrap())
|
.map(|l| l.split_once(' ').unwrap())
|
||||||
.map(|(hand, points)| {
|
.map(|(hand, points)| (<[_; 5]>::try_from(hand.as_bytes()).unwrap(), parse_num(points)))
|
||||||
(<[_; 5]>::try_from(hand.as_bytes()).unwrap().map(|b| CARDS.iter().position(|&c| c == b).unwrap()), parse_num(points))
|
|
||||||
})
|
|
||||||
.map(|(hand, points)| (hand, points, hand.iter().fold(0, |acc, n| (acc << 4) + n)))
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part1(hands: &Parsed) -> usize {
|
fn rate_hand(mut hand: Hand) -> Quality {
|
||||||
let mut rated_hands = hands
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.map(|(mut hand, points, tiebreak)| {
|
|
||||||
hand.sort();
|
hand.sort();
|
||||||
let paired = hand
|
let paired = hand
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -31,25 +50,56 @@ fn part1(hands: &Parsed) -> usize {
|
|||||||
.coalesce(|(c1, n1), (c2, n2)| if c1 == c2 { Ok((c1, n1 + n2)) } else { Err(((c1, n1), (c2, n2))) })
|
.coalesce(|(c1, n1), (c2, n2)| if c1 == c2 { Ok((c1, n1 + n2)) } else { Err(((c1, n1), (c2, n2))) })
|
||||||
.map(|(_, n)| n)
|
.map(|(_, n)| n)
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let value = match paired.as_slice() {
|
match paired.as_slice() {
|
||||||
[_] => (1 << 30) + tiebreak,
|
[_] => Quality::AllEqual,
|
||||||
[4, 1] | [1, 4] => (1 << 29) + tiebreak,
|
[4, 1] | [1, 4] => Quality::Quad,
|
||||||
[3, 2] | [2, 3] => (1 << 28) + tiebreak,
|
[3, 2] | [2, 3] => Quality::FullHouse,
|
||||||
[3, 1, 1] | [1, 3, 1] | [1, 1, 3] => (1 << 27) + tiebreak,
|
a @ [_, _, _] if a.contains(&3) => Quality::Triple,
|
||||||
// can only be 2 pair
|
[_, _, _] => Quality::TwoPair,
|
||||||
[_, _, _] => (1 << 26) + tiebreak,
|
[_, _, _, _] => Quality::Pair,
|
||||||
[_, _, _, _] => (1 << 25) + tiebreak,
|
_ => Quality::None,
|
||||||
_ => (1 << 24) + tiebreak,
|
}
|
||||||
};
|
}
|
||||||
(value, points)
|
|
||||||
|
fn tiebreaker(hand: &Hand, values: &[u8; 13]) -> usize {
|
||||||
|
let tiebreak_hand = hand.map(|b| values.iter().position(|&c| c == b).unwrap());
|
||||||
|
tiebreak_hand.iter().fold(0, |acc, n| (acc << 4) + n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(hands: &Parsed) -> usize {
|
||||||
|
let mut rated_hands = hands
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|(hand, points)| {
|
||||||
|
let tiebreak = tiebreaker(&hand, &CARDS);
|
||||||
|
(rate_hand(hand) as usize + tiebreak, points)
|
||||||
})
|
})
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
rated_hands.sort_unstable_by_key(|(v, _)| *v);
|
rated_hands.sort_unstable_by_key(|(v, _)| *v);
|
||||||
rated_hands.into_iter().zip(1..).map(|((_, points), position)| points * position).sum()
|
rated_hands.into_iter().zip(1..).map(|((_, points), position)| points * position).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(parsed: &Parsed) -> usize {
|
fn part2(hands: &Parsed) -> usize {
|
||||||
unimplemented!()
|
let mut rated_hands = hands
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|(mut hand, points)| {
|
||||||
|
let tiebreak = tiebreaker(&hand, &CARDS_P2);
|
||||||
|
// Count how many jokers there are and insert nonsense data for them so they can’t produce any pairs.
|
||||||
|
let mut jokers = 0;
|
||||||
|
for c in hand.iter_mut().filter(|c| c == &&b'J') {
|
||||||
|
*c = jokers;
|
||||||
|
jokers += 1;
|
||||||
|
}
|
||||||
|
let mut rating = rate_hand(hand);
|
||||||
|
for _ in 0..jokers {
|
||||||
|
rating = rating.upgrade();
|
||||||
|
}
|
||||||
|
(rating as usize + tiebreak, points)
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
rated_hands.sort_unstable_by_key(|(v, _)| *v);
|
||||||
|
rated_hands.into_iter().zip(1..).map(|((_, points), position)| points * position).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
boilerplate! {
|
boilerplate! {
|
||||||
@ -61,9 +111,9 @@ KTJJT 220
|
|||||||
QQQJA 483",
|
QQQJA 483",
|
||||||
tests: {
|
tests: {
|
||||||
part1: { TEST_INPUT => 6440 },
|
part1: { TEST_INPUT => 6440 },
|
||||||
part2: { TEST_INPUT => 0 },
|
part2: { TEST_INPUT => 5905 },
|
||||||
},
|
},
|
||||||
bench1 == 248812215,
|
bench1 == 248812215,
|
||||||
bench2 == 0,
|
bench2 == 250057090,
|
||||||
bench_parse: Vec::len => 1000,
|
bench_parse: Vec::len => 1000,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user