Quest 14: The Game of Light
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
Link to participate: https://everybody.codes/


Rust
Finally caught up with the puzzles.
use std::collections::{HashMap, HashSet}; use itertools::Itertools; pub fn solve_part_1(input: &str) -> String { let mut barrels: HashSet<(isize, isize)> = input .lines() .enumerate() .flat_map(|(i, line)| { line.chars() .enumerate() .filter(|&(_, ch)| ch == '#') .map(move |(j, _)| (i as isize, j as isize)) }) .collect(); let max_i = barrels.iter().map(|(i, _)| *i).max().unwrap(); let max_j = barrels.iter().map(|(_, j)| *j).max().unwrap(); let mut total_active = 0; for _ in 0..10 { let mut next_barrels = HashSet::new(); for i in 0..=max_i { for j in 0..=max_j { let active_neighbours = [(-1, -1), (1, 1), (-1, 1), (1, -1)] .iter() .filter(|(di, dj)| barrels.contains(&(i + di, j + dj))) .count(); let will_be_active = if barrels.contains(&(i, j)) { active_neighbours % 2 == 1 } else { active_neighbours % 2 == 0 }; if will_be_active { next_barrels.insert((i, j)); } } } barrels = next_barrels; total_active += barrels.len(); } total_active.to_string() } pub fn solve_part_2(input: &str) -> String { let mut barrels: HashSet<(isize, isize)> = input .lines() .enumerate() .flat_map(|(i, line)| { line.chars() .enumerate() .filter(|&(_, ch)| ch == '#') .map(move |(j, _)| (i as isize, j as isize)) }) .collect(); let max_i = barrels.iter().map(|(i, _)| *i).max().unwrap(); let max_j = barrels.iter().map(|(_, j)| *j).max().unwrap(); let mut total_active = 0; for _ in 0..2025 { let mut next_barrels = HashSet::new(); for i in 0..=max_i { for j in 0..=max_j { let active_neighbours = [(-1, -1), (1, 1), (-1, 1), (1, -1)] .iter() .filter(|(di, dj)| barrels.contains(&(i + di, j + dj))) .count(); let will_be_active = if barrels.contains(&(i, j)) { active_neighbours % 2 == 1 } else { active_neighbours % 2 == 0 }; if will_be_active { next_barrels.insert((i, j)); } } } barrels = next_barrels; total_active += barrels.len(); } total_active.to_string() } pub fn solve_part_3(input: &str) -> String { let pattern: HashSet<(isize, isize)> = input .lines() .enumerate() .flat_map(|(i, line)| { line.chars() .enumerate() .filter(|&(_, ch)| ch == '#') .map(move |(j, _)| (i as isize, j as isize)) }) .collect(); let pattern_max_i = pattern.iter().map(|(i, _)| *i).max().unwrap(); let pattern_max_j = pattern.iter().map(|(_, j)| *j).max().unwrap(); assert_eq!(7, pattern_max_i); assert_eq!(7, pattern_max_j); let mut barrels: HashSet<(isize, isize)> = HashSet::new(); let max_i = 33; let max_j = 33; let mut state_map = HashMap::<Vec<(isize, isize)>, usize>::new(); state_map.insert(vec![], 0); let mut current_round = 0; let rounds_to_simulate = 1000000000; let mut active_tiles_after_rounds = vec![0]; while current_round < rounds_to_simulate { let mut next_barrels = HashSet::new(); for i in 0..=max_i { for j in 0..=max_j { let active_neighbours = [(-1, -1), (1, 1), (-1, 1), (1, -1)] .iter() .filter(|(di, dj)| barrels.contains(&(i + di, j + dj))) .count(); let will_be_active = if barrels.contains(&(i, j)) { active_neighbours % 2 == 1 } else { active_neighbours % 2 == 0 }; if will_be_active { next_barrels.insert((i, j)); } } } barrels = next_barrels; current_round += 1; let state_key: Vec<_> = barrels.iter().copied().collect(); if let Some(&seen_before_after_round) = state_map.get(&state_key) { let loop_length = current_round - seen_before_after_round; let loops_remaining = (rounds_to_simulate - current_round) / loop_length; let iterations_remaining = rounds_to_simulate - current_round - (loops_remaining * loop_length); return (active_tiles_after_rounds[0..current_round] .iter() .sum::<usize>() + active_tiles_after_rounds[seen_before_after_round..current_round] .iter() .sum::<usize>() * loops_remaining + active_tiles_after_rounds [seen_before_after_round..(seen_before_after_round + iterations_remaining)] .iter() .sum::<usize>()) .to_string(); } state_map.insert(state_key, current_round); let does_pattern_match = (13..=20) .cartesian_product(13..=20) .all(|(i, j)| barrels.contains(&(i, j)) == pattern.contains(&(i - 13, j - 13))); active_tiles_after_rounds.push(if does_pattern_match { barrels.len() } else { 0 }); } active_tiles_after_rounds.iter().sum::<usize>().to_string() }