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