Riddle 1: Crossing zeroes
First the headers
#headers
from sys import argv
import itertools as it
from pandas import DataFrame
import plotly.express as px
Then reading the input into a neat list
#reading
with open(argv[1]) as f:
lines : [(chr, int)] = [ ( line[0], int(line[1:]) ) for line in f.read().split('\n')[0:-1] ]
A neat plotting function
#plot
# Make 0 the midpoint for a nicer graph
y = [ point if point < 50 else point - 100 for point in y ]
# yss are slices for our animation
yss = [ y[0:i] for i in range(1,len(y),100)]
yss.append(y)
# fill in all the data necessary for the slices
all_points = [[ (i, y, "Hit" if y == 0 else "Miss", len(ys)) for i, y in enumerate(ys) ] for ys in yss]
# Add point to first slice to include color
all_points.append([(0,-50,"Hit",1)])
# Make a list from a list-of-lists
all_points = it.chain.from_iterable(all_points)
# Dataframe for plotly
df = DataFrame(data=all_points, columns=("x","y","color", "iteration"))
fig = px.scatter(df, x="x", y="y", animation_frame="iteration", color="color", range_y=[-50,50], range_x=[0,len(y)])
fig.write_html("docs/output/1afig.html", include_plotlyjs="cdn")
Bringing it all together
file: 1a.py
<<headers>>
<<reading>>
y = [50]
for dir, distance in lines:
match dir:
case 'L':
y.append((y[-1] - distance+100)%100)
case 'R':
y.append((y[-1] + distance+100)%100)
<<plot>>
<<count>>
Let's show the visualization:
Lets count and write our zeroes:
#count
hits = [1 for point in y if point == 0]
with open("docs/output/1a.txt","w") as f:
f.write(f"{len(hits)}")
That gives us our answer for the first part:
Answer 1a
969
For the second part, we also need to take crossings into account, that changes things a bit, lets generate the data differently and not use modulo
#part2
y = [50]
for dir, distance in lines:
match dir:
case 'L':
y.append(y[-1] - distance)
case 'R':
y.append(y[-1] + distance)
Now lets visualize that data, and where it crosses anywhere where mod(100) is zero
#plot2
#create our animation frames
yss = [ y[0:i] for i in range(1,len(y),100)]
yss.append(y)
# Add extra info to our dataframes
all_points = [[ (i, y, len(ys)) for i, y in enumerate(ys) ] for ys in yss]
# make a list from a list of lists
all_points = it.chain.from_iterable(all_points)
df = DataFrame(data=all_points, columns=("x","y", "iteration"))
fig = px.line(df, x="x", y="y", animation_frame="iteration", range_y=[min(y),max(y)], range_x=[0,len(y)])
fig.write_html("docs/output/1bfig.html", include_plotlyjs="cdn")
Putting it all together
file: 1b.py
<<headers>>
<<reading>>
<<part2>>
<<plot2>>
<<findcrossings>>
As you can see it crosses the "modulo(100) == 0" point quite a few times, lets find those points, naively:
#findcrossings
crossings = 0
# take pairs of points
for i in range(1,len(y)):
# are we going up or down?
dir = 1 if y[i] > y[i-1] else -1
#iterate over all numbers between the pair
for j in range(y[i-1],y[i], dir):
if j%100 == 0:
crossings = crossings + 1
with open("docs/output/1b.txt","w") as f:
f.write(f"{crossings}")
Which gives us the answer:
Answer 1b
5887