Lots of cleanup for nim solutions and day 2 solutions in nim

This commit is contained in:
Daniel Flanagan 2021-12-02 11:00:05 -06:00
parent ff44a85cce
commit ea0a467b5c
Signed by: lytedev
GPG key ID: 5B2020A0F9921EF4
6 changed files with 127 additions and 32 deletions

1
2021/.gitignore vendored
View file

@ -1 +1,2 @@
*.input *.input
build

View file

@ -1,11 +1,18 @@
import { collectArray, inputLines, measureDuration } from "./common.ts"; import { collectArray, inputLines, measureDuration } from "./common.ts";
const input = await collectArray(await inputLines("2")); const input = await collectArray(await inputLines("2"));
type SubmarineCommand = ["forward", number] | ["up", number] | ["down", number];
// function parseSubmarineCommand(command: string): SubmarineCommand {
// let [cmd, arg] = command.split(" ", 2);
// cmd = ["forward", "up", "down"].includes(cmd) ? cmd : "up";
// return [cmd, parseInt(arg)];
// }
export function part1(input: string[]): number { export function part1(input: string[]): number {
let x = 0; let x = 0;
let y = 0; let y = 0;
for (const line of input) { for (const line of input) {
console.log(line);
if (line.startsWith("forward ")) { if (line.startsWith("forward ")) {
x += parseInt(line.substr(8)); x += parseInt(line.substr(8));
} else if (line.startsWith("up ")) { } else if (line.startsWith("up ")) {
@ -24,7 +31,6 @@ export function part2(input: string[]): number {
let y = 0; let y = 0;
let aim = 0; let aim = 0;
for (const line of input) { for (const line of input) {
console.log(line);
if (line.startsWith("forward ")) { if (line.startsWith("forward ")) {
const arg = parseInt(line.substr(8)); const arg = parseInt(line.substr(8));
x += arg; x += arg;
@ -32,11 +38,9 @@ export function part2(input: string[]): number {
} else if (line.startsWith("up ")) { } else if (line.startsWith("up ")) {
const arg = parseInt(line.substr(3)); const arg = parseInt(line.substr(3));
aim -= arg; aim -= arg;
// y -= arg;
} else if (line.startsWith("down ")) { } else if (line.startsWith("down ")) {
const arg = parseInt(line.substr(5)); const arg = parseInt(line.substr(5));
aim += arg; aim += arg;
// y += arg;
} }
} }
return x * y; return x * y;

35
2021/common.nim Normal file
View file

@ -0,0 +1,35 @@
import std/[streams, sequtils, strutils, sugar, strformat, times, httpclient, os]
const YEAR = getEnv("AOC_YEAR", "2021").parseInt()
proc getCookie(): string = "~/.advent-of-code-auth-cookie".expandTilde().readFile()
proc getCacheDir(): string = joinPath(expandTilde("~/.cache"), fmt"/aoc{YEAR}")
proc inputFilePath(day: int): string = joinPath(getCacheDir(), fmt"{day}.input")
proc fetchInput(day: int, filePath: string): StringStream =
let client = newHttpClient()
client.headers = {"cookie": getCookie()}.newHttpHeaders()
let content = client.getContent(fmt"https://adventofcode.com/{YEAR}/day/{day}/input")
filePath.writeFile(content)
content.newStringStream()
proc inputStream*(day: int): Stream =
getCacheDir().createDir()
let cachedFile = day.inputFilePath()
if not cachedFile.fileExists(): day.fetchInput(cachedFile)
else: openFileStream(cachedFile)
proc toInts*(s: seq[string]): seq[int] = s.map(parseInt)
proc loadInput*(day: int): seq[string] =
result = collect:
for l in day.inputStream().lines(): l
template time*(i: string, body: untyped): untyped =
let start = cpuTime()
body
let stop = cpuTime()
let diff = $((stop - start) * 1000)
echo i & " took " & diff & "ms to calculate solution"
when not defined(release):
echo "NOTE: This is not a real measurement of performance. Compile in release mode with -d:release for best performance."
# jkp: {(stop - start) * 1000} ms to calculate solution: {result}"

View file

@ -1,31 +1,15 @@
import std/[streams, strutils, sugar, strformat, times] import ./common
iterator inputForDay(day: int): int = proc countDepthIncreases(inputs: seq[int], dist=1): int =
var stream: FileStream = fmt"/home/daniel/.home/.config/aoc2021/{day}.input".openFileStream for i in dist..<inputs.len():
for s in stream.lines():
yield s.parseInt
proc part1(inputs: seq[int], dist=1): int =
result = 0
var i = dist
var x = inputs.len()-1
while i <= x:
if inputs[i] > inputs[i-dist]: inc result if inputs[i] > inputs[i-dist]: inc result
inc i
let dd1 = epochTime() let input = 1.loadInput().toInts()
var input = collect(newSeq): time("countDepthIncreases part 1"): echo input.countDepthIncreases()
for i in inputForDay(1): i time("countDepthIncreases part 2"): echo input.countDepthIncreases(3)
let dd2 = epochTime() when not defined(release):
echo &"{(dd2 - dd1) * 1000} ms (to load input)" static:
echo "Part 1" let testInputs = @[199, 200, 208, 210, 200, 207, 240, 269, 260, 263]
let d1 = epochTime() doAssert testInputs.countDepthIncreases() == 7
echo part1(input) doAssert testInputs.countDepthIncreases(3) == 5
let d2 = epochTime()
echo &"{(d2 - d1) * 1000} ms (to calculate solution)"
echo "Part 2"
let d21 = epochTime()
echo part1(input,3)
let d22 = epochTime()
echo &"{(d22 - d21) * 1000} ms (to calculate solution)"

View file

@ -12,16 +12,34 @@ Specifically, here's my `deno --version` output:
Enjoy! Enjoy!
**EDIT**: Since performance is not what I would like, it looks like I'm also doing some of these in nim.
## Usage ## Usage
Run these solutions like so: Run these solutions like so:
deno run --unstable --allow-all $DAY.ts deno run --unstable --allow-all $DAY.ts
And the nim ones like so:
nim c -d:release -d:ssl --run $DAYMODULE.nim
And if you want to measure memory usage:
mkdir -p build
deno compile --output build/$DAY --unstable --allow-all $DAY.ts
/usr/bin/time -v ./build/$DAY
Or
mkdir -p build
nim c -d:release -d:ssl --outdir:build $DAYMODULE.nim
/usr/bin/time -v ./$DAYMODULE
# Days # Days
- [x] [Day 1](./1.ts) - [x] [Day 1](./1.ts)
- [ ] Day 2 - [x] [Day 2](./2.ts)
- [ ] Day 3 - [ ] Day 3
- [ ] Day 4 - [ ] Day 4
- [ ] Day 5 - [ ] Day 5

53
2021/two.nim Normal file
View file

@ -0,0 +1,53 @@
import std/[strutils, sequtils]
import ./common
type SubmarineCommand = enum
Forward, Up, Down
proc parseArg(c: char): int = c.int() - 48
proc parseSubmarineCommand(l: string): (SubmarineCommand, int) =
case l[0]:
# since each arg is only one char, we can use this much faster method to
# convert to an integer
of 'd': return (Down, l[5].parseArg())
of 'u': return (Up, l[3].parseArg())
else: return (Forward, l[8].parseArg())
proc submarineCommands(inputs: seq[string]): int =
var x, y = 0
for (cmd, arg) in inputs.map(parseSubmarineCommand):
case cmd:
of Up: y -= arg
of Down: y += arg
of Forward: x += arg
x * y
proc submarineCommandsWithAim(inputs: seq[string]): int =
var x, y, aim = 0
for (cmd, arg) in inputs.map(parseSubmarineCommand):
case cmd:
of Up: aim -= arg
of Down: aim += arg
of Forward:
x += arg
y += aim * arg
x * y
let input = 2.loadInput()
time("submarineCommands part 1"): echo input.submarineCommands()
time("submarineCommandsWithAim part 2"): echo input.submarineCommandsWithAim()
when not defined(release):
static:
let testInput = @[
"forward 5",
"down 5",
"forward 8",
"up 3",
"down 8",
"forward 2",
]
doAssert testInput.submarineCommands() == 150
doAssert testInput.submarineCommandsWithAim() == 900