Compare commits

..

No commits in common. "67f4cb57ed9a71b38b55c1aac38d8cca580d74e7" and "52e7bb9af7bf2e6e9188cfc74232f4b9756df4a0" have entirely different histories.

5 changed files with 33 additions and 173 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,6 +1,6 @@
<!-- AOC TILES BEGIN -->
<h1 align="center">
2024 - 43 ⭐ - Rust
2024 - 40 ⭐ - Rust
</h1>
<a href="src/day1.rs">
<img src=".aoc_tiles/tiles/2024/01.png" width="161px">
@ -65,7 +65,4 @@
<a href="src/day21.rs">
<img src=".aoc_tiles/tiles/2024/21.png" width="161px">
</a>
<a href="src/day22.rs">
<img src=".aoc_tiles/tiles/2024/22.png" width="161px">
</a>
<!-- AOC TILES END -->

View File

@ -1,7 +1,18 @@
use std::collections::VecDeque;
use std::{
cmp::Reverse,
collections::{BinaryHeap, VecDeque},
};
use aoc_runner_derive::aoc;
use grid::Grid;
use rustc_hash::{FxHashMap, FxHashSet};
trait PathTrack {
const DOES_WORK: bool = true;
fn new() -> Self;
fn push(&mut self, pos: (i64, i64));
fn finalize(&mut self) {}
}
struct RaceTrack {
map: Grid<u8>,
@ -10,7 +21,7 @@ struct RaceTrack {
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
struct State {
pos: (i64, i64),
cost: u64,
cost: usize,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
@ -39,12 +50,15 @@ impl RaceTrack {
_ => None,
})
}
fn path_costs(&self, start: (i64, i64), goal: (i64, i64)) -> (Vec<(i64, i64)>, Grid<Option<u64>>) {
fn path_costs(&self, start: (i64, i64), goal: (i64, i64)) -> (Vec<(i64, i64)>, Grid<Option<usize>>) {
let mut queue = VecDeque::new();
let mut visited = self.map.same_shape(None);
let start_state = CheatState {
s: State { pos: start, cost: 0 },
s: State {
pos: start,
cost: 0usize,
},
p: Vec::new(),
};
visited.set(&start, Some(0));
@ -72,9 +86,9 @@ impl RaceTrack {
fn find_cheats(
&self,
path: &Vec<(i64, i64)>,
costs: &Grid<Option<u64>>,
min: u64,
) -> Vec<((i64, i64), (i64, i64), u64)> {
costs: &Grid<Option<usize>>,
min: usize,
) -> Vec<((i64, i64), (i64, i64), usize)> {
let mut cheats = Vec::new();
for pos in path {
let local_cost = costs.get(pos).unwrap().unwrap();
@ -93,47 +107,6 @@ impl RaceTrack {
}
cheats
}
fn taxi_dist(&self, from: &(i64, i64), to: &(i64, i64)) -> Option<u64> {
if self.map.is_valid(to) {
Some(from.0.abs_diff(to.0) + from.1.abs_diff(to.1))
} else {
None
}
}
fn find_cheats_n(
&self,
path: &Vec<(i64, i64)>,
costs: &Grid<Option<u64>>,
max_length: u64,
min: u64,
) -> Vec<((i64, i64), (i64, i64))> {
let mut cheats = Vec::new();
let mut solutions = self.map.clone();
for pos in path {
let from_cost = costs.get(pos).unwrap().unwrap();
for x in 0..self.map.width() as i64 {
for y in 0..self.map.height() as i64 {
if let Some(dist) = self.taxi_dist(pos, &(x, y)) {
if dist <= max_length && dist >= 2 {
if let Some(to_cost) = costs.get(&(x, y)).unwrap() {
solutions.set(pos, b'O');
solutions.set(&(x, y), b'O');
if *to_cost > (from_cost + dist) && (to_cost - (from_cost + dist) >= min) {
cheats.push((*pos, (x, y)));
}
}
}
}
solutions.set(&(x, y), *self.map.get(&(x, y)).unwrap());
}
}
solutions.set(pos, *self.map.get(pos).unwrap());
}
cheats
}
}
fn parse(input: &str) -> RaceTrack {
@ -141,7 +114,7 @@ fn parse(input: &str) -> RaceTrack {
RaceTrack { map }
}
fn part1_impl(input: &str, cheat_min: u64) -> i64 {
fn part1_impl(input: &str, cheat_min: usize) -> i64 {
let track = parse(input);
let start = track.map.find(&b'S').unwrap();
let goal = track.map.find(&b'E').unwrap();
@ -151,16 +124,6 @@ fn part1_impl(input: &str, cheat_min: u64) -> i64 {
cheats.len() as i64
}
fn part2_impl(input: &str, max_length: u64, cheat_min: u64) -> i64 {
let track = parse(input);
let start = track.map.find(&b'S').unwrap();
let goal = track.map.find(&b'E').unwrap();
let (best_path, costs) = track.path_costs(start.into(), goal.into());
let cheats = track.find_cheats_n(&best_path, &costs, max_length, cheat_min);
cheats.len() as i64
}
#[aoc(day20, part1)]
pub fn part1(input: &str) -> i64 {
part1_impl(input, 100)
@ -168,7 +131,7 @@ pub fn part1(input: &str) -> i64 {
#[aoc(day20, part2)]
pub fn part2(input: &str) -> i64 {
part2_impl(input, 20, 100)
todo!()
}
#[cfg(test)]
@ -197,7 +160,6 @@ mod tests {
#[test]
fn part2_example() {
assert_eq!(part2_impl(EXAMPLE, 2, 0), 44);
assert_eq!(part2_impl(EXAMPLE, 20, 50), 285);
assert_eq!(part2(EXAMPLE), 0);
}
}

View File

@ -1,17 +1,9 @@
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
struct Change {
price: i8,
delta: i8,
}
fn evolve_secret(mut n: i64) -> i64 {
n = ((n * 64) ^ n) % 16777216;
n = ((n / 32) ^ n) % 16777216;
n = ((n * 2048) ^ n) % 16777216;
n = ((n * 2048) ^ n) % 16777216;
n
}
@ -22,54 +14,6 @@ fn rounds(mut secret: i64, n: i64) -> i64 {
secret
}
fn prices(mut secret: i64, n: i64) -> Vec<i8> {
let mut prices = vec![(secret % 10) as i8];
for _ in 1..n {
secret = evolve_secret(secret);
prices.push((secret % 10) as i8);
}
prices
}
fn changes(prices: &Vec<i8>) -> Vec<Change> {
prices
.windows(2)
.map(|a| Change {
price: a[1],
delta: a[1] - a[0],
})
.collect()
}
fn profit_for_sequence(changes: &Vec<Vec<Change>>, seq: &[i8]) -> i64 {
changes
.par_iter()
.filter_map(|inner| {
if let Some(buy) = inner
.windows(seq.len())
.find(|window| window.iter().zip(seq).all(|(w, z)| w.delta == *z))
{
Some(buy[seq.len() - 1].price as i64)
} else {
None
}
})
.sum()
}
fn find_best_sequence(changes: &Vec<Vec<Change>>) -> [i8; 4] {
let mut best_seq = [0, 0, 0, 0];
let mut best_profit = 0;
for seq in (0..4).map(|_| (-9..=9 as i8)).multi_cartesian_product() {
let profit = profit_for_sequence(changes, &seq);
if profit > best_profit {
best_seq = seq.try_into().unwrap();
best_profit = profit;
}
}
best_seq
}
fn parse(input: &str) -> Vec<i64> {
input.lines().map(|l| l.parse().unwrap()).collect()
}
@ -83,26 +27,16 @@ fn part1(input: &str) -> i64 {
#[aoc(day22, part2)]
fn part2(input: &str) -> i64 {
let secrets = parse(input);
let price_changes = secrets.iter().map(|s| changes(&prices(*s, 2000))).collect_vec();
let seq = find_best_sequence(&price_changes);
println!("found best seq: {:?}", seq);
profit_for_sequence(&price_changes, &seq)
todo!()
}
#[cfg(test)]
mod tests {
use super::*;
const EXAMPLE: &str = "1
10
100
2024";
const EXAMPLE2: &str = "1
2
3
2024";
#[test]
@ -110,54 +44,21 @@ mod tests {
assert_eq!(evolve_secret(123), 15887950);
assert_eq!(evolve_secret(15887950), 16495136);
assert_eq!(evolve_secret(16495136), 527345);
}
}
#[test]
fn test_rounds() {
assert_eq!(rounds(1, 2000), 8685429);
assert_eq!(rounds(10, 2000), 4700978);
}
#[test]
fn test_prices() {
assert_eq!(prices(123, 10), vec![3, 0, 6, 5, 4, 4, 6, 4, 4, 2]);
}
#[test]
fn test_profit() {
assert_eq!(
profit_for_sequence(&vec![changes(&prices(123, 10))], &[-1, -1, 0, 2]),
6
);
let secrets = parse(EXAMPLE2);
let price_changes = secrets.iter().map(|s| changes(&prices(*s, 2000))).collect_vec();
assert_eq!(
profit_for_sequence(&price_changes, &[-2, 1, -1, 3]),
23
);
}
#[test]
fn test_changes() {
let changes = changes(&prices(123, 10));
assert_eq!(
changes.iter().map(|c| c.delta).collect_vec(),
vec![-3, 6, -1, -1, 0, 2, -2, 0, -2]
);
assert_eq!(
changes.iter().map(|c| c.price).collect_vec(),
vec![0, 6, 5, 4, 4, 6, 4, 4, 2]
);
}
}
#[test]
fn part1_example() {
assert_eq!(part1(EXAMPLE), 37327623);
assert_eq!(part1(EXAMPLE),37327623);
}
#[test]
fn part2_example() {
assert_eq!(part2(EXAMPLE2), 23);
assert_eq!(part2(EXAMPLE), 0);
}
}
}