Add day 1

A little bit of a rough start... part 1 was very easy and I did it with
a simple for loop (is_digit and to_digit). Unfortunately part 2 required
a major rework, so the code here is basically just a full rewrite.
Sorry.

Being honest I was a bit surprised: I normally expect days 1-5 to be
quite a slow start, but here we are on part 2 and I've already been
thrown a curveball.

My solution here works with a regular expression and a hashmap, I had a
bit of trouble because I initially tried to use an enum to represent my
values (being either a number or a string) before realizing first that
it wasn't hashable and second that it was overcomplicated. This one just
uses strings. Much better.

I'm sure there are more elegant ways (for example I've seen a neat
algorithm with a rolling window to match digit groups), but throwing a
regex at the problem was quick.

Change-Id: I1ac283d75d6571b08b5d9439f181e9dd7f308ec0
Reviewed-on: https://git.clicks.codes/c/Minion/AdventOfCode/2023/+/91
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5f518d3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.DS_Store
+.idea
+*.log
+tmp/
+input.txt
diff --git a/day1/.gitignore b/day1/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/day1/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/day1/Cargo.lock b/day1/Cargo.lock
new file mode 100644
index 0000000..a5b49ab
--- /dev/null
+++ b/day1/Cargo.lock
@@ -0,0 +1,153 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "day1"
+version = "0.1.0"
+dependencies = [
+ "phf",
+ "regex",
+]
+
+[[package]]
+name = "memchr"
+version = "2.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+
+[[package]]
+name = "phf"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_macros",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+dependencies = [
+ "phf_shared",
+ "rand",
+]
+
+[[package]]
+name = "phf_macros"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+
+[[package]]
+name = "regex"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "syn"
+version = "2.0.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/day1/Cargo.toml b/day1/Cargo.toml
new file mode 100644
index 0000000..29b595c
--- /dev/null
+++ b/day1/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "day1"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+phf = { version = "0.11.2", features = [ "macros" ] }
+regex = "1.10.2"
diff --git a/day1/src/main.rs b/day1/src/main.rs
new file mode 100644
index 0000000..1779973
--- /dev/null
+++ b/day1/src/main.rs
@@ -0,0 +1,59 @@
+use regex::Regex;
+use phf::phf_map;
+
+static NUMBERS: phf::Map<&'static str, u8> = phf_map! {
+    "zero" => 0,
+    "one" => 1,
+    "two" => 2,
+    "three" => 3,
+    "four" => 4,
+    "five" => 5,
+    "six" => 6,
+    "seven" => 7,
+    "eight" => 8,
+    "nine" => 9,
+    "0" => 0,
+    "1" => 1,
+    "2" => 2,
+    "3" => 3,
+    "4" => 4,
+    "5" => 5,
+    "6" => 6,
+    "7" => 7,
+    "8" => 8,
+    "9" => 9,
+};
+
+
+fn main() {
+    let first_and_last_digits: Regex = Regex::new(r"(zero|one|two|three|four|five|six|seven|eight|nine|[0-9]).*(zero|one|two|three|four|five|six|seven|eight|nine|[0-9])").unwrap();
+    let only_one_digit: Regex = Regex::new(r"([0-9])").unwrap();
+    let input = include_str!("../input.txt");
+
+    let mut vals: Vec<u16> = vec![];
+
+    for line in input.split('\n') {
+        if line == "" {
+            continue;
+        }
+
+        let result = first_and_last_digits.captures(line);
+
+        let group1;
+        let group2;
+
+        if let Some(captured) = result {
+            [group1, group2] = captured.extract().1;
+        } else {
+            [group1] = only_one_digit.captures(line).expect("Line did not have a capture").extract().1;
+            group2 = group1;
+        }
+
+        let first_digit = NUMBERS.get(group1).expect("Regex group 1 and phf hashmap were mismatched");
+        let last_digit = NUMBERS.get(group2).expect("Regex group 2 and phf hashmap were mismatched");
+
+        vals.push((first_digit * 10 + last_digit).into());
+    }
+
+    println!("{}", vals.into_iter().fold(0, | acc, curr | acc + curr));
+}