--- /dev/null
+use std::error::Error;
+
+pub fn run(input: &str) -> Result<(), Box<dyn Error>> {
+ println!("part 1: {}", part1(input)?);
+ println!("part 2: {}", part2(input)?);
+ Ok(())
+}
+
+fn part1(input: &str) -> Result<i32, Box<dyn Error>> {
+ let mut res = 0;
+ let mut pos = 50;
+ for l in input.lines() {
+ let (dir, step) = l.split_at(1);
+ let mut step = step.parse::<i32>()?;
+ if dir == "L" {
+ step *= -1;
+ }
+ pos = (pos + step) % 100;
+ if pos < 0 {
+ pos += 100;
+ }
+ if pos == 0 {
+ res += 1;
+ }
+ }
+
+ Ok(res)
+}
+
+fn part2(input: &str) -> Result<i32, Box<dyn Error>> {
+ let mut click = 0;
+ let mut pos = 50;
+ let mut pos_last = 50;
+ for l in input.lines() {
+ let (dir, step) = l.split_at(1);
+ let mut step = step.parse::<i32>()?;
+ if dir == "L" {
+ step *= -1;
+ }
+ click += step.abs() / 100; // number of turns
+ step = step % 100;
+ if step == 0 {
+ continue;
+ }
+ pos += step;
+ if pos == 0 {
+ click += if pos_last == 0 { 0 } else { 1 };
+ }
+ else if pos < 0 {
+ click += if pos_last == 0 { 0 } else { 1 };
+ pos += 100;
+ }
+ else if pos >= 100 {
+ click += if pos_last == 0 { 0 } else { 1 };
+ pos -= 100;
+ }
+ pos_last = pos;
+ }
+
+ Ok(click)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ static TEXT_INPUT: &str = "\
+L68
+L30
+R48
+L5
+R60
+L55
+L1
+L99
+R14
+L82";
+
+ #[test]
+ fn test_part1() {
+ assert_eq!(3, part1(TEXT_INPUT).unwrap());
+ }
+ #[test]
+ fn test_part2() {
+ assert_eq!(6, part2(TEXT_INPUT).unwrap());
+ }
+ #[test]
+ fn test_part2_r1000() {
+ assert_eq!(10, part2("R1000").unwrap());
+ }
+}
--- /dev/null
+use std::env;
+use std::process;
+use std::error::Error;
+use std::fs::File;
+use std::io::Read;
+
+pub mod day01;
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ if let Err(e) = run(&args[1], &args[2]) {
+ println!("Error: {e}");
+ process::exit(2);
+ }
+}
+
+fn run(day: &str, input_file: &str) -> Result<(), Box<dyn Error>> {
+ let mut f = File::open(input_file)?;
+ let mut input = String::new();
+ f.read_to_string(&mut input)?;
+
+ match day {
+ "day01" => day01::run(&input)?,
+ _ => return Err(format!("unknown or unimplemented day \"{day}\"").into()),
+ }
+ Ok(())
+}