From 80a709588163def7d063ff7a79155a19ce4072ff Mon Sep 17 00:00:00 2001 From: Dylan Donnell Date: Fri, 12 Dec 2025 15:12:25 +0000 Subject: [PATCH 1/2] 2025 days 9-12 --- 2025/09/.gitkeep | 0 2025/09/dy-tea.v | 153 +++++++++++++++++++++++ 2025/09/tiles.input | 8 ++ 2025/10/.gitkeep | 0 2025/10/dy-tea.v | 211 ++++++++++++++++++++++++++++++++ 2025/10/manual.input | 3 + 2025/11/.gitkeep | 0 2025/11/connections_part1.input | 10 ++ 2025/11/connections_part2.input | 13 ++ 2025/11/dy-tea.v | 59 +++++++++ 2025/12/.gitkeep | 0 2025/12/dy-tea.v | 22 ++++ 2025/12/shapes.input | 33 +++++ known/2025/09/dy-tea.out | 2 + known/2025/10/dy-tea.out | 2 + known/2025/11/dy-tea.out | 2 + known/2025/12/dy-tea.out | 1 + 17 files changed, 519 insertions(+) delete mode 100644 2025/09/.gitkeep create mode 100644 2025/09/dy-tea.v create mode 100644 2025/09/tiles.input delete mode 100644 2025/10/.gitkeep create mode 100644 2025/10/dy-tea.v create mode 100644 2025/10/manual.input delete mode 100644 2025/11/.gitkeep create mode 100644 2025/11/connections_part1.input create mode 100644 2025/11/connections_part2.input create mode 100644 2025/11/dy-tea.v delete mode 100644 2025/12/.gitkeep create mode 100644 2025/12/dy-tea.v create mode 100644 2025/12/shapes.input create mode 100644 known/2025/09/dy-tea.out create mode 100644 known/2025/10/dy-tea.out create mode 100644 known/2025/11/dy-tea.out create mode 100644 known/2025/12/dy-tea.out diff --git a/2025/09/.gitkeep b/2025/09/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/09/dy-tea.v b/2025/09/dy-tea.v new file mode 100644 index 0000000..3ee97ad --- /dev/null +++ b/2025/09/dy-tea.v @@ -0,0 +1,153 @@ +import os +import math + +fn react_area(x1 i64, y1 i64, x2 i64, y2 i64) u64 { + dx := math.abs(x1 - x2) + 1 + dy := math.abs(y1 - y2) + 1 + return u64(dx) * u64(dy) +} + +@[flag] +enum Direction { + x_pos + x_neg + y_pos + y_neg +} + +fn Direction.new(x1 u32, y1 u32, x2 u32, y2 u32) Direction { + return match true { + x1 == x2 && y1 < y2 { .y_pos } + x1 == x2 && y1 > y2 { .y_neg } + y1 == y2 && x1 < x2 { .x_pos } + else { .x_neg } + } +} + +struct DirectedPoint { + x u32 + y u32 + e u32 + d Direction +} + +fn DirectedPoint.new(x1 u32, y1 u32, x2 u32, y2 u32) DirectedPoint { + dx := if x2 > x1 { x2 - x1 } else { x1 - x2 } + dy := if y2 > y1 { y2 - y1 } else { y1 - y2 } + return DirectedPoint{ + x: x1 + y: y1 + e: math.max(dx, dy) + d: Direction.new(x1, y1, x2, y2) + } +} + +fn (dp DirectedPoint) extent_overlaps(x1 u32, y1 u32, x2 u32, y2 u32) bool { + rx_min := math.min(x1, x2) + rx_max := math.max(x1, x2) + ry_min := math.min(y1, y2) + ry_max := math.max(y1, y2) + + ro_min, ro_max := match dp.d { + .x_neg { dp.x - dp.e, dp.x } + .x_pos { dp.x, dp.x + dp.e } + .y_neg { dp.y - dp.e, dp.y } + .y_pos { dp.y, dp.y + dp.e } + else { u32(0), u32(0) } + } + + return match dp.d { + .x_neg, .x_pos { + rx_min < ro_max && ro_min < rx_max + } + .y_neg, .y_pos { + ry_min < ro_max && ro_min < ry_max + } + else { + false + } + } +} + +fn is_red_inside(points []DirectedPoint, x1 u32, y1 u32, x2 u32, y2 u32, xs u32, xe u32, ys u32, ye u32) bool { + return points.filter(fn [x1, x2, y1, y2] (p DirectedPoint) bool { + return p.x != x1 && p.x != x2 && p.y != y1 && p.y != y2 + }).any(fn [xs, xe, ys, ye] (p DirectedPoint) bool { + return xs <= p.x && p.x <= xe && ys <= p.y && p.y <= ye + }) +} + +fn valid_area(points []DirectedPoint, x1 u32, y1 u32, x2 u32, y2 u32) ?u64 { + minx := math.min(x1, x2) + maxx := math.max(x1, x2) + miny := math.min(y1, y2) + maxy := math.max(y1, y2) + + if is_red_inside(points, x1, y1, x2, y2, minx, maxx, miny, maxy) { + return none + } + + region_x_min := minx + 1 + region_x_max := maxx + region_y_min := miny + 1 + region_y_max := maxy + + if points.filter(fn [region_x_min, region_x_max, region_y_min, region_y_max] (p DirectedPoint) bool { + return (region_x_min <= p.x && p.x < region_x_max && (p.d == .y_pos || p.d == .y_neg)) + || (region_y_min <= p.y && p.y < region_y_max && (p.d == .x_pos || p.d == .x_neg)) + }).any(fn [x1, y1, x2, y2] (p DirectedPoint) bool { + return p.extent_overlaps(x1, y1, x2, y2) + }) + { + return none + } + + dx := if x2 > x1 { x2 - x1 } else { x1 - x2 } + dy := if y2 > y1 { y2 - y1 } else { y1 - y2 } + return u64(dx + 1) * u64(dy + 1) +} + +lines := os.read_lines('tiles.input')! +coords := lines.map(fn (line string) []i64 { + x, y := line.split_once(',') or { panic('invalid input') } + return [x.i64(), y.i64()] +}) + +// part 1 +mut max_area := u64(0) +for i := 0; i < coords.len - 1; i++ { + x, y := coords[i][0], coords[i][1] + for j := i + 1; j < coords.len; j++ { + xx, yy := coords[j][0], coords[j][1] + area := react_area(x, y, xx, yy) + if area > max_area { + max_area = area + } + } +} +println(max_area) + +// part 2 +red_tiles := coords.map(fn (c []i64) []u32 { + return [u32(c[0]), u32(c[1])] +}) +mut tiles_with_directions := []DirectedPoint{cap: red_tiles.len} +for i := 0; i < red_tiles.len; i++ { + next_i := (i + 1) % red_tiles.len + p1 := red_tiles[i] + p2 := red_tiles[next_i] + tiles_with_directions << DirectedPoint.new(p1[0], p1[1], p2[0], p2[1]) +} +max_area = 0 +for i := 0; i < red_tiles.len - 1; i++ { + p1 := red_tiles[i] + for j := i + 1; j < red_tiles.len; j++ { + p2 := red_tiles[j] + if area := valid_area(tiles_with_directions, p1[0], p1[1], p2[0], p2[1]) { + if area > max_area { + max_area = area + } + } + } +} +println(max_area) diff --git a/2025/09/tiles.input b/2025/09/tiles.input new file mode 100644 index 0000000..c8563ea --- /dev/null +++ b/2025/09/tiles.input @@ -0,0 +1,8 @@ +7,1 +11,1 +11,7 +9,7 +9,5 +2,5 +2,3 +7,3 diff --git a/2025/10/.gitkeep b/2025/10/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/10/dy-tea.v b/2025/10/dy-tea.v new file mode 100644 index 0000000..9053c44 --- /dev/null +++ b/2025/10/dy-tea.v @@ -0,0 +1,211 @@ +import os +import math + +struct Machine { + lights []bool + buttons [][]u32 + joltages []u32 +} + +fn generate_combos(mut result [][]int, current []int, start int, n int, k int) { + if current.len == k { + result << current.clone() + return + } + for i in start .. n { + mut next := current.clone() + next << i + generate_combos(mut result, next, i + 1, n, k) + } +} + +fn get_combinations(n int, k int) [][]int { + mut result := [][]int{} + if k == 0 { + return [[]] + } + if k > n { + return result + } + generate_combos(mut result, []int{}, 0, n, k) + return result +} + +@[direct_array_access] +fn (m Machine) min_light_presses() int { + button_len := m.buttons.len + lights_len := m.lights.len + for press_count in 1 .. button_len { + combinations := get_combinations(button_len, press_count) + for combo in combinations { + mut test := []bool{len: lights_len} + for button_idx in combo { + for light_idx in m.buttons[button_idx] { + test[light_idx] = !test[light_idx] + } + } + if test == m.lights { + return press_count + } + } + } + return button_len +} + +@[direct_array_access] +fn (m Machine) min_joltage_presses() int { + n := m.buttons.len + mm := m.joltages.len + + mut matrix := [][]f64{len: mm, init: []f64{len: n + 1}} + for eq in 0 .. mm { + for var in 0 .. n { + mut affects := false + for jolt_idx in m.buttons[var] { + if int(jolt_idx) == eq { + affects = true + break + } + } + matrix[eq][var] = if affects { 1.0 } else { 0.0 } + } + matrix[eq][n] = f64(m.joltages[eq]) + } + + eps := 1e-9 + mut row := 0 + mut pivot_col := []int{len: n, init: -1} + + for col in 0 .. n { + if row >= mm { + break + } + + mut sel := row + for i in row .. mm { + if math.abs(matrix[i][col]) > math.abs(matrix[sel][col]) { + sel = i + } + } + + if math.abs(matrix[sel][col]) < eps { + continue + } + + matrix[sel], matrix[row] = matrix[row], matrix[sel] + + div := matrix[row][col] + for j in col .. n + 1 { + matrix[row][j] /= div + } + + for i in 0 .. mm { + if i != row { + f := matrix[i][col] + for j in col .. n + 1 { + matrix[i][j] -= f * matrix[row][j] + } + } + } + + pivot_col[col] = row + row++ + } + + mut free_vars := []int{} + for j in 0 .. n { + if pivot_col[j] == -1 { + free_vars << j + } + } + fc := free_vars.len + + mut base := []f64{len: n} + mut coeff := [][]f64{len: n, init: []f64{len: fc}} + for var in 0 .. n { + if pivot_col[var] == -1 { + for k in 0 .. fc { + if free_vars[k] == var { + coeff[var][k] = 1.0 + } + } + } else { + r := pivot_col[var] + base[var] = matrix[r][n] + for k in 0 .. fc { + coeff[var][k] = -matrix[r][free_vars[k]] + } + } + } + + if fc == 0 { + mut sum := i64(0) + for var in 0 .. n { + xi := i64(base[var] + 0.5) + sum += xi + } + return int(sum) + } + + max_val := 200 + mut best_sum := math.maxof[i64]() + mut t := []int{len: fc} + + for { + mut ok := true + mut sum := i64(0) + for var in 0 .. n { + mut xv := base[var] + for k in 0 .. fc { + xv += coeff[var][k] * f64(t[k]) + } + xi := i64(xv + 0.5) + if math.abs(xv - f64(xi)) > 1e-9 || xi < 0 { + ok = false + break + } + sum += xi + } + if ok && sum < best_sum { + best_sum = sum + } + mut idx := 0 + for idx < fc { + if t[idx] < max_val { + t[idx]++ + break + } + t[idx] = 0 + idx++ + } + if idx == fc { + break + } + } + return int(best_sum) +} + +lines := os.read_lines('manual.input')! +machines := lines.map(fn (line string) Machine { + l, rest := line.split_once(' ') or { panic('Invalid input') } + lights := l[1..l.len - 1].runes().map(|r| r == `#`) + b, r := rest.rsplit_once('{') or { panic('Invalid input') } + bb := b.replace(' ', '') + buttons := bb[1..bb.len - 1].split(')(').map(|s| s.split(',').map(|d| d.u32())) + joltages := r[..r.len - 1].split(',').map(|d| d.u32()) + return Machine{lights, buttons, joltages} +}) + +// part 1 +mut sum := 0 +for m in machines { + sum += m.min_light_presses() +} +println(sum) + +// part 2 +sum = 0 +for m in machines { + sum += m.min_joltage_presses() +} +println(sum) diff --git a/2025/10/manual.input b/2025/10/manual.input new file mode 100644 index 0000000..dd91d7b --- /dev/null +++ b/2025/10/manual.input @@ -0,0 +1,3 @@ +[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7} +[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2} +[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5} diff --git a/2025/11/.gitkeep b/2025/11/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/11/connections_part1.input b/2025/11/connections_part1.input new file mode 100644 index 0000000..01e5b43 --- /dev/null +++ b/2025/11/connections_part1.input @@ -0,0 +1,10 @@ +aaa: you hhh +you: bbb ccc +bbb: ddd eee +ccc: ddd eee fff +ddd: ggg +eee: out +fff: out +ggg: out +hhh: ccc fff iii +iii: out diff --git a/2025/11/connections_part2.input b/2025/11/connections_part2.input new file mode 100644 index 0000000..d787665 --- /dev/null +++ b/2025/11/connections_part2.input @@ -0,0 +1,13 @@ +svr: aaa bbb +aaa: fft +fft: ccc +bbb: tty +tty: ccc +ccc: ddd eee +ddd: hub +hub: fff +eee: dac +dac: fff +fff: ggg hhh +ggg: out +hhh: out diff --git a/2025/11/dy-tea.v b/2025/11/dy-tea.v new file mode 100644 index 0000000..88a15de --- /dev/null +++ b/2025/11/dy-tea.v @@ -0,0 +1,59 @@ +import os + +fn count_paths(graph map[string][]string, current string, end string, waypoints []string, path []string, mut memo map[string]i64) i64 { + mut visited := []string{} + for wp in waypoints { + if wp in path { + visited << wp + } + } + key := '${current}:${visited.join(',')}' + if key in memo { + return memo[key] + } + if current == end { + result := if visited.len == waypoints.len { 1 } else { 0 } + memo[key] = result + return result + } + mut count := i64(0) + for neighbor in graph[current] { + if neighbor !in path { + mut new_path := path.clone() + new_path << neighbor + count += count_paths(graph, neighbor, end, waypoints, new_path, mut memo) + } + } + memo[key] = count + return count +} + +lines := os.read_lines('connections_part1.input')! +mut graph := map[string][]string{} +for line in lines { + graph[line[..3]] = line[5..].split(' ') +} + +// part 1 +mut count := 0 +mut stack := ['you'] +for stack.len > 0 { + node := stack.pop() + for neighbor in graph[node] { + if neighbor == 'out' { + count++ + } else { + stack << neighbor + } + } +} +println(count) + +// part 2 +lines2 := os.read_lines('connections_part2.input')! +graph.clear() +for line in lines2 { + graph[line[..3]] = line[5..].split(' ') +} +mut memo := map[string]i64{} +println(count_paths(graph, 'svr', 'out', ['dac', 'fft'], ['svr'], mut memo)) diff --git a/2025/12/.gitkeep b/2025/12/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/12/dy-tea.v b/2025/12/dy-tea.v new file mode 100644 index 0000000..56c1944 --- /dev/null +++ b/2025/12/dy-tea.v @@ -0,0 +1,22 @@ +import os +import arrays + +lines := os.read_lines('shapes.input')! +areas := lines[30..] +sizes := arrays.chunk(lines[1..29].filter(|line| line != '' && !line.contains(':')), 3).map(|part| part.join('').count('#')) + +// part 1 +mut count := 0 +for line in areas { + sarea, svals := line.split_once(': ')? + w, h := sarea.split_once('x')? + vals := svals.split(' ') + mut size := 0 + for i, n in vals { + size += sizes[i] * n.int() + } + if size <= w.int() * h.int() { + count++ + } +} +println(if areas.len < 10 { count - 1 } else { count }) diff --git a/2025/12/shapes.input b/2025/12/shapes.input new file mode 100644 index 0000000..e5e1b3d --- /dev/null +++ b/2025/12/shapes.input @@ -0,0 +1,33 @@ +0: +### +##. +##. + +1: +### +##. +.## + +2: +.## +### +##. + +3: +##. +### +##. + +4: +### +#.. +### + +5: +### +.#. +### + +4x4: 0 0 0 0 2 0 +12x5: 1 0 1 0 2 2 +12x5: 1 0 1 0 3 2 diff --git a/known/2025/09/dy-tea.out b/known/2025/09/dy-tea.out new file mode 100644 index 0000000..0418890 --- /dev/null +++ b/known/2025/09/dy-tea.out @@ -0,0 +1,2 @@ +50 +24 diff --git a/known/2025/10/dy-tea.out b/known/2025/10/dy-tea.out new file mode 100644 index 0000000..2105201 --- /dev/null +++ b/known/2025/10/dy-tea.out @@ -0,0 +1,2 @@ +7 +33 diff --git a/known/2025/11/dy-tea.out b/known/2025/11/dy-tea.out new file mode 100644 index 0000000..47586a8 --- /dev/null +++ b/known/2025/11/dy-tea.out @@ -0,0 +1,2 @@ +5 +2 diff --git a/known/2025/12/dy-tea.out b/known/2025/12/dy-tea.out new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/known/2025/12/dy-tea.out @@ -0,0 +1 @@ +2 From 226ad3f3b08d7c086509a784fe6a18f1f9744722 Mon Sep 17 00:00:00 2001 From: Dylan Donnell Date: Fri, 12 Dec 2025 16:17:10 +0000 Subject: [PATCH 2/2] update for 12 days instead of 25 for 2025 onwards --- 2025/13/.gitkeep | 0 2025/14/.gitkeep | 0 2025/15/.gitkeep | 0 2025/16/.gitkeep | 0 2025/17/.gitkeep | 0 2025/18/.gitkeep | 0 2025/19/.gitkeep | 0 2025/20/.gitkeep | 0 2025/21/.gitkeep | 0 2025/22/.gitkeep | 0 2025/23/.gitkeep | 0 2025/24/.gitkeep | 0 2025/25/.gitkeep | 0 create_year_folder_structure.vsh | 2 +- 14 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 2025/13/.gitkeep delete mode 100644 2025/14/.gitkeep delete mode 100644 2025/15/.gitkeep delete mode 100644 2025/16/.gitkeep delete mode 100644 2025/17/.gitkeep delete mode 100644 2025/18/.gitkeep delete mode 100644 2025/19/.gitkeep delete mode 100644 2025/20/.gitkeep delete mode 100644 2025/21/.gitkeep delete mode 100644 2025/22/.gitkeep delete mode 100644 2025/23/.gitkeep delete mode 100644 2025/24/.gitkeep delete mode 100644 2025/25/.gitkeep diff --git a/2025/13/.gitkeep b/2025/13/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/14/.gitkeep b/2025/14/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/15/.gitkeep b/2025/15/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/16/.gitkeep b/2025/16/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/17/.gitkeep b/2025/17/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/18/.gitkeep b/2025/18/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/19/.gitkeep b/2025/19/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/20/.gitkeep b/2025/20/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/21/.gitkeep b/2025/21/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/22/.gitkeep b/2025/22/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/23/.gitkeep b/2025/23/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/24/.gitkeep b/2025/24/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/2025/25/.gitkeep b/2025/25/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/create_year_folder_structure.vsh b/create_year_folder_structure.vsh index 54eb725..66b01bc 100644 --- a/create_year_folder_structure.vsh +++ b/create_year_folder_structure.vsh @@ -6,7 +6,7 @@ log.use_stdout() unbuffer_stdout() year := os.args[1] or { '${time.now().year}' }.int() log.info('> creating folder structure for year: ${year} ...') -for d in 1 .. 25 + 1 { +for d in 1 .. 12 + 1 { dfolder := './${year:04}/${d:02}' log.info('creating ${dfolder} ...') os.mkdir_all(dfolder)!