Skip to content

Instantly share code, notes, and snippets.

@jmikkola
Created December 8, 2024 15:46
Show Gist options
  • Save jmikkola/425a085a5e16640454947b2c34b46638 to your computer and use it in GitHub Desktop.
Save jmikkola/425a085a5e16640454947b2c34b46638 to your computer and use it in GitHub Desktop.
use std::env;
use std::fs;
use std::collections::HashSet;
use std::collections::HashMap;
fn main() {
let map = split_lines(get_content(get_arg()));
println!("Part 1: {}", part1(&map));
use std::time::Instant;
{
let start = Instant::now();
println!("Part 2: {}", part2(&map));
let time = start.elapsed();
println!("Part 2 time: {:.2?}", time);
}
}
fn part1(map: &[Vec<char>]) -> usize {
let mut points = HashSet::new();
let antennas = parse_antennas(map);
for (_frequency, locations) in antennas.iter() {
let n_locations = locations.len();
for i in 0..(n_locations-1) {
let antenna_i = locations[i];
for j in (i+1)..n_locations {
let antenna_j = locations[j];
if let Some(antinode) = get_antinode(map, antenna_i, antenna_j) {
points.insert(antinode);
}
if let Some(antinode) = get_antinode(map, antenna_j, antenna_i) {
points.insert(antinode);
}
}
}
}
points.len()
}
fn part2(map: &[Vec<char>]) -> usize {
let mut points = HashSet::new();
let antennas = parse_antennas(map);
for (_frequency, locations) in antennas.iter() {
let n_locations = locations.len();
for i in 0..(n_locations-1) {
let antenna_i = locations[i];
for j in (i+1)..n_locations {
let antenna_j = locations[j];
for antinode in list_antinodes(map, antenna_i, antenna_j).iter() {
points.insert(*antinode);
}
for antinode in list_antinodes(map, antenna_j, antenna_i).iter() {
points.insert(*antinode);
}
}
}
}
points.len()
}
fn list_antinodes(map: &[Vec<char>], start: (usize, usize), end: (usize, usize)) -> Vec<(usize, usize)> {
let start_i = to_i64(start);
let end_i = to_i64(end);
let delta = (end_i.0 - start_i.0, end_i.1 - start_i.1);
let mut antinodes = Vec::new();
let mut antinode = end_i;
loop {
if antinode.0 < 0 || antinode.1 < 0 {
break;
}
let antinode_u = to_usize(antinode);
if antinode_u.0 >= map.len() || antinode_u.1 >= map[0].len() {
break;
}
antinodes.push(antinode_u);
antinode = (antinode.0 + delta.0, antinode.1 + delta.1);
}
antinodes
}
fn get_antinode(map: &[Vec<char>], start: (usize, usize), end: (usize, usize)) -> Option<(usize, usize)> {
let start_i = to_i64(start);
let end_i = to_i64(end);
let delta = (end_i.0 - start_i.0, end_i.1 - start_i.1);
let antinode = (end_i.0 + delta.0, end_i.1 + delta.1);
if antinode.0 < 0 || antinode.1 < 0 {
return None;
}
let antinode_u = to_usize(antinode);
if antinode_u.0 >= map.len() || antinode_u.1 >= map[0].len() {
return None;
}
Some(antinode_u)
}
fn to_i64(point: (usize, usize)) -> (i64, i64) {
(point.0 as i64, point.1 as i64)
}
fn to_usize(point: (i64, i64)) -> (usize, usize) {
(point.0 as usize, point.1 as usize)
}
fn parse_antennas(map: &[Vec<char>]) -> HashMap<char, Vec<(usize, usize)>> {
let mut antennas = HashMap::new();
for (i, row) in map.iter().enumerate() {
for (j, location) in row.iter().enumerate() {
if *location != '.' {
if !antennas.contains_key(location) {
antennas.insert(*location, Vec::new());
}
antennas.get_mut(location).unwrap().push((i, j));
}
}
}
antennas
}
fn get_arg() -> String {
match env::args().nth(1) {
Some(f) => f,
None => "example".into(),
}
}
fn get_content(filename: String) -> String {
fs::read_to_string(filename).unwrap().trim().to_string()
}
fn split_lines(s: String) -> Vec<Vec<char>> {
s.split('\n')
.map(|line| line.chars().collect())
.collect()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment