diff --git a/day-07-rust/.gitignore b/day-07-rust/.gitignore new file mode 100644 index 0000000..9f97022 --- /dev/null +++ b/day-07-rust/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/day-07-rust/Cargo.lock b/day-07-rust/Cargo.lock new file mode 100644 index 0000000..30e7664 --- /dev/null +++ b/day-07-rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "day-07-rust" +version = "0.1.0" diff --git a/day-07-rust/Cargo.toml b/day-07-rust/Cargo.toml new file mode 100644 index 0000000..f5184f6 --- /dev/null +++ b/day-07-rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day-07-rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/day-07-rust/rust-toolchain.toml b/day-07-rust/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/day-07-rust/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/day-07-rust/src/common.rs b/day-07-rust/src/common.rs new file mode 100644 index 0000000..7a4e2f3 --- /dev/null +++ b/day-07-rust/src/common.rs @@ -0,0 +1,35 @@ +use std::io::{Bytes, Read}; +use std::iter::Peekable; + +pub type Number = i64; + +pub fn read_input_line(mut input: &mut Peekable>) -> Option<(Number, Vec)> { + let result = read_number(&mut input); + let mut parts = Vec::::with_capacity(20); + while let Some(Ok(ch)) = input.peek() { + match ch { + b'0'..=b'9' => parts.push(read_number(&mut input)), + b'\n' => { + input.next(); + break + } + _ => { + input.next(); + } + } + } + if parts.is_empty() { + None + } else { + Some((result, parts)) + } +} + +pub fn read_number(input: &mut Peekable>) -> Number { + let mut number: Number = 0; + while let Some(Ok(b'0'..=b'9')) = input.peek() { + number *= 10; + number += (input.next().unwrap().unwrap() - b'0') as Number; + } + number +} \ No newline at end of file diff --git a/day-07-rust/src/main.rs b/day-07-rust/src/main.rs new file mode 100644 index 0000000..73eac52 --- /dev/null +++ b/day-07-rust/src/main.rs @@ -0,0 +1,20 @@ +#![feature(let_chains)] + +mod task1; +mod common; +mod task2; + +fn main() { + let args = std::env::args().collect::>(); + + if args.len() != 3 { + eprintln!("Usage: {} <1|2> ", args[0]); + std::process::exit(1); + } + + match args[1].as_str() { + "1" => task1::run(std::fs::File::open(&args[2]).expect("Failed to open input file")), + "2" => task2::run(std::fs::File::open(&args[2]).expect("Failed to open input file")), + _ => eprintln!("Unknown task: {}", args[1]), + } +} diff --git a/day-07-rust/src/task1.rs b/day-07-rust/src/task1.rs new file mode 100644 index 0000000..bef4b00 --- /dev/null +++ b/day-07-rust/src/task1.rs @@ -0,0 +1,44 @@ +use crate::common; +use crate::common::Number; +use std::io::{BufReader, Read}; +use std::ops::Rem; + +pub(crate) fn run(read: R) { + let mut reader = BufReader::new(read).bytes().peekable(); + + let mut total = 0; + while let Some((result, parts)) = common::read_input_line(&mut reader) { + if let Some(ops) = brute(result, &parts) { + println!("{:?} & {:?} => {}", ops, parts, result); + total += result; + } + } + + println!("Result: {}", total); +} + +fn brute(result: Number, parts: &[Number]) -> Option> { + match parts.split_last() { + None => None, + Some((last, [])) => { + if result == *last { + Some(vec![]) + } else { + None + } + } + Some((cur, parts)) => { + let test_result = result - cur; + if let Some(mut ops) = brute(test_result, parts) { + ops.push('+'); + return Some(ops); + } + let test_result = result / cur; + if result.rem(cur) == 0 && let Some(mut ops) = brute(test_result, parts) { + ops.push('*'); + return Some(ops); + } + None + } + } +} diff --git a/day-07-rust/src/task2.rs b/day-07-rust/src/task2.rs new file mode 100644 index 0000000..44d6fa0 --- /dev/null +++ b/day-07-rust/src/task2.rs @@ -0,0 +1,53 @@ +use crate::common; +use crate::common::Number; +use std::io::{BufReader, Read}; +use std::ops::Rem; + +pub(crate) fn run(read: R) { + let mut reader = BufReader::new(read).bytes().peekable(); + + let mut total = 0; + while let Some((result, parts)) = common::read_input_line(&mut reader) { + if let Some(ops) = brute(result, &parts) { + println!("{:?} & {:?} => {}", ops, parts, result); + total += result; + } + } + + println!("Result: {}", total); +} + +fn brute(result: Number, parts: &[Number]) -> Option> { + match parts.split_last() { + None => None, + Some((last, [])) => { + if result == *last { + Some(vec![]) + } else { + None + } + } + Some((cur, parts)) => { + let test_result = result - cur; + if let Some(mut ops) = brute(test_result, parts) { + ops.push('+'); + return Some(ops); + } + let test_result = result / cur; + if result.rem(cur) == 0 && let Some(mut ops) = brute(test_result, parts) { + ops.push('*'); + return Some(ops); + } + let cur_str = cur.to_string(); + let result_str = result.to_string(); + if result_str.ends_with(cur_str.as_str()) { + let test_result = &result_str[..result_str.len() - cur_str.len()]; + if !test_result.is_empty() && let Some(mut ops) = brute(test_result.parse().unwrap(), parts) { + ops.push('|'); + return Some(ops); + } + } + None + } + } +}