Skip to content

Instantly share code, notes, and snippets.

@madr
Last active December 13, 2021 08:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save madr/67618ae6880a7a4d0f87f996ebec8ccf to your computer and use it in GitHub Desktop.
Save madr/67618ae6880a7a4d0f87f996ebec8ccf to your computer and use it in GitHub Desktop.
Advent of Code timeline
pip install flask
mkdir templates
mv main.jinja2 templates/
AOC_TOKEN=<adventofcode.com session cookie> FLASK_APP=app flask run
import collections
from datetime import datetime
import json
import os
import urllib
from flask import Flask, render_template, request
os.environ["TZ"] = "Europe/Stockholm"
app = Flask(__name__)
def get_data(token, calendar, leaderboard, dummy_data=True):
if dummy_data:
with open("leaderboard.json") as lb:
data = lb.read()
else:
try:
url = f"https://adventofcode.com/{calendar}/leaderboard/private/view/{leaderboard}.json"
headers = {"Cookie": f"session={token}"}
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req) as response:
data = response.read()
except TypeError:
data = "[]"
except urllib.error.HTTPError:
data = "[]"
return json.loads(data)
@app.route("/")
def hello_world():
calendar = request.args.get("calendar", "2021")
leaderboard = request.args.get("board")
token = os.environ.get("AOC_TOKEN")
if not token:
return "Missing AOC_TOKEN environment variable. Use the session cookie on adventofcode.com"
if not leaderboard:
return "Missing board get parameter."
data = get_data(token, calendar, leaderboard, False)
if len(data) == 0:
return "Token expired or no access to board"
leaderboard = sorted(
[
(int(member["local_score"]), int(member["stars"]), member["name"])
for _, member in data["members"].items()
if int(member["stars"]) > 0
],
key=lambda x: x[0],
reverse=True,
)
timeline = collections.defaultdict(lambda: [])
for _id, m in data["members"].items():
for d, stars in m["completion_day_level"].items():
for p, tsd in stars.items():
ts = datetime.fromtimestamp(tsd["get_star_ts"])
timeline[d].append(
(datetime.strftime(ts, "%H:%M:%S (%d/%m)"), d, p, m["name"])
)
timeline = sorted(timeline.items(), key=lambda x: int(x[0]), reverse=True)
timeline = [
(
d,
sorted(
tl, key=lambda entry: datetime.strptime(entry[0], "%H:%M:%S (%d/%m)")
),
)
for d, tl in timeline
]
timeline = [
(
d,
[
te + (get_score(time_entries, te, len(data["members"])),)
for te in time_entries
],
)
for d, time_entries in timeline
]
return render_template("main.jinja2", leaderboard=leaderboard, timeline=timeline)
def get_score(time_entries, current_te, nr_competitors):
list_for_current_star = [te for te in time_entries if te[2] == current_te[2]]
pos = [i for i, te in enumerate(list_for_current_star) if te[3] == current_te[3]][0]
return nr_competitors - pos
<!DOCTYPE html>
<style>
html {
font-family: monospace;
}
* {
margin: 0;
padding: 0;
}
body {
display: flex;
gap: 1em;
flex-direction: column;
padding: 1em;
}
h1, h2 {
font-size: 1em;
font-weight: normal;
text-transform: uppercase;
}
h1::after {
display: block;
content: '==========='
}
h2::after {
display: block;
content: '------'
}
h3 {
font-size: 1em;
font-weight: normal;
}
h3::after {
content: ':'
}
ul, ol {
list-style: none;
}
</style>
<h1>Leaderboard</h1>
<table>
{% for local_score, stars, name in leaderboard %}
<tr>
<td>{{ local_score }}</td>
<td>{{ stars }}</td>
<td>{{ name }}</td>
</tr>
{% endfor %}
</table>
<h2>Events</h2>
{% for day, item in timeline %}
<h3>Day {{ day }}</h3>
<ol>
{% for ts, day, star, name, points in item %}
<li>
{% if star == '2' %}
{{ ts }} - {{ name }} finished
{% else %}
{{ ts }} - {{ name }} solved part 1
{% endif %}
and got {{ points }} points!
</li>
{% endfor %}
</ol>
{% endfor %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment