🌟 Advent of Code (AoC) 2022 🌟

PermalÀnk
Medlem ★
●

Orkade inte ens pÄbörja gÄrdagens. 14 fick bli min sista, kÀnner att man inte orkar sitta 3+ timmar efter jobbet

Lycka till alla andra!

PermalÀnk
Medlem ★
●

Varit borta ett par dagar och började precis kika pÄ dag 16. Jag kÀnner nog ocksÄ att det börjar bli lite för rörigt och tidskrÀvande för att jag ska orka med mer.

Även om jag tror jag kommit pĂ„ en lösning pĂ„ del 1 sĂ„ vĂ„gar jag inte ge mig pĂ„ den, jag vet hur mycket smĂ„fel man brukar behöva leta efter. :')

Visa signatur

CPU: 7950X 5GHz@1.1v | RAM: 32GB 6000MHz CL36 | GPU: KFAÂČ 3090 SG w/ AlphaCool Eisblock Aurora
Ljudkort: Modius + Magnius | Lurar: GoldPlanar GL2000 / Sennheiser HD 650 / Philips Fidelio X3 / Supreme CD-99

PermalÀnk
Medlem ★
●

De fyra sista dagarna har varit lite jobbiga. Har lösningar pÄ alla men med caviates för del 2. Efter fyra dagar som kÀnns sÄdÀr börjar entusiasmen sina samtidigt som tillgÀnglig tid Àr pÄ nergÄng fram till jul sÄ vi fÄr se hur mÄnga till jag löser. Morgondagen fÄr morgonen pÄ sig men hinner jag inte dÄ har jag svÄrt att se att jag plockar upp den igen.

SprÄk: Rust

Dag: 14

HÀr funkar inte min utrÀkning i del 2, men visualiseringen gör det sÄ efter att ha rÀknat ut ett resultat
visualiserar jag i en strÀng och rÀknar mÀngden sand dÀr istÀllet för att rapportera det berÀknade resulatet:

use std::{collections::BTreeMap, fmt::Display}; #[derive(Debug, PartialEq)] enum Material { Rock, Sand, SandSource, } #[derive(Debug, Default)] struct Board { material: BTreeMap<(i32, i32), Material>, floor: bool, sand_source: (i32, i32), top: i32, bottom: i32, left: i32, right: i32, } impl Board { fn add_sand(&mut self) -> bool { let mut cord = self.sand_source; if let Some(&Material::SandSource) = self.material.get(&cord) { loop { let below = (cord.0, cord.1 + 1); if let Some(_) = self.material.get(&below) { let left = (cord.0 - 1, below.1); let right = (cord.0 + 1, below.1); if let None = self.material.get(&left) { cord = left; } else if let None = self.material.get(&right) { cord = right; } else { break; } } else { if cord.1 > self.bottom { if self.floor { break; } else { return false; } } cord = below; } } self.material.insert(cord, Material::Sand); self.left = self.left.min(cord.0); self.right = self.right.max(cord.0); return true; } false } } impl Display for Board { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for y in self.top..=self.bottom { for x in self.left..=self.right { let c = match self.material.get(&(x, y)) { Some(Material::Rock) => '#', Some(Material::Sand) => 'o', Some(Material::SandSource) => '+', None => '.', }; write!(f, "{}", c)?; } writeln!(f)?; } if self.floor { for _ in self.left..=self.right { write!(f, "#")?; } writeln!(f)?; } Ok(()) } } fn parse(input: &str) -> Board { let mut board = Board::default(); board.sand_source = (500, 0); board.material.insert(board.sand_source, Material::SandSource); for line in input.lines() { line.split(" -> ") .map(|part| { let mut parts = part.split(","); let x = parts.next().unwrap().parse::<i32>().unwrap(); let y = parts.next().unwrap().parse::<i32>().unwrap(); (x, y) }) .fold(Option::<(i32, i32)>::None, |mut state, to| { if let Some(from) = state.take() { let mut x_range = from.0..=to.0; let mut y_range = from.1..=to.1; if x_range.start() > x_range.end() { x_range = to.0..=from.0; } if y_range.start() > y_range.end() { y_range = to.1..=from.1; } for x in x_range { for y in y_range.clone() { board.material.insert((x, y), Material::Rock); } } } Some(to) }); } board.top = board.material.keys().next().unwrap().1; board.bottom = board.material.keys().next().unwrap().1; board.left = board.material.keys().next().unwrap().0; board.right = board.material.keys().next().unwrap().0; for (x, y) in board.material.keys() { board.top = board.top.min(*y); board.bottom = board.bottom.max(*y); board.left = board.left.min(*x); board.right = board.right.max(*x); } board } pub fn one() { let input = include_str!("input.txt"); let mut board = parse(input); let mut result = 0; while board.add_sand() { result += 1; } println!("{}", board); println!("Day 14, part 1: {}", result); } pub fn two() { let input = include_str!("input.txt"); let mut board = parse(input); board.floor = true; board.bottom += 1; #[allow(unused)] let mut result = 0; while board.add_sand() { result += 1; } println!("{}", board); let print = format!("{}", board); // sand and above result is wrong, count from print works // let sand = board.material.values().filter(|m| m == &&Material::Sand).count(); let result = print.chars().filter(|c| c == &'o').count(); println!("Day 14, part 2: {}", result); }

Lösning

Dag: 15

Hyffsat smÀrtfri dag, men del 2 Àr helt tack vare tippset frÄn huggeMugg i:

Skrivet av huggeMugg:

hur lÄng tid den hade tagit utan det Àr svÄrt att sÀga.

use std::{collections::{BTreeMap, BTreeSet}, fmt::Display}; use regex::Regex; #[derive(Debug, Default)] struct Board { sensors: BTreeMap<(i32, i32), (i32, i32)>, no_beacons: BTreeSet<(i32, i32)>, top: i32, bottom: i32, left: i32, right: i32, } impl Display for Board { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let beacons = self.sensors.values().collect::<BTreeSet<_>>(); for y in self.top..=self.bottom { write!(f, "{y: >8} ")?; for x in self.left..=self.right { let c = match self.sensors.get(&(x, y)) { Some(_) => 'S', None => if beacons.contains(&(x, y)) {'B'} else { if self.no_beacons.contains(&(x, y)) {'#'} else {'.'} }, }; write!(f, "{}", c)?; } writeln!(f)?; } Ok(()) } } fn parse(input: &str) -> Board { let mut board = Board::default(); let re = Regex::new(r"Sensor at x=(-?\d+), y=(-?\d+): closest beacon is at x=(-?\d+), y=(-?\d+)").unwrap(); for line in input.lines() { let caps = re.captures(line).unwrap(); let sx = caps.get(1).unwrap().as_str().parse::<i32>().unwrap(); let sy = caps.get(2).unwrap().as_str().parse::<i32>().unwrap(); let bx = caps.get(3).unwrap().as_str().parse::<i32>().unwrap(); let by = caps.get(4).unwrap().as_str().parse::<i32>().unwrap(); board.sensors.insert((sx, sy), (bx, by)); board.top = sy.min(by); board.bottom = sy.max(by); board.left = sy.min(bx); board.right = sy.max(bx); } for ((sx, sy), (bx, by)) in board.sensors.iter() { let distance = (sx - bx).abs() + (sy - by).abs(); board.top = board.top.min(*sy - distance); board.bottom = board.bottom.max(*sy + distance); board.left = board.left.min(*sx - distance); board.right = board.right.max(*sx + distance); board.top = board.top.min(*by); board.bottom = board.bottom.max(*by); board.left = board.left.min(*bx); board.right = board.right.max(*bx); } board } pub fn one() { let input = include_str!("input.txt"); let board = parse(input); let mut result = 0; let y = 2000000; for x in board.left..=board.right { for ((sx, sy), (bx, by)) in board.sensors.iter() { let a_distance = (sx - x).abs() + (sy - y).abs(); let b_distance = (sx - bx).abs() + (sy - by).abs(); if a_distance <= b_distance && (x, y) != (*bx, *by) { result += 1; break; } } } println!("Day 15, part 1: {}", result); } pub fn two() { let input = include_str!("input.txt"); let board = parse(input); let mut result = 0; let search_distance = 4000000; let search_range = 0..=search_distance; 'outer: for ((sx, sy), (bx, by)) in board.sensors.iter() { let distance = (sx - bx).abs() + (sy - by).abs(); let r = distance + 1; let search_circle = ((sx - r)..=(sx + r)).zip(((sy - r)..=*sy).rev().chain((sy - r + 1)..=*sy)) .chain(((sx - r + 1)..(sx + r)).rev().zip(((sy + 1)..=(sy + r)).chain((*sy..=(sy + r - 1)).rev()))); for (x, y) in search_circle { if !search_range.contains(&x) || !search_range.contains(&y) { continue; } let mut found = false; for ((sx, sy), (bx, by)) in board.sensors.iter() { let a_distance = (sx - x).abs() + (sy - y).abs(); let b_distance = (sx - bx).abs() + (sy - by).abs(); if a_distance <= b_distance { found = true; break; } } if !found { println!("Found at {}, {}", x, y); result = (x as u64) * 4000000 + (y as u64); break 'outer; } } } println!("Day 15, part 2: {}", result); }

Lösning

Dag: 16

Inte kul alls. Löste del 1 ganska snabbt men del 2 tar hur lÄng tid som helst.

efter att ha lÀst lite i subredditen verkar nÀstan alla enkla lösningar klara sig pÄ att köra del 1 tvÄ gÄnger och undvika redan tagna noder. Testade det men tyvÀrr fungerar det inte med min input dÄ den optimala lösningen krÀver att spelare 1 tar en annan vÀg Àn tidigare.

Försök pÄ workaround

Koden för del tvÄ tar för lÄng tid att köra sÄ jag gjorde sÄ att den printar det bÀsta resultatet den har hittat so far och lÀt den tugga över natten.
Idag utgick jag frÄn vad den kommit fram till so far och löste klart den för hand.

use pathfinding::prelude::dijkstra; use regex::Regex; use std::{collections::{BTreeMap, BTreeSet}, sync::{Arc, RwLock}}; use itertools::Itertools; use rayon::prelude::*; #[derive(Debug, Default)] struct Board { valves: BTreeMap<u32, Valve>, } impl Board { fn remove_empty(&mut self) { let mut empty = BTreeSet::new(); for (id, valve) in self.valves.iter() { if valve.flow_rate == 0 { empty.insert(*id); } } for id in empty { self.valves.remove(&id); for valve in self.valves.values_mut() { valve.tunnels.retain(|t| *t != id); } } } fn calculate_distances(&self) -> BTreeMap<(u32, u32), u32> { let mut distances = BTreeMap::new(); for from_valve in self.valves.values() { for to_valve in self.valves.values() { let path = dijkstra( &&from_valve.id, |id| self.valves[*id].tunnels.iter().map(|id| (id, 1)), |id| *id == &to_valve.id, ); distances.insert( (from_valve.id, to_valve.id), path.unwrap().1, ); } } distances } } #[derive(Debug, Default)] struct Valve { id: u32, flow_rate: u32, tunnels: Vec<u32>, } fn parse(input: &str) -> Board { let re = Regex::new(r"Valve ([A-Z]+) has flow rate=(\d+); tunnels? leads? to valves? ([A-Z, ]+)") .unwrap(); let mut board = Board::default(); let mut ids = BTreeMap::new(); ids.insert("AA".to_string(), 0); let mut next_id = 1; for line in input.lines() { let caps = re.captures(line).unwrap(); let valve = caps.get(1).unwrap().as_str(); let id = *ids.entry(valve.to_string()).or_insert_with(|| { let id = next_id; next_id += 1; id }); let flow_rate = caps.get(2).unwrap().as_str().parse().unwrap(); let valves = caps .get(3) .unwrap() .as_str() .split(", ") .map(|s| { *ids.entry(s.to_string()).or_insert_with(|| { let id = next_id; next_id += 1; id }) }) .collect(); board.valves.insert( id, Valve { id, flow_rate, tunnels: valves, }, ); } board } #[derive(Debug, Clone)] struct State { location: u32, remaining_time: u32, total_preasure_release: u32, open_valves: Vec<u32>, } fn asd(board: &Board, distances: &BTreeMap<(u32, u32), u32>, state: State) -> State { let move_time = 1; let open_time = 1; let remaining_valves = board .valves .values() .filter(|v| !state.open_valves.contains(&v.id)) .map(|v| { let time_to_open = distances[&(state.location, v.id)] * move_time + open_time; let total_presure_release = (state.remaining_time.max(time_to_open) - time_to_open) * v.flow_rate; (v.id.clone(), time_to_open, total_presure_release) }) .filter(|(_, time_to_open, _)| *time_to_open <= state.remaining_time); let best_result = remaining_valves .map(|(valve, time_to_open, total_presure_release)| { let mut new_state = state.clone(); new_state.location = valve; new_state.remaining_time -= time_to_open; new_state.total_preasure_release += total_presure_release; new_state.open_valves.push(valve); asd(board, distances, new_state) }) .max_by_key(|state| state.total_preasure_release); best_result.unwrap_or(state) } pub fn one() { let input = include_str!("input.txt"); let mut board = parse(input); let distances = board.calculate_distances(); board.remove_empty(); let result = asd( &board, &distances, State { location: 0, remaining_time: 30, total_preasure_release: 0, open_valves: Default::default(), }, ); println!("{:?}", result); println!("Day 16, part 1: {}", result.total_preasure_release); } pub fn two() { let input = include_str!("input.txt"); let mut board = parse(input); let mut distances = board.calculate_distances(); board.remove_empty(); let mut empty = BTreeSet::new(); for (a, b) in distances.keys() { if *a != 0 && *b != 0 && (!board.valves.contains_key(&a) || !board.valves.contains_key(&b)) { empty.insert((*a, *b)); } } for id in empty { distances.remove(&id); } let mut valves = board.valves.keys().collect::<Vec<_>>(); valves.sort_by_key(|id| 100 - board.valves[id].flow_rate); let perms1 = valves.clone().into_iter().permutations(7); let perms2 = valves.into_iter().permutations(7); let best = Arc::new(RwLock::new(0)); let result = perms1.cartesian_product(perms2).par_bridge() .map(|(perm1, perm2)| { let mut location1 = 0; let mut location2 = 0; let mut remaining_time1 = 26; let mut remaining_time2 = 26; let mut total_preasure_release = 0; let mut opened_valves = BTreeSet::new(); for i in 0..perm1.len() { let valve1 = unsafe { **perm1.get_unchecked(i) }; let valve2 = unsafe { **perm2.get_unchecked(i) }; if !opened_valves.contains(&valve1) { let time_to_open = distances[&(location1, valve1)] + 1; if time_to_open <= remaining_time1 { remaining_time1 -= time_to_open; total_preasure_release += board.valves[&valve1].flow_rate * remaining_time1; location1 = valve1; opened_valves.insert(valve1); } } if !opened_valves.contains(&valve2) { let time_to_open = distances[&(location2, valve2)] + 1; if time_to_open <= remaining_time2 { remaining_time2 -= time_to_open; total_preasure_release += board.valves[&valve2].flow_rate * remaining_time2; location2 = valve2; opened_valves.insert(valve2); } } } if total_preasure_release > 2500 { let b = best.read().unwrap(); if total_preasure_release > *b { drop(b); let mut b = best.write().unwrap(); println!("total_preasure_release: {}", total_preasure_release); println!("P1: {:?}", perm1); println!("P2: {:?}", perm2); println!(); *b = b.max(total_preasure_release); } } total_preasure_release }) .max() .unwrap(); println!("Day 16, part 2: {}", result); }

Min "fina" handlösning:

Detta Àr den andra bilden. Första blev för nerklottrad sÄ kastade den och började pÄ en ny nÀr jag var ganska nÀra.

Lösning

Dag 17:

HÀr Àr del 2 ocksÄ en partiell handlösning eftersom min optimerade kod har en ETA pÄ ~500h

Eftersom bÄde inputen och stenarna gÄr i cykler gör ocksÄ outputen det. Jag printade de första 50 000 raderna till en fil och letade efter cykeln manuellt.
Efter lite matte kom jag fram till att den Àr 2610 rader hög och bestÄr av 1695 stenar sÄ jag anvÀnde det för att hoppa över större delen av berÀkningen.
Variabeln cheat Àr 9 mindre Àn antalet hela cykler sÄ koden berÀknar "toppen" och "botten", dels för att cyklarna inte gÄr jÀmt ut pÄ de begÀrda 1000000000000 stenarna och dels för att jag behöver ha tillrÀckligt mycket stenar i brÀdet efter hoppet för att placera de sista korrekt.

#![allow(unused)] use std::{collections::BTreeSet, fmt::Display, time::Instant}; enum Dir { Left, Right, } #[derive(Debug, Clone)] struct Board<'a> { width: i64, height: i64, rocks: BTreeSet<(i64, i64)>, falling: Option<(&'a Rock, (i64, i64))>, } impl<'a> Board<'a> { fn new(width: i64) -> Self { Self { width, height: 0, rocks: BTreeSet::new(), falling: None, } } fn start_height(&self) -> i64 { self.height + 3 } fn add_falling(&mut self, rock: &'a Rock) { self.falling.replace((rock, (2, self.start_height()))); } fn fall(&mut self, move_dir: Dir) -> bool { let (rock, (x, y)) = self.falling.take().expect("No falling rock"); let mut left = rock.left() + x; let mut right = rock.right() + x; let mut bottom = rock.bottom() + y; let height = self.height; match move_dir { Dir::Left => { if left > 0 { left -= 1; right -= 1; } if bottom <= height { if rock.collides_with(&self.rocks, (left, bottom)) { left += 1; right += 1; } } }, Dir::Right => { if right < self.width - 1 { left += 1; right += 1; } if bottom <= height { if rock.collides_with(&self.rocks, (left, bottom)) { left -= 1; right -= 1; } } }, } bottom -= 1; if bottom < 0 || rock.collides_with(&self.rocks, (left, bottom)) { bottom += 1; let mut new_rocks = rock.0.iter().map(|(x, y)| (x + left, y + bottom)); self.rocks.extend(new_rocks); self.height = self.height.max(rock.top() + bottom + 1); return true; } self.falling.replace((rock, (left, bottom))); false } } impl Display for Board<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut height = self.height; if let Some((rock, (x, y))) = &self.falling { height = height.max(y + rock.top()); } for y in (0..=height).rev() { for x in -1..=self.width { if x == -1 || x == self.width { write!(f, "|")?; continue; } if let Some((rock, (rx, ry))) = &self.falling { if rock.0.contains(&(x - rx, y - ry)) { write!(f, "@")?; continue; } } if self.rocks.contains(&(x, y)) { write!(f, "#")?; } else { write!(f, ".")?; } } writeln!(f)?; } for x in -1..=(self.width as i64) { if x == -1 || x == self.width as i64 { write!(f, "+")?; continue; } write!(f, "-")?; } writeln!(f)?; writeln!(f, "height: {}", self.height)?; Ok(()) } } #[derive(Debug, PartialEq, Eq)] struct Rock(BTreeSet<(i64, i64)>, i64, i64, i64, i64); impl Rock { fn types() -> Vec<Rock> { let horiz_rock = BTreeSet::from([(0, 0), (1, 0), (2, 0), (3, 0)]); let plus_rock = BTreeSet::from([(1, 0), (0, 1), (1, 1), (2, 1), (1, 2)]); let l_rock = BTreeSet::from([(2, 2), (2, 1), (0, 0), (1, 0), (2, 0)]); let vert_rock = BTreeSet::from([(0, 0), (0, 1), (0, 2), (0, 3)]); let square_rock = BTreeSet::from([(0, 0), (1, 0), (0, 1), (1, 1)]); vec![ Rock( horiz_rock.clone(), *horiz_rock.iter().map(|(x, _)| x).min().unwrap(), *horiz_rock.iter().map(|(x, _)| x).max().unwrap(), *horiz_rock.iter().map(|(_, y)| y).max().unwrap(), *horiz_rock.iter().map(|(_, y)| y).min().unwrap() ), Rock( plus_rock.clone(), *plus_rock.iter().map(|(x, _)| x).min().unwrap(), *plus_rock.iter().map(|(x, _)| x).max().unwrap(), *plus_rock.iter().map(|(_, y)| y).max().unwrap(), *plus_rock.iter().map(|(_, y)| y).min().unwrap() ), Rock( l_rock.clone(), *l_rock.iter().map(|(x, _)| x).min().unwrap(), *l_rock.iter().map(|(x, _)| x).max().unwrap(), *l_rock.iter().map(|(_, y)| y).max().unwrap(), *l_rock.iter().map(|(_, y)| y).min().unwrap() ), Rock( vert_rock.clone(), *vert_rock.iter().map(|(x, _)| x).min().unwrap(), *vert_rock.iter().map(|(x, _)| x).max().unwrap(), *vert_rock.iter().map(|(_, y)| y).max().unwrap(), *vert_rock.iter().map(|(_, y)| y).min().unwrap() ), Rock( square_rock.clone(), *square_rock.iter().map(|(x, _)| x).min().unwrap(), *square_rock.iter().map(|(x, _)| x).max().unwrap(), *square_rock.iter().map(|(_, y)| y).max().unwrap(), *square_rock.iter().map(|(_, y)| y).min().unwrap() ), ] } fn left(&self) -> i64 { self.1 } fn right(&self) -> i64 { self.2 } fn top(&self) -> i64 { self.3 } fn bottom(&self) -> i64 { self.4 } fn collides_with(&self, rocks: &BTreeSet<(i64, i64)>, (x, y): (i64, i64)) -> bool { self.0.iter().any(|(rx, ry)| rocks.contains(&(x + rx, y + ry))) } } pub fn one() { let input = include_str!("input.txt").trim(); let mut board = Board::new(7); let rocks = Rock::types(); let mut rocks = rocks.iter().cycle(); let mut added_rocks = 0; for (i, c) in input.chars().cycle().enumerate() { if board.falling.is_none() { if added_rocks == 2022 { break; } board.add_falling(rocks.next().unwrap()); added_rocks += 1; } match c { '<' => { board.fall(Dir::Left); }, '>' => { board.fall(Dir::Right); }, c => { panic!("Unknown char: {}", c); }, } } println!("{}", board); let mut result = board.height; println!("Day 17, part 1: {}", result); } pub fn two() { let input = include_str!("input.txt").trim(); let mut board = Board::new(7); let rocks = Rock::types(); let mut rocks = rocks.iter().cycle(); let start = Instant::now(); let mut added_rocks = 0i64; for (i, c) in input.chars().cycle().enumerate() { if board.falling.is_none() { if added_rocks == 1000000000000 { break; } if added_rocks % 1000 == 0 { print!("Added {}% rocks ", (added_rocks as f64) / 10000000000f64); print!("in {}ms ", start.elapsed().as_millis()); println!("ETA: {:.2}h", (start.elapsed().as_millis() as f64) / (added_rocks as f64) * (1000000000000f64 - added_rocks as f64) / 3_600_000f64); } let cheat = 589970490; if added_rocks == 1000000000000 - 1695 * cheat { added_rocks += 1695 * cheat; board.height += 2610 * cheat; break; } board.add_falling(rocks.next().unwrap()); added_rocks += 1; } match c { '<' => { board.fall(Dir::Left); }, '>' => { board.fall(Dir::Right); }, c => { panic!("Unknown char: {}", c); }, } } let mut result = board.height; println!("Day 17, part 2: {}", result); }

Lösning
PermalÀnk
Medlem ★
●

Dagens var en frisk flÀkt jÀmfört med de 4 senaste

Dag: 18
SprÄk: Rust

use std::{collections::BTreeSet, ops::RangeInclusive}; type Space = BTreeSet<(i64, i64, i64)>; type SpaceSize = ( RangeInclusive<i64>, RangeInclusive<i64>, RangeInclusive<i64>, ); fn parse(input: &str) -> (Space, SpaceSize) { let mut space = BTreeSet::new(); let mut min_x = 1; let mut max_x = 1; let mut min_y = 1; let mut max_y = 1; let mut min_z = 1; let mut max_z = 1; for line in input.lines() { let mut sides = line.split(",").map(|s| s.parse::<i64>().unwrap()); let x = sides.next().unwrap(); let y = sides.next().unwrap(); let z = sides.next().unwrap(); space.insert((x, y, z)); min_x = min_x.min(x); max_x = max_x.max(x); min_y = min_y.min(y); max_y = max_y.max(y); min_z = min_z.min(z); max_z = max_z.max(z); } let space_size = (min_x..=max_x, min_y..=max_y, min_z..=max_z); (space, space_size) } fn is_reachable(space: &Space, space_size: &SpaceSize, coord: (i64, i64, i64)) -> bool { let mut queue = vec![coord]; let mut visited = BTreeSet::new(); while let Some((x, y, z)) = queue.pop() { if visited.contains(&(x, y, z)) { continue; } visited.insert((x, y, z)); if !space_size.0.contains(&x) || !space_size.1.contains(&y) || !space_size.2.contains(&z) { return true; } if !space.contains(&(x, y, z)) { queue.push((x - 1, y, z)); queue.push((x, y - 1, z)); queue.push((x, y, z - 1)); queue.push((x + 1, y, z)); queue.push((x, y + 1, z)); queue.push((x, y, z + 1)); } } false } pub fn one() { let input = include_str!("input.txt"); let (space, space_size) = parse(input); let mut result = 0; for x in space_size.0.clone() { for y in space_size.1.clone() { for z in space_size.2.clone() { if space.contains(&(x, y, z)) { if !space.contains(&(x - 1, y, z)) { result += 1; } if !space.contains(&(x, y - 1, z)) { result += 1; } if !space.contains(&(x, y, z - 1)) { result += 1; } if !space.contains(&(x + 1, y, z)) { result += 1; } if !space.contains(&(x, y + 1, z)) { result += 1; } if !space.contains(&(x, y, z + 1)) { result += 1; } } } } } println!("Day 18, part 1: {}", result); } pub fn two() { let input = include_str!("input.txt"); let (space, space_size) = parse(input); let mut result = 0; for x in space_size.0.clone() { for y in space_size.1.clone() { for z in space_size.2.clone() { if space.contains(&(x, y, z)) { if is_reachable(&space, &space_size, (x - 1, y, z)) { result += 1; } if is_reachable(&space, &space_size, (x, y - 1, z)) { result += 1; } if is_reachable(&space, &space_size, (x, y, z - 1)) { result += 1; } if is_reachable(&space, &space_size, (x + 1, y, z)) { result += 1; } if is_reachable(&space, &space_size, (x, y + 1, z)) { result += 1; } if is_reachable(&space, &space_size, (x, y, z + 1)) { result += 1; } } } } } println!("Day 18, part 2: {}", result); }

Lösning
PermalÀnk
●

Dag: 18
SprÄk: Nim
Lösning: Github

Har inte gjort dom senaste dagarnas uppgifter men dagens kÀndes förvÄnansvÀrt lÀtt för att vara sÄ hÀr pass sen. PÄ del 2 blev till att anvÀnda lite depth first search för att avgöra ifall en kub var helt innesluten eller inte.

Dold text
PermalÀnk
Datavetare ★
●

Dag: 18
SprÄk: Go
Lösning: Github

Representerar varje yta, 4 punkter, med en uint64 (5 bitar för varje koordinat och totalt 4 punkter per yta -> 60 bitar). DÄ Àr det bara rÀkna hur mÄnga ytor som finns pÄ samma "ytrepresentation".

Del 2 rÀknande jag ut storleken som behövs för att innesluta alla kuber i en större kub som har minst en "kub" med luft mellan sig och de inneslutna kuberna. Sedan fyller jag den stora kuben frÄn hörnet 0,0,0.

Efter det kan man rÀkna ut antalet fria ytor som i del 1. Detta innehÄller nu bÄde inneslutna ytor samt alla som ligger pÄ ytan av den "stora" kuben. Antalet kuber som ligger pÄ ytan av den stora kuben Àr trivialt att rÀkna ut, sÄ drar man bort dessa. Kvar Àr de inneslutna ytorna, detta drar man dÄ bort frÄn svaret i del 1.

Benchmark: 5,5 ms för att lösa del 2 pÄ en M1

goos: darwin goarch: arm64 pkg: aoc2022 BenchmarkDay18_parsing-8 866 1396972 ns/op BenchmarkDay18_part1-8 1291 909796 ns/op BenchmarkDay18_part2-8 216 5496644 ns/op PASS ok aoc2022 4.377s

Diskussion
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem ★
●

Dag: 16
SprÄk: Python

NÀr jag angrep detta som ett besök alla noder-problem, med valet att öppna eller inte Àppna en kran var det ganska bökigt. Men efter att byggt en ny komplett graf med distanser pÄ bÄgarna blev det mycket lÀttare. Nu handle det bara om i vilken ordning man skulle öppna kranarna.

Lösningen för del tvÄ som tar kryssprodukten av alla möjliga 26-stegstraverseringar Àr inte den snabbaste...

import re import itertools def bfs(l): visited = dict() while l: node, dist = l.pop(0) if node in visited: continue visited[node] = dist l += [(t, dist + 1) for t, _ in to[node]] return visited def flow(path, depth): return sum([rate[n] * (depth - t) for n, t in path if t < depth]) def join_solutions(d1, d2, depth): for d in [d2, {k: min(d1[k],d2[k]) for k in set(d1) & set(d2)}]: d1.update(d) return flow(d1.items(), depth) start, to, rate = 'AA', dict(), dict() for line in open("input16").readlines(): l = line.strip() m = re.match("Valve ([A-Z][A-Z]).*=(\d+).*valves? (.*)", l) rate[m[1]] = int(m[2]) to[m[1]] = [(n, 1) for n in m[3].split(', ')] valves = [n for n,r in rate.items() if r or r == start] kgraph = {node:{n:d for n,d in bfs([(node, 0)]).items() if rate[n] and n != node} for node in to if rate[node] or node == start } def open_valves(node, time, unopened, order, depth): if time >= depth or not unopened: return [order] time += 1 l = [] dists = kgraph[node] for i, u in enumerate(unopened): d = dists[u] if time + d < depth: l += open_valves(u, time + d, unopened[:i] + unopened[i+1:], order + [(u, time + d)], depth) return l if l else [order] print(max([flow(p, 30) for p in open_valves(start, 0, valves, [(start, 0)], 30) ]), max([join_solutions(dict(m), dict(e), 26) for m, e in itertools.combinations_with_replacement( open_valves(start, 0, valves, [(start, 0)], depth), 2)]))

Dold text
PermalÀnk
Medlem ★
●

Dag: 17
SprÄk: Python (Numpy)

import numpy as np import itertools as it shapes = [ np.where(np.array([[1,1,1,1]]) == 1), np.where(np.array([[0,1,0], [1,1,1], [0,1,0]]) == 1), np.where(np.array([[1,1,1], [0,0,1], [0,0,1]]) == 1), np.where(np.array([[1], [1], [1], [1]]) == 1), np.where(np.array([[1,1], [1,1]]) == 1) ] input = open("input17").read().strip() def direction(): for d in it.cycle(input): yield [-1, 1][d="='>'"] def drop(n): tunnel = np.zeros((200000, 9), dtype=np.int_) tunnel[0,:] = tunnel[:,0] = tunnel[:,8] = 1 shape = it.cycle(shapes) dirs = direction() for i in range(1, n + 1): height = max(np.where(tunnel[:,1:8] != 0)[0]) x, y, s = 3, height + 4, next(shape) while True: if not any(tunnel[s[0] + y, s[1] + (x + (d := next(dirs)))]): x += d if any(tunnel[s[0] + (y - 1), s[1] + x]): break y -= 1 tunnel[s[0] + y, s[1] + x] = i return tunnel tunnel = drop(2022) one = max(np.where(tunnel[:,1:8] != 0)[0]) def find_cycle(t): end = max(np.where(tunnel[:,1:8] != 0)[0]) // 2 for i in range(2, end): diff = tunnel[end - i:end + 1, 1:8] - tunnel[end - i - i:end - i + 1, 1:8] rock_diff = np.max(diff) diff[diff != 0] -= rock_diff if np.all(diff == 0): return i, rock_diff def find_start(tunnel, length): start = length while start: diff = (tunnel[start + length: start + length + length + 1, 1:8] - tunnel[start :start + length + 1, 1:8]) diff[diff != 0] -= np.max(diff) if np.any(diff != 0): return start, np.max(tunnel[:start]) start -= 1 tunnel = drop(len(input) * len(shapes)) cycle_height, cycle_rocks = find_cycle(tunnel) start_height, start_rocks = find_start(tunnel, cycle_height) cycles = (1000000000000 - start_rocks) // cycle_rocks remainder = (1000000000000 - start_rocks) % cycle_rocks two = cycles * cycle_height + max(np.where(tunnel == (remainder + start_rocks))[0]) print(one, two)

Dold text
PermalÀnk
Medlem ★
●

Dag: 18
SprÄk: Python (Trix med numpy igen )

import numpy as np offset = np.array([[ 1, 0, 0], [-1, 0, 0], [ 0, 1, 0], [ 0,-1, 0], [ 0, 0, 1], [ 0, 0,-1]]) def neighbors(point): return a[tuple((point + offset).T)] input = np.loadtxt("input18", dtype=np.int_, delimiter=',') input += (np.min(input) == 0) a = np.zeros([np.max(input) + 2] * 3, dtype=np.int_) a[tuple(input.T)] = 1 one = sum([6 - sum(neighbors(i)) for i in input]) a[0,:,:] = a[:,0,:] = a[:,:,0] = a[-1,:,:] = a[:,-1,:] = a[:,:,-1] = 2 loop = True while loop: loop = False for p in zip(*np.where(a == 0)): if np.any(neighbors(p) == 2): a[p] = 2 loop = True a //= 2 two = sum([sum(neighbors(i)) for i in input]) print(one, two)

Dold text
PermalÀnk
Medlem
●

Dag: 16
SprÄk: C#

Herregud, denna var inte nÄdig. Lyckades till slut att fÄ rÀtt pÄ den. Jag kör med en prioritetskö dÀr jag prioriterar "caves" som har högst pressure release. NÀr vÀl en cave har blivit fÀrdigberÀknad (minutes = 0) sÄ antar jag att dess total pressure release Àven Àr det rÀtta svar, vilket nog egentligen Àr ett fel att anta. MÀrkte nu att jag fÄr fel svar pÄ exempelinput men min riktiga input ger rÀtt svar.

using System.Collections.Immutable; using System.Text.RegularExpressions; namespace AOC2022.Puzzles; internal partial class Puzzle16 : Puzzle<int> { [GeneratedRegex(@.*([A-Z]{2}).*=(\d+);.*valve(?:s?) (.*))] private static partial Regex Regex(); record Valve(string Name, int FlowRate, List<Valve> ConnectedValves); record struct Cave(string OpenedValves, string MyPosition, string ElephantPosition, int MinutesLeft, int TotalPressure) { public int CalcPressure(IDictionary<string, Valve> valves) => OpenedValves.Chunk(2).Sum(x => valves[string.Concat(x)].FlowRate); } protected override void Solve(string[] lines) { var valves = CreateValves(lines); One = GetPressureResult(valves, true, 30); Two = GetPressureResult(valves, false, 26); } private static IDictionary<string, Valve> CreateValves(string[] lines) { var valves = lines .Select(line => { var groups = Regex().Match(line).Groups; return new Valve(groups[1].Value, int.Parse(groups[2].Value), new()); }) .ToDictionary(x => x.Name); foreach (var line in lines) { var match = Regex().Match(line); var valveId = match.Groups[1].Value; var connections = match.Groups[3].Value.Split(", ").ToList(); valves[valveId].ConnectedValves.AddRange(connections.Select(x => valves[x])); } return valves; } private static int GetPressureResult(IDictionary<string, Valve> valves, bool soloPlay, int minutes) { IEnumerable<Cave> CreateNewCaves(Cave cave, Valve myPos, string myPosition, Func<Cave> open, Func<Valve, Cave> move) { return Enumerable.Range(0, 2) .Select(x => x % 2 == 0) .Where(shouldOpen => !shouldOpen || (myPos.FlowRate > 0 && !cave.OpenedValves.Contains(myPosition))) .SelectMany(shouldOpen => { return shouldOpen ? new List<Cave>() { open() } : valves.Values .Where(valve => myPos.ConnectedValves.Contains(valve)) .Select(move); }); } var caves = new PriorityQueue<Cave, Cave>(new CaveComparer()); var start = new Cave("", "AA", "AA", minutes, 0); caves.Enqueue(start, start); var valvesWithFlowRate = valves.Values.Count(x => x.FlowRate > 0) * 2; while (true) { var cavesToVisit = Enumerable.Range(0, Math.Min(1000, caves.Count)).Select(_ => caves.Dequeue()).ToList(); var next = cavesToVisit .AsParallel() .SelectMany(cave => { if (cave.OpenedValves.Length == valvesWithFlowRate) { return new List<Cave> { cave with { MinutesLeft = 0, TotalPressure = cave.TotalPressure + cave.CalcPressure(valves) * cave.MinutesLeft } }; } var result = CreateNewCaves(cave, valves[cave.MyPosition], cave.MyPosition, () => cave with { MinutesLeft = cave.MinutesLeft - 1, OpenedValves = cave.OpenedValves + cave.MyPosition, TotalPressure = cave.TotalPressure + cave.CalcPressure(valves), }, valve => cave with { MinutesLeft = cave.MinutesLeft - 1, MyPosition = valve.Name, TotalPressure = cave.TotalPressure + cave.CalcPressure(valves), }); if (!soloPlay) { var elephant = valves[cave.ElephantPosition]; result = result.SelectMany(c => CreateNewCaves(c, elephant, cave.ElephantPosition, () => c with { OpenedValves = c.OpenedValves + c.ElephantPosition }, valve => c with { ElephantPosition = valve.Name })); } return result; }) .ToImmutableHashSet(); var completed = next .Where(x => x.MinutesLeft <= 0) .ToList(); if (completed.Count > 0) { return completed.Max(x => x.TotalPressure); } caves.EnqueueRange(next.Select(x => (x, x))); } } class CaveComparer : IComparer<Cave> { public int Compare(Cave x, Cave y) { return -1 * x.TotalPressure.CompareTo(y.TotalPressure); } } }

Dold text
PermalÀnk
Datavetare ★
●

Dag: 17
SprÄk: Go
Lösning: Github

Tweakat prestanda, körde med koordinater för varje pixel först men insÄg att man kan ju bara se varje rad som en "sprite" vilket gör det enkelt/snabbt att kolla kollisioner. Tar nu ~0,5 ms att lösa bÄda delarna...

goos: darwin goarch: arm64 pkg: aoc2022 BenchmarkDay17_parse-8 116707 9590 ns/op 46584 B/op 16 allocs/op BenchmarkDay17_part1-8 3085 440392 ns/op 389655 B/op 3387 allocs/op BenchmarkDay17_part2-8 2271 529469 ns/op 389229 B/op 3385 allocs/op PASS ok aoc2022 3.987s

Dold text
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem
●

Dag: 8
SprÄk: Basic v2.0 (Commodore 64)
Halkat efter, tidsbrist... nedan kod ej optimerad, kollar samma gran Àven fast den Àr registrerad att den redan syns frÄn ett hÄll och bitkontrollslösning var kanske inte en optimal lösning, koden börjar dessutom nu överstiga 10 rader

0 DIMA$(5):DIMT(25):FORX=0TO4:READA$(X):B$=B$+A$(X):NEXT:FORX=2TO4:FORY=1TO3
1 FORZ=0TO4:G=(Y*5)+X:H=(Z*5)+X:J=Y:K=4:C=2:D=4:GOSUB9:NEXTZ:NEXTY:NEXTX
2 FORY=1TO3:FORX=2TO4:FORZ=1TO5:G=(Y*5)+X:H=(Y*5)+Z:J=X:K=5:C=8:D=16:GOSUB9
3 NEXTZ:NEXTX:NEXTY:FORX=0TO24:IF(T(X)AND2)=0THENT(X)=1
4 IF(T(X)AND4)=0THENT(X)=1
5 IF(T(X)AND8)=0THENT(X)=1
6 IF(T(X)AND16)=0THENT(X)=1
7 IFT(X)=1THENS=S+1
8 NEXTX:PRINTS:END
9 IFG=HTHENRETURN
10 IFMID$(B$,G,1)=<MID$(B$,H,1)THENGOSUB12:RETURN
11 T(G)=T(G)OR1:RETURN
12 IFG>HTHENT(G)=T(G)ORC:Z=J:RETURN
13 IFG<HTHENT(G)=T(G)ORD:Z=K:RETURN
14 DATA30373,25512,65332,33549,35390

Dold text

Dag: 10
SprÄk: Basic v2.0 (Commodore 64)
Vart klar med dag 10 före dag 9...3 rader kod och en jÀkla massa data

0 DIMQ(220):X=1:FORI=1TO146:READA$:C=C+1:IFLEN(A$)>4THENC=C+1
1 D=20+(INT(C/40)*40):IFC=>DANDC<=D+1THENIFQ(D)=0THENS=X*D:Q(D)=S:T=T+S
2 X=X+VAL(RIGHT$(A$,LEN(A$)-4)):NEXT:PRINTT

3 DATA"ADDX 15","ADDX -11","ADDX 6","ADDX -3","ADDX 5","ADDX -1","ADDX -8"
4 DATA"ADDX 13","ADDX 4","NOOP","ADDX -1","ADDX 5","ADDX -1","ADDX 5"
5 DATA"ADDX -1","ADDX 5","ADDX -1","ADDX 5","ADDX -1","ADDX -35","ADDX 1"
6 DATA"ADDX 24","ADDX -19","ADDX 1","ADDX 16","ADDX -11","NOOP","NOOP"
7 DATA"ADDX 21","ADDX -15","NOOP","NOOP","ADDX -3","ADDX 9","ADDX 1"
8 DATA"ADDX -3","ADDX 8","ADDX 1","ADDX 5","NOOP","NOOP","NOOP","NOOP","NOOP"
9 DATA"ADDX -36","NOOP","ADDX 1","ADDX 7","NOOP","NOOP","NOOP","ADDX 2"
10 DATA"ADDX 6","NOOP","NOOP","NOOP","NOOP","NOOP","ADDX 1","NOOP","NOOP"
11 DATA"ADDX 7","ADDX 1","NOOP","ADDX -13","ADDX 13","ADDX 7","NOOP","ADDX 1"
12 DATA"ADDX -33","NOOP","NOOP","NOOP","ADDX 2","NOOP","NOOP","NOOP","ADDX 8"
13 DATA"NOOP","ADDX -1","ADDX 2","ADDX 1","NOOP","ADDX 17","ADDX -9","ADDX 1"
14 DATA"ADDX 1","ADDX -3","ADDX 11","NOOP","NOOP","ADDX 1","NOOP","ADDX 1"
15 DATA"NOOP","NOOP","ADDX -13","ADDX -19","ADDX 1","ADDX 3","ADDX 26"
16 DATA"ADDX -30","ADDX 12","ADDX -1","ADDX 3","ADDX 1","NOOP","NOOP","NOOP"
17 DATA"ADDX -9","ADDX 18","ADDX 1","ADDX 2","NOOP","NOOP","ADDX 9","NOOP"
18 DATA"NOOP","NOOP","ADDX -1","ADDX 2","ADDX -37","ADDX 1","ADDX 3","NOOP"
19 DATA"ADDX 15","ADDX -21","ADDX 22","ADDX -6","ADDX 1","NOOP","ADDX 2"
20 DATA"ADDX 1","NOOP","ADDX -10","NOOP","NOOP","ADDX 20","ADDX 1","ADDX 2"
21 DATA"ADDX 2","ADDX -6","ADDX -11","NOOP","NOOP","NOOP"

Dold text
Visa signatur

‱‱‱‱    ¹˜”°ÂșXTROÂș°”˜¹ ‱‱‱‱ ‱‱‱‱ Letar du efter nĂ„got? ‱‱‱‱ ‱‱‱‱  The Little Ninja  ‱‱‱‱
‱‱‱‱ C64 0.98MHz/64K ‱‱‱‱ ‱‱‱‱   Prova det ultimata!   ‱‱‱‱ ‱‱‱‱ Komplett Cracktro ‱‱‱‱
‱‱‱‱  -Tack för sĂ„sen..  ‱‱‱‱ ‱‱‱‱     GO `GOOGLEÂŽ NOW   ‱‱‱‱ ‱‱‱‱    250bytes Intro   ‱‱‱‱

PermalÀnk
Datavetare ★
●

Dag: 19
SprÄk: Go
Lösning: Github

Finns det nÄgon bÀttre lösning Àn "brute-force" med lite frisering av uppenbart meningslösa fall?

Första som inte gÄr att lösa vÀl under 1s... Del 1 gÄr att lösa pÄ ~150 ms, men del tvÄ tar ~2,5s pÄ en M1

goos: darwin goarch: arm64 pkg: aoc2022 BenchmarkDay19_parsing-8 7 147709095 ns/op 523019190 B/op 3356773 allocs/op BenchmarkDay19_part1-8 7 148290434 ns/op 523016699 B/op 3356752 allocs/op BenchmarkDay19_part2-8 1 2395778125 ns/op 15586308136 B/op 77265436 allocs/op PASS ok aoc2022 4.904s

Dold text
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem ★
●
Skrivet av Yoshman:

Dag: 19
SprÄk: Go
Lösning: Github

Finns det nÄgon bÀttre lösning Àn "brute-force" med lite frisering av uppenbart meningslösa fall?

Första som inte gÄr att lösa vÀl under 1s... Del 1 gÄr att lösa pÄ ~150 ms, men del tvÄ tar ~2,5s pÄ en M1

goos: darwin goarch: arm64 pkg: aoc2022 BenchmarkDay19_parsing-8 7 147709095 ns/op 523019190 B/op 3356773 allocs/op BenchmarkDay19_part1-8 7 148290434 ns/op 523016699 B/op 3356752 allocs/op BenchmarkDay19_part2-8 1 2395778125 ns/op 15586308136 B/op 77265436 allocs/op PASS ok aoc2022 4.904s

Dold text

https://github.com/albertdahlin/aoc-2022-c/blob/master/src/Da...

Skall enligt författaren exekvera Del 1 och Del 2 pÄ drygt 0.5s.

Visa signatur

:(){ :|:& };:

đŸŠđŸ»â€â™‚ïž   đŸšŽđŸ»â€â™‚ïž   đŸƒđŸ»â€â™‚ïž   ☕

PermalÀnk
Datavetare ★
●
Skrivet av GLaDER:

https://github.com/albertdahlin/aoc-2022-c/blob/master/src/Da...

Skall enligt författaren exekvera Del 1 och Del 2 pÄ drygt 0.5s.

Hmm, missen jag gjorde Àr nog att köra BFS... Kör man istÀllet DFS gÄr det nog att kapa en gÀng deltrÀd nÀr man kan se att dessa inte kan ge en högre poÀng.

DFS + lösningen ovan har hÄrdkodat lite saker kring hur mÄnga robotar av en viss typ man rimligen behöver ger nog rÀtt mycket.

Noterade t.ex. att min lösning tillÄter lite fler clay-robots Àn tests input / min input behöver. Bara genom att strypa den grÀnsen med 1 robot ~halverar körtiden! Dock inte helt pÄ det klara med om det Àr en generellt "safe" optimering...

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem ★
●

Dag: 15
SprÄk: Rust

Dag 15 fÄr bli sista för i Är, nu tar det för mycket tid för att jag ska ha en chans att hinna med.

Min första version av del 2 tog 453 minuter att köra pÄ en helt ok laptop, men fick rÀtt fram vÀrde. Sedan dess har jag lagt till parallellisering och massa minioptimeringar, för att tillslut komma ner pÄ ungefÀr 17 minuter för att fÄ rÀtt fram svar.

Ser att andra löser den pÄ nÄgra mikrosekunder, sÄ inser sÄ klart att jag borde vÀlja en smartare lösning, men kommer inte pÄ nÄgon utan att fuska.

Dold text

use std::cmp; use rayon::prelude::*; #[derive(Debug, Copy, Clone)] struct Pos { x: i32, y: i32, range: i32, } fn main() { let input = include_str!("./input.txt"); let mut sensor_list = vec![]; let mut beacon_list = vec![]; for line in input.lines() { let split: Vec<&str> = line.split(" ").collect(); let s_str_x: Vec<&str> = split[2].split("=").collect(); let s_str_x: Vec<&str> = s_str_x[1].split(",").collect(); let s_x = s_str_x[0].parse::<i32>().unwrap(); let s_str_y: Vec<&str> = split[3].split("=").collect(); let s_str_y: Vec<&str> = s_str_y[1].split(":").collect(); let s_y = s_str_y[0].parse::<i32>().unwrap(); let b_str_x: Vec<&str> = split[8].split("=").collect(); let b_str_x: Vec<&str> = b_str_x[1].split(",").collect(); let b_x = b_str_x[0].parse::<i32>().unwrap(); let b_str_y: Vec<&str> = split[9].split("=").collect(); let b_y = b_str_y[1].parse::<i32>().unwrap(); let sensor: Pos = Pos { x: s_x, y: s_y, range: manhattan_distance(s_x, s_y, b_x, b_y), }; let beacon: Pos = Pos { x: b_x, y: b_y, range: 0, }; sensor_list.push(sensor); beacon_list.push(beacon); } const X_OFFSET: usize = 1236383; // Biggest negative x beacon position const DIMENSIONS: usize = 4000000; const Y_FOR_PART_1: i32 = 2000000; const ROW_SIZE: usize = 5625609; //Max sensor.x + sensor.range; Magic number for optimization let mut row = vec![false; ROW_SIZE]; for sensor in sensor_list.as_slice() { for x in (0 as usize)..row.len() { if manhattan_distance( sensor.x + X_OFFSET as i32, sensor.y, x as i32, Y_FOR_PART_1 as i32, ) <= sensor.range { row[x as usize] = true; } } } for beacon in beacon_list.as_slice() { if (beacon.y as i32) == Y_FOR_PART_1 { row[(beacon.x + X_OFFSET as i32) as usize] = false; } } for sensor in sensor_list.as_slice() { if (sensor.y as i32) == Y_FOR_PART_1 { row[(sensor.x + X_OFFSET as i32) as usize] = false; } } let mut count = 0; for j in 0_usize..row.len() { if row[j] { count += 1; } } println!("Part 1: {}", count); (0..DIMENSIONS).into_par_iter().for_each(|y| { let mut row = vec![false; ROW_SIZE]; for sensor in sensor_list.as_slice() { if y as i32 >= sensor.y - sensor.range && y as i32 <= sensor.y + sensor.range { let diff = sensor.range - (sensor.y-y as i32).abs(); let min_range = cmp::max(0, sensor.x - diff) as usize; let max_range = cmp::min(sensor.x + diff +1, DIMENSIONS as i32) as usize; row[min_range..max_range].fill(true); } } if row[0..DIMENSIONS].iter().all(|&x| x) { return; } for x in 0..DIMENSIONS { if !row[x] { let res: u64 = ((x * 4000000) + y) as u64; println!("Part 2: {}", res); return; } } }); } fn manhattan_distance(x1: i32, y1: i32, x2: i32, y2: i32) -> i32 { return (x1 - x2).abs() + (y1 - y2).abs(); }

Dold text
PermalÀnk
●

Dag: 20
SprÄk: Nim
Lösning: Github

Det hÀr kÀndes som en enkel dag igen. KÀnns nÀstan som att den hÀr uppgiften hade passat under dom 10 första dagarna. Eller har man bara blivit sÄ skrÀmd av dom super-svÄra uppgifterna dom senaste dagarna?...

Dold text
PermalÀnk
Medlem ★
●

Dag: 2
SprÄk: ArnoldJS

import IT'S SHOWTIME input HASTA LA VISTA BABY from '../input/day2.js' TERMINATED CHILL OUT readInput STICK AROUND GIVE THESE PEOPLE AIR input ENOUGH TALK => input I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE split GIVE THESE PEOPLE AIR '\n' ENOUGH TALK TERMINATED CHILL OUT rows STICK AROUND readInput GIVE THESE PEOPLE AIR input ENOUGH TALK TERMINATED CHILL OUT hasha = IT'S SHOWTIME 'A X': 4, 'A Y': 8, 'A Z': 3, 'B X': 1, 'B Y': 5, 'B Z': 9, 'C X': 7, 'C Y': 2, 'C Z': 6 HASTA LA VISTA BABY CHILL OUT hashb = IT'S SHOWTIME 'A X': 3, 'A Y': 4, 'A Z': 8, 'B X': 1, 'B Y': 5, 'B Z': 9, 'C X': 2, 'C Y': 6, 'C Z': 7 HASTA LA VISTA BABY LISTEN TO ME VERY CAREFULLY solution GIVE THESE PEOPLE AIR hash ENOUGH TALK IT'S SHOWTIME YOU SET US UP points STICK AROUND 0 TERMINATED LET'S KICK SOME ICE GIVE THESE PEOPLE AIR CHILL OUT row of rows ENOUGH TALK IT'S SHOWTIME points STICK AROUND points GET UP hash[row] TERMINATED HASTA LA VISTA BABY TALK TO THE HAND GIVE THESE PEOPLE AIR points ENOUGH TALK TERMINATED HASTA LA VISTA BABY solution GIVE THESE PEOPLE AIR hasha ENOUGH TALK TERMINATED solution GIVE THESE PEOPLE AIR hashb ENOUGH TALK TERMINATED YOU ARE TERMINATED

Dold text
PermalÀnk
Datavetare ★
●

Dag: 20
SprÄk: Go
Lösning: Github

goos: darwin goarch: arm64 pkg: aoc2022 BenchmarkDay20_parse-8 7798 153661 ns/op 248266 B/op 5016 allocs/op BenchmarkDay20_part1-8 98 11837133 ns/op 44899 B/op 52 allocs/op BenchmarkDay20_part2-8 9 138439069 ns/op 304522 B/op 5018 allocs/op

benchmark
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem
●

Dag: 9
SprÄk: Basic v2.0 (Commodore 64)
Dag 9 vart lite efterslÀntande dÄ jag trodde den var krÄngligare Àn den var.. höll dock mÄlet att hÄlla mig pÄ max 10 rader kod

0 DIMH(30):DIMT(30):FORI=0TO7:READA$:D$(I)=LEFT$(A$,1):V(I)=VAL(RIGHT$(A$,1))
1 NEXT:FORX=0TO8:READM(X):NEXT:P=24:Q=P:H(P)=1:
2 T(Q)=1:FORI=0TO7:IFD$(I)="U"THENY=-6
3 IFD$(I)="D"THENY=6:DATA"R 4","U 4","L 3","D 1","R 4","D 1","L 5","R 2"
4 IFD$(I)="L"THENX=-1
5 IFD$(I)="R"THENX=1
6 FORF=1TOV(I):B=P:P=P+Y+X:H(P)=1:GOSUB8:NEXT:X=0:Y=0:NEXT
7 FORX=0TO29:T=T+T(X):NEXT:PRINTT:END
8 FORO=0TO8:IFQ=(P+M(O))THENRETURN
9 NEXT:Q=B:T(Q)=1:RETURN:DATA-7,-6,-5,-1,0,1,5,6,7

Dold text
Visa signatur

‱‱‱‱    ¹˜”°ÂșXTROÂș°”˜¹ ‱‱‱‱ ‱‱‱‱ Letar du efter nĂ„got? ‱‱‱‱ ‱‱‱‱  The Little Ninja  ‱‱‱‱
‱‱‱‱ C64 0.98MHz/64K ‱‱‱‱ ‱‱‱‱   Prova det ultimata!   ‱‱‱‱ ‱‱‱‱ Komplett Cracktro ‱‱‱‱
‱‱‱‱  -Tack för sĂ„sen..  ‱‱‱‱ ‱‱‱‱     GO `GOOGLEÂŽ NOW   ‱‱‱‱ ‱‱‱‱    250bytes Intro   ‱‱‱‱

PermalÀnk
●

Dag: 21
SprÄk: Nim
Lösning: Github

Dagens problem kÀndes Äterigen ganska snÀllt, men jag klagar inte. Del 2 var lite klurig först nÀr jag insÄg att det rÀtta svaret var i storleksordningen 1e12 sÄ att loopa genom alla tal och brute force:a var det inte frÄgan om. IstÀllet anvÀnda jag mig av en metod för numerisk lösning av ekvationer: Sekantmetoden. Denna hittade rÀtt vÀrde pÄ 3 (!) iterationer. Eller typ rÀtt vÀrde iaf, jag fick det till att det fanns tvÄ lösningar som uppfyllde kravet (301 och 302 pÄ test datan) men bara en av dom gav rÀtt. NÄgon annan som ocksÄ hade det problemet?

Dold text
PermalÀnk
Datavetare ★
●

Dag: 21
SprÄk: Go
Lösning: Github

Första delen var ju ovÀntat lÀtt.

Gjorde det enklast tÀnkbara i del 2. Startar med 0..1 och ökar den högre grÀnsen, N, till dess att differensen mellan "root"s tvÄ argument byter tecken. I det lÀget vet man att svaret ligger mellan N/2..N, kör sedan binÀrsökning i det intervallet.

@huggeMugg fÄr ocksÄ 301 och 302 som svar för test-data, sÄ Àr nog en "bug".

Tar ett tiotal iterationer för min del, men tar ÀndÄ <7 ms att lösa del 2

goos: darwin goarch: arm64 pkg: aoc2022 BenchmarkDay21_parse-10 866 1224673 ns/op 653776 B/op 17113 allocs/op BenchmarkDay21_part1-10 15974 74727 ns/op 49 B/op 1 allocs/op BenchmarkDay21_part2-10 183 6519531 ns/op 4637 B/op 98 allocs/op

Dold text
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
●

@Yoshman jag kollade upp det pÄ reddit och det verkar ha och göra med att jag anvÀnde heltalsdivision istÀllet för vanlig division. SÄ 302 Àr ingen lösning egentligen, men eftersom jag kastade bort decimalerna sÄ blev dom lika. SÄ jag tycker problemformuleringen var lite otydlig eftersom normen i AoC ÀndÄ Àr att man nÀstan aldrig behöver anvÀnda nÄgot annat Àn heltal.

Dold text
PermalÀnk
Datavetare ★
●
Skrivet av huggeMugg:

@Yoshman jag kollade upp det pÄ reddit och det verkar ha och göra med att jag anvÀnde heltalsdivision istÀllet för vanlig division. SÄ 302 Àr ingen lösning egentligen, men eftersom jag kastade bort decimalerna sÄ blev dom lika. SÄ jag tycker problemformuleringen var lite otydlig eftersom normen i AoC ÀndÄ Àr att man nÀstan aldrig behöver anvÀnda nÄgot annat Àn heltal.

Dold text

Det mÀrkliga Àr att jag anvÀnder inte flyttal, kör med int64 och fÄr ÀndÄ det som root...

Detta ger rÀtt svar direkt, vilket Àr ekvivalent med att testa "om jag sÀger 302, matchar det dÄ?".
Enbart heltalsaritmetik

func MyNumberForRootMonkeyMatch(mm MonkeyMatch, rootArgs string) int64 { result := make(chan int64) iYell := make(chan int64) go rootMatcher(mm, result, rootArgs) mm[MyName] = func(MonkeyMatch) int64 { return <-iYell } // Find range, xA..xB (xA>xB), where the root monkey function change sign // iYell <- 0 // xBIsPositive := isPositive(<-result) // xA := int64(1) // xB := int64(0) // for { // iYell <- int64(xA) // diff := <-result // if isPositive(diff) != xBIsPositive { // xB = xA / 2 // break // } // xA *= 2 // } // Answer is in range xA..xB for { //n := (xA-xB)/2 + xB n := int64(302) iYell <- n diff := <-result if diff == 0 { return n } // if isPositive(diff) == xBIsPositive { // // n on same "side" as xB // xB = n + 1 // } else { // // n on same "side" as xA // xA = n - 1 // } } }

Jag Àndrade denna del i parseMonkeyMatch() för att se vad man har för argument i divisionen som sker med 301 resp. 302

case "/": mm[monkeyName] = func(mm MonkeyMatch) int64 { a := mm[names[0]](mm) b := mm[names[1]](mm) return a / b }

Skulle sÀga att det Àr en bug för med 302 Àr a:=602 och med 301 Àr a:=600, i bÄda fallen Àr b:=4. Med heltals-division ger bÄda dessa samma svar: 150

Det Àr enda divisionen, sÄ enda fallet dÀr man kan "tappa" precision (undantaget overflow, vilket inte sker).

Edit: sure, man kan hÀvda att 302 ger en rest != 0 sÄ det borde inte matcha. Undrar dock om det riktigt var tanken...

Dold text
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem ★
●

Dag: 21
SprÄk: Python

@Yoshman Det finns andra sÀtt att lösa uppgiften dÀr men inte behöver befatta sig med flyttal.

Python tillhandahÄller bÄde evaluering, parser och traversering av uttryck...

import ast def evaluate(monkey): s = expressions[monkey] op = s.split() if len(op) == 3: s = "(" + evaluate(op[0]) + op[1] + evaluate(op[2]) + ")" try: s = str(int(eval(s))) except: pass expressions[monkey] = s return s class Visitor(ast.NodeVisitor): def __init__(self, v): self.v = v super().__init__() def visit_BinOp(self, node): left = right = None if isinstance(node.left, ast.Constant): left = node.left.value if isinstance(node.right, ast.Constant): right = node.right.value if isinstance(node.op, ast.Add): self.v -= left or right if isinstance(node.op, ast.Mult): self.v //= left or right if isinstance(node.op, ast.Sub): self.v = left - self.v if left else self.v + right if isinstance(node.op, ast.Div): self.v = left // self.v if left else self.v * right ast.NodeVisitor.generic_visit(self, node) expressions = dict([l.strip().split(": ") for l in open("input21").readlines()]) one = evaluate("root") expressions = dict([l.strip().split(": ") for l in open("input21").readlines()]) expressions["humn"] = "humn" e = expressions["root"].split() v = Visitor(eval(evaluate(e[2]))) v.visit(ast.parse(evaluate(e[0]))) two = v.v print(one, two)

Dold text
PermalÀnk
Medlem
●

Dag: 11
SprÄk: Basic v2.0 (Commodore 64)
(Ej variabel input för "ÄtgÀrd" och ca:12s körtid med 0.98MHz )

0 DIMM0(128):DIMM1(128):DIMM2(128):DIMM3(128):M0=2:M1=4:M2=3:M3=1:P0=23:P1=19
1 FORM=0TOM0-1:READM0(M):NEXT:FORM=0TOM1-1:READM1(M):NEXT:P2=13:P3=17
2 FORM=0TOM2-1:READM2(M):NEXT:READM3(0):FORQ=0TO19:IFMA=M0THEN6
3 FORI=MATOM0-1:M=INT((M0(I)*19)/3):IFINT(M/P0)=M/P0THENM2(M2)=M:M2=M2+1:GOTO5
4 M3(M3)=M:M3=M3+1
5 NEXT:MA=I
6 IFMB=M1THEN10
7 FORI=MBTOM1-1:M=INT((M1(I)+6)/3):IFINT(M/P1)=M/P1THENM2(M2)=M:M2=M2+1:GOTO9
8 M0(M0)=M:M0=M0+1
9 NEXT:MB=I
10 IFMC=M2THEN14
11 FORI=MCTOM2-1:M=INT((M2(I)^2)/3):IFINT(M/P2)=M/P2THENM1(M1)=M:M1=M1+1:GOTO13
12 M3(M3)=M:M3=M3+1
13 NEXT:MC=I
14 IFMD=M3THEN18
15 FORI=MDTOM3-1:M=INT((M3(I)+3)/3):IFINT(M/P3)=M/P3THENM0(M0)=M:M0=M0+1:GOTO17
16 M1(M1)=M:M1=M1+1
17 NEXT:MD=I
18 NEXTQ:PRINTMA;MB;MC;MD:Z(0)=MA:Z(1)=MB:Z(2)=MC:Z(3)=MD
19 FORZ=1TO3:IFZ(0)<Z(Z)THENA=Z(Z):Z(Z)=0
20 NEXT:FORZ=0TO3:IFZ(1)<Z(Z)THENB=Z(Z)
21 NEXT:PRINTB;A;A*B:DATA79,98,54,65,75,74,79,60,97,74

Dold text
Visa signatur

‱‱‱‱    ¹˜”°ÂșXTROÂș°”˜¹ ‱‱‱‱ ‱‱‱‱ Letar du efter nĂ„got? ‱‱‱‱ ‱‱‱‱  The Little Ninja  ‱‱‱‱
‱‱‱‱ C64 0.98MHz/64K ‱‱‱‱ ‱‱‱‱   Prova det ultimata!   ‱‱‱‱ ‱‱‱‱ Komplett Cracktro ‱‱‱‱
‱‱‱‱  -Tack för sĂ„sen..  ‱‱‱‱ ‱‱‱‱     GO `GOOGLEÂŽ NOW   ‱‱‱‱ ‱‱‱‱    250bytes Intro   ‱‱‱‱

PermalÀnk
Medlem
●

SprÄk: C#

Ligger efter lite men har försökt komma ikapp. Är pĂ„ dag 22 just nu.

Dag 17:

namespace AOC2022.Puzzles; internal class Puzzle17 : Puzzle<int, ulong> { protected override void Solve(string[] lines) { var rocks = File.ReadAllText("Inputs/Rocks.txt") .Split(new string[] { "\r\n\r\n" }, StringSplitOptions.RemoveEmptyEntries) .Select(rock => { var structure = new char[4, 4]; Grid.Fill(structure, '.'); var rows = rock.Split(Environment.NewLine); for (var y = 0; y < rows.Length; y++) { var row = rows[y]; for (int x = 0; x < rows[y].Length; x++) { structure[x, y] = row[x]; } } return structure; }) .ToArray(); var movements = lines[0]; One = DropRocks(movements, rocks, 2022, 0); // After analyzing the output we can see that the pattern repeat itself after a while. // Then we can only simulate the cyclic part and multiply that to get the correct result var (heightCycleStart, heightCycleLength, rockCycleStart, rockCycleLength, jetCycleStart) = (792U, 2724U, 496U, 1740U, 2870); ulong totalRocks = 1000000000000UL - rockCycleStart; ulong totalCycles = totalRocks / rockCycleLength; var rocksRemainder = (int) (totalRocks % rockCycleLength); Two = heightCycleStart + (ulong) DropRocks(movements, rocks, rocksRemainder, jetCycleStart) + (totalCycles * heightCycleLength); } private static int DropRocks(string movements, char[][,] rocks, int amountRocks, int jetIdx) { var depth = 4000; var chamber = new char[7, depth + 1]; Grid.Fill(chamber, '.'); foreach (var x in Enumerable.Range(0, 7)) { chamber[x, depth] = '#'; } var fallenRocks = 0; var tick = jetIdx; var height = depth; while (true) { foreach (var rock in rocks) { height = DropRock(chamber, rock, movements, ref tick, height); fallenRocks++; if (fallenRocks == amountRocks) { return depth - height; } } } } private static int DropRock(char[,] chamber, char[,] rock, string movements, ref int tick, int height) { var heightLeverage = height - 7; AddRockToChamber(height, chamber, rock); while (true) { var m = movements[tick % movements.Length]; Move(chamber, heightLeverage, m == '<'); tick++; if (Grid.Iterate(chamber, heightLeverage) .Where(x => chamber[x.x, x.y] == '@') .Any(p => chamber[p.x, p.y + 1] == '#')) { break; } MoveDown(chamber, heightLeverage); } foreach (var (x, y) in Grid.Iterate(chamber, heightLeverage) .Where(p => chamber[p.x, p.y] == '@')) { chamber[x, y] = '#'; } return GetNewHeight(chamber, height); } private static int GetNewHeight(char[,] chamber, int prevHeight) { for (int y = prevHeight - 4; y < prevHeight + 1; y++) { for (int x = 0; x < chamber.GetLength(0); x++) { if (chamber[x,y] == '#') { return y; } } } return 0; } private static void AddRockToChamber(int floor, char[,] chamber, char[,] rock) { foreach (var (x, y) in Grid.Iterate(rock)) { chamber[2 + x, floor - (7 - y)] = rock[x, y]; } } private static readonly (int x, int y) Left = (-1, 0); private static readonly (int x, int y) Right = (1, 0); private static void Move(char[,] chamber, int height, bool left) { var move = left ? Left : Right; var gridIterate = Grid.Iterate(chamber, height); if (!left) { gridIterate = gridIterate.Reverse(); } var count = gridIterate .Where(p => chamber[p.x, p.y] == '@') .Select(p => { if (Grid.IsOutOfRange(chamber, (p.x + move.x, p.y)) || chamber[p.x + move.x, p.y] == '#') { return (-1, -1); } return p; }) .ToList(); if (count.Any(x => x.Item1 == -1)) { return; } foreach (var (x, y) in count) { chamber[x + move.x, y] = chamber[x, y]; chamber[x, y] = '.'; } } private static void MoveDown(char[,] chamber, int height) { foreach (var (x, y) in Grid.Iterate(chamber, height).Reverse()) { if (chamber[x, y] == '@') { if (Grid.IsOutOfRange(chamber, (x, y + 1))) { return; } chamber[x, y + 1] = chamber[x, y]; chamber[x, y] = '.'; } } } }

Dold text

Dag 18:

namespace AOC2022.Puzzles; internal class Puzzle18 : Puzzle<int> { private static readonly Point[] Neighbours = new Point[] { new(-1 , 0, 0), new(0 , -1, 0), new(0 , 0, -1), new(1 , 0, 0), new(0 , 1, 0), new(0 , 0, 1) }; record struct Point(int X, int Y, int Z) { public static Point operator +(Point a, Point b) => new(a.X + b.X, a.Y + b.Y, a.Z + b.Z); } protected override void Solve(string[] lines) { var points = lines .Select(line => { var l = line.Split(',').Select(int.Parse).ToArray(); return new Point(l[0], l[1], l[2]); }) .ToHashSet(); One = GetSurfaceArea(points); var xMin = points.Min(x => x.X) + 1; var xMax = points.Max(x => x.X); var yMin = points.Min(x => x.Y) + 1; var yMax = points.Max(x => x.Y); var zMin = points.Min(x => x.Z) + 1; var zMax = points.Max(x => x.Z); var airPockets = Enumerable.Range(xMin, xMax - xMin) .SelectMany(x => Enumerable.Range(yMin, yMax - yMin) .SelectMany(y => Enumerable.Range(zMin, zMax - zMin) .Select(z => new Point(x, y, z)))) .Where(a => !points.Contains(a) && points.Any(b => a.Y == b.Y && a.Z == b.Z && a.X > b.X) && points.Any(b => a.Y == b.Y && a.Z == b.Z && a.X < b.X) && points.Any(b => a.X == b.X && a.Y == b.Y && a.Z < b.Z) && points.Any(b => a.X == b.X && a.Y == b.Y && a.Z > b.Z) && points.Any(b => a.X == b.X && a.Z == b.Z && a.Y < b.Y) && points.Any(b => a.X == b.X && a.Z == b.Z && a.Y > b.Y)) .ToHashSet(); Two = One - GetSurfaceArea(airPockets); } private static int GetSurfaceArea(IReadOnlyCollection<Point> points) => points .Sum(p => Neighbours.Select(n => n + p).Count(n => !points.Contains(n))); }

Dold text

Dag 19: Spenderade alldeles för lÄng tid för att fÄ denna att köra inom rimlig tid.

namespace AOC2022.Puzzles; internal class Puzzle19 : Puzzle<int> { private static readonly Materials Ore = new (1, 0, 0, 0); private static readonly Materials Clay = new (0, 1, 0, 0); private static readonly Materials Obsidian = new (0, 0, 1, 0); private static readonly Materials Geode = new (0, 0, 0, 1); enum Resource { Ore, Clay, Obsidian, Geode } record Cost(Resource Resource, int Amount) { public Materials ToMaterials() => Resource switch { Resource.Ore => new Materials(Amount, 0, 0, 0), Resource.Clay => new Materials(0, Amount, 0, 0), Resource.Obsidian => new Materials(0, 0, Amount, 0), Resource.Geode => new Materials(0, 0, 0, Amount), _ => throw new InvalidOperationException() }; } record struct Blueprint(int Id, Materials OreCost, Materials ClayCost, Materials ObsidianCost, Materials GeodeCost) { public (Materials Robot, Materials Cost)[] Robots = new[] { (Geode, GeodeCost), (Obsidian, ObsidianCost), (Clay, ClayCost), (Ore, OreCost) }; } record struct Materials(int Ore, int Clay, int Obsidian, int Geode) { public static bool operator >=(Materials a, Materials b) => a.Ore >= b.Ore && a.Clay >= b.Clay && a.Obsidian >= b.Obsidian && a.Geode >= b.Geode; public static bool operator <=(Materials a, Materials b) => a.Ore <= b.Ore && a.Clay <= b.Clay && a.Obsidian <= b.Obsidian && a.Geode <= b.Geode; public static Materials operator +(Materials a, Materials b) => new(a.Ore + b.Ore, a.Clay + b.Clay, a.Obsidian + b.Obsidian, a.Geode + b.Geode); public static Materials operator -(Materials a, Materials b) => new(a.Ore - b.Ore, a.Clay - b.Clay, a.Obsidian - b.Obsidian, a.Geode - b.Geode); } record struct Fortress(int MinutesRemaining, Materials Robots, Materials Inventory, (Materials Robot, Materials Cost)[]? Ignore) { public IEnumerable<Fortress> GetNextPossibleStates(Blueprint blueprint, int maxGeodes) { if (!(Inventory.Geode > (maxGeodes - 2))) { yield break; } if (!WorthBuilding(blueprint)) { yield break; } var inv = Inventory; var buildableRobots = blueprint.Robots .Where(x => x.Cost <= inv) .ToArray(); yield return this with { Inventory = Robots + Inventory, MinutesRemaining = MinutesRemaining - 1, Ignore = buildableRobots }; foreach (var robot in buildableRobots) { if (Ignore == null || !Ignore.Contains(robot)) { yield return this with { Robots = Robots + robot.Robot, Inventory = Robots + Inventory - robot.Cost, MinutesRemaining = MinutesRemaining - 1, Ignore = null }; if (robot.Robot == Geode) { yield break; } } } } public int PotentialGeodeCount() { var future = (Robots.Geode + Robots.Geode + MinutesRemaining) * MinutesRemaining / 2; return Inventory.Geode + future; } public bool WorthBuilding(Blueprint blueprint) { return blueprint.GeodeCost.Ore > Robots.Ore || blueprint.GeodeCost.Clay > Robots.Clay || blueprint.GeodeCost.Obsidian > Robots.Obsidian; } public override int GetHashCode() { return HashCode.Combine(MinutesRemaining, Robots, Inventory); } } protected override void Solve(string[] lines) { var blueprints = lines .Select(lines => { var blueprintIdx = lines.IndexOf(':'); var id = int.Parse(lines[10..blueprintIdx]); var costs = lines[blueprintIdx..] .Split('.', StringSplitOptions.TrimEntries) .Select(robot => ParseCost(robot).Aggregate(new Materials(0, 0, 0, 0), (a, b) => a + b.ToMaterials())) .ToList(); return new Blueprint(id, costs[0], costs[1], costs[2], costs[3]); }) .ToList(); One = blueprints .AsParallel() .Sum(x => CrackGeodes(x, 24) * x.Id); Two = blueprints .Where(x => x.Id <= 3) .AsParallel() .Select(x => CrackGeodes(x, 32)) .Aggregate(1, (a, b) => a * b); } private static int CrackGeodes(Blueprint blueprint, int minutes) { var fortress = new PriorityQueue<Fortress, int>(); var start = new Fortress(minutes, new Materials(1,0,0,0), new Materials(0,0,0,0), null); var seen = new HashSet<Fortress>(); var max = 0; fortress.Enqueue(start, -start.PotentialGeodeCount()); while (fortress.TryDequeue(out var arsenal, out var prio)) { if (prio * -1 < max) { break; } if (seen.Contains(arsenal)) { continue; } seen.Add(arsenal); if (arsenal.MinutesRemaining == 0) { max = Math.Max(max, arsenal.Inventory.Geode); } else { fortress.EnqueueRange(arsenal.GetNextPossibleStates(blueprint, max) .Select(x => (x, -x.PotentialGeodeCount()))); } } return max; } private static IEnumerable<Cost> ParseCost(string costStr) { var parts = costStr.Split(' ').Skip(2).ToList(); return Enum.GetValues<Resource>() .Select(x => { var idx = parts.LastIndexOf(x.ToString().ToLower()); return idx == -1 ? null : new Cost(x, int.Parse(parts[idx - 1])); }) .Where(x => x != null)!; } }

Dold text

Dag 20:

namespace AOC2022.Puzzles; internal class Puzzle20 : Puzzle<long> { record struct Number(int Idx, long Val); protected override void Solve(string[] lines) { var numbers = lines.Select((x, idx) => new Number(idx, int.Parse(x))).ToList(); One = Solve(numbers, 1, 1); Two = Solve(numbers, 811589153, 10); } private static long Solve(List<Number> source, long multiplyer, int mixAmount) { if (multiplyer != 1) { source = source.Select(x => new Number(x.Idx, x.Val * multiplyer)).ToList(); } var numbers = new LinkedList<Number>(source); LinkedListNode<Number> start = null!; foreach (var number in Enumerable.Range(0, mixAmount).SelectMany(_ => source)) { var prevNode = numbers.Find(number)!; if (number.Val == 0) { start = prevNode; continue; } var range = Enumerable.Range(0, Math.Abs((int)(number.Val % (source.Count - 1)))); var newNode = number.Val > 0 ? range.Aggregate(prevNode, (a, _) => a.Next ?? numbers.First!) : range.Aggregate(prevNode, (a, _) => a.Previous ?? numbers.Last!); if (prevNode == newNode) { continue; } numbers.Remove(prevNode); if (number.Val > 0) { numbers.AddAfter(newNode, number); } else { numbers.AddBefore(newNode, number); } } return Enumerable.Range(1, 3).Sum(x => Enumerable.Range(0, x * 1000 % source.Count) .Aggregate(start, (a, b) => a.Next ?? numbers.First!)!.Value.Val); } }

Dold text

Dag 21:

namespace AOC2022.Puzzles; internal class Puzzle21 : Puzzle<long> { interface IMonkey { long GetValue(); } class MathMonkey : IMonkey { public MathMonkey(string operation) => Operation = operation; public IMonkey First { get; set; } = null!; public IMonkey Second { get; set; } = null!; public string Operation { get; } public long GetValue() { var first = First.GetValue(); var second = Second.GetValue(); return Operation switch { "+" => first + second, "-" => first - second, "*" => first * second, "/" => first / second, _ => throw new InvalidOperationException() }; } } class ValueMonkey : IMonkey { public ValueMonkey(long value) => _value = value; public long _value; public long GetValue() => _value; } protected override void Solve(string[] lines) { var monkeys = CreateMonkeys(lines); var root = (MathMonkey)monkeys["root"]; One = root.GetValue(); var humn = (ValueMonkey)monkeys["humn"]; var next = root; var expectedValue = (HasMonkey(next.First, humn) ? next.Second : next.First).GetValue(); while ((next = GetNextTowards(next, humn) as MathMonkey) != null) { var goLeft = HasMonkey(next.First, humn); expectedValue = SolveEquation(goLeft, expectedValue, (goLeft ? next.Second : next.First).GetValue(), next.Operation); } Two = expectedValue; } private static IMonkey? GetNextTowards(IMonkey root, IMonkey target) { if (root == target || root is not MathMonkey mathMonkey) { return null; } return HasMonkey(mathMonkey.First, target) ? mathMonkey.First : mathMonkey.Second;; } private static bool HasMonkey(IMonkey root, IMonkey target) { if (root == target) { return true; } if (root is not MathMonkey mathMonkey) { return false; } return HasMonkey(mathMonkey.First, target) || HasMonkey(mathMonkey.Second, target); } private static long SolveEquation(bool goingLeft, long expectedValue, long frozenValue, string operation) => (goingLeft, operation) switch { (_, "*") => expectedValue / frozenValue, (_, "+") => expectedValue - frozenValue, (true, "/") => expectedValue * frozenValue, (true, "-") => expectedValue + frozenValue, (false, "/") => frozenValue / expectedValue, (false, "-") => frozenValue - expectedValue, _ => throw new InvalidOperationException(), }; private static IDictionary<string, IMonkey> CreateMonkeys(string[] lines) { var monkeys = lines .Select(line => { var nameIdx = line.IndexOf(':'); var name = line[0..nameIdx]; var operation = line[(nameIdx + 1)..].Split(' ', StringSplitOptions.RemoveEmptyEntries); IMonkey monkey = operation.Length == 1 ? new ValueMonkey(long.Parse(operation[0])) : new MathMonkey(operation[1]); return (name, monkey); }) .ToDictionary(x => x.name, x => x.monkey); ConnectMonkeys(lines, monkeys); return monkeys; } private static void ConnectMonkeys(string[] lines, IDictionary<string, IMonkey> monkeys) { foreach (var line in lines) { var nameIdx = line.IndexOf(':'); var name = line[0..nameIdx]; var monkey = monkeys[name]; if (monkey is not MathMonkey mathMonkey) { continue; } var operation = line[(nameIdx + 1)..].Split(' ', StringSplitOptions.RemoveEmptyEntries); mathMonkey.First = monkeys[operation[0]]; mathMonkey.Second = monkeys[operation[2]]; } } }

Dold text
Dold text
PermalÀnk
Medlem
●

Dag: 22
SprÄk: C#

using System.Text.RegularExpressions; namespace AOC2022.Puzzles; internal partial class Puzzle22 : Puzzle<int> { [GeneratedRegex("(R|L)")] private static partial Regex InstructionRegex(); public static readonly (int x, int y) Right = ( 1, 0); public static readonly (int x, int y) Down = ( 0, 1); public static readonly (int x, int y) Left = (-1, 0); public static readonly (int x, int y) Up = ( 0, -1); public static readonly List<(int x, int y)> Vectors = new List<(int x, int y)> { Right, Down, Left, Up }; delegate ((int x, int y) gridIdx, (int x, int y) pos, (int x, int y) vector) OobFunc((int x, int y) gridIdx, (int x, int y) vector, (int x, int y) current); protected override void Solve(string[] lines) { var grids = CreateGrids(lines); var gridlist = Iterate(grids) .Where(p => grids[p.x, p.y] != null) .Select(p => grids[p.x, p.y]) .ToList(); var getGridIndex = (int x, int y) => gridlist.IndexOf(grids[x, y]); var instructions = InstructionRegex().Split(lines[^1]); One = Walk(grids, instructions, (gridIdx, vector, current) => { char[,]? nextGrid = null; var newGridIdx = gridIdx; while (nextGrid == null) { var x = (newGridIdx.x + vector.x) % grids.GetLength(0); if (x == -1) { x = grids.GetLength(0) - 1; } var y = (newGridIdx.y + vector.y) % grids.GetLength(1); if (y == -1) { y = grids.GetLength(1) - 1; } nextGrid = grids[x, y]; newGridIdx = (x, y); } var pos = vector switch { { x: 1 } => (0, current.y), { x: -1 } => (49, current.y), { y: 1 } => (current.x, 0), _ => (current.x, 49), }; return (gridIdx: newGridIdx, pos, vector); }); Two = Walk(grids, instructions, (gridIdx, vector, current) => { var gridIndex = getGridIndex(gridIdx.x, gridIdx.y); var (newGridIndex, newVector, newPos) = gridIndex switch { 0 when vector == Right => (1, Right, (0, current.y)), 0 when vector == Down => (2, Down, (current.x, 0)), 0 when vector == Left => (3, Right, (0, 49 - current.y)), 0 when vector == Up => (5, Right, (0, current.x)), 1 when vector == Right => (4, Left, (49, 49 - current.y)), 1 when vector == Down => (2, Left, (49, current.x)), 1 when vector == Left => (0, Left, (49, current.y)), 1 when vector == Up => (5, Up, (current.x, 49)), 2 when vector == Right => (1, Up, (current.y, 49)), 2 when vector == Down => (4, Down, (current.x, 0)), 2 when vector == Left => (3, Down, (current.y, 0)), 2 when vector == Up => (0, Up, (current.x, 49)), 3 when vector == Right => (4, Right, (0, current.y)), 3 when vector == Down => (5, Down, (current.x, 0)), 3 when vector == Left => (0, Right, (0, 49 - current.y)), 3 when vector == Up => (2, Right, (0, current.x)), 4 when vector == Right => (1, Left, (49, 49 - current.y)), 4 when vector == Down => (5, Left, (49, current.x)), 4 when vector == Left => (3, Left, (49, current.y)), 4 when vector == Up => (2, Up, (current.x, 49)), 5 when vector == Right => (4, Up, (current.y, 49)), 5 when vector == Down => (1, Down, (current.x, 0)), 5 when vector == Left => (0, Down, (current.y, 0)), 5 when vector == Up => (3, Up, (current.x, 49)), _ => throw new InvalidOperationException() }; var newGrid = gridlist[newGridIndex]; var newGridIdx = Iterate(grids).First(p => grids[p.x, p.y] == newGrid); return (newGridIdx, newPos, newVector); }); } private static int Walk(char[,][,] grids, string[] instructions, OobFunc oobFunc) { var vec = Right; var pos = (x: 0, y: 0); var gridIdx = (x: 1, y: 0); foreach (var instruction in instructions) { if (int.TryParse(instruction, out var forward)) { foreach (var _ in Enumerable.Range(0, forward)) { var next = (gridIdx, pos: (x: pos.x + vec.x, y: pos.y + vec.y) , vec); if (Grid.IsOutOfRange(grids[gridIdx.x, gridIdx.y], next.pos)) { next = oobFunc(gridIdx, vec, pos); } if (grids[next.gridIdx.x, next.gridIdx.y][next.pos.x, next.pos.y] == '#') { break; } pos = next.pos; gridIdx = next.gridIdx; vec = next.vec; } } else { var vectorIdx = Vectors.IndexOf(vec); var newVectorIdx = instruction == "R" ? (vectorIdx + 1) % Vectors.Count : vectorIdx == 0 ? (Vectors.Count - 1) : (vectorIdx - 1); vec = Vectors[newVectorIdx]; } } return (1 + pos.y + (gridIdx.y * 50)) * 1000 + 4 * (1 + pos.x + (gridIdx.x * 50)) + Vectors.IndexOf(vec); } private static IEnumerable<(int x, int y)> Iterate<T>(T[,] arr) => Enumerable.Range(0, arr.GetLength(1)) .SelectMany(y => Enumerable.Range(0, arr.GetLength(0)).Select(x => (x, y))); private static char[,][,] CreateGrids(string[] lines) { var grid = Grid.CreateGrid(lines[..^2], x => x, ' '); var grids = new char[3, 4][,]; foreach (var gridIdx in Enumerable.Range(0, 12)) { var gridX = gridIdx % 3; var gridY = gridIdx / 3; var xStart = gridX * 50; var yStart = gridY * 50; if (Grid.IsOutOfRange(grid, (xStart, yStart)) || grid[xStart, yStart] == ' ') { continue; } var curGrid = new char[50, 50]; foreach (var (x, y) in Enumerable.Range(0, 50) .SelectMany(y => Enumerable.Range(0, 50).Select(x => (x, y)))) { var pos = (x: x + xStart, y: y + yStart); curGrid[x, y] = grid[pos.x, pos.y]; } grids[gridX, gridY] = curGrid; } return grids; } }

Dold text
PermalÀnk
Medlem
●

Dag: 12
SprÄk: Basic v2.0 (Commodore 64)
Ca: 3sek körtid, (îč…=Shift-E)

0 DIMA$(40):FORX=0TO4:READA$:FORZ=1TO8:A$((X*8)+Z-1)=MID$(A$,Z,1):NEXTZ:NEXTX
1 FORZ=0TO3:READZ(Z):NEXT
2 T=T+1:FORI=0TO3:Z=XY+Z(I):IFZ>39THENNEXT
3 IFA$(XY)="Z"THENIFA$(Z)="îč…"THENPRINTT:END
4 IFASC(A$(XY))+1=ASC(A$(Z))THENA$(XY)=CHR$(T+192):XY=Z:GOTO2
5 IFASC(A$(XY))=ASC(A$(Z))THEN:A$(XY)=CHR$(T+192):XY=Z:GOTO2
6 NEXT:DATA"@ABQPONM","ABCRYXXL","ACCSZîč…XK","ACCTUVWJ","ABDEFGHI",1,8,-1,-8

Dold text
Visa signatur

‱‱‱‱    ¹˜”°ÂșXTROÂș°”˜¹ ‱‱‱‱ ‱‱‱‱ Letar du efter nĂ„got? ‱‱‱‱ ‱‱‱‱  The Little Ninja  ‱‱‱‱
‱‱‱‱ C64 0.98MHz/64K ‱‱‱‱ ‱‱‱‱   Prova det ultimata!   ‱‱‱‱ ‱‱‱‱ Komplett Cracktro ‱‱‱‱
‱‱‱‱  -Tack för sĂ„sen..  ‱‱‱‱ ‱‱‱‱     GO `GOOGLEÂŽ NOW   ‱‱‱‱ ‱‱‱‱    250bytes Intro   ‱‱‱‱

PermalÀnk
Medlem
●

Jaha, nu var Ă„rets upplaga slut! NĂ„gra reflektioner?

Det hÀr var första Äret jag gjorde AoC (och dag 1 var första rust-programmet jag nÄgonsin skrivit) och jag mÄste sÀga att det var vÀldigt tillfredsstÀllande att skapa ihop stjÀrnor och jag lyckades fÄ ihop alla 50, alla utom en pÄ rÀtt dag Jag tyckte det var kul variation pÄ problem och svÄrighetsnivÄer, men favoriten Àr nog dag 22 eller 24 medan dag 16 var den mest frustrerade. Har ni andra nÄgon dag som ni tyckte var speciell?

Om nÄn - mot förmodan - vill se sÄ finns alla mina lösningar pÄ: https://github.com/abelsson/aoc2022