[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 day10;
|
||||||
mod day11;
|
mod day11;
|
||||||
mod day12;
|
mod day12;
|
||||||
|
mod day13;
|
||||||
|
|
||||||
const MAX_DAY: u8 = 12;
|
const MAX_DAY: u8 = 13;
|
||||||
const BENCHMARK_AMOUNT: u32 = 100;
|
const BENCHMARK_AMOUNT: u32 = 1000;
|
||||||
|
|
||||||
fn solve(day: u8) {
|
fn solve(day: u8) {
|
||||||
match day {
|
match day {
|
||||||
@@ -32,13 +33,13 @@ fn solve(day: u8) {
|
|||||||
10 => day10::solve(),
|
10 => day10::solve(),
|
||||||
11 => day11::solve(),
|
11 => day11::solve(),
|
||||||
12 => day12::solve(),
|
12 => day12::solve(),
|
||||||
|
13 => day13::solve(),
|
||||||
_ => println!("This day is not yet implemented")
|
_ => println!("This day is not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
|
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
|
||||||
let day_arg_idx = args.iter().position(|a| a == "-d");
|
let day_arg_idx = args.iter().position(|a| a == "-d");
|
||||||
@@ -51,8 +52,11 @@ fn main() {
|
|||||||
|
|
||||||
// This is essentially the warmup for the benchmark:
|
// This is essentially the warmup for the benchmark:
|
||||||
run_once(single_day, day, &mut bench_results);
|
run_once(single_day, day, &mut bench_results);
|
||||||
|
let first_run_time = bench_results[0];
|
||||||
|
|
||||||
if benchmark {
|
if benchmark {
|
||||||
|
// Ignore the warmup run in the rest of the benchmark:
|
||||||
|
bench_results.clear();
|
||||||
for _ in 0..BENCHMARK_AMOUNT {
|
for _ in 0..BENCHMARK_AMOUNT {
|
||||||
run_once(single_day, day, &mut bench_results);
|
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);
|
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 { "" });
|
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>) {
|
fn run_once(single_day: bool, day: u8, bench_results: &mut Vec<u128>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user