Day 1
This commit is contained in:
parent
43b3ece2c3
commit
e364357d00
7
.gitignore
vendored
7
.gitignore
vendored
@ -12,3 +12,10 @@ Cargo.lock
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# Added by cargo
|
||||
|
||||
/target
|
||||
|
||||
# Don't commit my personal input.txt files
|
||||
input.txt
|
||||
|
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "advent-of-code-2023"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
phf = { version = "0.11", features = ["macros"] }
|
4
src/day01/input/test1.txt
Normal file
4
src/day01/input/test1.txt
Normal file
@ -0,0 +1,4 @@
|
||||
1abc2
|
||||
pqr3stu8vwx
|
||||
a1b2c3d4e5f
|
||||
treb7uchet
|
7
src/day01/input/test2.txt
Normal file
7
src/day01/input/test2.txt
Normal file
@ -0,0 +1,7 @@
|
||||
two1nine
|
||||
eightwothree
|
||||
abcone2threexyz
|
||||
xtwone3four
|
||||
4nineeightseven2
|
||||
zoneight234
|
||||
7pqrstsixteen
|
107
src/day01/mod.rs
Normal file
107
src/day01/mod.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use std::cmp::min;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use phf::phf_map;
|
||||
|
||||
use crate::instrument::instrument;
|
||||
|
||||
const INPUT: &str = include_str!("input/input.txt");
|
||||
static DIGITS: phf::Map<&[u8], u8> = phf_map! {
|
||||
b"zero" => 0,
|
||||
b"one" => 1,
|
||||
b"two" => 2,
|
||||
b"three" => 3,
|
||||
b"four" => 4,
|
||||
b"five" => 5,
|
||||
b"six" => 6,
|
||||
b"seven" => 7,
|
||||
b"eight" => 8,
|
||||
b"nine" => 9,
|
||||
b"0" => 0,
|
||||
b"1" => 1,
|
||||
b"2" => 2,
|
||||
b"3" => 3,
|
||||
b"4" => 4,
|
||||
b"5" => 5,
|
||||
b"6" => 6,
|
||||
b"7" => 7,
|
||||
b"8" => 8,
|
||||
b"9" => 9,
|
||||
};
|
||||
|
||||
fn find_num(line: &[u8], reverse: bool) -> Option<u8> {
|
||||
let window_size = min(line.len(), 5);
|
||||
for i in 0..line.len() {
|
||||
for j in 1..min(window_size + 1, line.len() - i + 1) {
|
||||
if j == 2 {
|
||||
continue; // no two-byte digits
|
||||
}
|
||||
if !reverse {
|
||||
if let Some(digit) = DIGITS.get(&line[i..i + j]) {
|
||||
return Some(*digit);
|
||||
}
|
||||
} else if let Some(digit) = DIGITS.get(&line[line.len() - i - j..line.len() - i]) {
|
||||
return Some(*digit);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> Result<u32> {
|
||||
let mut sum: u32 = 0;
|
||||
for line in input.trim().split('\n') {
|
||||
let first = line
|
||||
.as_bytes()
|
||||
.iter()
|
||||
.find(|c| c.is_ascii_digit())
|
||||
.map(|c| c - b'0')
|
||||
.ok_or_else(|| anyhow!("Invalid input: no digits found in line {}", line))?;
|
||||
let last = line
|
||||
.as_bytes()
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|c| c.is_ascii_digit())
|
||||
.map(|c| c - b'0')
|
||||
.ok_or_else(|| anyhow!("Invalid input: no digits found in line {}", line))?;
|
||||
sum += (first as u32 * 10) + last as u32;
|
||||
}
|
||||
Ok(sum)
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> Result<u32> {
|
||||
let mut sum = 0;
|
||||
for line in input.trim().split('\n') {
|
||||
let first = find_num(line.as_bytes(), false)
|
||||
.ok_or_else(|| anyhow!("Invalid input: no digits found in line {}", line))?;
|
||||
let last = find_num(line.as_bytes(), true)
|
||||
.ok_or_else(|| anyhow!("Invalid input: no digits found in line {}", line))?;
|
||||
sum += (first as u32 * 10) + last as u32;
|
||||
}
|
||||
Ok(sum)
|
||||
}
|
||||
|
||||
pub fn solve() -> Result<()> {
|
||||
println!("Day 01");
|
||||
instrument!(part1(INPUT)?, part2(INPUT)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const TEST_INPUT1: &str = include_str!("input/test1.txt");
|
||||
const TEST_INPUT2: &str = include_str!("input/test2.txt");
|
||||
|
||||
#[test]
|
||||
fn test_part1() {
|
||||
assert_eq!(part1(TEST_INPUT1).unwrap(), 142);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() {
|
||||
assert_eq!(part2(TEST_INPUT1).unwrap(), 142);
|
||||
assert_eq!(part2(TEST_INPUT2).unwrap(), 281);
|
||||
}
|
||||
}
|
12
src/instrument.rs
Normal file
12
src/instrument.rs
Normal file
@ -0,0 +1,12 @@
|
||||
macro_rules! instrument {
|
||||
($part1:expr, $part2:expr) => {
|
||||
let mut now = std::time::Instant::now();
|
||||
println!("Part 1: {}", $part1);
|
||||
println!("(elapsed: {:?})", now.elapsed());
|
||||
now = std::time::Instant::now();
|
||||
println!("");
|
||||
println!("Part 2: {}", $part2);
|
||||
println!("(elapsed: {:?})", now.elapsed());
|
||||
};
|
||||
}
|
||||
pub(crate) use instrument;
|
10
src/main.rs
Normal file
10
src/main.rs
Normal file
@ -0,0 +1,10 @@
|
||||
pub mod day01;
|
||||
pub mod instrument;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
println!("Advent of Code 2023");
|
||||
day01::solve()?;
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user