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
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.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