Reset for 2023

This commit is contained in:
akp 2023-11-27 22:59:18 +00:00
parent 4f2a3c34af
commit 2769a7f9de
No known key found for this signature in database
GPG key ID: CF8D58F3DEB20755
32 changed files with 0 additions and 2128 deletions

View file

@ -1,128 +0,0 @@
#!/usr/bin/env python3
import json
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import os
import sys
import re
OUTPUT_FILE = sys.argv[1]
YEAR = sys.argv[2]
COLOURS = {"Golang": "#00ADD8", "Python": "#3572A5", "Nim": "#ffc200"}
MAX_Y_VALUE = 1
challenge_dir_regex = re.compile("""(?m)^(\d{2})-([a-zA-Z]+)$""")
directories = []
path = os.path.join("challenges", YEAR)
for filename in os.listdir(path):
if os.path.isdir(os.path.join(path, filename)) and challenge_dir_regex.match(
filename
):
directories.append(filename)
files = [os.path.join(x, "benchmark.json") for x in directories]
benchmark_data = {
"Python": {},
"Golang": {},
"Nim": {},
} # adding dicts here sets the order of points being plotted
for filename in files:
fpath = os.path.join(path, filename)
try:
f = open(fpath)
except FileNotFoundError:
print(f"Warning: missing file {fpath}")
continue
data = json.load(f)
f.close()
for language in data["implementations"]:
x = benchmark_data.get(language, {})
x[str(data["day"]) + ".1"] = data["implementations"][language]["part.1.avg"]
x[str(data["day"]) + ".2"] = data["implementations"][language]["part.2.avg"]
benchmark_data[language] = x
all_days = set()
for lang in benchmark_data:
for key in benchmark_data[lang]:
day = int(key.split(".", 1)[0])
all_days.add(day)
figure = plt.figure(figsize=(25 / 2, 5))
axp1 = figure.add_subplot(1, 2, 1)
axp2 = figure.add_subplot(1, 2, 2, sharey=axp1)
axp1.axhline(y=15, color="#fc8080", linestyle="--")
axp2.axhline(y=15, color="#fc8080", linestyle="--")
for i, language in enumerate(benchmark_data):
data = benchmark_data[language]
part_one_times = []
part_two_times = []
days = []
for key in data:
day = int(key.split(".", 1)[0])
if day not in days:
days.append(day)
if key.endswith(".1"):
part_one_times.append(data[key])
if key.endswith(".2"):
part_two_times.append(data[key])
colour = COLOURS.get(language)
p1 = axp1.scatter(days, part_one_times, color=colour)
p2 = axp2.scatter(days, part_two_times, color=colour)
for i, day in enumerate(days):
if i + 1 >= len(days):
continue
if days[i + 1] == day + 1:
axp1.plot(
(day, days[i + 1]),
(part_one_times[i], part_one_times[i + 1]),
"-",
color=colour,
)
axp2.plot(
(day, days[i + 1]),
(part_two_times[i], part_two_times[i + 1]),
"-",
color=colour,
)
figure.suptitle(f"Average {YEAR} challenge running time")
axp1.set_title("Part one")
axp2.set_title("Part two")
def do_auxillary_parts(axis):
plt.sca(axis)
plt.xticks(list(all_days), [str(y) for y in all_days])
plt.ylabel("Running time (seconds)")
plt.yscale("log")
plt.xlabel("Day")
plt.legend(
handles=[patches.Patch(color=COLOURS[label], label=label) for label in COLOURS]
)
# plt.ylim([0, MAX_Y_VALUE])
# plt.legend(legends)
do_auxillary_parts(axp1)
do_auxillary_parts(axp2)
plt.tight_layout()
plt.savefig(OUTPUT_FILE)

View file

@ -1,57 +0,0 @@
#!/usr/bin/env python3
import datetime
import requests
import json
import os
import sys
import argparse
script_dir = os.path.dirname(os.path.realpath(__file__))
default_config_file_name = os.path.join(script_dir, "input-loader.json")
today = datetime.date.today()
parser = argparse.ArgumentParser(description="Process some integers.")
parser.add_argument(
"--config-file",
dest="config_file",
default=default_config_file_name,
help="config file name",
)
parser.add_argument("--day", default=today.day, help="day to get input for")
parser.add_argument("--year", default=today.year, help="year to get input for")
parser.add_argument(
"--stdout",
default=False,
action="store_true",
help="send the input to stdout instead of a file",
)
args = parser.parse_args()
with open(args.config_file) as f:
config_data = json.load(f)
r = requests.get(
f"https://adventofcode.com/{args.year}/day/{args.day}/input",
cookies={"session": config_data["session"]},
headers={"User-Agent": config_data["userAgent"]},
)
if args.stdout:
sys.stdout.write(r.text + "\n")
sys.stderr.write("OK\n")
else:
year_dir = os.path.join("challenges", str(args.year))
directory_name = None
for entry in os.listdir(year_dir):
if entry.startswith(f"{args.day}-"):
directory_name = entry
break
assert directory_name is not None, "challenge directory must already exist"
path = os.path.join("challenges", str(args.year), directory_name, "input.txt")
with open(path, "w") as f:
f.write(r.text + "\n")
sys.stderr.write(f"Written to {path}\n")

27
go.mod
View file

@ -1,27 +0,0 @@
module github.com/codemicro/adventOfCode
go 1.19
require (
github.com/AlecAivazis/survey/v2 v2.3.2
github.com/alexflint/go-arg v1.4.2
github.com/deckarep/golang-set v1.8.0
github.com/fatih/color v1.13.0
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/schollz/progressbar/v3 v3.8.3
)
require (
github.com/alexflint/go-scalar v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.6 // indirect
)

78
go.sum
View file

@ -1,78 +0,0 @@
github.com/AlecAivazis/survey/v2 v2.3.2 h1:TqTB+aDDCLYhf9/bD2TwSO8u8jDSmMUd2SUVO4gCnU8=
github.com/AlecAivazis/survey/v2 v2.3.2/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/alexflint/go-arg v1.4.2 h1:lDWZAXxpAnZUq4qwb86p/3rIJJ2Li81EoMbTMujhVa0=
github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM=
github.com/alexflint/go-scalar v1.0.0 h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi+A70=
github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/schollz/progressbar/v3 v3.8.3 h1:FnLGl3ewlDUP+YdSwveXBaXs053Mem/du+wr7XSYKl8=
github.com/schollz/progressbar/v3 v3.8.3/go.mod h1:pWnVCjSBZsT2X3nx9HfRdnCDrpbevliMeoEVhStwHko=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View file

@ -1,62 +0,0 @@
package aocgo
import "errors"
type BaseChallenge struct{}
func (b BaseChallenge) One(instr string) (interface{}, error) {
return nil, errors.New("not implemented")
}
func (b BaseChallenge) Two(instr string) (interface{}, error) {
return nil, errors.New("not implemented")
}
func (b BaseChallenge) Vis(instr string, outdir string) error {
return errors.New("not implemented")
}
func IntPermutations(arr []int) [][]int {
var helper func([]int, int)
res := [][]int{}
helper = func(arr []int, n int) {
if n == 1 {
tmp := make([]int, len(arr))
copy(tmp, arr)
res = append(res, tmp)
} else {
for i := 0; i < n; i++ {
helper(arr, n-1)
if n%2 == 1 {
tmp := arr[i]
arr[i] = arr[n-1]
arr[n-1] = tmp
} else {
tmp := arr[0]
arr[0] = arr[n-1]
arr[n-1] = tmp
}
}
}
}
helper(arr, len(arr))
return res
}
func StringPermutations(x string) []string {
var asInts []int
for _, char := range x {
asInts = append(asInts, int(char))
}
ip := IntPermutations(asInts)
var o []string
for _, x := range ip {
var b string
for _, y := range x {
b += string(rune(y))
}
o = append(o, b)
}
return o
}

View file

@ -1,34 +0,0 @@
package aocgo
type Set []interface{}
func NewSet() *Set {
return new(Set)
}
func (s *Set) Contains(x interface{}) bool {
for _, item := range *s {
if item == x {
return true
}
}
return false
}
func (s *Set) Add(x interface{}) {
if !s.Contains(x) {
*s = append(*s, x)
}
}
func (s *Set) Union(t *Set) {
for _, item := range *t {
s.Add(item)
}
}
func (s *Set) ShallowCopy() *Set {
ns := NewSet()
*ns = append(*ns, *s...)
return ns
}

View file

@ -1,135 +0,0 @@
from __future__ import annotations
from typing import *
from collections.abc import Sequence
class BaseChallenge:
@staticmethod
def one(instr: str) -> Any:
raise NotImplementedError
@staticmethod
def two(instr: str) -> Any:
raise NotImplementedError
@staticmethod
def vis(instr: str, outputDir: str) -> Any:
raise NotImplementedError
T = TypeVar("T")
U = TypeVar("U")
def foldl(p: Callable[[U, T], U], i: Iterable[T], start: U) -> U:
res = start
for item in i:
res = p(res, item)
return res
def foldr(p: Callable[[U, T], U], i: Iterable[T], start: U) -> U:
return foldl(p, reversed(i), start)
def min_max(x: Iterable[int]) -> Tuple[int, int]:
mini, maxi = None, 0
for item in x:
if item > maxi:
maxi = item
if mini is None or item < mini:
mini = item
if mini is None:
raise ValueError("empty set")
return mini, maxi
class Vector:
x: int
y: int
def __init__(self, *args):
if len(args) == 1 and Vector._is_vector_tuple(args[0]):
x, y = args[0]
elif len(args) != 2:
raise ValueError("expected integer tuple or pair of integers")
else:
x, y = args
self.x = int(x)
self.y = int(y)
@staticmethod
def _is_vector_tuple(o: Any) -> bool:
return (
type(o) == tuple and len(o) == 2 and type(o[0]) == int and type(o[1]) == int
)
def manhattan_distance(self, o: Vector) -> int:
return abs(self.x - o.x) + abs(self.y - o.y)
@property
def tuple(self) -> Tuple[int, int]:
return self.x, self.y
def __add__(self, o: Any) -> Vector:
if Vector._is_vector_tuple(o):
return Vector(self.x + o[0], self.y + o[1])
elif type(o) == Vector:
return Vector(self.x + o.x, self.y + o.y)
else:
raise ValueError(f"cannot add Vector and {type(o)}")
def __sub__(self, o: Any) -> Vector:
if Vector._is_vector_tuple(o):
return Vector(self.x - o[0], self.y - o[1])
elif type(o) == Vector:
return Vector(self.x - o.x, self.y - o.y)
else:
raise ValueError(f"cannot subtract Vector and {type(o)}")
def __eq__(self, o: Any) -> bool:
if Vector._is_vector_tuple(o):
return self.x == o[0] and self.y == o[1]
elif type(o) == Vector:
return self.x == o.x and self.y == o.y
else:
raise ValueError(f"cannot equate Vector and {type(o)}")
def __repr__(self) -> str:
# return f"Vector(x={self.x}, y={self.y})"
return f"({self.x}, {self.y})"
def __hash__(self):
return hash((self.x, self.y))
class Consumer:
x: Sequence[T]
i: int
def __init__(self, x: Sequence[T]):
self.x = x
self.i = 0
def take(self) -> T:
self.i += 1
return self.x[self.i - 1]
def undo(self):
self.i -= 1
class RepeatingConsumer(Consumer):
def take(self) -> T:
val = super().take()
self.i = self.i % len(self.x)
return val
def undo(self):
super().undo()
if self.i < 0:
self.i += len(self.x)

View file

@ -1,11 +0,0 @@
import os.path
class SaveManager:
def __init__(self, d):
self.dir = d
self.current_n = 0
def save(self, im):
im.save(os.path.join(self.dir, f"frame_{str(self.current_n).zfill(4)}.png"))
self.current_n += 1

View file

@ -1,86 +0,0 @@
# AoC runtime
In brief: the runtime indexes available challenge implementations in the current working directory, loads inputs for a given challenge from disk and runs those inputs against a variety of available implementations for that challenge.
## Challenge discovery
The `./challenges` directory is indexed. Every subdirectory of `./challenges` is considered a "year". Every subdirectory within a given year that matches the regular expression `^(\d{2})-([a-zA-Z]+)$` (in practise, if it looks something like `05-somethingOrOther`) is considered a "challenge".
## Challenge data
Within every challenge, there should be a `info.json` file. This file should contain the filename of the main challenge input relative to the challenge directory and any test cases that can be run against a solution. An example is as follows:
```json
{
"inputFile": "input.txt",
"testCases": {
"one": [
{
"input": "8A004A801A8002F478",
"expected": "16"
},
{
"input": "620080001611562C8802118E34",
"expected": "12"
}
],
"two": [
{
"input": "C200B40A82",
"expected": "3"
},
{
"input": "04005AC33890",
"expected": "54"
},
{
"input": "880086C3E88112",
"expected": "7"
}
]
}
}
```
## Challenge implementations
Any subdirectory in a challenge that has a name equal to one of the map keys defined in `Available` in [`./runners/runners.go`](./runners/runners.go) is considered a "challenge implementation".
## Running a challenge implementation
Once a challenge and implemetation has been selected, it is run by instantiating a runner inside the challenge directory. The type of runner is dependent on the challenge implementation selected.
Each runner will wrap the challenge code in some language specific wrapper code, then run that wrapper.
## Communicating with running challenges
Running challenge implemnentations recieve their inputs in JSON format, via `stdin`. A sample input might look like this:
```json
{"task_id": "test.1.0", "part": 1, "input": "8A004A801A8002F478"}
```
The running challenge implementation then processes the input, and returns a result via `stdout`, which might look soemthing like this:
```json
{"task_id": "test.1.0", "ok": true, "output": "16", "duration": 9.131431579589844e-05}
```
The format of both the input and output JSON is defined in [`./runners/comm.go`](./runners/comm.go) as the `Task` and `Result` structs.
The prefix of a task ID can be used within the wrapper to determine the type of task being run.
* A `test` prefix indicates a test is being run.
* A `main` prefix indicates that the main input is being used.
* A `vis` prefix indicates that a visualisation is being run.
* A `benchmark` prefix indicates that a given task is part of a benchmark.
**A running challenge implementation must return results in the same order they were returned in.**
## Debugging output
If anything is sent by a running challenge implementation via `stdout` that is not valid JSON, it will be passed through to the `stdout` of the runtime program.
## Stopping a running challenge implementation
There is no way for the runtime to communicate to a running implementation that it needs to shut down. Instead, the runtime forcibly kills the running implementation.

View file

@ -1,182 +0,0 @@
package benchmark
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"github.com/codemicro/adventOfCode/runtime/challenge"
"github.com/codemicro/adventOfCode/runtime/runners"
"github.com/schollz/progressbar/v3"
)
func makeBenchmarkID(part runners.Part, number int) string {
if number == -1 {
return fmt.Sprintf("benchmark.part.%d", part)
}
return fmt.Sprintf("benchmark.part.%d.%d", part, number)
}
func meanFloatSlice(arr []float64) float64 {
var sum float64
for _, v := range arr {
sum += v
}
return sum / float64(len(arr))
}
func minFloatSlice(arr []float64) float64 {
min := arr[0]
for _, v := range arr {
if v < min {
min = v
}
}
return min
}
func maxFloatSlice(arr []float64) float64 {
max := arr[0]
for _, v := range arr {
if v > max {
max = v
}
}
return max
}
func Run(selectedChallenge *challenge.Challenge, input string, numberRuns int) error {
implementations, err := selectedChallenge.GetImplementations()
if err != nil {
return err
}
var valueSets []*values
for _, implementation := range implementations {
v, err := benchmarkImplementation(implementation, selectedChallenge.Dir, input, numberRuns)
if err != nil {
return err
}
valueSets = append(valueSets, v)
}
// make file
jdata := make(map[string]interface{})
jdata["day"] = selectedChallenge.Number
jdata["dir"] = selectedChallenge.Dir
jdata["numRuns"] = numberRuns
jdata["implementations"] = make(map[string]interface{})
for _, vs := range valueSets {
x := make(map[string]interface{})
for _, v := range vs.values {
x[v.key] = v.value
}
(jdata["implementations"].(map[string]interface{}))[vs.implementation] = x
}
fpath := filepath.Join(selectedChallenge.Dir, "benchmark.json")
fmt.Println("Writing results to", fpath)
jBytes, err := json.MarshalIndent(jdata, "", " ")
if err != nil {
return err
}
return ioutil.WriteFile(
fpath,
jBytes,
0644,
)
}
type values struct {
implementation string
values []kv
}
type kv struct {
key string
value float64
}
func benchmarkImplementation(implementation string, dir string, inputString string, numberRuns int) (*values, error) {
var (
tasks []*runners.Task
results []*runners.Result
)
runner := runners.Available[implementation](dir)
for i := 0; i < numberRuns; i++ {
tasks = append(tasks, &runners.Task{
TaskID: makeBenchmarkID(runners.PartOne, i),
Part: runners.PartOne,
Input: inputString,
}, &runners.Task{
TaskID: makeBenchmarkID(runners.PartTwo, i),
Part: runners.PartTwo,
Input: inputString,
})
}
pb := progressbar.NewOptions(
numberRuns * 2, // two parts means 2x the number of runs
progressbar.OptionSetDescription(
fmt.Sprintf("Running %s benchmarks", runners.RunnerNames[implementation]),
),
)
if err := runner.Start(); err != nil {
return nil, err
}
defer func() {
_ = runner.Stop()
_ = runner.Cleanup()
}()
for _, task := range tasks {
res, err := runner.Run(task)
if err != nil {
_ = pb.Close()
return nil, err
}
results = append(results, res)
_ = pb.Add(1)
}
fmt.Println()
var (
p1, p2 []float64
p1id = makeBenchmarkID(runners.PartOne, -1)
p2id = makeBenchmarkID(runners.PartTwo, -1)
)
for _, result := range results {
if strings.HasPrefix(result.TaskID, p1id) {
p1 = append(p1, result.Duration)
} else if strings.HasPrefix(result.TaskID, p2id) {
p2 = append(p2, result.Duration)
}
}
return &values{
implementation: runners.RunnerNames[implementation],
values: []kv{
{"part.1.avg", meanFloatSlice(p1)},
{"part.1.min", minFloatSlice(p1)},
{"part.1.max", maxFloatSlice(p1)},
{"part.2.avg", meanFloatSlice(p2)},
{"part.2.min", minFloatSlice(p2)},
{"part.2.max", maxFloatSlice(p2)},
},
}, nil
}

View file

@ -1,53 +0,0 @@
package challenge
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"github.com/codemicro/adventOfCode/runtime/util"
)
type Challenge struct {
Number int
Name string
Dir string
}
func (c *Challenge) String() string {
return fmt.Sprintf("%d - %s", c.Number, c.Name)
}
var challengeDirRegexp = regexp.MustCompile(`(?m)^(\d{2})-([a-zA-Z]+)$`)
func ListingFromDir(sourceDir string) ([]*Challenge, error) {
dirEntries, err := os.ReadDir(sourceDir)
if err != nil {
return nil, err
}
var o []*Challenge
for _, entry := range dirEntries {
if entry.IsDir() && challengeDirRegexp.MatchString(entry.Name()) {
dir := entry.Name()
x := strings.Split(dir, "-")
dayInt, _ := strconv.Atoi(x[0]) // error ignored because regex should have ensured this is ok
dayTitle := util.CamelToTitle(x[1])
o = append(o, &Challenge{
Number: dayInt,
Name: dayTitle,
Dir: filepath.Join(sourceDir, dir),
})
}
}
return o, nil
}

View file

@ -1,35 +0,0 @@
package challenge
import (
"encoding/json"
"io/ioutil"
)
type Info struct {
InputFile string `json:"inputFile"`
TestCases struct {
One []*TestCase `json:"one"`
Two []*TestCase `json:"two"`
} `json:"testCases"`
}
type TestCase struct {
Input string `json:"input"`
Expected string `json:"expected"`
}
func LoadChallengeInfo(fname string) (*Info, error) {
fcont, err := ioutil.ReadFile(fname)
if err != nil {
return nil, err
}
c := new(Info)
err = json.Unmarshal(fcont, c)
if err != nil {
return nil, err
}
return c, nil
}

View file

@ -1,26 +0,0 @@
package challenge
import (
"github.com/codemicro/adventOfCode/runtime/runners"
"os"
"strings"
)
func (c *Challenge) GetImplementations() ([]string, error) {
dirEntries, err := os.ReadDir(c.Dir)
if err != nil {
return nil, err
}
var o []string
for _, de := range dirEntries {
if !de.IsDir() {
continue
}
if _, ok := runners.Available[strings.ToLower(de.Name())]; ok {
o = append(o, de.Name())
}
}
return o, nil
}

View file

@ -1,147 +0,0 @@
package main
import (
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"github.com/codemicro/adventOfCode/runtime/benchmark"
au "github.com/logrusorgru/aurora"
"github.com/alexflint/go-arg"
"github.com/codemicro/adventOfCode/runtime/challenge"
"github.com/codemicro/adventOfCode/runtime/runners"
)
const (
challengeDir = "challenges"
challengeInfoFile = "info.json"
)
var args struct {
Year string `arg:"-y,--year" help:"AoC year to use"`
ChallengeDay *int `arg:"-d,--day" help:"challenge day number to run"`
Implementation string `arg:"-i,--implementation" help:"implementation to use"`
Benchmark bool `arg:"-b,--benchmark" help:"benchmark a day's implementations'"`
BenchmarkN int `arg:"-n,--benchmark-n" help:"Number of iterations to run for benchmarking" default:"1000"`
TestOnly bool `arg:"-t,--test-only" help:"Only run test inputs"`
NoTest bool `arg:"-x,--no-test" help:"Do not run test inputs"`
Visualise bool `arg:"-g,--visualise" help:"Run visualisation generation"`
}
func run() error {
arg.MustParse(&args)
// List and select year
selectedYear, err := selectYear(challengeDir)
if err != nil {
return err
}
// List and select challenges
selectedChallenge, err := selectChallenge(selectedYear)
if err != nil {
return err
}
// Load info.json file
challengeInfo, err := challenge.LoadChallengeInfo(filepath.Join(selectedChallenge.Dir, challengeInfoFile))
if err != nil {
return err
}
// Load challenge input
challengeInput, err := ioutil.ReadFile(filepath.Join(selectedChallenge.Dir, challengeInfo.InputFile))
if err != nil {
return err
}
challengeInputString := string(challengeInput)
if args.Benchmark {
return benchmark.Run(selectedChallenge, challengeInputString, args.BenchmarkN)
}
// List and select implementations
selectedImplementation, err := selectImplementation(selectedChallenge)
if err != nil {
return err
}
fmt.Print(
au.Bold(
fmt.Sprintf(
"%s-%d %s (%s)\n\n",
strings.TrimPrefix(selectedYear, "challenges/"),
selectedChallenge.Number,
selectedChallenge.Name,
runners.RunnerNames[selectedImplementation],
),
),
)
runner := runners.Available[selectedImplementation](selectedChallenge.Dir)
if err := runner.Start(); err != nil {
return err
}
defer func() {
_ = runner.Stop()
_ = runner.Cleanup()
}()
if args.Visualise {
id := "vis"
r, err := runner.Run(&runners.Task{
TaskID: id,
Part: runners.Visualise,
Input: challengeInputString,
OutputDir: ".", // directory the runner is run in, which is the challenge directory
})
if err != nil {
return err
}
fmt.Print(au.Bold("Visualisation: "))
var status string
var followUpText string
if !r.Ok {
status = incompleteLabel
followUpText = "saying \"" + r.Output + "\""
} else {
status = passLabel
}
if followUpText == "" {
followUpText = fmt.Sprintf("in %.4f seconds", r.Duration)
}
fmt.Print(status)
fmt.Println(au.Gray(10, " "+followUpText))
} else {
fmt.Print("Running...\n\n")
if !args.NoTest {
if err := runTests(runner, challengeInfo); err != nil {
return err
}
}
if !args.TestOnly {
if err := runMainTasks(runner, challengeInputString); err != nil {
return err
}
}
}
return nil
}
func main() {
if err := run(); err != nil {
panic(err)
}
}

View file

@ -1,108 +0,0 @@
package runners
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"os/exec"
"strings"
"sync"
"time"
au "github.com/logrusorgru/aurora"
)
type Task struct {
TaskID string `json:"task_id"`
Part Part `json:"part"`
Input string `json:"input"`
OutputDir string `json:"output_dir,omitempty"`
}
type Result struct {
TaskID string `json:"task_id"`
Ok bool `json:"ok"`
Output string `json:"output"`
Duration float64 `json:"duration"`
}
type customWriter struct {
pending []byte
entries [][]byte
mux sync.Mutex
}
func (c *customWriter) Write(b []byte) (int, error) {
var n int
c.mux.Lock()
for _, x := range b {
if x == '\n' {
c.entries = append(c.entries, c.pending)
c.pending = nil
} else {
c.pending = append(c.pending, x)
}
n += 1
}
c.mux.Unlock()
return n, nil
}
func (c *customWriter) GetEntry() ([]byte, error) {
c.mux.Lock()
defer c.mux.Unlock()
if len(c.entries) == 0 {
return nil, errors.New("no entries")
}
var x []byte
x, c.entries = c.entries[0], c.entries[1:]
return x, nil
}
func setupBuffers(cmd *exec.Cmd) (io.WriteCloser, error) {
stdoutWriter := &customWriter{}
cmd.Stdout = stdoutWriter
cmd.Stderr = new(bytes.Buffer)
return cmd.StdinPipe()
}
func checkWait(cmd *exec.Cmd) ([]byte, error) {
c := cmd.Stdout.(*customWriter)
for {
e, err := c.GetEntry()
if err == nil {
return e, nil
}
if cmd.ProcessState != nil {
// this is only populated after program exit - we have an issue
return nil, fmt.Errorf("run failed with exit code %d: %s", cmd.ProcessState.ExitCode(), cmd.Stderr.(*bytes.Buffer).String())
}
time.Sleep(time.Millisecond * 10)
}
}
func readJSONFromCommand(res interface{}, cmd *exec.Cmd) error {
for {
inp, err := checkWait(cmd)
if err != nil {
return err
}
err = json.Unmarshal(inp, res)
if err != nil {
// echo anything that won't parse to stdout (this lets us add debug print statements)
fmt.Printf("[%s] %v\n", au.BrightRed("DBG"), strings.TrimSpace(string(inp)))
} else {
break
}
}
return nil
}

View file

@ -1,128 +0,0 @@
package runners
import (
"bytes"
_ "embed"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"text/template"
)
const (
golangInstallation = "go"
golangWrapperFilename = "runtime-wrapper.go"
golangWrapperExecutableFilename = "runtime-wrapper"
)
type golangRunner struct {
dir string
cmd *exec.Cmd
wrapperFilepath string
executableFilepath string
stdin io.WriteCloser
}
func newGolangRunner(dir string) Runner {
return &golangRunner{
dir: dir,
}
}
//go:embed interface/go.go
var golangInterface []byte
func (g *golangRunner) Start() error {
g.wrapperFilepath = filepath.Join(g.dir, golangWrapperFilename)
g.executableFilepath = filepath.Join(g.dir, golangWrapperExecutableFilename)
// determine package import path
buildPath := fmt.Sprintf("github.com/codemicro/adventOfCode/challenges/%s/%s", filepath.Base(filepath.Dir(g.dir)), filepath.Base(g.dir))
importPath := buildPath + "/go"
// generate code
var wrapperContent []byte
{
tpl := template.Must(template.New("").Parse(string(golangInterface)))
b := new(bytes.Buffer)
err := tpl.Execute(b, struct {
ImportPath string
}{importPath})
if err != nil {
return err
}
wrapperContent = b.Bytes()
}
// save interaction code
if err := ioutil.WriteFile(g.wrapperFilepath, wrapperContent, 0644); err != nil {
return err
}
// compile executable
stderrBuffer := new(bytes.Buffer)
cmd := exec.Command(golangInstallation, "build", "-tags", "runtime", "-o", g.executableFilepath, buildPath)
cmd.Stderr = stderrBuffer
if err := cmd.Run(); err != nil {
return fmt.Errorf("compilation failed: %s: %s", err, stderrBuffer.String())
}
if !cmd.ProcessState.Success() {
return errors.New("compilation failed, hence cannot continue")
}
// now we run!
absExecPath, err := filepath.Abs(g.executableFilepath)
if err != nil {
return err
}
// run executable
g.cmd = exec.Command(absExecPath)
cmd.Dir = g.dir
if stdin, err := setupBuffers(g.cmd); err != nil {
return err
} else {
g.stdin = stdin
}
return g.cmd.Start()
}
func (g *golangRunner) Stop() error {
if g.cmd == nil || g.cmd.Process == nil {
return nil
}
return g.cmd.Process.Kill()
}
func (g *golangRunner) Cleanup() error {
if g.wrapperFilepath != "" {
_ = os.Remove(g.wrapperFilepath)
}
if g.executableFilepath != "" {
_ = os.Remove(g.executableFilepath)
}
return nil
}
func (g *golangRunner) Run(task *Task) (*Result, error) {
taskJSON, err := json.Marshal(task)
if err != nil {
return nil, err
}
_, _ = g.stdin.Write(append(taskJSON, '\n'))
res := new(Result)
if err := readJSONFromCommand(res, g.cmd); err != nil {
return nil, err
}
return res, nil
}

View file

@ -1,80 +0,0 @@
//+build runtime
package main
import (
"bufio"
"encoding/json"
"fmt"
"github.com/codemicro/adventOfCode/runtime/runners"
"os"
"time"
chcode "{{ .ImportPath }}"
)
func sendResult(taskID string, ok bool, output string, duration float64) {
x := runners.Result{
TaskID: taskID,
Ok: ok,
Output: output,
Duration: duration,
}
dat, err := json.Marshal(&x)
if err != nil {
panic(err)
}
fmt.Println(string(dat))
}
func run() error {
reader := bufio.NewReader(os.Stdin)
for {
task := new(runners.Task)
taskBytes, err := reader.ReadBytes('\n')
if err != nil {
return err
}
if err := json.Unmarshal(taskBytes, task); err != nil {
return err
}
var run func() (interface{}, error)
switch task.Part {
case runners.PartOne:
run = func() (interface{}, error) {
return (chcode.Challenge{}).One(task.Input)
}
case runners.PartTwo:
run = func() (interface{}, error) {
return (chcode.Challenge{}).Two(task.Input)
}
case runners.Visualise:
run = func() (interface{}, error) {
return "", (chcode.Challenge{}).Vis(task.Input, task.OutputDir)
}
}
startTime := time.Now()
res, err := run()
endTIme := time.Now()
runningTime := endTIme.Sub(startTime).Seconds()
if err != nil {
sendResult(task.TaskID, false, err.Error(), runningTime)
} else {
sendResult(task.TaskID, true, fmt.Sprintf("%v", res), runningTime)
}
}
return nil
}
func main() {
if err := run(); err != nil {
panic(err)
}
}

View file

@ -1,58 +0,0 @@
import std/strutils
import std/options
import std/json
import std/monotimes
import std/times
from nim/challenge as solutions import nil
proc sendResult(taskID: string, ok: bool, output: string, duration: float64) =
let jobj = %* {
"task_id": taskID,
"ok": ok,
"output": output,
"duration": duration,
}
echo $jobj
type
Task = ref object
task_id: string
part: int
input: string
output_dir: Option[string]
while true:
let
taskString = readLine(stdin)
task = to(parseJson(taskString), Task)
var runProc: proc(): string
case task.part
of 1:
runProc = proc(): string = $(solutions.partOne(task.input))
of 2:
runProc = proc(): string = $(solutions.partTwo(task.input))
else:
sendResult(task.task_id, false, "unknown task part", 0.0)
var
result: string
error: string
let startTime = getMonoTime()
try:
result = runProc()
except:
error = getCurrentExceptionMsg()
let endTime = getMonoTime()
let runningTime = endTime - startTime
let runningTimeSeconds = float(inNanoseconds(runningTime)) / float(1000000000)
if error != "":
sendResult(task.task_id, false, error, runningTimeSeconds)
else:
sendResult(task.task_id, true, result, runningTimeSeconds)

View file

@ -1,58 +0,0 @@
from py import Challenge
import time
import json
# TASKS_STR = input()
# TASKS = json.loads(TASKS_STR)
def send_result(task_id, ok, output, duration):
print(
json.dumps(
{
"task_id": task_id,
"ok": ok,
"output": str(output) if output is not None else "",
"duration": float(duration),
}
),
flush=True,
)
while True:
task = json.loads(input())
taskPart = task["part"]
task_id = task["task_id"]
run = None
if taskPart == 1:
run = lambda: Challenge.one(task["input"])
elif taskPart == 2:
run = lambda: Challenge.two(task["input"])
elif taskPart == 3:
run = lambda: Challenge.vis(task["input"], task["output_dir"])
else:
send_result(task_id, False, "unknown task part", 0)
continue
start_time = time.time()
res = None
err = None
try:
res = run()
except Exception as e:
err = f"{type(e)}: {e}"
import traceback
err = f"{type(e)}: {e}\n{''.join(traceback.format_tb(e.__traceback__))}"
end_time = time.time()
running_time = end_time - start_time
if err is not None:
send_result(task_id, False, err, running_time)
else:
send_result(task_id, True, res, running_time)

View file

@ -1,109 +0,0 @@
package runners
import (
"bytes"
_ "embed"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
)
const (
nimInstallation = "nim"
nimWrapperFilename = "runtimeWrapper.nim"
nimWrapperExecutableFilename = "runtimeWrapper"
)
type nimRunner struct {
dir string
cmd *exec.Cmd
wrapperFilepath string
executableFilepath string
stdin io.WriteCloser
}
func newNimRunner(dir string) Runner {
return &nimRunner{
dir: dir,
}
}
//go:embed interface/nim.nim
var nimInterface []byte
func (n *nimRunner) Start() error {
n.wrapperFilepath = filepath.Join(n.dir, nimWrapperFilename)
n.executableFilepath = filepath.Join(n.dir, nimWrapperExecutableFilename)
// save interaction code
err := ioutil.WriteFile(n.wrapperFilepath, nimInterface, 0644)
if err != nil {
return err
}
// compile
stderrBuffer := new(bytes.Buffer)
cmd := exec.Command(nimInstallation, "compile", "-o:"+n.executableFilepath, "-d:release", n.wrapperFilepath)
cmd.Stderr = stderrBuffer
err = cmd.Run()
if err != nil {
return fmt.Errorf("compilation failed: %s: %s", err, stderrBuffer.String())
}
if !cmd.ProcessState.Success() {
return errors.New("compilation failed, hence cannot continue")
}
// now we run!
absExecPath, err := filepath.Abs(n.executableFilepath)
if err != nil {
return err
}
n.cmd = exec.Command(absExecPath)
n.cmd.Dir = n.dir
if stdin, err := setupBuffers(n.cmd); err != nil {
return err
} else {
n.stdin = stdin
}
return n.cmd.Start()
}
func (n *nimRunner) Stop() error {
if n.cmd == nil || n.cmd.Process == nil {
return nil
}
return n.cmd.Process.Kill()
}
func (n *nimRunner) Cleanup() error {
if n.wrapperFilepath != "" {
_ = os.Remove(n.wrapperFilepath)
}
if n.executableFilepath != "" {
_ = os.Remove(n.executableFilepath)
}
return nil
}
func (n *nimRunner) Run(task *Task) (*Result, error) {
taskJSON, err := json.Marshal(task)
if err != nil {
return nil, err
}
_, _ = n.stdin.Write(append(taskJSON, '\n'))
res := new(Result)
if err := readJSONFromCommand(res, n.cmd); err != nil {
return nil, err
}
return res, nil
}

View file

@ -1,99 +0,0 @@
package runners
import (
_ "embed"
"encoding/json"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
)
const (
python3Installation = "python3"
pythonWrapperFilename = "runtime-wrapper.py"
)
type pythonRunner struct {
dir string
cmd *exec.Cmd
wrapperFilepath string
stdin io.WriteCloser
}
func newPythonRunner(dir string) Runner {
return &pythonRunner{
dir: dir,
}
}
//go:embed interface/python.py
var pythonInterface []byte
func (p *pythonRunner) Start() error {
p.wrapperFilepath = filepath.Join(p.dir, pythonWrapperFilename)
// Save interaction code
if err := ioutil.WriteFile(p.wrapperFilepath, pythonInterface, 0644); err != nil {
return err
}
// Sort out PYTHONPATH
cwd, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(p.dir)
if err != nil {
return err
}
pythonPathVar := strings.Join([]string{
filepath.Join(cwd, "lib"), // so we can use aocpy
filepath.Join(absDir, "py"), // so we can import stuff in the challenge directory
}, ":")
p.cmd = exec.Command(python3Installation, "-B", pythonWrapperFilename) // -B prevents .pyc files from being written
p.cmd.Env = append(p.cmd.Env, "PYTHONPATH="+pythonPathVar)
p.cmd.Dir = p.dir
if stdin, err := setupBuffers(p.cmd); err != nil {
return err
} else {
p.stdin = stdin
}
return p.cmd.Start()
}
func (p *pythonRunner) Stop() error {
if p.cmd == nil || p.cmd.Process == nil {
return nil
}
return p.cmd.Process.Kill()
}
func (p *pythonRunner) Cleanup() error {
if p.wrapperFilepath == "" {
return nil
}
_ = os.Remove(p.wrapperFilepath)
return nil
}
func (p *pythonRunner) Run(task *Task) (*Result, error) {
taskJSON, err := json.Marshal(task)
if err != nil {
return nil, err
}
_, _ = p.stdin.Write(append(taskJSON, '\n'))
res := new(Result)
if err := readJSONFromCommand(res, p.cmd); err != nil {
return nil, err
}
return res, nil
}

View file

@ -1,35 +0,0 @@
package runners
type Part uint8
const (
PartOne Part = iota + 1
PartTwo
Visualise
)
type Runner interface {
Start() error
Stop() error
Cleanup() error
Run(task *Task) (*Result, error)
}
type ResultOrError struct {
Result *Result
Error error
}
type RunnerCreator func(dir string) Runner
var Available = map[string]RunnerCreator{
"py": newPythonRunner,
"go": newGolangRunner,
"nim": newNimRunner,
}
var RunnerNames = map[string]string{
"py": "Python",
"go": "Golang",
"nim": "Nim",
}

View file

@ -1,154 +0,0 @@
package main
import (
"errors"
"fmt"
"github.com/AlecAivazis/survey/v2"
"github.com/codemicro/adventOfCode/runtime/challenge"
"github.com/codemicro/adventOfCode/runtime/runners"
"os"
"path/filepath"
"strings"
)
func userSelect(question string, choices []string) (int, error) {
var o string
prompt := &survey.Select{
Message: question,
Options: choices,
}
//err := survey.AskOne(prompt, &o, survey.WithStdio(os.Stdin, os.Stderr, os.Stderr))
err := survey.AskOne(prompt, &o)
if err != nil {
return 0, err
}
for i, x := range choices {
if x == o {
return i, nil
}
}
return -1, nil
}
func selectYear(dir string) (string, error) {
var opts []string
entries, err := os.ReadDir(dir)
if err != nil {
return "", err
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
opts = append(opts, entry.Name())
}
if len(opts) == 0 {
return "", errors.New("no years to use")
}
if args.Year != "" {
for _, x := range opts {
if x == args.Year {
return filepath.Join(dir, x), nil
}
}
fmt.Printf("Could not locate year %s\n", args.Year)
}
var selectedYearIndex int
if x := len(opts); x == 1 {
selectedYearIndex = 0
} else {
selectedYearIndex, err = userSelect("Which year do you want to use?", opts)
if err != nil {
return "", err
}
}
return filepath.Join(dir, opts[selectedYearIndex]), nil
}
func selectChallenge(dir string) (*challenge.Challenge, error) {
challenges, err := challenge.ListingFromDir(dir)
if err != nil {
return nil, err
}
if len(challenges) == 0 {
return nil, errors.New("no challenges to run")
}
if args.ChallengeDay != nil {
for _, ch := range challenges {
if ch.Number == *args.ChallengeDay {
return ch, nil
}
}
fmt.Printf("Could not locate day %d\n", *args.ChallengeDay)
}
var selectedChallengeIndex int
if x := len(challenges); x == 1 {
selectedChallengeIndex = 0
} else {
var opts []string
for _, c := range challenges {
opts = append(opts, c.String())
}
selectedChallengeIndex, err = userSelect("Which challenge do you want to run?", opts)
if err != nil {
return nil, err
}
}
return challenges[selectedChallengeIndex], nil
}
func selectImplementation(ch *challenge.Challenge) (string, error) {
implementations, err := ch.GetImplementations()
if err != nil {
return "", err
}
if len(implementations) == 0 {
return "", errors.New("no implementations to use")
}
if args.Implementation != "" {
for _, im := range implementations {
if strings.EqualFold(im, args.Implementation) {
return im, nil
}
}
fmt.Printf("Could not locate implementation %#v\n", args.Implementation)
}
var selectedImplementationIndex int
if x := len(implementations); x == 1 {
selectedImplementationIndex = 0
} else {
var opts []string
for _, i := range implementations {
opts = append(opts, runners.RunnerNames[i])
}
selectedImplementationIndex, err = userSelect("Which implementation do you want to use?", opts)
if err != nil {
return "", err
}
}
return implementations[selectedImplementationIndex], nil
}

View file

@ -1,132 +0,0 @@
package main
import (
"fmt"
"strconv"
"strings"
"github.com/codemicro/adventOfCode/runtime/challenge"
"github.com/codemicro/adventOfCode/runtime/runners"
au "github.com/logrusorgru/aurora"
)
var (
passLabel = au.BrightGreen("pass").String()
failLabel = au.BrightRed("fail").String()
incompleteLabel = au.BgBrightRed("did not complete").String()
)
func makeTestID(part runners.Part, n int) string {
return fmt.Sprintf("test.%d.%d", part, n)
}
func parseTestID(x string) (runners.Part, int) {
y := strings.Split(x, ".")
p, _ := strconv.Atoi(y[1])
n, _ := strconv.Atoi(y[2])
return runners.Part(p), n
}
func makeMainID(part runners.Part) string {
return fmt.Sprintf("main.%d", part)
}
func parseMainID(x string) runners.Part {
y := strings.Split(x, ".")
p, _ := strconv.Atoi(y[1])
return runners.Part(p)
}
func runTests(runner runners.Runner, info *challenge.Info) error {
for i, testCase := range info.TestCases.One {
id := makeTestID(runners.PartOne, i)
result, err := runner.Run(&runners.Task{
TaskID: id,
Part: runners.PartOne,
Input: testCase.Input,
})
if err != nil {
return err
}
handleTestResult(result, testCase)
}
for i, testCase := range info.TestCases.Two {
id := makeTestID(runners.PartTwo, i)
result, err := runner.Run(&runners.Task{
TaskID: id,
Part: runners.PartTwo,
Input: testCase.Input,
})
if err != nil {
return err
}
handleTestResult(result, testCase)
}
return nil
}
func handleTestResult(r *runners.Result, testCase *challenge.TestCase) {
part, n := parseTestID(r.TaskID)
fmt.Print(au.Bold(fmt.Sprintf("Test %s: ",
au.BrightBlue(fmt.Sprintf("%d.%d", part, n)),
)))
passed := r.Output == testCase.Expected
var status string
var followUpText string
if !r.Ok {
status = incompleteLabel
followUpText = "saying \"" + r.Output + "\""
} else if passed {
status = passLabel
} else {
status = failLabel
}
if followUpText == "" {
followUpText = fmt.Sprintf("in %.4f seconds", r.Duration)
}
fmt.Print(status)
fmt.Println(au.Gray(10, " "+followUpText))
if !passed && r.Ok {
fmt.Printf(" └ Expected %s, got %s\n", au.BrightBlue(testCase.Expected), au.BrightBlue(r.Output))
}
}
func runMainTasks(runner runners.Runner, input string) error {
for part := runners.PartOne; part <= runners.PartTwo; part += 1 {
id := makeMainID(part)
result, err := runner.Run(&runners.Task{
TaskID: id,
Part: part,
Input: input,
})
if err != nil {
return err
}
handleMainResult(result)
}
return nil
}
func handleMainResult(r *runners.Result) {
part := parseMainID(r.TaskID)
fmt.Print(au.Bold(fmt.Sprintf("Part %d: ", au.Yellow(part))))
if !r.Ok {
fmt.Print(incompleteLabel)
fmt.Println(au.Gray(10, " saying \""+r.Output+"\""))
} else {
fmt.Print(au.BrightBlue(r.Output))
fmt.Println(au.Gray(10, fmt.Sprintf(" in %.4f seconds", r.Duration)))
}
}

View file

@ -1,19 +0,0 @@
package util
import (
"unicode"
)
func CamelToTitle(x string) string {
var o string
for i, char := range x {
if i == 0 {
o += string(unicode.ToUpper(char))
} else if unicode.IsUpper(char) {
o += " " + string(char)
} else {
o += string(char)
}
}
return o
}

View file

@ -1,12 +0,0 @@
{
"_extensions": ["local_extensions.camel_case", "local_extensions.current_year", "local_extensions.current_day"],
"year": "{{ 0 | current_year }}",
"dayNumber": "{{ 0 | current_day }}",
"challengeTitle": null,
"__formattedTitle": "{{ cookiecutter.challengeTitle | title }}",
"__camelTitle": "{{ cookiecutter.challengeTitle | camel_case }}",
"__formattedDayNumber": "{{ '%02d' | format(cookiecutter.dayNumber|int) }}"
}

View file

@ -1,25 +0,0 @@
import datetime
from cookiecutter.utils import simple_filter
@simple_filter
def camel_case(v):
res = v.split(" ")
for i in range(len(res)):
f = lambda x: x.upper()
if i == 0:
f = lambda x: x.lower()
res[i] = f(res[i][0]) + res[i][1:]
return "".join(res)
@simple_filter
def current_year(_):
return datetime.datetime.now().year
@simple_filter
def current_day(_):
return datetime.datetime.now().day

View file

@ -1 +0,0 @@
# [Day {{ cookiecutter.dayNumber }}: {{ cookiecutter.__formattedTitle }}](https://adventofcode.com/{{ cookiecutter.year }}/day/{{ cookiecutter.dayNumber }})

View file

@ -1,15 +0,0 @@
package challenge
import "github.com/codemicro/adventOfCode/lib/aocgo"
type Challenge struct {
aocgo.BaseChallenge
}
func (c Challenge) One(instr string) (any, error) {
return nil, nil
}
func (c Challenge) Two(instr string) (any, error) {
return nil, nil
}

View file

@ -1,17 +0,0 @@
{
"inputFile": "input.txt",
"testCases": {
"one": [
{
"input": "",
"expected": ""
}
],
"two": [
{
"input": "",
"expected": ""
}
]
}
}

View file

@ -1,5 +0,0 @@
proc partOne*(instr: string): untyped =
raise newException(CatchableError, "not implemented")
proc partTwo*(instr: string): untyped =
raise newException(CatchableError, "not implemented")

View file

@ -1,12 +0,0 @@
from typing import *
from aocpy import BaseChallenge
class Challenge(BaseChallenge):
@staticmethod
def one(instr: str) -> int:
raise NotImplementedError
@staticmethod
def two(instr: str) -> int:
raise NotImplementedError