summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2024-12-02 09:05:35 +0100
committerGravatar Tom van der Lee <tom@vanderlee.io>2024-12-02 09:05:35 +0100
commitc459715f321248cab0cc7081667bb61116d4fc31 (patch)
treec2e40266d630a82200c65b1dee0d8ad542242a4a
download2024-c459715f321248cab0cc7081667bb61116d4fc31.tar.gz
2024-c459715f321248cab0cc7081667bb61116d4fc31.tar.bz2
2024-c459715f321248cab0cc7081667bb61116d4fc31.zip
Base framework
-rw-r--r--.gitignore133
-rw-r--r--.idea/.gitignore8
-rw-r--r--.idea/aoc2024.iml15
-rw-r--r--.idea/inspectionProfiles/Project_Default.xml177
-rw-r--r--.idea/inspectionProfiles/profiles_settings.xml6
-rw-r--r--.idea/misc.xml4
-rw-r--r--.idea/modules.xml8
-rw-r--r--.idea/vcs.xml6
-rw-r--r--Cargo.toml3
-rw-r--r--aoc/Cargo.toml7
-rw-r--r--aoc/src/lib.rs74
11 files changed, 441 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0f22051
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,133 @@
1# Created by https://www.toptal.com/developers/gitignore/api/rust,intellij
2# Edit at https://www.toptal.com/developers/gitignore?templates=rust,intellij
3
4### Intellij ###
5# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
6# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
7
8# User-specific stuff
9.idea/**/workspace.xml
10.idea/**/tasks.xml
11.idea/**/usage.statistics.xml
12.idea/**/dictionaries
13.idea/**/shelf
14
15# AWS User-specific
16.idea/**/aws.xml
17
18# Generated files
19.idea/**/contentModel.xml
20
21# Sensitive or high-churn files
22.idea/**/dataSources/
23.idea/**/dataSources.ids
24.idea/**/dataSources.local.xml
25.idea/**/sqlDataSources.xml
26.idea/**/dynamic.xml
27.idea/**/uiDesigner.xml
28.idea/**/dbnavigator.xml
29
30# Gradle
31.idea/**/gradle.xml
32.idea/**/libraries
33
34# Gradle and Maven with auto-import
35# When using Gradle or Maven with auto-import, you should exclude module files,
36# since they will be recreated, and may cause churn. Uncomment if using
37# auto-import.
38# .idea/artifacts
39# .idea/compiler.xml
40# .idea/jarRepositories.xml
41# .idea/modules.xml
42# .idea/*.iml
43# .idea/modules
44# *.iml
45# *.ipr
46
47# CMake
48cmake-build-*/
49
50# Mongo Explorer plugin
51.idea/**/mongoSettings.xml
52
53# File-based project format
54*.iws
55
56# IntelliJ
57out/
58
59# mpeltonen/sbt-idea plugin
60.idea_modules/
61
62# JIRA plugin
63atlassian-ide-plugin.xml
64
65# Cursive Clojure plugin
66.idea/replstate.xml
67
68# SonarLint plugin
69.idea/sonarlint/
70
71# Crashlytics plugin (for Android Studio and IntelliJ)
72com_crashlytics_export_strings.xml
73crashlytics.properties
74crashlytics-build.properties
75fabric.properties
76
77# Editor-based Rest Client
78.idea/httpRequests
79
80# Android studio 3.1+ serialized cache file
81.idea/caches/build_file_checksums.ser
82
83### Intellij Patch ###
84# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
85
86# *.iml
87# modules.xml
88# .idea/misc.xml
89# *.ipr
90
91# Sonarlint plugin
92# https://plugins.jetbrains.com/plugin/7973-sonarlint
93.idea/**/sonarlint/
94
95# SonarQube Plugin
96# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
97.idea/**/sonarIssues.xml
98
99# Markdown Navigator plugin
100# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
101.idea/**/markdown-navigator.xml
102.idea/**/markdown-navigator-enh.xml
103.idea/**/markdown-navigator/
104
105# Cache file creation bug
106# See https://youtrack.jetbrains.com/issue/JBR-2257
107.idea/$CACHE_FILE$
108
109# CodeStream plugin
110# https://plugins.jetbrains.com/plugin/12206-codestream
111.idea/codestream.xml
112
113# Azure Toolkit for IntelliJ plugin
114# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
115.idea/**/azureSettings.xml
116
117### Rust ###
118# Generated by Cargo
119# will have compiled files and executables
120debug/
121target/
122
123# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
124# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
125Cargo.lock
126
127# These are backup files generated by rustfmt
128**/*.rs.bk
129
130# MSVC Windows builds of rustc generate these, which store debugging information
131*.pdb
132
133# End of https://www.toptal.com/developers/gitignore/api/rust,intellij
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
1# Default ignored files
2/shelf/
3/workspace.xml
4# Editor-based HTTP Client requests
5/httpRequests/
6# Datasource local storage ignored files
7/dataSources/
8/dataSources.local.xml
diff --git a/.idea/aoc2024.iml b/.idea/aoc2024.iml
new file mode 100644
index 0000000..784d79e
--- /dev/null
+++ b/.idea/aoc2024.iml
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<module type="PYTHON_MODULE" version="4">
3 <component name="NewModuleRootManager">
4 <content url="file://$MODULE_DIR$">
5 <sourceFolder url="file://$MODULE_DIR$/aoc/src" isTestSource="false" />
6 <sourceFolder url="file://$MODULE_DIR$/day1/src" isTestSource="false" />
7 <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
8 <sourceFolder url="file://$MODULE_DIR$/day2/src" isTestSource="false" />
9 <excludeFolder url="file://$MODULE_DIR$/aoc/target" />
10 <excludeFolder url="file://$MODULE_DIR$/target" />
11 </content>
12 <orderEntry type="inheritedJdk" />
13 <orderEntry type="sourceFolder" forTests="false" />
14 </component>
15</module> \ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..a9696b0
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,177 @@
1<component name="InspectionProjectProfileManager">
2 <profile version="1.0">
3 <option name="myName" value="Project Default" />
4 <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5 <inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
6 <option name="ourVersions">
7 <value>
8 <list size="3">
9 <item index="0" class="java.lang.String" itemvalue="3.12" />
10 <item index="1" class="java.lang.String" itemvalue="3.11" />
11 <item index="2" class="java.lang.String" itemvalue="3.10" />
12 </list>
13 </value>
14 </option>
15 </inspection_tool>
16 <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
17 <option name="ignoredPackages">
18 <value>
19 <list size="151">
20 <item index="0" class="java.lang.String" itemvalue="stringcase" />
21 <item index="1" class="java.lang.String" itemvalue="django-sitemaps" />
22 <item index="2" class="java.lang.String" itemvalue="dj-database-url" />
23 <item index="3" class="java.lang.String" itemvalue="tabulate" />
24 <item index="4" class="java.lang.String" itemvalue="django-s3-storage" />
25 <item index="5" class="java.lang.String" itemvalue="whitenoise" />
26 <item index="6" class="java.lang.String" itemvalue="form-designer" />
27 <item index="7" class="java.lang.String" itemvalue="gunicorn" />
28 <item index="8" class="java.lang.String" itemvalue="django-cabinet" />
29 <item index="9" class="java.lang.String" itemvalue="django-debug-toolbar" />
30 <item index="10" class="java.lang.String" itemvalue="dataclasses-json" />
31 <item index="11" class="java.lang.String" itemvalue="celery" />
32 <item index="12" class="java.lang.String" itemvalue="django-sortedm2m" />
33 <item index="13" class="java.lang.String" itemvalue="Django" />
34 <item index="14" class="java.lang.String" itemvalue="django-redis" />
35 <item index="15" class="java.lang.String" itemvalue="feincms3" />
36 <item index="16" class="java.lang.String" itemvalue="django-db-geventpool" />
37 <item index="17" class="java.lang.String" itemvalue="django-redis-cache" />
38 <item index="18" class="java.lang.String" itemvalue="django-admin-sortable2" />
39 <item index="19" class="java.lang.String" itemvalue="gevent" />
40 <item index="20" class="java.lang.String" itemvalue="pycountry" />
41 <item index="21" class="java.lang.String" itemvalue="djangorestframework" />
42 <item index="22" class="java.lang.String" itemvalue="django-cors-headers" />
43 <item index="23" class="java.lang.String" itemvalue="greenlet" />
44 <item index="24" class="java.lang.String" itemvalue="pickleshare" />
45 <item index="25" class="java.lang.String" itemvalue="py" />
46 <item index="26" class="java.lang.String" itemvalue="invoke" />
47 <item index="27" class="java.lang.String" itemvalue="geocoder" />
48 <item index="28" class="java.lang.String" itemvalue="pycparser" />
49 <item index="29" class="java.lang.String" itemvalue="redis" />
50 <item index="30" class="java.lang.String" itemvalue="postmarker" />
51 <item index="31" class="java.lang.String" itemvalue="coreschema" />
52 <item index="32" class="java.lang.String" itemvalue="django-widget-tweaks" />
53 <item index="33" class="java.lang.String" itemvalue="Authlib" />
54 <item index="34" class="java.lang.String" itemvalue="ipython-genutils" />
55 <item index="35" class="java.lang.String" itemvalue="django-admin-sortable" />
56 <item index="36" class="java.lang.String" itemvalue="PyNaCl" />
57 <item index="37" class="java.lang.String" itemvalue="Pygments" />
58 <item index="38" class="java.lang.String" itemvalue="django-easy-select2" />
59 <item index="39" class="java.lang.String" itemvalue="django-tinymce" />
60 <item index="40" class="java.lang.String" itemvalue="bleach" />
61 <item index="41" class="java.lang.String" itemvalue="monotonic" />
62 <item index="42" class="java.lang.String" itemvalue="python-pdf" />
63 <item index="43" class="java.lang.String" itemvalue="django-nose" />
64 <item index="44" class="java.lang.String" itemvalue="asgiref" />
65 <item index="45" class="java.lang.String" itemvalue="pexpect" />
66 <item index="46" class="java.lang.String" itemvalue="click" />
67 <item index="47" class="java.lang.String" itemvalue="FeinCMS" />
68 <item index="48" class="java.lang.String" itemvalue="ratelim" />
69 <item index="49" class="java.lang.String" itemvalue="attrs" />
70 <item index="50" class="java.lang.String" itemvalue="simplejson" />
71 <item index="51" class="java.lang.String" itemvalue="jedi" />
72 <item index="52" class="java.lang.String" itemvalue="django-markdownify" />
73 <item index="53" class="java.lang.String" itemvalue="paramiko" />
74 <item index="54" class="java.lang.String" itemvalue="salesforce-bulk" />
75 <item index="55" class="java.lang.String" itemvalue="fabric" />
76 <item index="56" class="java.lang.String" itemvalue="openapi-codec" />
77 <item index="57" class="java.lang.String" itemvalue="idna" />
78 <item index="58" class="java.lang.String" itemvalue="decorator" />
79 <item index="59" class="java.lang.String" itemvalue="pluggy" />
80 <item index="60" class="java.lang.String" itemvalue="pyasn1" />
81 <item index="61" class="java.lang.String" itemvalue="requests" />
82 <item index="62" class="java.lang.String" itemvalue="pyOpenSSL" />
83 <item index="63" class="java.lang.String" itemvalue="zipp" />
84 <item index="64" class="java.lang.String" itemvalue="prompt-toolkit" />
85 <item index="65" class="java.lang.String" itemvalue="cached-property" />
86 <item index="66" class="java.lang.String" itemvalue="uritemplate" />
87 <item index="67" class="java.lang.String" itemvalue="rcssmin" />
88 <item index="68" class="java.lang.String" itemvalue="django-select2" />
89 <item index="69" class="java.lang.String" itemvalue="enum-compat" />
90 <item index="70" class="java.lang.String" itemvalue="django-compressor" />
91 <item index="71" class="java.lang.String" itemvalue="pdfkit" />
92 <item index="72" class="java.lang.String" itemvalue="pathtools" />
93 <item index="73" class="java.lang.String" itemvalue="watchdog" />
94 <item index="74" class="java.lang.String" itemvalue="python-http-client" />
95 <item index="75" class="java.lang.String" itemvalue="future" />
96 <item index="76" class="java.lang.String" itemvalue="typing_extensions" />
97 <item index="77" class="java.lang.String" itemvalue="itypes" />
98 <item index="78" class="java.lang.String" itemvalue="django-sslify" />
99 <item index="79" class="java.lang.String" itemvalue="olefile" />
100 <item index="80" class="java.lang.String" itemvalue="click-repl" />
101 <item index="81" class="java.lang.String" itemvalue="pytz" />
102 <item index="82" class="java.lang.String" itemvalue="unicodecsv" />
103 <item index="83" class="java.lang.String" itemvalue="webencodings" />
104 <item index="84" class="java.lang.String" itemvalue="Pillow" />
105 <item index="85" class="java.lang.String" itemvalue="traitlets" />
106 <item index="86" class="java.lang.String" itemvalue="html5lib" />
107 <item index="87" class="java.lang.String" itemvalue="python-dateutil" />
108 <item index="88" class="java.lang.String" itemvalue="psycopg2-binary" />
109 <item index="89" class="java.lang.String" itemvalue="kombu" />
110 <item index="90" class="java.lang.String" itemvalue="MarkupSafe" />
111 <item index="91" class="java.lang.String" itemvalue="mollie-api-python" />
112 <item index="92" class="java.lang.String" itemvalue="django-extensions" />
113 <item index="93" class="java.lang.String" itemvalue="docopt" />
114 <item index="94" class="java.lang.String" itemvalue="Faker" />
115 <item index="95" class="java.lang.String" itemvalue="certifi" />
116 <item index="96" class="java.lang.String" itemvalue="pyparsing" />
117 <item index="97" class="java.lang.String" itemvalue="Markdown" />
118 <item index="98" class="java.lang.String" itemvalue="vine" />
119 <item index="99" class="java.lang.String" itemvalue="django-sekizai" />
120 <item index="100" class="java.lang.String" itemvalue="image" />
121 <item index="101" class="java.lang.String" itemvalue="dnspython" />
122 <item index="102" class="java.lang.String" itemvalue="rjsmin" />
123 <item index="103" class="java.lang.String" itemvalue="nodeenv" />
124 <item index="104" class="java.lang.String" itemvalue="requests-mock" />
125 <item index="105" class="java.lang.String" itemvalue="django-rest-swagger" />
126 <item index="106" class="java.lang.String" itemvalue="zope.interface" />
127 <item index="107" class="java.lang.String" itemvalue="django-appconf" />
128 <item index="108" class="java.lang.String" itemvalue="simple-salesforce" />
129 <item index="109" class="java.lang.String" itemvalue="sendgrid" />
130 <item index="110" class="java.lang.String" itemvalue="appnope" />
131 <item index="111" class="java.lang.String" itemvalue="bcrypt" />
132 <item index="112" class="java.lang.String" itemvalue="django-mptt" />
133 <item index="113" class="java.lang.String" itemvalue="django-filter" />
134 <item index="114" class="java.lang.String" itemvalue="charset-normalizer" />
135 <item index="115" class="java.lang.String" itemvalue="typing" />
136 <item index="116" class="java.lang.String" itemvalue="mock" />
137 <item index="117" class="java.lang.String" itemvalue="pbr" />
138 <item index="118" class="java.lang.String" itemvalue="django-ckeditor" />
139 <item index="119" class="java.lang.String" itemvalue="async-timeout" />
140 <item index="120" class="java.lang.String" itemvalue="django-bulk-update" />
141 <item index="121" class="java.lang.String" itemvalue="ptyprocess" />
142 <item index="122" class="java.lang.String" itemvalue="more-itertools" />
143 <item index="123" class="java.lang.String" itemvalue="wcwidth" />
144 <item index="124" class="java.lang.String" itemvalue="click-didyoumean" />
145 <item index="125" class="java.lang.String" itemvalue="django-classy-tags" />
146 <item index="126" class="java.lang.String" itemvalue="Jinja2" />
147 <item index="127" class="java.lang.String" itemvalue="simplegeneric" />
148 <item index="128" class="java.lang.String" itemvalue="newrelic" />
149 <item index="129" class="java.lang.String" itemvalue="cloudinary" />
150 <item index="130" class="java.lang.String" itemvalue="sqlparse" />
151 <item index="131" class="java.lang.String" itemvalue="django-cloudinary-storage" />
152 <item index="132" class="java.lang.String" itemvalue="netaddr" />
153 <item index="133" class="java.lang.String" itemvalue="xmltodict" />
154 <item index="134" class="java.lang.String" itemvalue="urllib3" />
155 <item index="135" class="java.lang.String" itemvalue="zope.event" />
156 <item index="136" class="java.lang.String" itemvalue="Cython" />
157 <item index="137" class="java.lang.String" itemvalue="billiard" />
158 <item index="138" class="java.lang.String" itemvalue="coverage" />
159 <item index="139" class="java.lang.String" itemvalue="nose" />
160 <item index="140" class="java.lang.String" itemvalue="six" />
161 <item index="141" class="java.lang.String" itemvalue="asn1crypto" />
162 <item index="142" class="java.lang.String" itemvalue="parso" />
163 <item index="143" class="java.lang.String" itemvalue="text-unidecode" />
164 <item index="144" class="java.lang.String" itemvalue="packaging" />
165 <item index="145" class="java.lang.String" itemvalue="chardet" />
166 <item index="146" class="java.lang.String" itemvalue="django" />
167 <item index="147" class="java.lang.String" itemvalue="coreapi" />
168 <item index="148" class="java.lang.String" itemvalue="colorama" />
169 <item index="149" class="java.lang.String" itemvalue="django-js-asset" />
170 <item index="150" class="java.lang.String" itemvalue="click-plugins" />
171 </list>
172 </value>
173 </option>
174 </inspection_tool>
175 <inspection_tool class="Stylelint" enabled="true" level="ERROR" enabled_by_default="true" />
176 </profile>
177</component> \ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
1<component name="InspectionProjectProfileManager">
2 <settings>
3 <option name="USE_PROJECT_PROFILE" value="false" />
4 <version value="1.0" />
5 </settings>
6</component> \ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..23231ce
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<project version="4">
3 <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13" project-jdk-type="Python SDK" />
4</project> \ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..18c94bc
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<project version="4">
3 <component name="ProjectModuleManager">
4 <modules>
5 <module fileurl="file://$PROJECT_DIR$/.idea/aoc2024.iml" filepath="$PROJECT_DIR$/.idea/aoc2024.iml" />
6 </modules>
7 </component>
8</project> \ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<project version="4">
3 <component name="VcsDirectoryMappings">
4 <mapping directory="" vcs="Git" />
5 </component>
6</project> \ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..8018f3d
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,3 @@
1[workspace]
2members = ["aoc", "day1"]
3resolver = "2" \ No newline at end of file
diff --git a/aoc/Cargo.toml b/aoc/Cargo.toml
new file mode 100644
index 0000000..44564e1
--- /dev/null
+++ b/aoc/Cargo.toml
@@ -0,0 +1,7 @@
1[package]
2name = "aoc"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7clap = { version = "4.5.21", features = ["derive"] }
diff --git a/aoc/src/lib.rs b/aoc/src/lib.rs
new file mode 100644
index 0000000..5fad72d
--- /dev/null
+++ b/aoc/src/lib.rs
@@ -0,0 +1,74 @@
1use clap::Parser;
2use std::fs::File;
3use std::io;
4use std::io::{BufRead, BufReader, Read};
5
6#[derive(Parser, Debug)]
7#[command(version, about, long_about = None)]
8struct Args {
9 #[arg(short, long, default_value = "-")]
10 file: String,
11
12 #[arg(short, long, default_value_t = 1)]
13 part: u8,
14}
15
16pub trait Day {
17 fn example_input(&self) -> &'static str;
18 fn example_result_part_1(&self) -> &'static str;
19 fn example_result_part_2(&self) -> &'static str;
20
21 fn read_lines(&self, input: BufReader<Box<dyn Read>>) -> Vec<String> {
22 let mut lines = Vec::new();
23
24 for line in input.lines() {
25 match line {
26 Ok(content) => lines.push(content),
27 Err(e) => eprintln!("Error reading line: {}", e),
28 }
29 }
30
31 lines
32 }
33
34 fn part_1(&self, input: BufReader<Box<dyn Read>>) -> String;
35 fn part_2(&self, input: BufReader<Box<dyn Read>>) -> String;
36}
37
38pub fn main(day: &dyn Day) {
39 let args = Args::parse();
40
41 let reader: Box<dyn Read> = if args.file == "-" {
42 Box::new(io::stdin())
43 } else {
44 Box::new(File::open(&args.file).expect("Failed to open file"))
45 };
46
47 let buffer = BufReader::new(reader);
48
49 let result: String;
50 if args.part == 1 {
51 result = day.part_1(buffer);
52 } else {
53 result = day.part_2(buffer);
54 }
55
56 println!("Result: {result}")
57}
58
59pub fn test_day<T: Day>(day: &T) {
60 use std::io::Cursor;
61 use std::io::{BufReader, Read};
62
63 let example_input = day.example_input();
64
65 // Test Part 1
66 let input = BufReader::new(Box::new(Cursor::new(example_input)) as Box<dyn Read>);
67 let output = day.part_1(input);
68 assert_eq!(output.trim(), day.example_result_part_1(), "Part 1 failed");
69
70 // Test Part 2
71 let input = BufReader::new(Box::new(Cursor::new(example_input)) as Box<dyn Read>);
72 let output = day.part_2(input);
73 assert_eq!(output.trim(), day.example_result_part_2(), "Part 2 failed");
74} \ No newline at end of file