Skip to content

Commit f4b46f5

Browse files
committed
WIP on master: 2c5ab37 fixup
2 parents 2c5ab37 + 3a1d74c commit f4b46f5

File tree

14 files changed

+834
-28
lines changed

14 files changed

+834
-28
lines changed

2022/day12/src/main.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::fs;
66
use std::fs::File;
77
use std::io;
88
use std::io::Write;
9+
use std::ops::{Add, Sub};
910
use std::path::Path;
1011

1112
fn main() {
@@ -22,6 +23,7 @@ fn main() {
2223
}
2324

2425
fn part1(input: &Input) -> usize {
26+
let mut prev: HashMap<(usize, usize), (usize, usize)> = HashMap::new();
2527
let mut best: HashMap<(usize, usize), usize> = [(input.start, 0)].into_iter().collect();
2628
let mut edge = vec![input.start];
2729

@@ -34,6 +36,7 @@ fn part1(input: &Input) -> usize {
3436
for neighbour in input.neighbour(pos) {
3537
let steps = best[&pos] + 1;
3638
if best.get(&neighbour).map(|best| steps < *best).unwrap_or(true) {
39+
prev.insert(neighbour, pos);
3740
best.insert(neighbour, steps);
3841
edge.push(neighbour);
3942
}
@@ -42,6 +45,16 @@ fn part1(input: &Input) -> usize {
4245
edge.sort_by(|a, b| best[b].cmp(&best[a]));
4346
}
4447

48+
// Walk path
49+
let mut pos = input.end;
50+
println!("[");
51+
println!(" ({}, {}, {}),", pos.0, pos.1, input.map[&pos]);
52+
while let Some(&p) = prev.get(&pos) {
53+
println!(" ({}, {}, {}),", p.0, p.1, input.map[&p]);
54+
pos = p;
55+
}
56+
println!("]");
57+
4558
// What is the fewest steps required to move from your current position
4659
// to the location that should get the best signal?
4760
best[&input.end]

2023/Cargo.lock

Lines changed: 72 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

2023/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ members = [
2424
"day22",
2525
"day23",
2626
"day24",
27-
# "day25",
27+
"day25",
2828
]
2929
exclude = []
3030
resolver = "2"

2023/day12/example1.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
?###???????? 3,2,1
12
???.### 1,1,3
23
.??..??...?##. 1,1,3
34
?#?#?#?#?#?#?#? 1,3,1,6

2023/day12/src/main.rs

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::path::Path;
66

77
fn main() {
88
let input = Input::from_file(format!("{}/input.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
9-
//let input = Input::from_file(format!("{}/example1.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
9+
let input = Input::from_file(format!("{}/example1.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
1010

1111
// Part 1
1212
println!("Part 1: {}", part1(&input));
@@ -36,7 +36,7 @@ fn part1(input: &Input) -> usize {
3636
combinations.push(count);
3737
}
3838

39-
println!("{:?}", combinations);
39+
//println!("{:?}", combinations);
4040
combinations.into_iter().sum()
4141
}
4242

@@ -69,6 +69,105 @@ fn is_match(state: &[State], groups: &[usize]) -> bool {
6969
}
7070

7171
fn part2(input: &Input) -> usize {
72+
for (records, groups) in &input.values {
73+
let mut records = records.clone();
74+
println!("{records:?} {groups:?}");
75+
76+
let total = records.len();
77+
let n_damaged: usize = groups.iter().sum();
78+
let n_ok = total - n_damaged;
79+
80+
println!("total: {total}, damaged: {n_damaged}, ok: {n_ok}");
81+
82+
// We can split these up into groups of ok/broken/ok/.../broken/ok
83+
// N0 + A + (1 + N1) + B + (1 + N2) + ... + Z + Nn = total
84+
// We know that N0 .. Nn must be in the range 0..a
85+
let mut a = n_ok - (groups.len() - 1);
86+
println!("a: {a}");
87+
88+
// There's always at least one OK spring between broken sets
89+
let mut ns = vec![[0, a]; groups.len() + 1];
90+
for n in 1..groups.len() {
91+
ns[n][0] += 1;
92+
ns[n][1] += 1;
93+
}
94+
95+
let mut ok_known = records.iter().filter(|r| matches!(r, State::Operational)).count();
96+
let mut damaged_known = records.iter().filter(|r| matches!(r, State::Damaged)).count();
97+
let mut unknown = records.iter().filter(|r| matches!(r, State::Unknown)).count();
98+
assert_eq!(ok_known + damaged_known + unknown, records.len());
99+
100+
let mut n = 0;
101+
let mut ok_seen = 0;
102+
let mut damaged_seen = 0;
103+
let mut unknown_seen = 0;
104+
for i in 0..records.len() {
105+
println!("{i:02}: OK={ok_seen:2}, NG={damaged_seen:2}, UNK={unknown_seen:2} {ns:?}");
106+
match records[i] {
107+
State::Damaged => {
108+
damaged_seen += 1;
109+
110+
ns[n][1] = ns[n][1].min(i); // This can probably be more agressive
111+
112+
if damaged_seen == groups[0] {
113+
if (i + 1) > groups[n] {
114+
// This set must be preceeded by an undamaged mirror
115+
assert!(!matches!(records[i - groups[n]], State::Damaged));
116+
117+
if matches!(records[i - groups[n]], State::Unknown) {
118+
records[i - groups[n]] = State::Operational;
119+
ok_known += 1;
120+
unknown -= 1;
121+
}
122+
123+
ns[n][0] += 1;
124+
a = a.saturating_sub(1);
125+
for m in (0..ns.len()).filter(|&m| m != n) {
126+
ns[m][1] = ns[m][1].min(a);
127+
}
128+
}
129+
130+
if (i + 1) < records.len() {
131+
// This set must be followed by an undamaged mirror
132+
assert!(!matches!(records[i + 1], State::Damaged));
133+
134+
if matches!(records[i + 1], State::Unknown) {
135+
records[i + 1] = State::Operational;
136+
ok_known += 1;
137+
unknown -= 1;
138+
}
139+
140+
assert_eq!(ns[n + 1][0], 1); // already accounted for there being at least 1
141+
}
142+
143+
ok_seen = 0;
144+
damaged_seen = 0;
145+
unknown_seen = 0;
146+
147+
n += 1;
148+
}
149+
},
150+
State::Operational => {
151+
ok_seen += 1;
152+
},
153+
State::Unknown => {
154+
unknown_seen += 1;
155+
},
156+
}
157+
158+
// We have to always maintain these invariants
159+
assert!(ok_seen <= n_ok);
160+
assert!(damaged_seen <= n_damaged);
161+
assert_eq!(ok_known + damaged_known + unknown, records.len());
162+
assert!(ns.iter().map(|[lower, _]| lower).sum::<usize>() <= n_ok, "violated lower-bounds: {ns:?}");
163+
assert!(ns.iter().map(|[_, upper]| upper).sum::<usize>() >= n_ok, "violated upper-bounds: {ns:?}");
164+
assert!(ns.iter().all(|[lower, upper]| lower <= upper));
165+
}
166+
167+
// We've done all we can
168+
println!();
169+
}
170+
72171
0
73172
}
74173

2023/day18/src/main.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,96 @@ fn part1(input: &Input) -> usize {
5252
}
5353

5454
fn part2(input: &Input) -> usize {
55+
let mut x = 0;
56+
let mut y = 0;
57+
let mut coords = vec![(x, y)];
58+
59+
60+
/*
61+
for (_, _, color) in &input.values {
62+
let distance = i64::from_str_radix(&color[1..6], 16).unwrap();
63+
match &color[6..7] {
64+
"0" => x += distance, // Right,
65+
"1" => y += distance, // Down
66+
"2" => x -= distance, // Left
67+
"3" => y -= distance, // Up
68+
s => panic!("unknown directional ordinal: {s:?}"),
69+
}
70+
71+
coords.push((x, y));
72+
}
73+
*/
74+
for (direction, distance, _) in &input.values {
75+
match direction {
76+
Direction::Up => y -= distance,
77+
Direction::Down => y += distance,
78+
Direction::Left => x -= distance,
79+
Direction::Right => x += distance,
80+
}
81+
82+
coords.push((x, y));
83+
}
84+
85+
assert_eq!(coords.first().unwrap(), coords.last().unwrap());
86+
87+
let forward: Vec<(i64, i64)> = coords.iter().copied().collect();
88+
let backwards: Vec<(i64, i64)> = coords.iter().rev().copied().collect();
89+
90+
let mut i = 0;
91+
let mut j = 0;
92+
93+
let mut begin: Pos = (0, 0);
94+
let mut a: Pos = (0, 0);
95+
let mut b: Pos = (0, 0);
96+
let mut total_area = 0;
97+
98+
99+
loop {
100+
while a.0 - begin.0 == 0 || a.1 - begin.1 == 0 {
101+
i += 1;
102+
a = forward[i];
103+
}
104+
105+
while b.0 - begin.0 == 0 || b.1 - begin.1 == 0 {
106+
j += 1;
107+
b = backwards[j];
108+
}
109+
110+
let dx_a = a.0 - begin.0;
111+
let dx_b = b.0 - begin.0;
112+
let dy_a = a.1 - begin.1;
113+
let dy_b = b.1 - begin.1;
114+
115+
let dx = dx_a;
116+
let dy = if dy_a.abs() < dy_b.abs() { dy_a } else { dy_b };
117+
118+
println!("dx {dx}, dy {dy}");
119+
120+
total_area += (dx.abs() + 1) * (dy.abs() + 1);
121+
122+
begin = (begin.0 + dx_b + dx_b.signum(), begin.1 + dy + dy.signum());
123+
124+
println!("{}", total_area);
125+
126+
if total_area > 10 {
127+
break;
128+
}
129+
}
130+
55131
0
56132
}
57133

134+
type Pos = (i64, i64);
135+
136+
fn delta(x1: (i64, i64), x0: (i64, i64)) -> (i64, i64) {
137+
(x1.0 - x0.0, x1.1 - x0.1)
138+
}
139+
140+
fn area(x0: Pos, x1: Pos) -> i64 {
141+
(x1.0 - x0.0).abs() * (x1.1 - x0.1).abs()
142+
}
143+
144+
58145
#[derive(Debug, Clone)]
59146
struct Input {
60147
/// `(direction, distance, color)`

2023/day24/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const T_MIN: f64 = 0.0;
99
const RANGE: RangeInclusive<f64> = 200000000000000.0..=400000000000000.0;
1010

1111
fn main() {
12-
let input = Input::from_file(format!("{}/input.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
13-
//let input = Input::from_file(format!("{}/example1.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
12+
//let input = Input::from_file(format!("{}/input.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
13+
let input = Input::from_file(format!("{}/example1.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
1414
//println!("{input:?}");
1515

1616
// Part 1
@@ -37,7 +37,7 @@ fn intersections_within_area(input: &Input, range: RangeInclusive<f64>) -> usize
3737
let b = input.values[j];
3838
let (intersect, (t_a, t_b)) = solve_xy_intersection(a, b);
3939

40-
//println!("{a:?} {b:?}: {intersect:?} @ {t_a}/{t_b} ns");
40+
println!("{a:?} {b:?}: {intersect:?} @ {t_a}/{t_b} ns");
4141
if range.contains(&intersect.x) && range.contains(&intersect.y) && t_a > T_MIN && t_b > T_MIN {
4242
n += 1;
4343
}

0 commit comments

Comments
 (0)