day8, part1

This commit is contained in:
Joe Ardent 2024-12-28 16:26:02 -08:00
parent 342dd2982a
commit eb89350ddf
4 changed files with 223 additions and 1 deletions

7
Cargo.lock generated
View file

@ -45,6 +45,13 @@ dependencies = [
"winnow",
]
[[package]]
name = "day08"
version = "0.1.0"
dependencies = [
"winnow",
]
[[package]]
name = "memchr"
version = "2.7.4"

View file

@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["day01", "day02", "day03", "day04", "day05", "day06", "day07"]
members = ["day01", "day02", "day03", "day04", "day05", "day06", "day07", "day08"]
[workspace.dependencies]
winnow = "0.6"

7
day08/Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "day08"
version = "0.1.0"
edition = "2024"
[dependencies]
winnow.workspace = true

208
day08/src/main.rs Normal file
View file

@ -0,0 +1,208 @@
use std::{
collections::{HashMap, HashSet},
fmt::{Display, Write},
};
use winnow::{
PResult, Parser,
ascii::newline,
combinator::{opt, repeat, separated, seq},
token::one_of,
};
fn main() {
let input = std::fs::read_to_string("input").unwrap();
println!("{}", pt1(&input));
println!("{}", pt2(&input));
}
fn pt1(input: &str) -> usize {
let mut board = Board::new(input);
let mut antinodes = HashSet::new();
for f in board.freqs() {
for a1 in board.antennae[&f].iter() {
for a2 in board.antennae[&f].iter() {
if a1 == a2 {
continue;
}
for antinode in board.antinodes(*a1, *a2) {
antinodes.insert(antinode);
}
}
}
}
for &antinode in antinodes.iter() {
board.set(antinode, Cell::Antinode);
}
println!("{board}");
antinodes.len()
}
fn pt2(input: &str) -> usize {
let mut total = 0;
total
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
struct Loc(usize, usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Cell {
Empty,
Antenna(char),
Antinode,
}
impl Display for Cell {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Cell::*;
let c = match self {
Empty => '.',
Antinode => '#',
Antenna(c) => *c,
};
f.write_char(c)
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
struct Board {
cells: Vec<Vec<Cell>>,
antennae: HashMap<char, HashSet<Loc>>,
right: usize,
bottom: usize,
}
impl Display for Board {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(
&self
.cells
.iter()
.map(|row| {
row.iter().fold(String::new(), |mut out, c| {
let _ = write!(out, "{c}");
out
})
})
.collect::<Vec<_>>()
.join("\n"),
)
}
}
impl Board {
fn new(input: &str) -> Self {
let cells = parse(input);
let right = cells[0].len();
let bottom = cells.len();
let mut antennae: HashMap<char, HashSet<Loc>> = HashMap::new();
for (r, row) in cells.iter().enumerate() {
for (c, cell) in row.iter().enumerate() {
if let Cell::Antenna(a) = cell {
antennae.entry(*a).or_default().insert(Loc(r, c));
}
}
}
Board {
cells,
right,
bottom,
antennae,
}
}
fn set(&mut self, loc: Loc, cell: Cell) -> bool {
if let Some(row) = self.cells.get_mut(loc.0) {
if let Some(c) = row.get_mut(loc.1) {
*c = cell;
return true;
}
}
false
}
fn antinodes(&self, a1: Loc, a2: Loc) -> Vec<Loc> {
let dy = (a1.0 as i64 - a2.0 as i64).unsigned_abs() as usize;
let dx = (a1.1 as i64 - a2.1 as i64).unsigned_abs() as usize;
let mut n1: Loc;
let mut n2: Loc;
// row 0 is at the top
let (top, bottom) = if a1.0 <= a2.0 { (a1, a2) } else { (a2, a1) };
let (left, right) = if a1.1 <= a2.1 { (a1, a2) } else { (a2, a1) };
let mut antinodes = Vec::new();
let ny_top = top.0.wrapping_sub(dy);
let ny_bot = bottom.0 + dy;
let nx_left = left.1.wrapping_sub(dx);
let nx_right = right.1 + dx;
let (n1, n2) = match (a1, a2) {
_ if a1 == top && a1 == left => (Loc(ny_top, nx_left), Loc(ny_bot, nx_right)),
_ if a1 == top && a1 == right => (Loc(ny_top, nx_right), Loc(ny_bot, nx_left)),
_ if a1 == bottom && a1 == left => (Loc(ny_bot, nx_left), Loc(ny_top, nx_right)),
_ => (Loc(ny_bot, nx_right), Loc(ny_top, nx_left)),
};
if n1.0 < self.bottom && n1.1 < self.right {
antinodes.push(n1);
}
if n2.0 < self.bottom && n2.1 < self.right {
antinodes.push(n2);
}
antinodes
}
fn freqs(&self) -> HashSet<char> {
self.antennae.keys().copied().collect()
}
}
fn parse_cell(input: &mut &str) -> PResult<Cell> {
let cell = one_of(('.', 'a'..='z', 'A'..='Z', '0'..='9')).parse_next(input)?;
match cell {
'.' => Ok(Cell::Empty),
c => Ok(Cell::Antenna(c)),
}
}
fn parse_line(input: &mut &str) -> PResult<Vec<Cell>> {
repeat(1.., parse_cell).parse_next(input)
}
fn parse(input: &str) -> Vec<Vec<Cell>> {
let (cells, _): (Vec<Vec<Cell>>, _) = seq!(separated(1.., parse_line, newline), opt(newline))
.parse(input)
.unwrap();
cells
}
#[cfg(test)]
mod test {
use super::*;
static INPUT: &str = "............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............";
#[test]
fn p1() {
assert_eq!(14, pt1(INPUT));
}
#[test]
fn p2() {
assert_eq!(6, pt2(INPUT));
}
}