add: all junk
This commit is contained in:
Generated
+32
@@ -7,6 +7,7 @@ name = "advent-of-code-2024"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
|
"threadpool",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -18,12 +19,34 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.167"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
@@ -52,3 +75,12 @@ name = "regex-syntax"
|
|||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "threadpool"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
||||||
|
dependencies = [
|
||||||
|
"num_cpus",
|
||||||
|
]
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
|
threadpool = "1.8.1"
|
||||||
|
|||||||
+68
-12
@@ -23,44 +23,78 @@ fn solve(lines: Vec<String>) -> SResult<(usize, usize)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (count, paths) = walk(&map, start_position, cur_icon, &vels).unwrap();
|
let mut real = RealPath { path: Vec::new() };
|
||||||
|
let mut seen_with_direction_reuse: HashSet<(Pair, usize)> = HashSet::new();
|
||||||
|
let mut seen_with_direction: HashSet<(Pair, usize)> = HashSet::new();
|
||||||
|
walk(
|
||||||
|
&map,
|
||||||
|
start_position,
|
||||||
|
cur_icon,
|
||||||
|
&vels,
|
||||||
|
&seen_with_direction,
|
||||||
|
&mut seen_with_direction_reuse,
|
||||||
|
&mut real,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Try placing problems
|
// Try placing problems
|
||||||
let mut blocks: HashSet<Pair> = HashSet::new();
|
let mut blocks: HashSet<Pair> = HashSet::new();
|
||||||
for path in paths.iter() {
|
let mut seen = HashSet::with_capacity(real.path.len());
|
||||||
|
seen.insert(start_position);
|
||||||
|
for path in real.path.into_iter() {
|
||||||
|
seen.insert(path.0);
|
||||||
let next = match next(path.0, vels[path.1].1, map.len()) {
|
let next = match next(path.0, vels[path.1].1, map.len()) {
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
None => continue,
|
None => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
// We've already been here, so couldn't have placed a block here.
|
||||||
|
if seen.contains(&next) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let o = map[next.0][next.1];
|
let o = map[next.0][next.1];
|
||||||
if o == '#' {
|
if o == '#' {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
map[next.0][next.1] = '#';
|
map[next.0][next.1] = '#';
|
||||||
if let None = walk(&map, start_position, cur_icon, &vels) {
|
if let None = walk(
|
||||||
|
&map,
|
||||||
|
path.0,
|
||||||
|
path.1,
|
||||||
|
&vels,
|
||||||
|
&seen_with_direction,
|
||||||
|
&mut seen_with_direction_reuse,
|
||||||
|
&mut FakePath {},
|
||||||
|
) {
|
||||||
blocks.insert(next);
|
blocks.insert(next);
|
||||||
}
|
}
|
||||||
map[next.0][next.1] = o;
|
map[next.0][next.1] = o;
|
||||||
|
seen_with_direction.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((count, blocks.len()))
|
Ok((seen.len(), blocks.len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of covered squares if the path ends; else, None.
|
// Returns the number of covered squares if the path ends; else, None.
|
||||||
fn walk(
|
fn walk<P: Pather>(
|
||||||
map: &[Vec<char>],
|
map: &[Vec<char>],
|
||||||
mut cur_position: Pair,
|
mut cur_position: Pair,
|
||||||
mut cur_icon: usize,
|
mut cur_icon: usize,
|
||||||
vels: &[(char, Pair<i64>)],
|
vels: &[(char, Pair<i64>)],
|
||||||
) -> Option<(usize, HashSet<(Pair, usize)>)> {
|
initial_seen_with_direction: &HashSet<(Pair, usize)>,
|
||||||
let mut seen_cells: HashSet<Pair> = HashSet::new();
|
seen_with_direction: &mut HashSet<(Pair, usize)>,
|
||||||
let mut seen_with_direction: HashSet<(Pair, usize)> = HashSet::new();
|
pather: &mut P,
|
||||||
|
) -> Option<()> {
|
||||||
|
seen_with_direction.clear();
|
||||||
loop {
|
loop {
|
||||||
if seen_with_direction.contains(&(cur_position, cur_icon)) {
|
if seen_with_direction.contains(&(cur_position, cur_icon))
|
||||||
|
|| initial_seen_with_direction.contains(&(cur_position, cur_icon))
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
seen_cells.insert(cur_position);
|
|
||||||
seen_with_direction.insert((cur_position, cur_icon));
|
seen_with_direction.insert((cur_position, cur_icon));
|
||||||
|
pather.record((cur_position, cur_icon));
|
||||||
if let Some(next) = next(cur_position, vels[cur_icon].1, map.len()) {
|
if let Some(next) = next(cur_position, vels[cur_icon].1, map.len()) {
|
||||||
if map[next.0][next.1] == '#' {
|
if map[next.0][next.1] == '#' {
|
||||||
cur_icon = (cur_icon + 1) % vels.len();
|
cur_icon = (cur_icon + 1) % vels.len();
|
||||||
@@ -71,7 +105,29 @@ fn walk(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some((seen_cells.len(), seen_with_direction))
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Pather {
|
||||||
|
fn record(&mut self, _: (Pair, usize));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RealPath {
|
||||||
|
path: Vec<(Pair, usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pather for RealPath {
|
||||||
|
fn record(&mut self, p: (Pair, usize)) {
|
||||||
|
self.path.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FakePath {}
|
||||||
|
|
||||||
|
impl Pather for FakePath {
|
||||||
|
fn record(&mut self, _: (Pair, usize)) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
use std::{collections::HashSet, str::Chars};
|
||||||
|
|
||||||
|
use advent_of_code_2024::{make_main, next, Pair, SResult};
|
||||||
|
|
||||||
|
make_main!();
|
||||||
|
|
||||||
|
fn solve(lines: Vec<String>) -> SResult<(usize, usize)> {
|
||||||
|
let mut total = 0;
|
||||||
|
for line in lines {
|
||||||
|
let (_, (target, trip)) = parse_problem(&line).unwrap();
|
||||||
|
for opt in trip.make_opts() {
|
||||||
|
if opt.eval() == target {
|
||||||
|
total += target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((total as usize, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
type PResult<'a, S> = Result<(&'a str, S), &'static str>;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone)]
|
||||||
|
struct Triple {
|
||||||
|
left: Op,
|
||||||
|
right: Op,
|
||||||
|
oper: Oper,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Triple {
|
||||||
|
fn make_opts(&self) -> Vec<Triple> {
|
||||||
|
if self.oper != Oper::UNKNOWN {
|
||||||
|
return vec![self.clone()];
|
||||||
|
}
|
||||||
|
let mut ret = vec!();
|
||||||
|
for oper in [Oper::ADD, Oper::MUL] {
|
||||||
|
for left in self.left.make_opts() {
|
||||||
|
for right in self.right.make_opts() {
|
||||||
|
ret.push(Triple{left: left.clone(), right, oper});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self) -> i64 {
|
||||||
|
match self.oper {
|
||||||
|
Oper::MUL => self.left.eval() * self.right.eval(),
|
||||||
|
Oper::ADD => self.left.eval() + self.right.eval(),
|
||||||
|
Oper::UNKNOWN => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone)]
|
||||||
|
enum Op {
|
||||||
|
Const(i64),
|
||||||
|
Triple(Box<Triple>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Op {
|
||||||
|
fn make_opts(&self) -> Vec<Op> {
|
||||||
|
match self {
|
||||||
|
Op::Const(x) => vec![Op::Const(*x)],
|
||||||
|
Op::Triple(t) => {
|
||||||
|
let mut ret = vec!();
|
||||||
|
for triple in t.make_opts() {
|
||||||
|
ret.push(Op::Triple(Box::new(triple)));
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self) -> i64 {
|
||||||
|
match self {
|
||||||
|
Op::Const(x) => *x,
|
||||||
|
Op::Triple(t) => t.eval(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
|
enum Oper {
|
||||||
|
UNKNOWN,
|
||||||
|
ADD,
|
||||||
|
MUL,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_problem(s: &str) -> PResult<(i64, Triple)> {
|
||||||
|
let (s, target) = take_int(s)?;
|
||||||
|
let (s, _) = take_one(s)?;
|
||||||
|
let (s, triple) = parse_triple(s)?;
|
||||||
|
Ok((s, (target.eval(), triple)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_one(s: &str) -> PResult<char> {
|
||||||
|
let c = s.chars().next().ok_or("missing char")?;
|
||||||
|
Ok((s, c))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_ws(s: &str) -> PResult<()> {
|
||||||
|
let mut chars = s,chars();
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
|
Ok((s.split_at(i), ()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_triple(s: &str) -> PResult<Triple> {
|
||||||
|
let (s, _) = take_ws(s)?;
|
||||||
|
let (s, left) = take_int(s)?;
|
||||||
|
let (s, _) = take_ws(s)?;
|
||||||
|
let oper = Oper::UNKNOWN;
|
||||||
|
let (s, _) = take_ws(s)?;
|
||||||
|
let (s, right) = match parse_triple(s) {
|
||||||
|
Ok((s, triple)) => (s, Op::Triple(Box::new(triple))),
|
||||||
|
Err(_) => take_int(s)?,
|
||||||
|
};
|
||||||
|
let (s, _) = take_ws(s)?;
|
||||||
|
|
||||||
|
Ok((s, Triple{left, right, oper}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_int(s: &str) -> PResult<Op> {
|
||||||
|
let mut total = 0;
|
||||||
|
let mut i = 0;
|
||||||
|
let mut chars = s.chars();
|
||||||
|
while let Some(c) = chars.by_ref().peekable().next_if(|c| c.is_digit(10)) {
|
||||||
|
total = total * 10 + c.to_digit(10).unwrap();
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
panic!("here");
|
||||||
|
Err("no digits")
|
||||||
|
} else {
|
||||||
|
Ok((chars.as_str(), Op::Const(total as i64)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use advent_of_code_2024::input;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn sample_input() {
|
||||||
|
let strings: Vec<String> = input!("d7p1.txt");
|
||||||
|
let got = solve(strings).unwrap();
|
||||||
|
assert_eq!(got, (3749, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
190: 10 19
|
||||||
|
3267: 81 40 27
|
||||||
|
83: 17 5
|
||||||
|
156: 15 6
|
||||||
|
7290: 6 8 6 15
|
||||||
|
161011: 16 10 13
|
||||||
|
192: 17 8 14
|
||||||
|
21037: 9 7 18 13
|
||||||
|
292: 11 6 16 20
|
||||||
Reference in New Issue
Block a user