This commit is contained in:
parent
3cb6474521
commit
7e06788d8d
|
@ -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
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
session.key filter=git-crypt diff=git-crypt
|
|
@ -1,2 +1,7 @@
|
|||
# binaries
|
||||
**/first
|
||||
**/second
|
||||
**/both
|
||||
|
||||
# input files
|
||||
input.txt
|
||||
**/input.txt
|
||||
|
|
|
@ -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}"
|
|
@ -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}"
|
|
@ -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}"
|
|
@ -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}"
|
|
@ -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}"
|
||||
|
|
@ -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}"
|
|
@ -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}"
|
|
@ -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)
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue