Skip to content

Commit 80a7095

Browse files
committed
2025 days 9-12
1 parent fb35d22 commit 80a7095

File tree

17 files changed

+519
-0
lines changed

17 files changed

+519
-0
lines changed

2025/09/.gitkeep

Whitespace-only changes.

2025/09/dy-tea.v

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import os
2+
import math
3+
4+
fn react_area(x1 i64, y1 i64, x2 i64, y2 i64) u64 {
5+
dx := math.abs(x1 - x2) + 1
6+
dy := math.abs(y1 - y2) + 1
7+
return u64(dx) * u64(dy)
8+
}
9+
10+
@[flag]
11+
enum Direction {
12+
x_pos
13+
x_neg
14+
y_pos
15+
y_neg
16+
}
17+
18+
fn Direction.new(x1 u32, y1 u32, x2 u32, y2 u32) Direction {
19+
return match true {
20+
x1 == x2 && y1 < y2 { .y_pos }
21+
x1 == x2 && y1 > y2 { .y_neg }
22+
y1 == y2 && x1 < x2 { .x_pos }
23+
else { .x_neg }
24+
}
25+
}
26+
27+
struct DirectedPoint {
28+
x u32
29+
y u32
30+
e u32
31+
d Direction
32+
}
33+
34+
fn DirectedPoint.new(x1 u32, y1 u32, x2 u32, y2 u32) DirectedPoint {
35+
dx := if x2 > x1 { x2 - x1 } else { x1 - x2 }
36+
dy := if y2 > y1 { y2 - y1 } else { y1 - y2 }
37+
return DirectedPoint{
38+
x: x1
39+
y: y1
40+
e: math.max(dx, dy)
41+
d: Direction.new(x1, y1, x2, y2)
42+
}
43+
}
44+
45+
fn (dp DirectedPoint) extent_overlaps(x1 u32, y1 u32, x2 u32, y2 u32) bool {
46+
rx_min := math.min(x1, x2)
47+
rx_max := math.max(x1, x2)
48+
ry_min := math.min(y1, y2)
49+
ry_max := math.max(y1, y2)
50+
51+
ro_min, ro_max := match dp.d {
52+
.x_neg { dp.x - dp.e, dp.x }
53+
.x_pos { dp.x, dp.x + dp.e }
54+
.y_neg { dp.y - dp.e, dp.y }
55+
.y_pos { dp.y, dp.y + dp.e }
56+
else { u32(0), u32(0) }
57+
}
58+
59+
return match dp.d {
60+
.x_neg, .x_pos {
61+
rx_min < ro_max && ro_min < rx_max
62+
}
63+
.y_neg, .y_pos {
64+
ry_min < ro_max && ro_min < ry_max
65+
}
66+
else {
67+
false
68+
}
69+
}
70+
}
71+
72+
fn is_red_inside(points []DirectedPoint, x1 u32, y1 u32, x2 u32, y2 u32, xs u32, xe u32, ys u32, ye u32) bool {
73+
return points.filter(fn [x1, x2, y1, y2] (p DirectedPoint) bool {
74+
return p.x != x1 && p.x != x2 && p.y != y1 && p.y != y2
75+
}).any(fn [xs, xe, ys, ye] (p DirectedPoint) bool {
76+
return xs <= p.x && p.x <= xe && ys <= p.y && p.y <= ye
77+
})
78+
}
79+
80+
fn valid_area(points []DirectedPoint, x1 u32, y1 u32, x2 u32, y2 u32) ?u64 {
81+
minx := math.min(x1, x2)
82+
maxx := math.max(x1, x2)
83+
miny := math.min(y1, y2)
84+
maxy := math.max(y1, y2)
85+
86+
if is_red_inside(points, x1, y1, x2, y2, minx, maxx, miny, maxy) {
87+
return none
88+
}
89+
90+
region_x_min := minx + 1
91+
region_x_max := maxx
92+
region_y_min := miny + 1
93+
region_y_max := maxy
94+
95+
if points.filter(fn [region_x_min, region_x_max, region_y_min, region_y_max] (p DirectedPoint) bool {
96+
return (region_x_min <= p.x && p.x < region_x_max && (p.d == .y_pos || p.d == .y_neg))
97+
|| (region_y_min <= p.y && p.y < region_y_max && (p.d == .x_pos || p.d == .x_neg))
98+
}).any(fn [x1, y1, x2, y2] (p DirectedPoint) bool {
99+
return p.extent_overlaps(x1, y1, x2, y2)
100+
})
101+
{
102+
return none
103+
}
104+
105+
dx := if x2 > x1 { x2 - x1 } else { x1 - x2 }
106+
dy := if y2 > y1 { y2 - y1 } else { y1 - y2 }
107+
return u64(dx + 1) * u64(dy + 1)
108+
}
109+
110+
lines := os.read_lines('tiles.input')!
111+
coords := lines.map(fn (line string) []i64 {
112+
x, y := line.split_once(',') or { panic('invalid input') }
113+
return [x.i64(), y.i64()]
114+
})
115+
116+
// part 1
117+
mut max_area := u64(0)
118+
for i := 0; i < coords.len - 1; i++ {
119+
x, y := coords[i][0], coords[i][1]
120+
for j := i + 1; j < coords.len; j++ {
121+
xx, yy := coords[j][0], coords[j][1]
122+
area := react_area(x, y, xx, yy)
123+
if area > max_area {
124+
max_area = area
125+
}
126+
}
127+
}
128+
println(max_area)
129+
130+
// part 2
131+
red_tiles := coords.map(fn (c []i64) []u32 {
132+
return [u32(c[0]), u32(c[1])]
133+
})
134+
mut tiles_with_directions := []DirectedPoint{cap: red_tiles.len}
135+
for i := 0; i < red_tiles.len; i++ {
136+
next_i := (i + 1) % red_tiles.len
137+
p1 := red_tiles[i]
138+
p2 := red_tiles[next_i]
139+
tiles_with_directions << DirectedPoint.new(p1[0], p1[1], p2[0], p2[1])
140+
}
141+
max_area = 0
142+
for i := 0; i < red_tiles.len - 1; i++ {
143+
p1 := red_tiles[i]
144+
for j := i + 1; j < red_tiles.len; j++ {
145+
p2 := red_tiles[j]
146+
if area := valid_area(tiles_with_directions, p1[0], p1[1], p2[0], p2[1]) {
147+
if area > max_area {
148+
max_area = area
149+
}
150+
}
151+
}
152+
}
153+
println(max_area)

2025/09/tiles.input

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
7,1
2+
11,1
3+
11,7
4+
9,7
5+
9,5
6+
2,5
7+
2,3
8+
7,3

2025/10/.gitkeep

Whitespace-only changes.

2025/10/dy-tea.v

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
import os
2+
import math
3+
4+
struct Machine {
5+
lights []bool
6+
buttons [][]u32
7+
joltages []u32
8+
}
9+
10+
fn generate_combos(mut result [][]int, current []int, start int, n int, k int) {
11+
if current.len == k {
12+
result << current.clone()
13+
return
14+
}
15+
for i in start .. n {
16+
mut next := current.clone()
17+
next << i
18+
generate_combos(mut result, next, i + 1, n, k)
19+
}
20+
}
21+
22+
fn get_combinations(n int, k int) [][]int {
23+
mut result := [][]int{}
24+
if k == 0 {
25+
return [[]]
26+
}
27+
if k > n {
28+
return result
29+
}
30+
generate_combos(mut result, []int{}, 0, n, k)
31+
return result
32+
}
33+
34+
@[direct_array_access]
35+
fn (m Machine) min_light_presses() int {
36+
button_len := m.buttons.len
37+
lights_len := m.lights.len
38+
for press_count in 1 .. button_len {
39+
combinations := get_combinations(button_len, press_count)
40+
for combo in combinations {
41+
mut test := []bool{len: lights_len}
42+
for button_idx in combo {
43+
for light_idx in m.buttons[button_idx] {
44+
test[light_idx] = !test[light_idx]
45+
}
46+
}
47+
if test == m.lights {
48+
return press_count
49+
}
50+
}
51+
}
52+
return button_len
53+
}
54+
55+
@[direct_array_access]
56+
fn (m Machine) min_joltage_presses() int {
57+
n := m.buttons.len
58+
mm := m.joltages.len
59+
60+
mut matrix := [][]f64{len: mm, init: []f64{len: n + 1}}
61+
for eq in 0 .. mm {
62+
for var in 0 .. n {
63+
mut affects := false
64+
for jolt_idx in m.buttons[var] {
65+
if int(jolt_idx) == eq {
66+
affects = true
67+
break
68+
}
69+
}
70+
matrix[eq][var] = if affects { 1.0 } else { 0.0 }
71+
}
72+
matrix[eq][n] = f64(m.joltages[eq])
73+
}
74+
75+
eps := 1e-9
76+
mut row := 0
77+
mut pivot_col := []int{len: n, init: -1}
78+
79+
for col in 0 .. n {
80+
if row >= mm {
81+
break
82+
}
83+
84+
mut sel := row
85+
for i in row .. mm {
86+
if math.abs(matrix[i][col]) > math.abs(matrix[sel][col]) {
87+
sel = i
88+
}
89+
}
90+
91+
if math.abs(matrix[sel][col]) < eps {
92+
continue
93+
}
94+
95+
matrix[sel], matrix[row] = matrix[row], matrix[sel]
96+
97+
div := matrix[row][col]
98+
for j in col .. n + 1 {
99+
matrix[row][j] /= div
100+
}
101+
102+
for i in 0 .. mm {
103+
if i != row {
104+
f := matrix[i][col]
105+
for j in col .. n + 1 {
106+
matrix[i][j] -= f * matrix[row][j]
107+
}
108+
}
109+
}
110+
111+
pivot_col[col] = row
112+
row++
113+
}
114+
115+
mut free_vars := []int{}
116+
for j in 0 .. n {
117+
if pivot_col[j] == -1 {
118+
free_vars << j
119+
}
120+
}
121+
fc := free_vars.len
122+
123+
mut base := []f64{len: n}
124+
mut coeff := [][]f64{len: n, init: []f64{len: fc}}
125+
for var in 0 .. n {
126+
if pivot_col[var] == -1 {
127+
for k in 0 .. fc {
128+
if free_vars[k] == var {
129+
coeff[var][k] = 1.0
130+
}
131+
}
132+
} else {
133+
r := pivot_col[var]
134+
base[var] = matrix[r][n]
135+
for k in 0 .. fc {
136+
coeff[var][k] = -matrix[r][free_vars[k]]
137+
}
138+
}
139+
}
140+
141+
if fc == 0 {
142+
mut sum := i64(0)
143+
for var in 0 .. n {
144+
xi := i64(base[var] + 0.5)
145+
sum += xi
146+
}
147+
return int(sum)
148+
}
149+
150+
max_val := 200
151+
mut best_sum := math.maxof[i64]()
152+
mut t := []int{len: fc}
153+
154+
for {
155+
mut ok := true
156+
mut sum := i64(0)
157+
for var in 0 .. n {
158+
mut xv := base[var]
159+
for k in 0 .. fc {
160+
xv += coeff[var][k] * f64(t[k])
161+
}
162+
xi := i64(xv + 0.5)
163+
if math.abs(xv - f64(xi)) > 1e-9 || xi < 0 {
164+
ok = false
165+
break
166+
}
167+
sum += xi
168+
}
169+
if ok && sum < best_sum {
170+
best_sum = sum
171+
}
172+
mut idx := 0
173+
for idx < fc {
174+
if t[idx] < max_val {
175+
t[idx]++
176+
break
177+
}
178+
t[idx] = 0
179+
idx++
180+
}
181+
if idx == fc {
182+
break
183+
}
184+
}
185+
return int(best_sum)
186+
}
187+
188+
lines := os.read_lines('manual.input')!
189+
machines := lines.map(fn (line string) Machine {
190+
l, rest := line.split_once(' ') or { panic('Invalid input') }
191+
lights := l[1..l.len - 1].runes().map(|r| r == `#`)
192+
b, r := rest.rsplit_once('{') or { panic('Invalid input') }
193+
bb := b.replace(' ', '')
194+
buttons := bb[1..bb.len - 1].split(')(').map(|s| s.split(',').map(|d| d.u32()))
195+
joltages := r[..r.len - 1].split(',').map(|d| d.u32())
196+
return Machine{lights, buttons, joltages}
197+
})
198+
199+
// part 1
200+
mut sum := 0
201+
for m in machines {
202+
sum += m.min_light_presses()
203+
}
204+
println(sum)
205+
206+
// part 2
207+
sum = 0
208+
for m in machines {
209+
sum += m.min_joltage_presses()
210+
}
211+
println(sum)

2025/10/manual.input

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
2+
[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
3+
[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}

2025/11/.gitkeep

Whitespace-only changes.

2025/11/connections_part1.input

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
aaa: you hhh
2+
you: bbb ccc
3+
bbb: ddd eee
4+
ccc: ddd eee fff
5+
ddd: ggg
6+
eee: out
7+
fff: out
8+
ggg: out
9+
hhh: ccc fff iii
10+
iii: out

0 commit comments

Comments
 (0)