main.rs (3424B)
1 use std::cmp::Ordering; 2 use std::collections::HashMap; 3 4 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] 5 struct Coord(i32, i32); 6 7 impl Coord { 8 fn from_str(s: &str) -> Self { 9 let tmp = s 10 .split(',') 11 .map(|x| x.parse::<i32>().unwrap()) 12 .collect::<Vec<i32>>(); 13 Self(tmp[0], tmp[1]) 14 } 15 } 16 17 #[derive(Debug, Clone, Copy)] 18 enum Terrain { 19 Sand, 20 Rock, 21 } 22 23 fn sign(a: i32) -> i32 { 24 match a.cmp(&0) { 25 Ordering::Less => -1, 26 Ordering::Equal => 0, 27 Ordering::Greater => 1, 28 } 29 } 30 31 fn main() { 32 let input = { 33 let mut tmp = HashMap::new(); 34 for l in std::fs::read_to_string("input.txt") 35 .unwrap() 36 .trim() 37 .split('\n') 38 { 39 let points = l 40 .split(" -> ") 41 .map(|s| Coord::from_str(s)) 42 .collect::<Vec<Coord>>(); 43 let mut curr = points[0]; 44 tmp.insert(curr, Terrain::Rock); 45 for next in &points[1..] { 46 while curr != *next { 47 curr = Coord( 48 curr.0 + sign(next.0 - curr.0), 49 curr.1 + sign(next.1 - curr.1), 50 ); 51 tmp.insert(curr, Terrain::Rock); 52 } 53 } 54 } 55 tmp 56 }; 57 let source = Coord(500, 0); 58 // 1072 59 println!("Part 1: {}", part_1(&input, source)); 60 // 24659 61 println!("Part 2: {}", part_2(&input, source, 2)); 62 } 63 64 fn part_1(input: &HashMap<Coord, Terrain>, source: Coord) -> usize { 65 let y_max = input.keys().map(|c| c.1).max().unwrap(); 66 let mut sim: HashMap<Coord, Terrain> = input.clone(); 67 'outer: loop { 68 let mut sand_curr = source; 69 while sand_curr.1 < y_max { 70 let mut comes_to_rest = true; 71 for (dx, dy) in [(0, 1), (-1, 1), (1, 1)] { 72 let sand_next = Coord(sand_curr.0 + dx, sand_curr.1 + dy); 73 if !sim.contains_key(&sand_next) { 74 sand_curr = sand_next; 75 comes_to_rest = false; 76 break; 77 } 78 } 79 if comes_to_rest { 80 sim.insert(sand_curr, Terrain::Sand); 81 continue 'outer; 82 } 83 } 84 break; 85 } 86 sim.values() 87 .filter(|x| if let Terrain::Sand = x { true } else { false }) 88 .count() 89 } 90 91 fn part_2(input: &HashMap<Coord, Terrain>, source: Coord, floor_offset: i32) -> usize { 92 let y_max = input.keys().map(|c| c.1).max().unwrap() + floor_offset; 93 let mut sim: HashMap<Coord, Terrain> = input.clone(); 94 while !sim.contains_key(&source) { 95 let mut sand_curr = source; 96 loop { 97 let mut comes_to_rest = true; 98 for (dx, dy) in [(0, 1), (-1, 1), (1, 1)] { 99 let sand_next = Coord(sand_curr.0 + dx, sand_curr.1 + dy); 100 if !sim.contains_key(&sand_next) { 101 sand_curr = sand_next; 102 comes_to_rest = false; 103 break; 104 } 105 } 106 comes_to_rest = comes_to_rest || sand_curr.1 == y_max - 1; 107 if comes_to_rest { 108 sim.insert(sand_curr, Terrain::Sand); 109 break; 110 } 111 } 112 } 113 sim.values() 114 .filter(|x| if let Terrain::Sand = x { true } else { false }) 115 .count() 116 }