Rust
For the first time, I can post my solution, because I actually solved it on the day :D Probably not the cleanest or optimal solution, but it does solve the problem.
Very long, looking forward to someone solving it in 5 lines of unicode :D
#[cfg(test)]
mod tests {
fn get_frequences(input: &str) -> Vec<char> {
let mut freq = vec![];
for char in input.chars() {
if char == '.' {
continue;
}
if !freq.contains(&char) {
freq.push(char);
}
}
freq
}
fn find_antennas(board: &Vec<Vec<char>>, freq: char) -> Vec<(isize, isize)> {
let mut antennas = vec![];
for (i, line) in board.iter().enumerate() {
for (j, char) in line.iter().enumerate() {
if *char == freq {
antennas.push((i as isize, j as isize));
}
}
}
antennas
}
fn calc_antinodes(first: &(isize, isize), second: &(isize, isize)) -> Vec<(isize, isize)> {
let deltax = second.0 - first.0;
let deltay = second.1 - first.1;
if deltax == 0 && deltay == 0 {
return vec![];
}
vec![
(first.0 - deltax, first.1 - deltay),
(second.0 + deltax, second.1 + deltay),
]
}
#[test]
fn test_calc_antinodes() {
let expected = vec![(0, -1), (0, 2)];
let actual = calc_antinodes(&(0, 0), &(0, 1));
for i in &expected {
assert!(actual.contains(i));
}
let actual = calc_antinodes(&(0, 1), &(0, 0));
for i in &expected {
assert!(actual.contains(i));
}
}
fn calc_all_antinodes(board: &Vec<Vec<char>>, freq: char) -> Vec<(isize, isize)> {
let antennas = find_antennas(&board, freq);
let mut antinodes = vec![];
for (i, first) in antennas.iter().enumerate() {
for second in antennas[i..].iter() {
antinodes.extend(calc_antinodes(first, second));
}
}
antinodes
}
fn prune_nodes(
nodes: &Vec<(isize, isize)>,
height: isize,
width: isize,
) -> Vec<(isize, isize)> {
let mut pruned = vec![];
for node in nodes {
if pruned.contains(node) {
continue;
}
if node.0 < 0 || node.0 >= height {
continue;
}
if node.1 < 0 || node.1 >= width {
continue;
}
pruned.push(node.clone());
}
pruned
}
fn print_board(board: &Vec<Vec<char>>, pruned: &Vec<(isize, isize)>) {
for (i, line) in board.iter().enumerate() {
for (j, char) in line.iter().enumerate() {
if pruned.contains(&(i as isize, j as isize)) {
print!("#");
} else {
print!("{char}");
}
}
println!();
}
}
#[test]
fn day8_part1_test() {
let input: String = std::fs::read_to_string("src/input/day_8.txt").unwrap();
let frequencies = get_frequences(&input);
let board = input
.trim()
.split('\n')
.map(|line| line.chars().collect::<Vec<char>>())
.collect::<Vec<Vec<char>>>();
let mut all_nodes = vec![];
for freq in frequencies {
let nodes = calc_all_antinodes(&board, freq);
all_nodes.extend(nodes);
}
let height = board.len() as isize;
let width = board[0].len() as isize;
let pruned = prune_nodes(&all_nodes, height, width);
println!("{:?}", pruned);
print_board(&board, &pruned);
println!("{}", pruned.len());
// 14 in test
}
fn calc_antinodes2(first: &(isize, isize), second: &(isize, isize)) -> Vec<(isize, isize)> {
let deltax = second.0 - first.0;
let deltay = second.1 - first.1;
if deltax == 0 && deltay == 0 {
return vec![];
}
let mut nodes = vec![];
for n in 0..50 {
nodes.push((first.0 - deltax * n, first.1 - deltay * n));
nodes.push((second.0 + deltax * n, second.1 + deltay * n));
}
nodes
}
fn calc_all_antinodes2(board: &Vec<Vec<char>>, freq: char) -> Vec<(isize, isize)> {
let antennas = find_antennas(&board, freq);
let mut antinodes = vec![];
for (i, first) in antennas.iter().enumerate() {
for second in antennas[i..].iter() {
antinodes.extend(calc_antinodes2(first, second));
}
}
antinodes
}
#[test]
fn day8_part2_test() {
let input: String = std::fs::read_to_string("src/input/day_8.txt").unwrap();
let frequencies = get_frequences(&input);
let board = input
.trim()
.split('\n')
.map(|line| line.chars().collect::<Vec<char>>())
.collect::<Vec<Vec<char>>>();
let mut all_nodes = vec![];
for freq in frequencies {
let nodes = calc_all_antinodes2(&board, freq);
all_nodes.extend(nodes);
}
let height = board.len() as isize;
let width = board[0].len() as isize;
let pruned = prune_nodes(&all_nodes, height, width);
println!("{:?}", pruned);
print_board(&board, &pruned);
println!("{}", pruned.len());
}
}