This commit is contained in:
Danny Hpy 2023-01-25 18:11:20 +01:00
parent 3cb6474521
commit 7e06788d8d
Signed by: dannyhpy
GPG Key ID: 7139FBBEA22D1CEC
13 changed files with 409 additions and 11 deletions

4
.git-crypt/.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
# Do not edit this file. To specify the files to encrypt, create your own
# .gitattributes file in the directory where your files are.
* !filter !diff
*.gpg binary

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
session.key filter=git-crypt diff=git-crypt

7
.gitignore vendored
View File

@ -1,2 +1,7 @@
# binaries
**/first
**/second
**/both
# input files
input.txt
**/input.txt

38
2022/01/both.nim Normal file
View File

@ -0,0 +1,38 @@
import
std/strformat,
std/strutils
when defined(second):
import
std/algorithm,
std/math
import
../../adventofcode
let input = adventofcode.getInput()
when not defined(second):
var mostCalories = 0
else:
var elveCalories: seq[int]
let inventories = input.split("\L\L")
for inventory in inventories:
var calories = 0
let items = inventory.split("\L")
for item in items:
calories += item.parseInt()
when not defined(second):
mostCalories = max(mostCalories, calories)
else:
elveCalories.add calories
when not defined(second):
echo fmt"Answer: {mostCalories}"
else:
elveCalories.sort(order=Descending)
let totalCalories = sum elveCalories[0 ..< 3]
echo fmt"Answer: {totalCalories}"

43
2022/02/first.nim Normal file
View File

@ -0,0 +1,43 @@
import
std/strformat,
std/strutils,
std/tables
import
../../adventofcode
let input = adventofcode.getInput()
var score = 0
type
Choices = enum
rock, paper, scissors
let choices = toTable({
'A': rock,
'B': paper,
'C': scissors,
'X': rock,
'Y': paper,
'Z': scissors,
})
for line in input.splitLines:
let opponentChoice = choices[line[0]]
let ourChoice = choices[line[2]]
# The choice we make is added to the score
score += 1 + ord ourChoice
let outcome = ord(ourChoice) - ord(opponentChoice)
case outcome
of -2: score += 6
of -1: score += 0
of 0: score += 3
of 1: score += 6
of 2: score += 0
else:
raise newException(ValueError, fmt"Outcome: {outcome}")
echo fmt"Answer: {score}"

60
2022/02/second.nim Normal file
View File

@ -0,0 +1,60 @@
import
std/strformat,
std/strutils,
std/tables
import
../../adventofcode
let input = adventofcode.getInput()
var score = 0
type
Choice = enum
cRock = 'A',
cPaper = 'B',
cScissors = 'C'
RequiredOutcome = enum
roDefeat = 'X',
roDraw = 'Y',
roVictory = 'Z'
let choiceScores = toTable({
cRock: 1,
cPaper: 2,
cScissors: 3,
})
for line in input.splitLines:
let opponentChoice = Choice line[0]
let requiredOutcome = RequiredOutcome line[2]
var ourChoice: Choice
case requiredOutcome
of roDefeat:
score += 0
case opponentChoice
of cRock:
ourChoice = cScissors
of cPaper:
ourChoice = cRock
of cScissors:
ourChoice = cPaper
of roDraw:
score += 3
ourChoice = opponentChoice
of roVictory:
score += 6
case opponentChoice
of cRock:
ourChoice = cPaper
of cPaper:
ourChoice = cScissors
of cScissors:
ourChoice = cRock
# The choice we make is added to the score
score += choiceScores[ourChoice]
echo fmt"Answer: {score}"

50
2022/03/both.nim Normal file
View File

@ -0,0 +1,50 @@
import
std/sequtils,
std/strformat,
std/strutils
import
../../adventofcode
let input = adventofcode.getInput()
var answer = 0
let itemTypePriorities = block:
toSeq "-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
when not defined(second):
for rucksack in input.splitLines:
let items = toSeq rucksack
let cmp1 = items[0 ..< items.len() div 2]
let cmp2 = items[items.len() div 2 .. ^1]
for item in cmp1:
if item in cmp2:
answer += itemTypePriorities.find item
break
else:
let inputLines = input.splitLines()
iterator groups*(): tuple[
itemList1: seq[char],
itemList2: seq[char],
itemList3: seq[char]
] =
var i = 0
while i < inputLines.len():
yield (
toSeq inputLines[i],
toSeq inputLines[i+1],
toSeq inputLines[i+2]
)
i += 3
for rucksack1, rucksack2, rucksack3 in groups():
for item in rucksack1:
if item notin rucksack2: continue
if item notin rucksack3: continue
answer += itemTypePriorities.find item
break
echo fmt"Answer: {answer}"

41
2022/04/both.nim Normal file
View File

@ -0,0 +1,41 @@
import
std/strformat,
std/strutils
import
../../adventofcode
let input = adventofcode.getInput()
var score = 0
for pair in input.splitLines:
let sepIdx = pair.find(',')
assert sepIdx != -1
let range1Str = pair[0 ..< sepIdx]
let range2Str = pair[sepIdx + 1 .. ^1]
var range1: set[0 .. 65535]
var range2: set[0 .. 65535]
for i in 0 .. 1:
let rangeStr = block:
if i == 0: range1Str
else: range2Str
let rangeStrSepIdx = rangeStr.find('-')
assert rangeStrSepIdx != -1
let rangeStart = parseInt rangeStr[0 ..< rangeStrSepIdx]
let rangeEnd = parseInt rangeStr[rangeStrSepIdx + 1 .. ^1]
if i == 0: range1 = {rangeStart .. rangeEnd}
else: range2 = {rangeStart .. rangeEnd}
var total = range1 + range2
when not defined(second):
if range1.len == total.len or range2.len == total.len:
score += 1
else:
if total.len != (range1.len + range2.len):
score += 1
echo fmt"Answer: {score}"

84
2022/05/both.nim Normal file
View File

@ -0,0 +1,84 @@
import
std/algorithm,
std/sequtils,
std/strformat,
std/strutils
import
../../adventofcode
let input = adventofcode.getInput()
let lines = input.splitLines()
var stacks = newSeq[seq[char]]()
let sepIdx = lines.find("")
assert sepIdx != -1
let drawInstructions = lines[0 ..< sepIdx]
let moveInstructions = lines[sepIdx + 1 .. ^1]
when not defined(release):
proc echoRepr(stacks: seq[seq[char]]) =
let m = max stacks.mapIt(high it)
for i in countdown(m, 0):
echo join(stacks.map(proc(it: seq[char]): string =
if it.high < i: return " "
return fmt"[{it[i]}]"
), sep=" ")
echo " " & join(toSeq {1 .. stacks.high() + 1}, " ") & " "
for line in reversed drawInstructions:
if line.startsWith(" 1 "):
for n in line.splitWhitespace().mapIt(parseInt it):
assert n - 1 == len stacks
stacks.add(@[])
else:
var containers = newSeq[string]()
for i in countup(0, line.len - 2, 4):
containers.add line[i ..< i + 3]
for i in 0 ..< containers.len():
let cnt = containers[i]
if cnt[1] == ' ': continue
stacks[i].add cnt[1]
when not defined(release) and defined(stepByStep):
echoRepr stacks
echo ""
for line in moveInstructions.mapIt(it.splitWhitespace()):
when not defined(release) and defined(stepByStep):
echo line
echo ""
let howMany = parseInt line[1]
var srcStack = parseInt line[3]
srcStack.dec()
var destStack = parseInt line[5]
destStack.dec()
assert howMany <= len stacks[srcStack]
let sliceStart = stacks[srcStack].len() - howMany
let sliceEnd = stacks[srcStack].len() - 1
let movedItems = block:
when not defined(second):
reversed stacks[srcStack][sliceStart .. sliceEnd]
else:
stacks[srcStack][sliceStart .. sliceEnd]
stacks[srcStack].delete(sliceStart .. sliceEnd)
stacks[destStack] &= movedItems
when not defined(release) and defined(stepByStep):
echoRepr stacks
echo ""
echo "Press ENTER to continue."
discard stdin.readChar()
echo ""
when not defined(release):
echoRepr stacks
echo ""
let answer = join(stacks.mapIt it[high it])
echo fmt "Answer: {answer}"

35
2022/06/both.nim Normal file
View File

@ -0,0 +1,35 @@
import
std/strformat
import
../../adventofcode
let input = adventofcode.getInput()
const markerLen = block:
when not defined(second):
4
else:
14
var queue = newSeq[char](markerLen)
var answer: int
block process:
for i in 0 ..< len input:
let dup = input[i] in queue
discard queue.pop()
queue.insert(input[i], 0)
assert markerLen == len queue
if not dup and i >= markerLen:
block check:
for j in 0 ..< len queue:
for k in 0 ..< len queue:
if j == k: continue
if queue[k] == queue[j]:
break check
answer = i + 1
break process
echo fmt"Answer: {answer}"

View File

@ -1,26 +1,63 @@
#[
This file works by doing a lot of assumptions
about the project folder structure.
For instance, it assumes the executable
directory to be something in a "YYYY/DD"
format.
It also assumes the session key to be
available at the project root.
(in other words "../../session.key")
]#
import
std/httpclient,
std/os,
std/strformat,
std/strutils
when isMainModule:
stderr.writeLine "adventofcode> This can not be ran directly."
quit 1
let sessionKeyPath = os.getAppDir() / ".." / ".." / "session.key"
if not fileExists sessionKeyPath:
stderr.writeLine "adventofcode> secret.key could not be found."
let sessionKey = readFile sessionKeyPath
if sessionKey[0 ..< 10] == "\x00GITCRYPT\x00":
stderr.writeLine "adventofcode> secret.key is encrypted."
quit 1
proc getInput*(year, day: int): string =
try:
let input = readFile(getCurrentDir() / "input.txt")
## Automatically downloads the input from
## AdventOfCode, unless there is a local copy
## of the input as 'input.txt' in the app dir.
let inputPath = os.getAppDir() / "input.txt"
if fileExists inputPath:
echo "adventofcode> Proceeding with current input.txt file."
let input = readFile inputPath
return input.strip(chars = {'\n'})
except IOError:
else:
echo "adventofcode> Missing input.txt. Downloading..."
let session = os.getEnv("SESSION")
if session == "":
echo "adventofcode> Unable to download without the SESSION environment variable."
quit 1
let client = newHttpClient()
client.headers = newHttpHeaders({ "Cookie": fmt"session={session}" })
client.headers = newHttpHeaders({ "Cookie": fmt"session={sessionKey}" })
let input = client.getContent fmt"https://adventofcode.com/{year}/day/{day}/input"
writeFile(getCurrentDir() / "input.txt", input)
writeFile(inputPath, input)
return input.strip(chars = {'\n'})
return input.strip(chars = {'\n'})
proc getInput*(): string =
## Tries to determine year and date of
## day by looking at the app dir path.
let day = block:
let p = os.getAppDir().splitPath()
p.tail.parseInt()
let year = block:
let p = os.getAppDir().parentDir().splitPath()
p.tail.parseInt()
result = getInput(year, day)

BIN
session.key Normal file

Binary file not shown.