[TASK] Solved day 13
This commit is contained in:
2
input/day13.txt
Normal file
2
input/day13.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
1006605
|
||||
19,x,x,x,x,x,x,x,x,x,x,x,x,37,x,x,x,x,x,883,x,x,x,x,x,x,x,23,x,x,x,x,13,x,x,x,17,x,x,x,x,x,x,x,x,x,x,x,x,x,797,x,x,x,x,x,x,x,x,x,41,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,29
|
||||
7
input/day13_example.txt
Normal file
7
input/day13_example.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
939
|
||||
3,7919
|
||||
7,31
|
||||
67,7,x,59,61
|
||||
1789,37,47,1889
|
||||
7,13,x,x,59,x,31,19
|
||||
67,x,7,59,61
|
||||
116
src/day13.rs
Normal file
116
src/day13.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use super::util;
|
||||
|
||||
pub fn solve() {
|
||||
let lines = util::read_file("input/day13.txt");
|
||||
|
||||
let target_time = lines[0].parse::<u32>().unwrap();
|
||||
let part1 = lines[1].split(",").filter(|s| s != &"x")
|
||||
.map(|s| s.parse::<u32>().unwrap())
|
||||
.map(|t| (t, t - (target_time % t)))
|
||||
.min_by_key(|t| t.1)
|
||||
.map(|bt| bt.0 * bt.1)
|
||||
.unwrap();
|
||||
println!("Day 13 Part 1: {}", part1);
|
||||
|
||||
|
||||
let schedule_parts = lines[1].split(",").collect::<Vec<_>>();
|
||||
let mut schedules = Vec::new();
|
||||
// print!("[");
|
||||
for i in 0..schedule_parts.len() {
|
||||
let s = schedule_parts[i];
|
||||
if s == "x" { continue; }
|
||||
let bus_id = s.parse::<u64>().unwrap();
|
||||
let mut offset = i as u64;
|
||||
if offset > bus_id { offset = offset % bus_id; }
|
||||
// print!("(x + {}) mod {} = 0, ", offset, bus_id );
|
||||
schedules.push(Schedule {
|
||||
bus_id, offset
|
||||
});
|
||||
}
|
||||
// println!("]");
|
||||
|
||||
|
||||
|
||||
// schedules.sort_by_key(|s| s.bus_id);
|
||||
let part2 = find_fitting(&schedules);
|
||||
|
||||
println!("Day 13 Part 2: {}", part2);
|
||||
}
|
||||
|
||||
fn find_fitting(schedules: &Vec<Schedule>) -> u64 {
|
||||
|
||||
let mut root_schedule = find_fitting_match(&schedules[0], &schedules[1]);
|
||||
for schedule in schedules.iter().skip(2) {
|
||||
root_schedule = find_fitting_match(schedule, &root_schedule)
|
||||
}
|
||||
return root_schedule.bus_id - root_schedule.offset;
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn find_fitting_match(s1: &Schedule, s2: &Schedule) -> Schedule {
|
||||
|
||||
// We know that the pattern repeats every s1.bus_id * s2.bus_id (and at no other times, since all bus_ids are at least co-prime).
|
||||
// So all we need to do is find out what offset works:
|
||||
let match_bus_id = s1.bus_id * s2.bus_id;
|
||||
let mut res = Schedule { bus_id: 1, offset: 0 };
|
||||
let mut sol_count = 0;
|
||||
for mult in 0..s1.bus_id {
|
||||
let offset = mult * s2.bus_id + s2.offset;
|
||||
if offset > match_bus_id {
|
||||
println!("Error finding solution for schedules {:?} and {:?}", s1, s2);
|
||||
println!(" offset: {}, bus_id: {}", offset, match_bus_id)
|
||||
}
|
||||
let solution = match_bus_id - offset;
|
||||
if (solution + s1.offset) % s1.bus_id == 0 {
|
||||
sol_count += 1;
|
||||
res = Schedule {
|
||||
bus_id: match_bus_id,
|
||||
offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
if sol_count == 0 {
|
||||
println!("Error finding solution for schedules {:?} and {:?}", s1, s2);
|
||||
panic!("No solution for schedules!");
|
||||
} else if sol_count > 1 {
|
||||
println!("Multiple solutions for schedules {:?} and {:?}", s1, s2);
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
fn find_fitting_brute_force(schedules: &Vec<Schedule>) -> u64 {
|
||||
|
||||
let mut mult = 1u64;
|
||||
let mut max_res = 0;
|
||||
let last_schedule = schedules.last().unwrap();
|
||||
loop {
|
||||
let start_t = last_schedule.bus_id * mult - last_schedule.offset;
|
||||
let mut failed = false;
|
||||
for schedule in schedules.iter().rev().skip(1) {
|
||||
|
||||
if (start_t + schedule.offset) % schedule.bus_id != 0 {
|
||||
failed = true;
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
if !failed {
|
||||
println!("{}", start_t);
|
||||
max_res += 1;
|
||||
if max_res > 10 {
|
||||
return start_t;
|
||||
}
|
||||
// return start_t;
|
||||
}
|
||||
mult += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Schedule {
|
||||
bus_id: u64,
|
||||
offset: u64,
|
||||
}
|
||||
23
src/main.rs
23
src/main.rs
@@ -14,9 +14,10 @@ mod day9;
|
||||
mod day10;
|
||||
mod day11;
|
||||
mod day12;
|
||||
mod day13;
|
||||
|
||||
const MAX_DAY: u8 = 12;
|
||||
const BENCHMARK_AMOUNT: u32 = 100;
|
||||
const MAX_DAY: u8 = 13;
|
||||
const BENCHMARK_AMOUNT: u32 = 1000;
|
||||
|
||||
fn solve(day: u8) {
|
||||
match day {
|
||||
@@ -32,13 +33,13 @@ fn solve(day: u8) {
|
||||
10 => day10::solve(),
|
||||
11 => day11::solve(),
|
||||
12 => day12::solve(),
|
||||
13 => day13::solve(),
|
||||
_ => println!("This day is not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
|
||||
let day_arg_idx = args.iter().position(|a| a == "-d");
|
||||
@@ -51,8 +52,11 @@ fn main() {
|
||||
|
||||
// This is essentially the warmup for the benchmark:
|
||||
run_once(single_day, day, &mut bench_results);
|
||||
let first_run_time = bench_results[0];
|
||||
|
||||
if benchmark {
|
||||
// Ignore the warmup run in the rest of the benchmark:
|
||||
bench_results.clear();
|
||||
for _ in 0..BENCHMARK_AMOUNT {
|
||||
run_once(single_day, day, &mut bench_results);
|
||||
}
|
||||
@@ -61,6 +65,19 @@ fn main() {
|
||||
let avg_runtime: u128 = bench_results.iter().sum::<u128>() / (bench_results.len() as u128);
|
||||
|
||||
println!("Execution took {} μs {}", avg_runtime, if benchmark { "on average" } else { "" });
|
||||
if benchmark {
|
||||
bench_results.sort();
|
||||
println!("Min: {} μs, Max: {} μs, Median: {} μs",
|
||||
bench_results[0],
|
||||
bench_results[bench_results.len() - 1],
|
||||
bench_results[bench_results.len() / 2]
|
||||
);
|
||||
println!("First time took {} μs", first_run_time);
|
||||
|
||||
for res in bench_results {
|
||||
println!("{}", res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_once(single_day: bool, day: u8, bench_results: &mut Vec<u128>) {
|
||||
|
||||
Reference in New Issue
Block a user