restructure and optimize (fuck you @Doloro1978)

This commit is contained in:
2025-12-03 19:19:09 +04:00
parent 8bee5bd9a3
commit 492b61bd04
13 changed files with 776 additions and 105 deletions

12
src/bin/day01.rs Normal file
View File

@@ -0,0 +1,12 @@
use aoc_2025::day01;
use color_eyre::Report;
fn main() -> Result<(), Report> {
color_eyre::install()?;
let data = day01::data("inputs/day01.txt")?;
let code1 = day01::part1(&data)?;
let code2 = day01::part2(&data)?;
println!("code1: {code1}");
println!("code2: {code2}");
Ok(())
}

12
src/bin/day02.rs Normal file
View File

@@ -0,0 +1,12 @@
use aoc_2025::day02;
use color_eyre::Report;
fn main() -> Result<(), Report> {
color_eyre::install()?;
let data = day02::data("inputs/day02.txt")?;
let code1 = day02::part1(&data)?;
let code2 = day02::part2(&data)?;
println!("code1: {code1}");
println!("code2: {code2}");
Ok(())
}

View File

@@ -1,82 +0,0 @@
use color_eyre::{Report, eyre::ContextCompat};
use std::{fs::File, io::Read};
#[derive(Debug)]
struct IdRange {
start: u64,
end: u64,
}
impl TryFrom<&str> for IdRange {
type Error = Report;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let mut split = value.split("-");
let start: u64 = split.next().context("Invalid start ID")?.parse()?;
let end: u64 = split.next().context("Invalid end ID")?.parse()?;
Ok(Self { start, end })
}
}
impl IdRange {
fn get_invalid(&self) -> Result<Vec<u64>, Report> {
Ok((self.start..self.end + 1)
.filter(|v| {
let str = v.to_string();
let len = str.len();
if (len % 2) != 0 {
return false;
}
str[0..len / 2] == str[len / 2..len]
})
.collect())
}
fn get_invalid2(&self) -> Result<Vec<u64>, Report> {
Ok((self.start..self.end + 1)
.filter(|v| {
let str = v.to_string();
let len = str.len();
(1..len + 1)
.filter(|v| (len % v) == 0)
.filter(|v| (len / v) != 1)
.filter(|v| {
let strchunk = str.chars().collect::<Vec<char>>();
let strchunk = strchunk.chunks(*v).collect::<Vec<&[char]>>();
!strchunk.iter().any(|v| strchunk.iter().any(|x| v != x))
})
.sum::<usize>()
> 0
})
.collect())
}
}
fn main() -> Result<(), Report> {
color_eyre::install()?;
// let filepath = "testinput2.txt";
let filepath = "inputs/day2.txt";
let mut file = File::open(filepath)?;
let mut string = String::new();
let _ = file.read_to_string(&mut string);
let ranges = string
.trim_end()
.split(",")
.map(IdRange::try_from)
.collect::<Result<Vec<IdRange>, Report>>()?;
let code1 = ranges
.iter()
.map(|v| v.get_invalid().map(|v| v.into_iter().sum::<u64>()))
.collect::<Result<Vec<u64>, Report>>()?
.into_iter()
.sum::<u64>();
println!("code1: {code1}");
let code2 = ranges
.iter()
.map(|v| v.get_invalid2().map(|v| v.into_iter().sum::<u64>()))
.collect::<Result<Vec<u64>, Report>>()?
.into_iter()
.sum::<u64>();
println!("code1: {code2}");
Ok(())
}

View File

@@ -1,6 +1,6 @@
use std::{
fs::File,
io::{BufRead, BufReader},
io::{self, BufRead, BufReader, Lines, Read},
};
use color_eyre::{
@@ -34,36 +34,66 @@ impl TryFrom<&str> for DialDir {
}
}
fn main() -> Result<(), Report> {
color_eyre::install()?;
// let filepath = "testinput.txt";
let filepath = "inputs/day1.txt";
let file = File::open(filepath)?;
let bufreader = BufReader::new(file);
let mut lines = bufreader.lines();
pub fn part1(lines: &[String]) -> Result<i32, Report> {
let mut total_value = 50;
let mut code = 0;
let mut code2 = 0;
while let Some(Ok(line)) = lines.next() {
for line in lines {
let dialcode = DialDir::try_from(line.as_str())?;
total_value += std::convert::Into::<i32>::into(dialcode.clone());
total_value = total_value.rem_euclid(100);
if total_value == 0 {
code += 1;
}
}
Ok(code)
}
pub fn part2(lines: &[String]) -> Result<i32, Report> {
let mut total_value = 50;
let mut code = 0;
for line in lines {
let prev = total_value;
let dialcode = DialDir::try_from(line.as_str())?;
total_value += std::convert::Into::<i32>::into(dialcode.clone());
let big_jump = total_value.div_euclid(100);
total_value = total_value.rem_euclid(100);
if big_jump < 0 && prev == 0 {
code2 -= 1;
code -= 1;
}
if big_jump > 0 && total_value == 0 {
code2 -= 1;
code -= 1;
}
code2 += big_jump.abs();
code += big_jump.abs();
if total_value == 0 {
code += 1;
}
println!("{dialcode:?} {prev}->{total_value} {code} {code2}");
}
println!("code is {} {}!", code, code + code2);
Ok(())
Ok(code)
}
pub fn data(filepath: &str) -> Result<Vec<String>, Report> {
let file = File::open(filepath)?;
let bufreader = BufReader::new(file);
let lines = bufreader
.lines()
.collect::<Result<Vec<String>, io::Error>>()?;
Ok(lines)
}
#[cfg(test)]
mod tests {
use super::*;
use criterion::Criterion;
use criterion_macro::criterion;
#[criterion]
fn bench_part1(b: &mut Criterion) {
let data = data("inputs/day01.txt").unwrap();
b.bench_function("day01-part1", |b| b.iter(|| part1(&data).unwrap()));
}
#[criterion]
fn bench_part2(b: &mut Criterion) {
let data = data("inputs/day01.txt").unwrap();
b.bench_function("day01-part2", |b| b.iter(|| part2(&data).unwrap()));
}
}

108
src/day02.rs Normal file
View File

@@ -0,0 +1,108 @@
use color_eyre::{Report, eyre::ContextCompat};
use std::{
fs::File,
io::Read,
ops::{Div, Rem},
};
#[derive(Debug)]
pub struct IdRange {
start: u64,
end: u64,
}
impl TryFrom<&str> for IdRange {
type Error = Report;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let mut split = value.split("-");
let start: u64 = split.next().context("Invalid start ID")?.parse()?;
let end: u64 = split.next().context("Invalid end ID")?.parse()?;
Ok(Self { start, end })
}
}
impl IdRange {
fn get_invalid(&self) -> Result<Vec<u64>, Report> {
Ok((self.start..=self.end)
.filter(|v| {
let len = v.checked_ilog10().unwrap_or(0) + 1;
if !len.is_multiple_of(2) {
return false;
}
let d = 10_u64.pow(len / 2);
let first = v.div(d);
let second = v.rem(d);
first == second
})
.collect())
}
fn get_invalid2(&self) -> Result<Vec<u64>, Report> {
Ok((self.start..=self.end)
.filter(|v| {
let len = (v.checked_ilog10().unwrap_or(0) + 1) as usize;
let mut digits = vec![0; len];
let mut temp = *v;
for i in 1..=len {
digits[len - i] = temp % 10;
temp /= 10;
}
(1..=len)
.filter(|v| len.is_multiple_of(*v) && (len / v) != 1)
.any(|c| {
let mut chunks = digits.chunks(c);
chunks
.next()
.is_some_and(|first| chunks.all(|chunk| chunk == first))
})
})
.collect())
}
}
pub fn part1(data: &[IdRange]) -> Result<u64, Report> {
Ok(data
.iter()
.map(|v| v.get_invalid().map(|v| v.into_iter().sum::<u64>()))
.collect::<Result<Vec<u64>, Report>>()?
.into_iter()
.sum::<u64>())
}
pub fn part2(data: &[IdRange]) -> Result<u64, Report> {
Ok(data
.iter()
.map(|v| v.get_invalid2().map(|v| v.into_iter().sum::<u64>()))
.collect::<Result<Vec<u64>, Report>>()?
.into_iter()
.sum::<u64>())
}
pub fn data(filepath: &str) -> Result<Vec<IdRange>, Report> {
let mut file = File::open(filepath)?;
let mut string = String::new();
let _ = file.read_to_string(&mut string);
string
.trim_end()
.split(",")
.map(IdRange::try_from)
.collect::<Result<Vec<IdRange>, Report>>()
}
#[cfg(test)]
mod tests {
use super::*;
use criterion::Criterion;
use criterion_macro::criterion;
#[criterion]
fn bench_part1(b: &mut Criterion) {
let data = data("inputs/day02.txt").unwrap();
b.bench_function("day02-part1", |b| b.iter(|| part1(&data).unwrap()));
}
#[criterion]
fn bench_part2(b: &mut Criterion) {
let data = data("inputs/day01.txt").unwrap();
b.bench_function("day02-part2", |b| b.iter(|| part2(&data).unwrap()));
}
}

View File

@@ -1 +1,6 @@
#![feature(custom_test_frameworks)]
#![test_runner(criterion::runner)]
#![feature(test)]
extern crate test;
pub mod day01;
pub mod day02;