aoc

My solutions for the Advent of Code
git clone https://git.tronto.net/aoc
Download | Log | Files | Refs | README

commit bce2009698f7ef4ba066ee5122500fe32c1289cd
parent 7e4982be44b980ccbe00c88a66abd773dba62f1a
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Wed,  2 Jul 2025 11:21:58 +0200

Day 14 2022

Diffstat:
A2022/14/a.rs | 22++++++++++++++++++++++
A2022/14/b.rs | 22++++++++++++++++++++++
A2022/14/common.rs | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 173 insertions(+), 0 deletions(-)

diff --git a/2022/14/a.rs b/2022/14/a.rs @@ -0,0 +1,22 @@ +mod common; +use common::*; + +fn drop(map: &mut Map, i: (usize, usize)) -> bool { + let (x, y) = i; + if y > map.ymax { return false; } + + for j in vec![(x, y+1), (x-1, y+1), (x+1, y+1)].into_iter() { + if !map.at(j) { return drop(map, j); } + } + + map[i] = true; + true +} + +fn main() { + let mut map = read_map_from_stdin(); + let mut i = 0; + while drop(&mut map, (500, 0)) { i+= 1; } + //map.print(); + println!("{i}"); +} diff --git a/2022/14/b.rs b/2022/14/b.rs @@ -0,0 +1,22 @@ +mod common; +use common::*; + +fn drop(map: &mut Map, i: (usize, usize)) -> bool { + let (x, y) = i; + if y < map.ymax { + for j in vec![(x, y+1), (x-1, y+1), (x+1, y+1)].into_iter() { + if !map.at(j) { return drop(map, j); } + } + } + + map[i] = true; + !map.at((500, 0)) // Returns false after filling the last -> off by 1 +} + +fn main() { + let mut map = read_map_from_stdin(); + let mut i = 0; + while drop(&mut map, (500, 0)) { i += 1; } + //map.print(); + println!("{}", i+1); +} diff --git a/2022/14/common.rs b/2022/14/common.rs @@ -0,0 +1,129 @@ +use std::cmp::{min, max}; +use std::ops::{Index, IndexMut}; + +pub struct Map { + cells: Vec<Vec<bool>>, + pub xmin: usize, + pub xmax: usize, + pub ymin: usize, + pub ymax: usize +} + +fn line_from_str(s: &str) -> Vec<(usize, usize)> { + let mut line = vec![]; + let mut i = 0; + while i < s.len() { + let mut j = s[i..].find(',').unwrap(); + let x = s[i..i+j].parse::<usize>().unwrap(); + i += j+1; + j = s[i..].find(|c| c == ' ' || c == '\n').unwrap(); + let y = s[i..i+j].parse::<usize>().unwrap(); + i += j+4; + line.push((x, y)); + } + line +} + +impl Index<(usize, usize)> for Map { + type Output = bool; + fn index(&self, i: (usize, usize)) -> &bool { + self.validate_index(i); + &self.cells[i.1-self.ymin][i.0-self.xmin] + } +} + +impl IndexMut<(usize, usize)> for Map { + fn index_mut(&mut self, i: (usize, usize)) -> &mut bool { + self.validate_index(i); + &mut self.cells[i.1-self.ymin][i.0-self.xmin] + } +} + +impl Map { + fn in_bounds(&self, i: (usize, usize)) -> bool { + i.0 >= self.xmin && i.0 <= self.xmax && + i.1 >= self.ymin && i.1 <= self.ymax + } + + fn validate_index(&self, i: (usize, usize)) { + if !self.in_bounds(i) { + panic!("Out of bounds: {} {} outside [{}, {}]x[{}, {}]", + i.0, i.1, self.xmin, self.xmax, self.ymin, self.ymax); + } + } + + pub fn at(&self, i: (usize, usize)) -> bool { + self.in_bounds(i) && self[i] + } + + fn set_bounds(&mut self, lines: &Vec<Vec<(usize, usize)>>) { + for l in lines { + for p in l { + self.xmin = min(self.xmin, p.0); + self.xmax = max(self.xmax, p.0); + self.ymin = min(self.ymin, p.1); + self.ymax = max(self.ymax, p.1+1); + } + } + + // Part 2 requires a larger map + self.xmin = min(self.xmin, 500 - self.ymax - 1); + self.xmax = max(self.xmax, 500 + self.ymax + 1); + self.cells = vec![ + vec![false; self.xmax-self.xmin+1]; self.ymax-self.ymin+1 + ]; + } + + fn fill_line(&mut self, line: &Vec<(usize, usize)>) { + for i in 0..line.len()-1 { + if line[i].0 == line[i+1].0 { + let y0 = min(line[i].1, line[i+1].1); + let y1 = max(line[i].1, line[i+1].1); + for y in y0..=y1 { + self[(line[i].0, y)] = true; + } + } else { + let x0 = min(line[i].0, line[i+1].0); + let x1 = max(line[i].0, line[i+1].0); + for x in x0..=x1 { + self[(x, line[i].1)] = true; + } + } + } + } + + fn from_lines(lines: &Vec<Vec<(usize, usize)>>) -> Map { + let mut map = Map { + cells: vec![], + xmin: 500, + xmax: 500, + ymin: 0, + ymax: 0 + }; + map.set_bounds(lines); + for l in lines { map.fill_line(l); } + map + } + + #[allow(dead_code)] + pub fn print(&self) { + println!("x: {} to {}", self.xmin, self.xmax); + println!("y: {} to {}", self.ymin, self.ymax); + for v in &self.cells { + for b in v { + print!("{}", if *b { '#' } else { '.' }); + } + println!(); + } + } +} + +pub fn read_map_from_stdin() -> Map { + let mut lines = Vec::<Vec<(usize, usize)>>::new(); + let mut s = String::new(); + while std::io::stdin().read_line(&mut s).unwrap() > 0 { + lines.push(line_from_str(&s)); + s.clear(); + } + Map::from_lines(&lines) +}