Compare commits
2 Commits
a985a81d6d
...
fc5670b37e
Author | SHA1 | Date |
---|---|---|
Andrew Coleman | fc5670b37e | |
Andrew Coleman | e6cf50fb47 |
|
@ -4,14 +4,12 @@ const MAX_RED: u32 = 12;
|
||||||
const MAX_GREEN: u32 = 13;
|
const MAX_GREEN: u32 = 13;
|
||||||
const MAX_BLUE: u32 = 14;
|
const MAX_BLUE: u32 = 14;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Turn {
|
struct Turn {
|
||||||
red: u32,
|
red: u32,
|
||||||
green: u32,
|
green: u32,
|
||||||
blue: u32,
|
blue: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Game {
|
struct Game {
|
||||||
id: u32,
|
id: u32,
|
||||||
turns: Vec<Turn>,
|
turns: Vec<Turn>,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use aoc_runner_derive::{aoc, aoc_generator};
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Card {
|
struct Card {
|
||||||
id: usize,
|
id: usize,
|
||||||
winning: HashSet<u32>,
|
winning: HashSet<u32>,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use aoc_runner_derive::{aoc, aoc_generator};
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Race {
|
struct Race {
|
||||||
time: u64,
|
time: u64,
|
||||||
distance: u64,
|
distance: u64,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::cmp::Ordering;
|
||||||
use std::collections::{BTreeMap, HashSet};
|
use std::collections::{BTreeMap, HashSet};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
|
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
enum Card {
|
enum Card {
|
||||||
A,
|
A,
|
||||||
K,
|
K,
|
||||||
|
@ -20,7 +20,7 @@ enum Card {
|
||||||
C2,
|
C2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
enum Part2Card {
|
enum Part2Card {
|
||||||
A,
|
A,
|
||||||
K,
|
K,
|
||||||
|
@ -77,7 +77,7 @@ impl FromStr for Card {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
enum HandKinds {
|
enum HandKinds {
|
||||||
FiveAlike,
|
FiveAlike,
|
||||||
FourAlike,
|
FourAlike,
|
||||||
|
@ -88,7 +88,7 @@ enum HandKinds {
|
||||||
HighCard,
|
HighCard,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
struct Hand {
|
struct Hand {
|
||||||
bid: u64,
|
bid: u64,
|
||||||
cards: [Card; 5],
|
cards: [Card; 5],
|
||||||
|
@ -123,10 +123,7 @@ impl Ord for Hand {
|
||||||
} else if self.cards[4] != other.cards[4] {
|
} else if self.cards[4] != other.cards[4] {
|
||||||
self.cards[4].cmp(&other.cards[4])
|
self.cards[4].cmp(&other.cards[4])
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!("could not sort hand")
|
||||||
"could not sort hand {:?} with {:?}",
|
|
||||||
self.cards, other.cards
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.hand_kind.cmp(&other.hand_kind)
|
self.hand_kind.cmp(&other.hand_kind)
|
||||||
|
@ -162,10 +159,7 @@ impl Ord for Part2Hand {
|
||||||
} else if self.cards[4] != other.cards[4] {
|
} else if self.cards[4] != other.cards[4] {
|
||||||
self.cards[4].cmp(&other.cards[4])
|
self.cards[4].cmp(&other.cards[4])
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!("could not sort hand")
|
||||||
"could not sort hand {:?} with {:?}",
|
|
||||||
self.cards, other.cards
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.hand_kind.cmp(&other.hand_kind)
|
self.hand_kind.cmp(&other.hand_kind)
|
||||||
|
@ -175,7 +169,7 @@ impl Ord for Part2Hand {
|
||||||
|
|
||||||
fn get_hand_type<T>(cards: &[T; 5]) -> HandKinds
|
fn get_hand_type<T>(cards: &[T; 5]) -> HandKinds
|
||||||
where
|
where
|
||||||
T: std::fmt::Debug + Eq + PartialEq + PartialOrd + std::hash::Hash,
|
T: Eq + PartialEq + PartialOrd + std::hash::Hash,
|
||||||
{
|
{
|
||||||
let mut distinct_cards: HashSet<&T> = HashSet::new();
|
let mut distinct_cards: HashSet<&T> = HashSet::new();
|
||||||
for c in cards.iter() {
|
for c in cards.iter() {
|
||||||
|
@ -212,14 +206,12 @@ where
|
||||||
4 => HandKinds::OnePair,
|
4 => HandKinds::OnePair,
|
||||||
5 => HandKinds::HighCard,
|
5 => HandKinds::HighCard,
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
"expected to find size 1-5, but instead got {} from line {:?}",
|
"expected to find size 1-5, but instead got {}",
|
||||||
distinct_cards.len(),
|
distinct_cards.len()
|
||||||
cards
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Part2Hand {
|
struct Part2Hand {
|
||||||
bid: u64,
|
bid: u64,
|
||||||
cards: [Part2Card; 5],
|
cards: [Part2Card; 5],
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct MetalIsland {
|
||||||
start: Step,
|
start: Step,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum Pieces {
|
enum Pieces {
|
||||||
Empty,
|
Empty,
|
||||||
Start,
|
Start,
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl Galaxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
#[derive(Eq, PartialEq, Copy, Clone)]
|
||||||
struct Coord(usize, usize);
|
struct Coord(usize, usize);
|
||||||
|
|
||||||
impl Coord {
|
impl Coord {
|
||||||
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
type Cache = HashMap<(Vec<Condition>, Vec<usize>), usize>;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
enum Condition {
|
||||||
|
Unknown,
|
||||||
|
Functional,
|
||||||
|
Damaged,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Condition {
|
||||||
|
type Err = String;
|
||||||
|
fn from_str(input: &str) -> Result<Condition, Self::Err> {
|
||||||
|
match input {
|
||||||
|
"?" => Ok(Condition::Unknown),
|
||||||
|
"." => Ok(Condition::Functional),
|
||||||
|
"#" => Ok(Condition::Damaged),
|
||||||
|
n @ _ => Err(format!("Unknown character '{}'", n)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Spring {
|
||||||
|
list: Vec<Condition>,
|
||||||
|
groups: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc_generator(day12)]
|
||||||
|
fn parse(input: &str) -> Vec<Spring> {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.filter_map(|line| {
|
||||||
|
if !line.is_empty() {
|
||||||
|
let parts = line.split(" ").collect::<Vec<&str>>();
|
||||||
|
let list = parts[0]
|
||||||
|
.split("")
|
||||||
|
.filter_map(|e| {
|
||||||
|
if e.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Condition::from_str(e).ok()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let groups = parts[1]
|
||||||
|
.split(",")
|
||||||
|
.map(|e| e.parse::<usize>().unwrap())
|
||||||
|
.collect();
|
||||||
|
Some(Spring { list, groups })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_solutions(list: &Vec<Condition>, groups: &Vec<usize>, cache: &mut Cache) -> usize {
|
||||||
|
if list.is_empty() {
|
||||||
|
if groups.is_empty() {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match list[0] {
|
||||||
|
Condition::Functional => calc_solutions(&list[1..].to_vec(), groups, cache),
|
||||||
|
Condition::Damaged => calc_damaged_solutions(list, groups, cache),
|
||||||
|
Condition::Unknown => {
|
||||||
|
calc_solutions(&list[1..].to_vec(), groups, cache)
|
||||||
|
+ calc_damaged_solutions(list, groups, cache)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_damaged_solutions(list: &Vec<Condition>, groups: &Vec<usize>, cache: &mut Cache) -> usize {
|
||||||
|
if let Some(&result) = cache.get(&(list.clone(), groups.clone())) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if groups.is_empty() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if list.len() < groups[0] {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..groups[0] {
|
||||||
|
if list[i] == Condition::Functional {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if list.len() == groups[0] {
|
||||||
|
if groups.len() == 1 {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if list[groups[0]] == Condition::Damaged {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let result = calc_solutions(
|
||||||
|
&list[(groups[0] + 1)..].to_vec(),
|
||||||
|
&groups[1..].to_vec(),
|
||||||
|
cache,
|
||||||
|
);
|
||||||
|
cache.insert((list.clone(), groups.clone()), result);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day12, part1)]
|
||||||
|
fn part1(input: &[Spring]) -> usize {
|
||||||
|
let mut result: usize = 0;
|
||||||
|
for src in input.iter() {
|
||||||
|
let mut cache: Cache = HashMap::new();
|
||||||
|
result += calc_solutions(&src.list, &src.groups, &mut cache);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day12, part2)]
|
||||||
|
fn part2(input: &[Spring]) -> usize {
|
||||||
|
let mut result: usize = 0;
|
||||||
|
for src in input.iter() {
|
||||||
|
let mut l: Vec<Condition> = Vec::with_capacity(src.groups.len() * 5 + 5);
|
||||||
|
let mut g: Vec<usize> = Vec::with_capacity(src.list.len() * 5);
|
||||||
|
for index in 0..5 {
|
||||||
|
l.append(&mut src.list.clone());
|
||||||
|
if index < 4 {
|
||||||
|
l.push(Condition::Unknown);
|
||||||
|
}
|
||||||
|
g.append(&mut src.groups.clone());
|
||||||
|
}
|
||||||
|
let mut cache: Cache = HashMap::new();
|
||||||
|
let s = calc_solutions(&l, &g, &mut cache);
|
||||||
|
result += s;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SAMPLE_DATA: &'static str = r#"???.### 1,1,3
|
||||||
|
.??..??...?##. 1,1,3
|
||||||
|
?#?#?#?#?#?#?#? 1,3,1,6
|
||||||
|
????.#...#... 4,1,1
|
||||||
|
????.######..#####. 1,6,5
|
||||||
|
?###???????? 3,2,1
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_data_part1() {
|
||||||
|
let input = parse(&SAMPLE_DATA);
|
||||||
|
assert_eq!(part1(&input), 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_data_3() {
|
||||||
|
let line1 = Spring {
|
||||||
|
list: vec![
|
||||||
|
Condition::Unknown,
|
||||||
|
Condition::Unknown,
|
||||||
|
Condition::Unknown,
|
||||||
|
Condition::Functional,
|
||||||
|
Condition::Damaged,
|
||||||
|
Condition::Damaged,
|
||||||
|
Condition::Damaged,
|
||||||
|
],
|
||||||
|
groups: vec![1, 1, 3],
|
||||||
|
};
|
||||||
|
assert_eq!(part2(&[line1]), 1);
|
||||||
|
|
||||||
|
let line2 = Spring {
|
||||||
|
list: vec![
|
||||||
|
Condition::Functional,
|
||||||
|
Condition::Unknown,
|
||||||
|
Condition::Unknown,
|
||||||
|
Condition::Functional,
|
||||||
|
Condition::Functional,
|
||||||
|
Condition::Unknown,
|
||||||
|
Condition::Unknown,
|
||||||
|
Condition::Functional,
|
||||||
|
Condition::Functional,
|
||||||
|
Condition::Functional,
|
||||||
|
Condition::Unknown,
|
||||||
|
Condition::Damaged,
|
||||||
|
Condition::Damaged,
|
||||||
|
Condition::Functional,
|
||||||
|
],
|
||||||
|
groups: vec![1, 1, 3],
|
||||||
|
};
|
||||||
|
assert_eq!(part2(&[line2]), 16384);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_data_part2() {
|
||||||
|
let input = parse(&SAMPLE_DATA);
|
||||||
|
assert_eq!(part2(&input), 525152);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,5 +11,6 @@ mod day08;
|
||||||
mod day09;
|
mod day09;
|
||||||
mod day10;
|
mod day10;
|
||||||
mod day11;
|
mod day11;
|
||||||
|
mod day12;
|
||||||
|
|
||||||
aoc_lib! { year = 2023 }
|
aoc_lib! { year = 2023 }
|
||||||
|
|
Loading…
Reference in New Issue