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 }