From ad83cc84d8ed2a537d1b75a6235e3c8ea2ba7ffd Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Wed, 2 Dec 2020 21:33:18 -0600 Subject: [PATCH] Add 2020 for nim stuff --- 2020/.gitignore | 2 ++ 2020/aoc2020.nimble | 14 ++++++++++++++ 2020/config.nims | 3 +++ 2020/makefile | 2 ++ 2020/readme.md | 5 +++++ 2020/src/aoc2020.nim | 11 +++++++++++ 2020/src/day1.nim | 30 ++++++++++++++++++++++++++++++ 2020/src/day2.nim | 7 +++++++ 2020/src/day_loader.nim | 18 ++++++++++++++++++ 2020/src/input_requestor.nim | 28 ++++++++++++++++++++++++++++ 10 files changed, 120 insertions(+) create mode 100644 2020/.gitignore create mode 100644 2020/aoc2020.nimble create mode 100644 2020/config.nims create mode 100644 2020/makefile create mode 100644 2020/readme.md create mode 100644 2020/src/aoc2020.nim create mode 100644 2020/src/day1.nim create mode 100644 2020/src/day2.nim create mode 100644 2020/src/day_loader.nim create mode 100644 2020/src/input_requestor.nim diff --git a/2020/.gitignore b/2020/.gitignore new file mode 100644 index 0000000..aa01a95 --- /dev/null +++ b/2020/.gitignore @@ -0,0 +1,2 @@ +/build +*.log diff --git a/2020/aoc2020.nimble b/2020/aoc2020.nimble new file mode 100644 index 0000000..e68f5ac --- /dev/null +++ b/2020/aoc2020.nimble @@ -0,0 +1,14 @@ +# Package + +version = "0.1.0" +author = "Daniel Flanagan" +description = "@lytedev's Advent of Code 2020 code" +license = "MIT" +srcDir = "src" +bin = @["aoc2020"] +binDir = "build" + +# Dependencies + +requires "nim >= 1.4.0" + diff --git a/2020/config.nims b/2020/config.nims new file mode 100644 index 0000000..7bda3d9 --- /dev/null +++ b/2020/config.nims @@ -0,0 +1,3 @@ +switch "define", "ssl" +switch "path", "src/" + diff --git a/2020/makefile b/2020/makefile new file mode 100644 index 0000000..d0a1bd3 --- /dev/null +++ b/2020/makefile @@ -0,0 +1,2 @@ +run: + nimble run diff --git a/2020/readme.md b/2020/readme.md new file mode 100644 index 0000000..4603f87 --- /dev/null +++ b/2020/readme.md @@ -0,0 +1,5 @@ +# Advent of Code 2020 + +This year, I've decided to tinker around with [`nim`][nim]. + +Enjoy the mess! diff --git a/2020/src/aoc2020.nim b/2020/src/aoc2020.nim new file mode 100644 index 0000000..814cd49 --- /dev/null +++ b/2020/src/aoc2020.nim @@ -0,0 +1,11 @@ +import day_loader, tables + +proc solve_all() {.used.} = + for (_, solver) in solvers.pairs(): + echo solver() + +proc solve_for_day(n: int) {.used.} = + echo solvers[n]() + +when isMainModule: + solve_for_day(2) diff --git a/2020/src/day1.nim b/2020/src/day1.nim new file mode 100644 index 0000000..df28e2e --- /dev/null +++ b/2020/src/day1.nim @@ -0,0 +1,30 @@ +import sets, streams, strutils, options + +# Day 1 + +let day1TargetSum = 2020 + +proc part1*(strm: Stream): Option[int] = + var targets = initHashSet[int]() + for line in strm.lines(): + let n = parseInt line + if targets.contains(day1TargetSum - n): + return some((day1TargetSum - n) * n) + else: + targets.incl n + +proc part2*(strm: Stream): Option[int] = + # this works exactly the same as the previous algorithm, except we simply + # permute once more + # TODO: if I was really cool, I could split the shared functionality into + # a shared proc + var nums: seq[int] + for line in strm.lines(): + nums.add parseInt line + for n in nums: + var iset = initHashSet[int]() + let nTargetSum = day1TargetSum - n + for n2 in nums: + if iset.contains(nTargetSum - n2): + return some(n * n2 * (nTargetSum - n2)) + iset.incl n2 diff --git a/2020/src/day2.nim b/2020/src/day2.nim new file mode 100644 index 0000000..e003789 --- /dev/null +++ b/2020/src/day2.nim @@ -0,0 +1,7 @@ +import streams + +proc part1*(strm: Stream): string = + "ayy" + +proc part2*(strm: Stream): string = + "ayy" diff --git a/2020/src/day_loader.nim b/2020/src/day_loader.nim new file mode 100644 index 0000000..6414b48 --- /dev/null +++ b/2020/src/day_loader.nim @@ -0,0 +1,18 @@ +import input_requestor, os, macros, strformat, tables + +macro loadDays(): untyped = + var solver_str = "var solvers = {\n" + result = newStmtList() + for day in 1..2: + let module = fmt"day{day}" + if fileExists joinPath("src/", &"{module}.nim"): + result.add parseStmt fmt"from {module} import nil" + solver_str = solver_str & &""" + {day}: proc(): (string, string) = ( + $(day{day}.part1(getInputFileStreamForDay({day}))), + $(day{day}.part2(getInputFileStreamForDay({day}))) + ), + """ + result.add parseStmt (solver_str & "\n}.newTable()\nexport solvers") + +loadDays() diff --git a/2020/src/input_requestor.nim b/2020/src/input_requestor.nim new file mode 100644 index 0000000..c35d8f5 --- /dev/null +++ b/2020/src/input_requestor.nim @@ -0,0 +1,28 @@ +import httpclient, strformat, os, logging, streams + +var fileLog = newFileLogger("aoc2020.log") +var consoleLog = newConsoleLogger() +addHandler(consoleLog) +addHandler(fileLog) + +let cacheDir = joinPath(getEnv("XDG_CACHE_HOME", expandTilde("~/.cache")), "/aoc2020-cache") +createDir(cacheDir) + +# TODO: add login capabilities via `pass` for auto-cookie-retrieval? + +proc requestAocContentAuthed(url: string): TaintedString = + let cookie = getEnv("ADVENT_OF_CODE_AUTH_COOKIE", readFile(expandTilde("~/.advent-of-code-auth-cookie"))) + let client = newHttpClient() + client.headers = newHttpHeaders({"cookie": cookie}) + client.getContent(url) + +proc getInputFileStreamForDay*(day: int): FileStream = + # retrieve the input and dump it to a file if we don't have it yet + let cacheFile = joinPath(cacheDir, fmt"/day-{day}.aoc-input") + if not fileExists(cacheFile): + let url = fmt"https://adventofcode.com/2020/day/{day}/input" + writeFile(cacheFile, requestAocContentAuthed(url).string) + openFileStream(cacheFile) + +proc getInputForDay*(day: int): string = + getInputFileStreamForDay(day).readAll()