Add day 2

Day 2 was a breeze, and part 2 followed on very nicely from part 1.

I expected part 2 to be something similar to the elf not adding cubes
back into the bag, but I was able to adapt my solution just fine anyway.

Nothing much to say beyond that, but I always expect early AOC to be
easy enough - I'm sure I'll be porting my Python pathfinding library to
Rust soon enough ;)

Change-Id: Ic9daab4439b68885375cb5fcb9c6728db6ef4f47
Reviewed-on: https://git.clicks.codes/c/Minion/AdventOfCode/2023/+/99
diff --git a/.gitignore b/.gitignore
index 5f518d3..64a7457 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 *.log
 tmp/
 input.txt
+target/
diff --git a/day2/Cargo.lock b/day2/Cargo.lock
new file mode 100644
index 0000000..63c2f60
--- /dev/null
+++ b/day2/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "day2"
+version = "0.1.0"
diff --git a/day2/Cargo.toml b/day2/Cargo.toml
new file mode 100644
index 0000000..8aa34bb
--- /dev/null
+++ b/day2/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "day2"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/day2/src/main.rs b/day2/src/main.rs
new file mode 100644
index 0000000..9e11667
--- /dev/null
+++ b/day2/src/main.rs
@@ -0,0 +1,72 @@
+fn main() {
+    let input = include_str!("../input.txt");
+
+    let mut part1_possible_id_sum = 0;
+    let mut game_power_sum = 0;
+
+    for (index, line) in input.split('\n').enumerate() {
+        if line == "" {
+            continue;
+        }
+
+        let game_data = line.split(": ").collect::<Vec<&str>>()[1];
+
+        let mut part1_possible = true;
+        let mut min_red = 0;
+        let mut min_green = 0;
+        let mut min_blue = 0;
+
+        for round in game_data.split("; ") {
+
+            for draw in round.split(", ") {
+                let [number_as_text, color] = draw.split(" ").collect::<Vec<&str>>()[..] else { panic!("Unparseable draw") };
+
+                let number = number_as_text.parse::<i32>().unwrap();
+
+                match color {
+                    "red" => {
+                        if number > 12 {
+                            part1_possible = false;
+                        }
+                        if number > min_red {
+                            min_red = number;
+                        }
+                    },
+                    "green" => {
+                        if number > 13 {
+                            part1_possible = false;
+                        }
+                        if number > min_green {
+                            min_green = number;
+                        }
+                    },
+                    "blue" => {
+                        if number > 14 {
+                            part1_possible = false;
+                        }
+                        if number > min_blue {
+                            min_blue = number;
+                        }
+                    },
+                    noncolor => {
+                        panic!("bogus color {}", noncolor);
+                    }
+                }
+            }
+        }
+
+        if part1_possible {
+            part1_possible_id_sum += index + 1;
+            println!("Game {} is possible with 12, 13, 14", index + 1);
+        } else {
+            println!("Game {} is not possible with 12, 13, 14", index + 1);
+        }
+
+        let game_power = min_red * min_green * min_blue;
+        game_power_sum += game_power;
+        println!("Game {} has power {}", index + 1, game_power);
+    }
+
+    println!("Possible with 12, 13, 14 ID sum: {}", part1_possible_id_sum);
+    println!("Game power sum: {}", game_power_sum);
+}