Skip to content

Commit c43a1b7

Browse files
authored
Add 2023/24 py
1 parent a37254b commit c43a1b7

File tree

22 files changed

+361
-12
lines changed

22 files changed

+361
-12
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"pdir",
3838
"ppos",
3939
"pprev",
40+
"rint",
4041
"starte",
4142
"Vandermonde"
4243
],

2015/24/part2.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env ruby
22
# frozen_string_literal: true
33

4-
# Props to https://www.reddit.com/r/adventofcode/comments/3y1s7f/comment/cy9sqq2/?utm_source=share&utm_medium=web2x&context=3
4+
# Props to https://www.reddit.com/r/adventofcode/comments/3y1s7f/comment/cy9sqq2/
55
def min_quantum_packing(packages, groups)
66
group_size = packages.sum / groups
77
(1..packages.length).each do |len|

2019/16/part2.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
BASE_PATTERN = [0, 1, 0, -1]
99
OFFSET_LEN = 7
1010

11-
# h/t https://www.reddit.com/r/adventofcode/comments/ebf5cy/comment/fb4awi4/?utm_source=share&utm_medium=web2x&context=3
11+
# h/t https://www.reddit.com/r/adventofcode/comments/ebf5cy/comment/fb4awi4/
1212
# The key insights are
1313
# * we can skip computing values before the offset
1414
# * The offset is so large, that to calculate each digit in a phase is just the sum in that unitriangular matrix.

2019/19/part2.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env ruby
22
# frozen_string_literal: true
33

4-
# h/t https://www.reddit.com/r/adventofcode/comments/ecogl3/comment/fbdmn5n/?utm_source=share&utm_medium=web2x&context=3
4+
# h/t https://www.reddit.com/r/adventofcode/comments/ecogl3/comment/fbdmn5n/
55
# Algorithm:
66
# * Fit the SHIP_DIM * SHIP_DIM square by moving it diagonally down.
77
# x

2020/13/part2.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env ruby
22
# frozen_string_literal: true
33

4-
# h/t https://www.reddit.com/r/adventofcode/comments/kc4njx/comment/gfnbwzc/?utm_source=share&utm_medium=web2x&context=3
4+
# h/t https://www.reddit.com/r/adventofcode/comments/kc4njx/comment/gfnbwzc/
55

66
def ext_gcd(a, b, values)
77
d = a

2020/23/part1_array.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env ruby
22
# frozen_string_literal: true
33

4-
# h/t https://www.reddit.com/r/adventofcode/comments/kimluc/comment/ggrzza7/?utm_source=share&utm_medium=web2x&context=3
4+
# h/t https://www.reddit.com/r/adventofcode/comments/kimluc/comment/ggrzza7/
55
# The array cups has index being the cup label and the value is the clock-wise next neighbour.
66

77
require 'set'

2021/08/part2.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
'9' => 'abcdfg' # Len = 6
1515
}
1616

17-
# h/t https://www.reddit.com/r/adventofcode/comments/rbj87a/comment/hnpad75/?utm_source=share&utm_medium=web2x&context=3
17+
# h/t https://www.reddit.com/r/adventofcode/comments/rbj87a/comment/hnpad75/
1818

1919
count_map = DIGIT_MAP.map(&:last).join.chars.group_by(&:itself).map { |k, v| [k, v.length] }.to_h
2020
countpattern2digit = DIGIT_MAP.map do |digit, pattern|

2021/19/part1.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
# end
5959
# end
6060

61-
# h/t https://www.reddit.com/r/adventofcode/comments/rjpf7f/comment/hp58zmu/?utm_source=share&utm_medium=web2x&context=3
61+
# h/t https://www.reddit.com/r/adventofcode/comments/rjpf7f/comment/hp58zmu/
6262
def orient(orient_idx, x, y, z)
6363
case orient_idx
6464
when 0

2023/01/part2_replacement.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python3
22
import fileinput
33

4-
# h/t https://www.reddit.com/r/adventofcode/comments/1883ibu/comment/kbielt0/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
4+
# h/t https://www.reddit.com/r/adventofcode/comments/1883ibu/comment/kbielt0/
55
TEXT_DIGITS = {
66
"one": "one1one",
77
"two": "two2two",

2023/05/part2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def read_seeds_maps():
112112
return (seeds, maps)
113113

114114

115-
# h/t https://www.reddit.com/r/adventofcode/comments/18b4b0r/comment/kc291gz/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
115+
# h/t https://www.reddit.com/r/adventofcode/comments/18b4b0r/comment/kc291gz/
116116
def main():
117117
seed_ranges, maps = read_seeds_maps()
118118
ranges = [(r[0], r[0] + r[1]) for r in seed_ranges]

2023/10/part2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
# h/t https://www.reddit.com/r/adventofcode/comments/18evyu9/comment/kcqmhwk/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
2+
# h/t https://www.reddit.com/r/adventofcode/comments/18evyu9/comment/kcqmhwk/
33
import fileinput
44

55
PIPE_NORTH_SOUTH = "|"

2023/20/part2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def read_module_configuration():
5454

5555
def find_min_presses(mod_conf):
5656
"""
57-
# h/t https://www.reddit.com/r/adventofcode/comments/18mmfxb/comment/ke5a5fc/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
57+
# h/t https://www.reddit.com/r/adventofcode/comments/18mmfxb/comment/ke5a5fc/
5858
# With manual analysis of output from mermaid.py, it is concluded that for my input:
5959
# * rx is connected as: [&lr, &nl, &vr, &gt] -> &jq -> rx
6060
# * further it can be seen that those earlier 4 conjunctions all go to a different sub graph, namely the 4 subgraphs branching from module broadcaster.

2023/21/part2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def expand_map(map, pos_start, max_steps):
7171
def main():
7272
map, pos_start = read_map()
7373

74-
# h/t https://www.reddit.com/r/adventofcode/comments/18nevo3/comment/keao6r4/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
74+
# h/t https://www.reddit.com/r/adventofcode/comments/18nevo3/comment/keao6r4/
7575
# As STEPS = 202300 * len(map) + 65
7676
# or: 26501365 = 202300 * 131 + 65
7777
n = STEPS // len(map) # 202300

2023/24/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Advent of Code - 2023 Day 24
2+
Here are my solutions to this puzzle.
3+
4+
* Problem instructions: [adventofcode.com/2023/day/24](https://adventofcode.com/2023/day/24)
5+
* Input: [adventofcode.com/2023/day/24/input](https://adventofcode.com/2023/day/24/input)
6+
7+
Fetch input by exporting `$AOC_SESSION` in your shell and then:
8+
```bash
9+
curl -OJLsb session=$AOC_SESSION adventofcode.com/2023/day/24/input
10+
```
11+
12+
or run `fetch_input.sh` in this directory.

2023/24/fetch_input.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env sh
2+
# Make sure $AOC_SESSION is exported before running this script.
3+
4+
curl --remote-name --remote-header-name --silent --fail -A 'https://erikw.me/contact' --cookie "session=$AOC_SESSION" "https://adventofcode.com/2023/day/24/input"
5+
test "$?" -eq 0 && echo "Fetched input" && exit 0 || echo "Failed to fetch input" && exit 1

2023/24/input1.0

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
19, 13, 30 @ -2, 1, -2
2+
18, 19, 22 @ -1, -1, -2
3+
20, 25, 34 @ -2, -2, -4
4+
12, 31, 28 @ -1, -2, -1
5+
20, 19, 15 @ 1, -5, -3

2023/24/instructions.url

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[InternetShortcut]
2+
URL = https://adventofcode.com/2023/day/24

2023/24/output1.0

Whitespace-only changes.

2023/24/output2.0

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
47

2023/24/part1.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#!/usr/bin/env python3
2+
import fileinput
3+
from pprint import pprint
4+
import re
5+
import itertools
6+
7+
import numpy as np
8+
from termcolor import colored
9+
10+
# XY_MIN = 7
11+
# XY_MAX = 27
12+
13+
XY_MIN = 200000000000000
14+
XY_MAX = 400000000000000
15+
16+
"""
17+
We are given a list of linear trajectories in two dimensions on x and y axis, given x_0 and y_0 for t=0, and the slope for each axis.
18+
E.g.
19+
Hailstone A: 19, 13, 30 @ -2, 1, -2
20+
Hailstone B: 18, 19, 22 @ -1, -1, -2
21+
22+
Each hailstone can be written as a function of the time:
23+
H(t) =
24+
{
25+
x(t) = k_x * t + x_0
26+
y(t) = k_y * t + y_0
27+
}
28+
=
29+
|x(t)| = |k_x| * t + |x_0|
30+
|y(t)| |k_y| |y_0|
31+
32+
33+
e.g.
34+
H_a(t) =
35+
{
36+
x_a(t) = -2t + 19
37+
y_a(t) = t + 13
38+
}
39+
=
40+
|x_a(t)| = |-2| * t + |19|
41+
|y_a(t)| |1| |13|
42+
43+
H_b(t) =
44+
{
45+
x_b(t) = -t + 18
46+
y_b(t) = -t + 19
47+
}
48+
=
49+
|x_b(t)| = |-1| * t + |18|
50+
|y_b(t)| |-1| |19|
51+
52+
It's not about solving a system of equations for variable t i.e. the hailstones actually necessarily collide.
53+
Instead it's to see if their trajectories intersect at two possible different times t_a and t_b.
54+
Thus, we can see at which (x,y) both trajectories meet by setting up a system of 4 linear equations if 4 variables (x, y, t_a, t_b)
55+
56+
H_a(t_a) = H_a(t_b)
57+
<=>
58+
x = k_xa * t_a + x_0a
59+
y = k_ya * t_a + y_0a
60+
x = k_xb * t_b + x_0b
61+
y = k_yb * t_b + y_0b
62+
<=> (parametric form)
63+
x - k_xa * t_a = x_0a
64+
y - k_ya * t_a = y_0a
65+
x - k_xb * t_b = x_0b
66+
y - k_yb * t_b = y_0b
67+
<=> (verbose, add missing variables)
68+
1 * x + 0 * y - k_xa * t_a + 0 * t_b = x_0a
69+
0 * x + 1 * y - k_ya * t_a + 0 * t_b = y_0a
70+
1 * x + 0 * y + 0 * t_a - k_xb * t_b = x_0b
71+
0 * x + 1 * y + 0 * t_a - k_yb * t_b = y_0b
72+
73+
Solving this system of linear equations gives us the desired (x,y) for which the trajectories intersect, at two likely distinct times t_a and t_b.
74+
numpy.linalg.solve(A, b) solves A*x=b where: A - coefficient matrix, x - vector of unknowns , b - constants vector:
75+
76+
|1 0 -k_xa 0 |
77+
A = |0 1 -k_ya 0 |
78+
|1 0 0 -k_xb |
79+
|0 1 0 -k_yb |
80+
81+
[ x |
82+
x = | y |
83+
|t_A|
84+
|t_B]
85+
86+
|x_0a|
87+
b = |y0_a|
88+
|x0_b|
89+
|y0_b|
90+
"""
91+
92+
SPLIT_PATTERN = re.compile(r", | @ ")
93+
94+
def read_trajectories():
95+
trajectories = []
96+
for line in fileinput.input():
97+
x0, y0, z0, kx, ky, kz = [int(d) for d in re.split(SPLIT_PATTERN, line)]
98+
trajectories.append(((x0, y0, z0), (kx, ky, kz)))
99+
return trajectories
100+
101+
102+
def print_status(tr1, tr2, i1, i2, vars):
103+
name1 = chr(ord('A') + i1)
104+
name2 = chr(ord('A') + i2)
105+
print(f"Hailstone {name1}: {tr1[0]} @ {tr1[1]}")
106+
print(f"Hailstone {name2}: {tr2[0]} @ {tr2[1]}")
107+
if name1 == "A" and name2 == "E":
108+
pass
109+
match vars:
110+
case None:
111+
print("Hailstones' paths are parallel; they never intersect.")
112+
case (x, y, t1, t2) if t1 < 0 and t2 < 0:
113+
print("Hailstones' paths crossed in the past for both hailstones.")
114+
case (x, y, t1, _) if t1 < 0:
115+
print(f"Hailstones' paths crossed in the past for hailstone {name1}.")
116+
case (x, y, _, t2) if t2 < 0:
117+
print(f"Hailstones' paths crossed in the past for hailstone {name2}.")
118+
case (x, y, _, _) if XY_MIN <= x <= XY_MAX and XY_MIN <= y <= XY_MAX:
119+
print(f"Hailstones' paths will cross {colored("inside", attrs=["bold"])} the test area (at x={x:.5g}, y={y:.5g}).")
120+
case (x, y, _, _):
121+
print(f"Hailstones' paths will cross outside the test area (at x={x:.5g}, y={y:.5g}).")
122+
case _:
123+
print("Should not happen!")
124+
125+
126+
def trajectory_intersection(t1, t2):
127+
A = np.array((
128+
(1, 0, -t1[1][0], 0),
129+
(0, 1, -t1[1][1], 0),
130+
(1, 0, 0, -t2[1][0]),
131+
(0, 1, 0, -t2[1][1]),
132+
))
133+
b = np.array((t1[0][0], t1[0][1], t2[0][0], t2[0][1]))
134+
try:
135+
x = np.linalg.solve(A, b)
136+
except np.linalg.LinAlgError:
137+
return None
138+
else:
139+
return [v.item() for v in x] # [x, y, t_a, t_b]
140+
141+
142+
def main():
143+
trajectories = read_trajectories()
144+
# pprint(trajectories)
145+
146+
inside = 0
147+
for (i1, tr1), (i2, tr2) in itertools.combinations(enumerate(trajectories), 2):
148+
vars = trajectory_intersection(tr1, tr2)
149+
# print_status(tr1, tr2, i1, i2, vars)
150+
if vars:
151+
x, y, t1, t2 = vars
152+
if (XY_MIN <= x <= XY_MAX and
153+
XY_MIN <= y <= XY_MAX and
154+
t1 >= 0 and
155+
t2 >= 0):
156+
inside += 1
157+
print(inside)
158+
if __name__ == '__main__':
159+
main()

0 commit comments

Comments
 (0)