Compare commits
3 commits
df07812ce8
...
dbd5139991
Author | SHA1 | Date | |
---|---|---|---|
dbd5139991 | |||
b02d56254d | |||
10e53e648d |
47
Cargo.lock
generated
47
Cargo.lock
generated
|
@ -8,8 +8,10 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"aoc-runner",
|
||||
"aoc-runner-derive",
|
||||
"bitvec",
|
||||
"itertools",
|
||||
"num",
|
||||
"radix_fmt",
|
||||
"yap",
|
||||
]
|
||||
|
||||
|
@ -48,12 +50,30 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "0.22.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium",
|
||||
"tap",
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.1"
|
||||
|
@ -163,6 +183,18 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
|
||||
|
||||
[[package]]
|
||||
name = "radix_fmt"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce082a9940a7ace2ad4a8b7d0b1eac6aa378895f18be598230c5f2284ac05426"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.6"
|
||||
|
@ -208,12 +240,27 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188"
|
||||
dependencies = [
|
||||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yap"
|
||||
version = "0.7.1"
|
||||
|
|
|
@ -8,6 +8,8 @@ edition = "2021"
|
|||
[dependencies]
|
||||
aoc-runner = "0.3.0"
|
||||
aoc-runner-derive = "0.3.0"
|
||||
bitvec = "0.22.3"
|
||||
itertools = "0.10.1"
|
||||
num = "0.4.0"
|
||||
radix_fmt = "1.0.0"
|
||||
yap = "0.7.1"
|
||||
|
|
|
@ -1,80 +1,88 @@
|
|||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
|
||||
use bitvec::prelude::*;
|
||||
|
||||
type Mbv = BitVec<Msb0>;
|
||||
|
||||
#[aoc_generator(day3)]
|
||||
pub fn parse_diagnostics(input: &str) -> Vec<String> {
|
||||
input.lines().map(String::from).collect()
|
||||
pub fn parse_diagnostics(input: &str) -> Vec<Mbv> {
|
||||
input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let length = line.len();
|
||||
let mut element = usize::from_str_radix(line, 2).unwrap();
|
||||
element <<= usize::BITS - length as u32;
|
||||
let mut vec: Mbv = Mbv::from_element(element);
|
||||
vec.truncate(length);
|
||||
vec
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[aoc(day3, part1)]
|
||||
pub fn calculate_power_consumption(input: &[String]) -> usize {
|
||||
let gamma_factor = most_common_bit_string(input);
|
||||
let epsilon_factor = invert_binary_string(&gamma_factor);
|
||||
let gamma_factor = usize::from_str_radix(&gamma_factor, 2).unwrap();
|
||||
let epsilon_factor = usize::from_str_radix(&epsilon_factor, 2).unwrap();
|
||||
pub fn calculate_power_consumption(input: &[Mbv]) -> usize {
|
||||
let gamma_factor = most_common_bit_vec(input);
|
||||
let epsilon_factor = invert_bit_vec(&gamma_factor);
|
||||
let gamma_factor = bit_vec_to_usize(&gamma_factor);
|
||||
let epsilon_factor = bit_vec_to_usize(&epsilon_factor);
|
||||
gamma_factor * epsilon_factor
|
||||
}
|
||||
|
||||
pub fn most_common_bit(input: &[String], pos: usize) -> char {
|
||||
let mut count = 0;
|
||||
for val in input {
|
||||
if val.get(pos..=pos).unwrap() == "1" {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
if count * 2 >= input.len() {
|
||||
'1'
|
||||
} else {
|
||||
'0'
|
||||
}
|
||||
pub fn most_common_bit(input: &[Mbv], pos: usize) -> bool {
|
||||
let count = input.iter().filter(|vec| *vec.get(pos).unwrap()).count();
|
||||
count * 2 >= input.len()
|
||||
}
|
||||
|
||||
pub fn most_common_bit_string(input: &[String]) -> String {
|
||||
let mut ret_val = String::new();
|
||||
pub fn most_common_bit_vec(input: &[Mbv]) -> Mbv {
|
||||
let mut ret_val = Mbv::new();
|
||||
for i in 0..input[0].len() {
|
||||
ret_val.push(most_common_bit(input, i))
|
||||
}
|
||||
ret_val
|
||||
}
|
||||
|
||||
pub fn invert_binary_string(val: &str) -> String {
|
||||
let mut ret_val = String::new();
|
||||
for charactor in val.chars() {
|
||||
match charactor {
|
||||
'0' => ret_val.push('1'),
|
||||
'1' => ret_val.push('0'),
|
||||
_ => (),
|
||||
pub fn invert_bit_vec(val: &Mbv) -> Mbv {
|
||||
val.iter().map(|val| !*val).collect()
|
||||
}
|
||||
|
||||
pub fn bit_vec_to_usize(val: &Mbv) -> usize {
|
||||
let mut ret_val = 0;
|
||||
for bit in val {
|
||||
ret_val <<= 1;
|
||||
if *bit {
|
||||
ret_val += 1;
|
||||
}
|
||||
}
|
||||
ret_val
|
||||
}
|
||||
|
||||
pub fn get_oxygen_generator_rating(input: &[String]) -> usize {
|
||||
get_recursive_prefix_match(input, false)
|
||||
pub fn get_oxygen_generator_rating(input: &[Mbv]) -> usize {
|
||||
bit_vec_to_usize(&get_recursive_prefix_match(input, false))
|
||||
}
|
||||
|
||||
pub fn get_co2_scrubber_rating(input: &[String]) -> usize {
|
||||
get_recursive_prefix_match(input, true)
|
||||
pub fn get_co2_scrubber_rating(input: &[Mbv]) -> usize {
|
||||
bit_vec_to_usize(&get_recursive_prefix_match(input, true))
|
||||
}
|
||||
|
||||
pub fn get_recursive_prefix_match(input: &[String], invert: bool) -> usize {
|
||||
let mut input = Vec::from(input);
|
||||
pub fn get_recursive_prefix_match(input: &[Mbv], invert: bool) -> Mbv {
|
||||
let mut input: Vec<Mbv> = input.to_vec();
|
||||
for i in 0..input[0].len() {
|
||||
if input.len() > 1 {
|
||||
let mut target = String::from(most_common_bit(&input, i));
|
||||
let mut target = most_common_bit(&input, i);
|
||||
if invert {
|
||||
target = invert_binary_string(&target);
|
||||
target = !target;
|
||||
}
|
||||
input.retain(|val| val.get(i..=i) == Some(&target));
|
||||
input.retain(|val| val.get(i).unwrap() == target);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert_eq!(input.len(), 1);
|
||||
usize::from_str_radix(&input[0], 2).unwrap()
|
||||
input[0].clone()
|
||||
}
|
||||
|
||||
#[aoc(day3, part2)]
|
||||
pub fn calculate_life_support_rating(input: &[String]) -> usize {
|
||||
pub fn calculate_life_support_rating(input: &[Mbv]) -> usize {
|
||||
get_oxygen_generator_rating(input) * get_co2_scrubber_rating(input)
|
||||
}
|
||||
|
||||
|
|
65
src/day_06/mod.rs
Normal file
65
src/day_06/mod.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
use yap::IntoTokens;
|
||||
|
||||
mod model;
|
||||
mod parsing;
|
||||
|
||||
pub use model::{Fish, School, SmartSchool};
|
||||
pub use parsing::parse_school_of_fish;
|
||||
|
||||
#[aoc_generator(day6)]
|
||||
pub fn parse_input(input: &str) -> School {
|
||||
parse_school_of_fish(&mut input.into_tokens())
|
||||
}
|
||||
|
||||
#[aoc(day6, part1)]
|
||||
pub fn part1(input: &School) -> usize {
|
||||
let mut school = input.clone();
|
||||
for _ in 0..80 {
|
||||
school.tick()
|
||||
}
|
||||
school.size()
|
||||
}
|
||||
|
||||
#[aoc(day6, part1, smart_school)]
|
||||
pub fn part1_smart(input: &School) -> usize {
|
||||
let mut school = SmartSchool::from(input);
|
||||
for _ in 0..80 {
|
||||
school.tick()
|
||||
}
|
||||
school.size()
|
||||
}
|
||||
|
||||
#[aoc(day6, part2)]
|
||||
pub fn part2(input: &School) -> usize {
|
||||
let mut school = SmartSchool::from(input);
|
||||
for _ in 0..256 {
|
||||
school.tick()
|
||||
}
|
||||
school.size()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
const EXAMPLE_INPUT: &str = "3,4,3,1,2";
|
||||
const RESULT_PART_1: usize = 5934;
|
||||
const RESULT_PART_2: usize = 26_984_457_539;
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
let result = super::part1(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
let result = super::part2(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_example() {
|
||||
let example = super::parse_input(EXAMPLE_INPUT);
|
||||
assert!(example.size() == 5);
|
||||
}
|
||||
}
|
119
src/day_06/model.rs
Normal file
119
src/day_06/model.rs
Normal file
|
@ -0,0 +1,119 @@
|
|||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub struct Fish {
|
||||
pub timer: u8,
|
||||
}
|
||||
|
||||
impl Default for Fish {
|
||||
fn default() -> Fish {
|
||||
Fish::new(8)
|
||||
}
|
||||
}
|
||||
|
||||
impl Fish {
|
||||
fn tick(&mut self) -> Option<Fish> {
|
||||
match self.timer {
|
||||
0 => {
|
||||
self.timer = 6;
|
||||
Some(Fish::default())
|
||||
}
|
||||
_ => {
|
||||
self.timer -= 1;
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new(timer: u8) -> Fish {
|
||||
Fish { timer }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
pub struct School {
|
||||
pub fishes: Vec<Fish>,
|
||||
}
|
||||
|
||||
impl School {
|
||||
pub fn tick(&mut self) {
|
||||
let mut spawned = Vec::new();
|
||||
for fish in self.fishes.iter_mut() {
|
||||
if let Some(fish) = fish.tick() {
|
||||
spawned.push(fish);
|
||||
}
|
||||
}
|
||||
self.fishes.append(&mut spawned);
|
||||
}
|
||||
|
||||
pub fn add(&mut self, fish: Fish) {
|
||||
self.fishes.push(fish);
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.fishes.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
pub struct SmartSchool {
|
||||
pub fish_counter: [usize; 9],
|
||||
}
|
||||
|
||||
impl SmartSchool {
|
||||
pub fn tick(&mut self) {
|
||||
let new_fish = self.fish_counter[0];
|
||||
for i in 1..self.fish_counter.len() {
|
||||
self.fish_counter[i - 1] = self.fish_counter[i];
|
||||
}
|
||||
self.fish_counter[8] = new_fish;
|
||||
self.fish_counter[6] += new_fish;
|
||||
}
|
||||
|
||||
pub fn add(&mut self, fish: Fish) {
|
||||
self.fish_counter[fish.timer as usize] += 1;
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.fish_counter.iter().sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&School> for SmartSchool {
|
||||
fn from(school: &School) -> Self {
|
||||
let mut smart = SmartSchool::default();
|
||||
for fish in &school.fishes {
|
||||
smart.add(*fish);
|
||||
}
|
||||
smart
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{Fish, School};
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
assert_eq!(Fish::default().timer, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spawn() {
|
||||
let mut fish = Fish::default();
|
||||
for _ in 0..8 {
|
||||
assert_eq!(fish.tick(), None);
|
||||
}
|
||||
assert_eq!(fish.tick(), Some(Fish::default()));
|
||||
assert_eq!(fish.timer, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn school_growth() {
|
||||
let mut school = School::default();
|
||||
school.add(Fish::new(0));
|
||||
school.add(Fish::new(0));
|
||||
school.add(Fish::new(0));
|
||||
assert_eq!(school.size(), 3);
|
||||
school.tick();
|
||||
assert_eq!(school.size(), 6);
|
||||
}
|
||||
}
|
35
src/day_06/parsing.rs
Normal file
35
src/day_06/parsing.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use super::model::{Fish, School};
|
||||
use crate::parsing::parse_number;
|
||||
use yap::Tokens;
|
||||
|
||||
pub fn parse_fish(tokens: &mut impl Tokens<Item = char>) -> Option<Fish> {
|
||||
parse_number(tokens).map(|num| Fish { timer: num })
|
||||
}
|
||||
|
||||
pub fn parse_school_of_fish(tokens: &mut impl Tokens<Item = char>) -> School {
|
||||
School {
|
||||
fishes: tokens.sep_by(|t| parse_fish(t), |t| t.token(',')).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::model::Fish;
|
||||
use yap::IntoTokens;
|
||||
|
||||
#[test]
|
||||
fn parse_fish() {
|
||||
assert_eq!(
|
||||
Some(Fish { timer: 1 }),
|
||||
super::parse_fish(&mut "1".into_tokens())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_school() {
|
||||
assert_eq!(
|
||||
5,
|
||||
super::parse_school_of_fish(&mut "3,4,3,1,2".into_tokens()).size()
|
||||
);
|
||||
}
|
||||
}
|
70
src/day_07/mod.rs
Normal file
70
src/day_07/mod.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
mod model;
|
||||
mod parsing;
|
||||
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
pub use model::CrabSub;
|
||||
pub use parsing::parse_crab_sub_swarm;
|
||||
use yap::IntoTokens;
|
||||
|
||||
#[aoc_generator(day7)]
|
||||
pub fn parse_input(input: &str) -> Vec<CrabSub> {
|
||||
parse_crab_sub_swarm(&mut input.into_tokens())
|
||||
}
|
||||
|
||||
#[aoc(day7, part1)]
|
||||
pub fn part1(input: &[CrabSub]) -> usize {
|
||||
solve(input, &|x| x)
|
||||
}
|
||||
|
||||
fn bounds(input: &[CrabSub]) -> (usize, usize) {
|
||||
let locations: Vec<usize> = input.iter().map(|sub| sub.location).collect();
|
||||
(
|
||||
*locations.iter().min().unwrap(),
|
||||
*locations.iter().max().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn solve(input: &[CrabSub], fuel_calc: &dyn Fn(usize) -> usize) -> usize {
|
||||
let mut req_fuel = usize::MAX;
|
||||
let (min, max) = bounds(input);
|
||||
for i in min..=max {
|
||||
let mut new_req_fuel = 0;
|
||||
for sub in input.iter() {
|
||||
new_req_fuel += fuel_calc((i as isize - sub.location as isize).abs() as usize);
|
||||
}
|
||||
if req_fuel > new_req_fuel {
|
||||
req_fuel = new_req_fuel;
|
||||
}
|
||||
}
|
||||
req_fuel
|
||||
}
|
||||
|
||||
#[aoc(day7, part2)]
|
||||
pub fn part2(input: &[CrabSub]) -> usize {
|
||||
solve(input, &|distance| (1..=distance).sum())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
const EXAMPLE_INPUT: &str = "16,1,2,0,4,2,7,1,2,14";
|
||||
const RESULT_PART_1: usize = 37;
|
||||
const RESULT_PART_2: usize = 168;
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
let result = super::part1(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
let result = super::part2(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_example() {
|
||||
let example = super::parse_input(EXAMPLE_INPUT);
|
||||
assert_eq!(example.len(), 10);
|
||||
}
|
||||
}
|
4
src/day_07/model.rs
Normal file
4
src/day_07/model.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub struct CrabSub {
|
||||
pub location: usize,
|
||||
}
|
35
src/day_07/parsing.rs
Normal file
35
src/day_07/parsing.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use super::CrabSub;
|
||||
use crate::parsing::parse_number;
|
||||
use yap::Tokens;
|
||||
|
||||
pub fn parse_crab_sub(tokens: &mut impl Tokens<Item = char>) -> Option<CrabSub> {
|
||||
parse_number(tokens).map(|num| CrabSub { location: num })
|
||||
}
|
||||
|
||||
pub fn parse_crab_sub_swarm(tokens: &mut impl Tokens<Item = char>) -> Vec<CrabSub> {
|
||||
tokens
|
||||
.sep_by(|t| parse_crab_sub(t), |t| t.token(','))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::CrabSub;
|
||||
use yap::IntoTokens;
|
||||
|
||||
#[test]
|
||||
fn parse_crab_sub() {
|
||||
assert_eq!(
|
||||
Some(CrabSub { location: 1 }),
|
||||
super::parse_crab_sub(&mut "1".into_tokens())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_crab_sub_swarm() {
|
||||
assert_eq!(
|
||||
10,
|
||||
super::parse_crab_sub_swarm(&mut "16,1,2,0,4,2,7,1,2,14".into_tokens()).len()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,5 +7,7 @@ pub mod day_02;
|
|||
pub mod day_03;
|
||||
pub mod day_04;
|
||||
pub mod day_05;
|
||||
pub mod day_06;
|
||||
pub mod day_07;
|
||||
|
||||
aoc_lib! { year = 2021 }
|
||||
|
|
Loading…
Reference in a new issue