Browse Source

Day 3 part 1

Tyler Hallada 5 years ago
parent
commit
e54d9297ff
7 changed files with 1666 additions and 0 deletions
  1. 91 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 1401 0
      inputs/3.txt
  4. 3 0
      inputs/3_test.txt
  5. 3 0
      inputs/3_test_malformed.txt
  6. 164 0
      src/day3.rs
  7. 3 0
      src/main.rs

+ 91 - 0
Cargo.lock

@@ -1,4 +1,95 @@
1 1
 [[package]]
2 2
 name = "advent-of-code-2018"
3 3
 version = "0.1.0"
4
+dependencies = [
5
+ "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
6
+]
4 7
 
8
+[[package]]
9
+name = "aho-corasick"
10
+version = "0.6.9"
11
+source = "registry+https://github.com/rust-lang/crates.io-index"
12
+dependencies = [
13
+ "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
14
+]
15
+
16
+[[package]]
17
+name = "cfg-if"
18
+version = "0.1.6"
19
+source = "registry+https://github.com/rust-lang/crates.io-index"
20
+
21
+[[package]]
22
+name = "lazy_static"
23
+version = "1.2.0"
24
+source = "registry+https://github.com/rust-lang/crates.io-index"
25
+
26
+[[package]]
27
+name = "libc"
28
+version = "0.2.45"
29
+source = "registry+https://github.com/rust-lang/crates.io-index"
30
+
31
+[[package]]
32
+name = "memchr"
33
+version = "2.1.2"
34
+source = "registry+https://github.com/rust-lang/crates.io-index"
35
+dependencies = [
36
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
37
+ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
38
+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
39
+]
40
+
41
+[[package]]
42
+name = "regex"
43
+version = "1.1.0"
44
+source = "registry+https://github.com/rust-lang/crates.io-index"
45
+dependencies = [
46
+ "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
47
+ "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
48
+ "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
49
+ "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
50
+ "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
51
+]
52
+
53
+[[package]]
54
+name = "regex-syntax"
55
+version = "0.6.4"
56
+source = "registry+https://github.com/rust-lang/crates.io-index"
57
+dependencies = [
58
+ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
59
+]
60
+
61
+[[package]]
62
+name = "thread_local"
63
+version = "0.3.6"
64
+source = "registry+https://github.com/rust-lang/crates.io-index"
65
+dependencies = [
66
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
67
+]
68
+
69
+[[package]]
70
+name = "ucd-util"
71
+version = "0.1.3"
72
+source = "registry+https://github.com/rust-lang/crates.io-index"
73
+
74
+[[package]]
75
+name = "utf8-ranges"
76
+version = "1.0.2"
77
+source = "registry+https://github.com/rust-lang/crates.io-index"
78
+
79
+[[package]]
80
+name = "version_check"
81
+version = "0.1.5"
82
+source = "registry+https://github.com/rust-lang/crates.io-index"
83
+
84
+[metadata]
85
+"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
86
+"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
87
+"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
88
+"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
89
+"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9"
90
+"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
91
+"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
92
+"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
93
+"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
94
+"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
95
+"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"

+ 1 - 0
Cargo.toml

@@ -5,3 +5,4 @@ authors = ["Tyler Hallada <tyler@hallada.net>"]
5 5
 edition = "2018"
6 6
 
7 7
 [dependencies]
8
+regex = "1"

File diff suppressed because it is too large
+ 1401 - 0
inputs/3.txt


+ 3 - 0
inputs/3_test.txt

@@ -0,0 +1,3 @@
1
+#1 @ 1,3: 4x4
2
+#2 @ 3,1: 4x4
3
+#3 @ 5,5: 2x2

+ 3 - 0
inputs/3_test_malformed.txt

@@ -0,0 +1,3 @@
1
+#1 @ 1,3: 4x4
2
+#2 @  3,1: 4x4
3
+#3 @ 5,5: 2x2

+ 164 - 0
src/day3.rs

@@ -0,0 +1,164 @@
1
+extern crate regex;
2
+
3
+use std::error::Error;
4
+use std::fs::File;
5
+use std::io::{BufRead, BufReader};
6
+use std::fmt;
7
+use std::collections::HashMap;
8
+
9
+use regex::{Regex, Captures};
10
+
11
+const INPUT: &str = "inputs/3.txt";
12
+
13
+#[derive(Debug, PartialEq)]
14
+struct Claim {
15
+    id: u32,
16
+    left: u32,
17
+    top: u32,
18
+    width: u32,
19
+    height: u32,
20
+}
21
+
22
+#[derive(Debug, PartialEq, Eq, Hash)]
23
+struct Point {
24
+    x: u32,
25
+    y: u32,
26
+}
27
+
28
+#[derive(Debug, Clone, PartialEq)]
29
+struct MalformedClaim {
30
+    details: String
31
+}
32
+
33
+impl MalformedClaim {
34
+    fn new(msg: &str) -> MalformedClaim {
35
+        MalformedClaim{ details: msg.to_string() }
36
+    }
37
+}
38
+
39
+impl fmt::Display for MalformedClaim {
40
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41
+        write!(f, "{}", self.details)
42
+    }
43
+}
44
+
45
+impl Error for MalformedClaim {
46
+    fn description(&self) -> &str {
47
+        &self.details
48
+    }
49
+}
50
+
51
+pub fn solve_part1() -> Result<u32, Box<Error>> {
52
+    Ok(count_overlapping_claimed_points(read_claims(INPUT)?))
53
+}
54
+
55
+fn count_overlapping_claimed_points(claims: Vec<Claim>) -> u32 {
56
+    let mut claimed_points: HashMap<Point, u32> = HashMap::new();
57
+    for claim in claims {
58
+        for point in list_points_in_claim(claim) {
59
+            let current_point = claimed_points.get(&point).unwrap_or(&0);
60
+            claimed_points.insert(point, current_point + 1);
61
+        }
62
+    }
63
+    return claimed_points.values().fold(0, |acc, claims| {
64
+        if claims > &1 {
65
+            return acc + 1
66
+        }
67
+        acc
68
+    })
69
+}
70
+
71
+fn list_points_in_claim(claim: Claim) -> Vec<Point> {
72
+    let mut points = Vec::new();
73
+    for x in 0..claim.width {
74
+        for y in 0..claim.height {
75
+            points.push(Point { x: claim.left + x, y: claim.top + y });
76
+        }
77
+    }
78
+    points
79
+}
80
+
81
+fn read_claims(filename: &str) -> Result<Vec<Claim>, Box<Error>> {
82
+    let mut claims: Vec<Claim> = Vec::new();
83
+    let claim_regex =
84
+        Regex::new(r"#(?P<id>\d+) @ (?P<left>\d+),(?P<top>\d+): (?P<width>\d+)x(?P<height>\d+)")?;
85
+    let file = File::open(filename)?;
86
+    for line in BufReader::new(file).lines() {
87
+        match claim_regex.captures(&line?) {
88
+            Some(captures) => {
89
+                let claim = Claim {
90
+                    id: get_captured_field(&captures, "id")?,
91
+                    left: get_captured_field(&captures, "left")?,
92
+                    top: get_captured_field(&captures, "top")?,
93
+                    width: get_captured_field(&captures, "width")?,
94
+                    height: get_captured_field(&captures, "height")?,
95
+                };
96
+                claims.push(claim);
97
+            },
98
+            None => return Err(Box::new(MalformedClaim {
99
+                details: "Malformed claim line, no fields could be found".to_string()
100
+            })),
101
+        };
102
+    }
103
+    Ok(claims)
104
+}
105
+
106
+fn get_captured_field(captures: &Captures, field: &str) -> Result<u32, Box<Error>> {
107
+    match captures.name(field) {
108
+        Some(capture) => Ok(capture.as_str().parse()?),
109
+        None => return Err(Box::new(MalformedClaim {
110
+            details: format!("Malformed claim line, field {} could not be found", field)
111
+        }))
112
+    }
113
+}
114
+
115
+
116
+#[cfg(test)]
117
+mod tests {
118
+    use super::*;
119
+
120
+    const TEST_INPUT: &str = "inputs/3_test.txt";
121
+    const TEST_INPUT_MALFORMED: &str = "inputs/3_test_malformed.txt";
122
+
123
+    #[test]
124
+    fn reads_claims_file() {
125
+        assert_eq!(read_claims(TEST_INPUT).unwrap(), vec![
126
+            Claim { id: 1, left: 1, top: 3, width: 4, height: 4 },
127
+            Claim { id: 2, left: 3, top: 1, width: 4, height: 4 },
128
+            Claim { id: 3, left: 5, top: 5, width: 2, height: 2 },
129
+        ]);
130
+    }
131
+
132
+    #[test]
133
+    fn errors_on_malformed_claims_file() {
134
+        match read_claims(TEST_INPUT_MALFORMED) {
135
+            Ok(_) => assert!(false, "read_claims should have returned an error"),
136
+            Err(err) => assert_eq!(
137
+                (*err).description(),
138
+                "Malformed claim line, no fields could be found".to_string(),
139
+            ),
140
+        }
141
+    }
142
+
143
+    #[test]
144
+    fn lists_points_in_claim() {
145
+        assert_eq!(list_points_in_claim(Claim { id: 1, left: 0, top: 0, width: 2, height: 2 }),
146
+            vec![
147
+                Point { x: 0, y: 0 },
148
+                Point { x: 0, y: 1 },
149
+                Point { x: 1, y: 0 },
150
+                Point { x: 1, y: 1 },
151
+            ]
152
+        )
153
+    }
154
+
155
+    #[test]
156
+    fn counts_overlapping_claimed_points() {
157
+        let test_claims = vec![
158
+            Claim { id: 1, left: 1, top: 3, width: 4, height: 4 },
159
+            Claim { id: 2, left: 3, top: 1, width: 4, height: 4 },
160
+            Claim { id: 3, left: 5, top: 5, width: 2, height: 2 },
161
+        ];
162
+        assert_eq!(count_overlapping_claimed_points(test_claims), 4);
163
+    }
164
+}

+ 3 - 0
src/main.rs

@@ -1,5 +1,6 @@
1 1
 mod day1;
2 2
 mod day2;
3
+mod day3;
3 4
 
4 5
 fn main() {
5 6
     println!("Day 1:");
@@ -8,4 +9,6 @@ fn main() {
8 9
     println!("Day 2:");
9 10
     println!("{}", day2::solve_part1().unwrap());
10 11
     println!("{}", day2::solve_part2().unwrap().unwrap());
12
+    println!("Day 3:");
13
+    println!("{}", day3::solve_part1().unwrap());
11 14
 }