day8, part1
This commit is contained in:
parent
342dd2982a
commit
eb89350ddf
4 changed files with 223 additions and 1 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -45,6 +45,13 @@ dependencies = [
|
|||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day08"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
|
|
|
@ -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
7
day08/Cargo.toml
Normal 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
208
day08/src/main.rs
Normal 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));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue