day 3 and 4 solutions
This commit is contained in:
7 files changed
+1846
No files matched your search
+114
@@ -0,0 +1,114 @@
|
||||
use crate::utils::read_file;
|
||||
use anyhow::Result;
|
||||
|
||||
fn strings_to_ints(s: &str) -> Vec<usize> {
|
||||
s.lines()
|
||||
.map(|line| usize::from_str_radix(line, 2).unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn diagnose_power(s: &str) -> usize {
|
||||
// collect all positions with ones
|
||||
let bits = s.lines().next().unwrap().len();
|
||||
let n_words = s.lines().count();
|
||||
let mut counts = vec![0; bits];
|
||||
s.lines().for_each(|line| {
|
||||
line.chars().enumerate().for_each(|(i, c)| {
|
||||
if c == '1' {
|
||||
counts[i] += 1;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// determine whether zero or one is greatter than half for each position
|
||||
let ret: String = counts
|
||||
.iter()
|
||||
.map(|n| if n > &(n_words / 2) { '1' } else { '0' })
|
||||
.collect();
|
||||
|
||||
// put together gamma (all majority 1 slots) and epsilon (!gamma)
|
||||
let gamma = usize::from_str_radix(&ret, 2).unwrap();
|
||||
let epsilon = !gamma & ((1 << bits) - 1);
|
||||
gamma * epsilon
|
||||
}
|
||||
|
||||
fn find_oxygen_or_co2(s: &str, oxygen: bool) -> usize {
|
||||
let bits = s.lines().next().unwrap().len();
|
||||
let mut kept = strings_to_ints(s);
|
||||
usize::from_str_radix(
|
||||
&(0..bits)
|
||||
.rev()
|
||||
.map(|bit| {
|
||||
// split current set into ones/zeroes for current bit
|
||||
let mut ones = vec![];
|
||||
let mut zeroes = vec![];
|
||||
kept.iter().for_each(|x| {
|
||||
if x & (1 << bit) != 0 {
|
||||
ones.push(*x);
|
||||
} else {
|
||||
zeroes.push(*x);
|
||||
}
|
||||
});
|
||||
|
||||
if kept.len() == 1 {
|
||||
// only one left so we take its 0 or 1 regardless
|
||||
if kept[0] & (1 << bit) != 0 {
|
||||
'1'
|
||||
} else {
|
||||
'0'
|
||||
}
|
||||
} else if oxygen {
|
||||
// keep whichever has the most, ties are 1
|
||||
if ones.len() >= zeroes.len() {
|
||||
kept = ones;
|
||||
'1'
|
||||
} else {
|
||||
kept = zeroes;
|
||||
'0'
|
||||
}
|
||||
} else {
|
||||
// keep whichever has the least, ties are 0
|
||||
if zeroes.len() <= ones.len() {
|
||||
kept = zeroes;
|
||||
'0'
|
||||
} else {
|
||||
kept = ones;
|
||||
'1'
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<String>(),
|
||||
2,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
fn diagnose_lifesupport(s: &str) -> usize {
|
||||
let oxygen_generator = find_oxygen_or_co2(s, true);
|
||||
let co2_scrubber = find_oxygen_or_co2(s, false);
|
||||
oxygen_generator * co2_scrubber
|
||||
}
|
||||
|
||||
pub(crate) fn run() -> Result<(usize, usize)> {
|
||||
let input = read_file("data/day03.txt")?;
|
||||
Ok((diagnose_power(&input), diagnose_lifesupport(&input)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_example() {
|
||||
let input = read_file("data/day03-test.txt").unwrap();
|
||||
assert_eq!(diagnose_power(&input), 198);
|
||||
assert_eq!(diagnose_lifesupport(&input), 230);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_my_data() {
|
||||
let input = read_file("data/day03.txt").unwrap();
|
||||
assert_eq!(diagnose_power(&input), 4191876);
|
||||
// assert_eq!(follow_course(&input), 2070300);
|
||||
// assert_eq!(follow_course_better(&input), 2078985210);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
use crate::utils::read_file;
|
||||
use anyhow::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Bingo {
|
||||
draws: Vec<usize>,
|
||||
boards: Vec<Vec<usize>>,
|
||||
}
|
||||
|
||||
fn parse_bingo(s: &str) -> Bingo {
|
||||
Bingo {
|
||||
// take the first line and split on comma
|
||||
draws: s
|
||||
.lines()
|
||||
.next()
|
||||
.unwrap()
|
||||
.split(',')
|
||||
.map(|s| s.parse::<usize>().unwrap())
|
||||
.collect(),
|
||||
// split on whitespace, collect all the remaining numbers and then chunk them out in 25s
|
||||
boards: s
|
||||
.lines()
|
||||
.skip(2)
|
||||
.map(|line| line.split_whitespace().map(|s| s.parse::<usize>().unwrap()))
|
||||
.flatten()
|
||||
.collect::<Vec<usize>>()
|
||||
.chunks(25)
|
||||
.map(|c| c.into())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn test_for_win(marked: usize) -> bool {
|
||||
let col_mask: usize = 0b1000010000100001000010000;
|
||||
let row_mask: usize = 0b1111100000000000000000000;
|
||||
(0..5).any(|i| {
|
||||
marked & (col_mask >> i) == (col_mask >> i)
|
||||
|| marked & (row_mask >> (i * 5)) == (row_mask >> (i * 5))
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_score(board: &[usize], marked: usize, last_draw: usize) -> usize {
|
||||
(0..25)
|
||||
.map(|i| if marked & 1 << i == 0 { board[i] } else { 0 })
|
||||
.sum::<usize>()
|
||||
* last_draw
|
||||
}
|
||||
|
||||
fn find_winning_score(s: &str, first: bool) -> usize {
|
||||
let bingo = parse_bingo(s);
|
||||
let mut markers = vec![0; bingo.boards.len()];
|
||||
let mut boards_won = vec![false; bingo.boards.len()];
|
||||
// for every drawn number, mark each board and check whether it wins
|
||||
for draw in bingo.draws {
|
||||
for i in 0..bingo.boards.len() {
|
||||
for j in 0..bingo.boards[i].len() {
|
||||
if bingo.boards[i][j] == draw {
|
||||
markers[i] |= 1 << j;
|
||||
}
|
||||
if test_for_win(markers[i]) {
|
||||
boards_won[i] = true;
|
||||
if first || (!first && boards_won.iter().all(|w| *w)) {
|
||||
return compute_score(&bingo.boards[i], markers[i], draw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn run() -> Result<(usize, usize)> {
|
||||
let input = read_file("data/day04.txt")?;
|
||||
Ok((
|
||||
find_winning_score(&input, true),
|
||||
find_winning_score(&input, false),
|
||||
))
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_example() {
|
||||
let input = read_file("data/day04-test.txt").unwrap();
|
||||
assert_eq!(find_winning_score(&input, true), 4512);
|
||||
assert_eq!(find_winning_score(&input, false), 1924);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_my_data() {
|
||||
let input = read_file("data/day04.txt").unwrap();
|
||||
assert_eq!(find_winning_score(&input, true), 71708);
|
||||
assert_eq!(find_winning_score(&input, false), 34726);
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,14 @@ use anyhow::Result;
|
||||
|
||||
mod day01;
|
||||
mod day02;
|
||||
mod day03;
|
||||
mod day04;
|
||||
mod utils;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
println!("day01: {:?}", day01::run()?);
|
||||
println!("day02: {:?}", day02::run()?);
|
||||
println!("day03: {:?}", day03::run()?);
|
||||
println!("day04: {:?}", day04::run()?);
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user