parent
cc49d8009d
commit
c5de45d22a
@ -0,0 +1,12 @@
|
||||
# Day 6
|
||||
|
||||
## Instructions
|
||||
|
||||
From the root directory of the crate (where this README is) just execute:
|
||||
|
||||
```
|
||||
cargo run
|
||||
```
|
||||
|
||||
The solution will be printed to the terminal output.
|
||||
|
@ -0,0 +1,16 @@
|
||||
# Day 7
|
||||
|
||||
## Instructions
|
||||
|
||||
From the root directory of the crate (where this README is) just execute:
|
||||
|
||||
```
|
||||
cargo run
|
||||
```
|
||||
|
||||
The solution will be printed to the terminal output.
|
||||
|
||||
## Notes
|
||||
|
||||
Was unable to get to part 2. Hopefully will be able to revisit this.
|
||||
|
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "day8"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
itertools = "*"
|
@ -0,0 +1,12 @@
|
||||
# Day 8
|
||||
|
||||
## Instructions
|
||||
|
||||
From the root directory of the crate (where this README is) just execute:
|
||||
|
||||
```
|
||||
cargo run
|
||||
```
|
||||
|
||||
The solution will be printed to the terminal output.
|
||||
|
@ -0,0 +1,220 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
fs::File,
|
||||
io::{BufRead, BufReader},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
/// Basic error type
|
||||
#[derive(Debug)]
|
||||
enum ParsingError {
|
||||
ParserFailure,
|
||||
IndexOutOfBounds,
|
||||
InconsistentGrid,
|
||||
}
|
||||
|
||||
impl Display for ParsingError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ParsingError::ParserFailure => write!(f, "Failed to parse segment"),
|
||||
ParsingError::IndexOutOfBounds => write!(f, "Index out of bounds for CharGrid"),
|
||||
ParsingError::InconsistentGrid => write!(f, "File is not a consistent char grid"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type MyResult<T> = Result<T, Box<dyn Error>>;
|
||||
|
||||
impl Error for ParsingError {}
|
||||
|
||||
/// Struct that flattens out the input grid
|
||||
#[derive(Clone)]
|
||||
pub struct CharGrid {
|
||||
pub chars: Vec<char>,
|
||||
pub m: usize,
|
||||
pub n: usize,
|
||||
pub same_freq_positions: Vec<Vec<usize>>,
|
||||
}
|
||||
|
||||
impl CharGrid {
|
||||
/// Take a file and split it into a CharGrid. Since input has only ASCII characters this should
|
||||
/// be fine
|
||||
pub fn new(input_file: &str) -> MyResult<CharGrid> {
|
||||
let file = File::open(input_file)?;
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
let mut m = 0;
|
||||
let mut n: Option<usize> = None;
|
||||
let chars: Vec<char> = reader
|
||||
.lines()
|
||||
.map(|line| -> MyResult<Vec<char>> {
|
||||
let parsed_line = Vec::from_iter(line?.chars());
|
||||
m += 1;
|
||||
if n.is_none() {
|
||||
n = Some(parsed_line.len());
|
||||
} else if n.unwrap() != parsed_line.len() {
|
||||
return Err(Box::new(ParsingError::InconsistentGrid));
|
||||
}
|
||||
Ok(parsed_line)
|
||||
})
|
||||
.collect::<MyResult<Vec<Vec<char>>>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let n = n.unwrap();
|
||||
// Now loop and get all the unique indices
|
||||
let mut char_indices: HashMap<char, usize> = HashMap::new();
|
||||
let mut curr_idx = 0;
|
||||
let mut same_freq_positions: Vec<Vec<usize>> = Vec::new();
|
||||
|
||||
for (i, c) in chars.iter().enumerate() {
|
||||
if *c != '.' {
|
||||
let idx = match char_indices.get(c) {
|
||||
Some(idx) => idx,
|
||||
None => {
|
||||
char_indices.insert(*c, curr_idx);
|
||||
curr_idx += 1;
|
||||
same_freq_positions.push(vec![]);
|
||||
&(curr_idx - 1)
|
||||
}
|
||||
};
|
||||
|
||||
same_freq_positions[*idx].push(i);
|
||||
}
|
||||
}
|
||||
Ok(CharGrid {
|
||||
chars,
|
||||
m,
|
||||
n,
|
||||
same_freq_positions,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get an index within the grid
|
||||
pub fn get(&self, i: i32, j: i32) -> MyResult<char> {
|
||||
let idx = self.two2one_index(i, j)?;
|
||||
Ok(self.chars[idx])
|
||||
}
|
||||
|
||||
// Convert the one dimensional index to two dimensional index
|
||||
pub fn one2two_index(&self, idx: usize) -> (usize, usize) {
|
||||
let i = idx / self.n;
|
||||
let j = idx % self.n;
|
||||
(i, j)
|
||||
}
|
||||
|
||||
// Convert the two dimensional index to one dimensional index
|
||||
pub fn two2one_index(&self, i: i32, j: i32) -> MyResult<usize> {
|
||||
if i < 0 || j < 0 {
|
||||
Err(Box::new(ParsingError::IndexOutOfBounds))
|
||||
} else if i as usize >= self.m || j as usize >= self.n {
|
||||
Err(Box::new(ParsingError::IndexOutOfBounds))
|
||||
} else {
|
||||
Ok((i as usize) * self.n + (j as usize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the antinodes for a single frequency assuming only resonant frequencies
|
||||
pub fn get_antinodes_single_freq_part1(grid: &CharGrid, positions: &[usize]) -> HashSet<usize> {
|
||||
let grid_iter = positions.iter();
|
||||
let mut unique_position = HashSet::new();
|
||||
for (node1, node2) in grid_iter.clone().cartesian_product(grid_iter) {
|
||||
if node1 != node2 {
|
||||
let (x1, y1) = grid.one2two_index(*node1);
|
||||
let (x2, y2) = grid.one2two_index(*node2);
|
||||
|
||||
let x_antinode = (2 * x1).checked_sub(x2);
|
||||
let y_antinode = (2 * y1).checked_sub(y2);
|
||||
|
||||
if let (Some(x_antinode), Some(y_antinode)) = (x_antinode, y_antinode) {
|
||||
if let Ok(idx) = grid.two2one_index(x_antinode as i32, y_antinode as i32) {
|
||||
unique_position.insert(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unique_position
|
||||
}
|
||||
|
||||
/// Get the antinodes for a single frequency assuming resonant harmonics
|
||||
/// NOTE: We shouldn't need two separate functions since part1 is a subset of part2 but running out
|
||||
/// of time again so leaving it as a separate function for now
|
||||
pub fn get_antinodes_single_freq_part2(grid: &CharGrid, positions: &[usize]) -> HashSet<usize> {
|
||||
let grid_iter = positions.iter();
|
||||
let mut unique_position = HashSet::new();
|
||||
for (node1, node2) in grid_iter.clone().cartesian_product(grid_iter) {
|
||||
if node1 != node2 {
|
||||
let mut step = 1;
|
||||
loop {
|
||||
let (x1, y1) = grid.one2two_index(*node1);
|
||||
let (x2, y2) = grid.one2two_index(*node2);
|
||||
|
||||
let xstep = x1 as i32 - x2 as i32;
|
||||
let ystep = y1 as i32 - y2 as i32;
|
||||
|
||||
let x_antinode: MyResult<usize> = (x1 as i32 - (step * xstep))
|
||||
.try_into()
|
||||
.map_err(|err| -> Box<dyn Error> { Box::new(err) });
|
||||
|
||||
let y_antinode: MyResult<usize> = (y1 as i32 - (step * ystep))
|
||||
.try_into()
|
||||
.map_err(|err| -> Box<dyn Error> { Box::new(err) });
|
||||
|
||||
if let (Ok(x_antinode), Ok(y_antinode)) = (x_antinode, y_antinode) {
|
||||
if let Ok(idx) = grid.two2one_index(x_antinode as i32, y_antinode as i32) {
|
||||
unique_position.insert(idx);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
step += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unique_position
|
||||
}
|
||||
pub enum Mode {
|
||||
Part1,
|
||||
Part2,
|
||||
}
|
||||
/// Get antinodes for all frequencies
|
||||
pub fn get_antinode_count(grid: &CharGrid, mode: &Mode) -> usize {
|
||||
let mut unique_positions: HashSet<usize> = HashSet::new();
|
||||
for positions in grid.same_freq_positions.iter() {
|
||||
match mode {
|
||||
Mode::Part1 => {
|
||||
unique_positions.extend(get_antinodes_single_freq_part1(grid, positions))
|
||||
}
|
||||
Mode::Part2 => {
|
||||
unique_positions.extend(get_antinodes_single_freq_part2(grid, positions))
|
||||
}
|
||||
}
|
||||
}
|
||||
unique_positions.len()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_antinode_calc() {
|
||||
let grid = CharGrid::new("test_inputs/test_input.txt").unwrap();
|
||||
assert_eq!(get_antinode_count(&grid, &Mode::Part1), 14);
|
||||
assert_eq!(get_antinode_count(&grid, &Mode::Part2), 34);
|
||||
}
|
||||
#[test]
|
||||
fn simple_part2_test() {
|
||||
let grid = CharGrid::new("./test_inputs/simple_part2.txt").unwrap();
|
||||
assert_eq!(get_antinode_count(&grid, &Mode::Part2), 9);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
use day8::{get_antinode_count, CharGrid, Mode};
|
||||
|
||||
fn main() {
|
||||
let grid = match CharGrid::new("test_inputs/input.txt") {
|
||||
Ok(grid) => grid,
|
||||
Err(err) => {
|
||||
println!("Failed because of \n{err}");
|
||||
panic!("Program failed to execute")
|
||||
}
|
||||
};
|
||||
|
||||
println!(
|
||||
"Solution to part 1 is {}",
|
||||
get_antinode_count(&grid, &Mode::Part1)
|
||||
);
|
||||
println!(
|
||||
"Solution to part 2 is {}",
|
||||
get_antinode_count(&grid, &Mode::Part2)
|
||||
);
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
.C...............w.......................M.E......
|
||||
...............G........V.............Q....M......
|
||||
u........k...........V.y..3........Q..........4.a.
|
||||
..........c.9........k..................i..7..a...
|
||||
..............y.......................o....a......
|
||||
.......C...........6.......y.............E........
|
||||
.............................5....x............i..
|
||||
...............c.....wy..V.......5..............E.
|
||||
........k.......c....G..I............o.........m..
|
||||
............C....s......G......o..........5.......
|
||||
......................Q...............5....e...4i.
|
||||
.....I.....................................m.....j
|
||||
....9K.T.....I...c......w...................X.....
|
||||
................I.........w....f............3..e.N
|
||||
C............9..........6..............7...3......
|
||||
...Z........K.......T.................6...........
|
||||
......Z..................6...............HN.E.m...
|
||||
...K...........................1....N...e.o..X....
|
||||
............hz......................7........j....
|
||||
.........9......U.R......n.....4.Q..L...X.........
|
||||
..................A...........S.......0...........
|
||||
...............l.........p...........2.3M.......x.
|
||||
.h........................U.................g.....
|
||||
...Hld...........A..W.......................1x....
|
||||
.....Z.....n.......lp...e............Xj...L.......
|
||||
........hU................7...j...S...............
|
||||
......n............U..........D....S..q...........
|
||||
....H.....d.r..T..............0..........L.S......
|
||||
......H......A..T...lp.........LK....1.....2.f.x..
|
||||
....Z............................g....4...........
|
||||
..d..r............V...............f..g....2.......
|
||||
.rn.........D............Pp........q....g.........
|
||||
..................................................
|
||||
...................D...0.........Y..t...P.q.......
|
||||
.......R.s.......................q.P..1...........
|
||||
...........h..........................2.........f.
|
||||
........................W.........................
|
||||
...8...........O................k.................
|
||||
....rY...........D................P...............
|
||||
....................O...u.........................
|
||||
..s..................F............................
|
||||
...................R......F.......................
|
||||
......8...........z0....F................J.W......
|
||||
...................F..z................u..........
|
||||
..............R.........O.............v.Jt........
|
||||
s.............8.........m........J.t............v.
|
||||
......Y.....M........................u..tv........
|
||||
.................................................v
|
||||
..................................................
|
||||
.................z.W..................J...........
|
@ -0,0 +1,10 @@
|
||||
T.........
|
||||
...T......
|
||||
.T........
|
||||
..........
|
||||
..........
|
||||
..........
|
||||
..........
|
||||
..........
|
||||
..........
|
||||
..........
|
@ -0,0 +1,12 @@
|
||||
............
|
||||
........0...
|
||||
.....0......
|
||||
.......0....
|
||||
....0.......
|
||||
......A.....
|
||||
............
|
||||
............
|
||||
........A...
|
||||
.........A..
|
||||
............
|
||||
............
|
Loading…
Reference in new issue