Compare commits
No commits in common. "main" and "5e5192c9a3d7e2338ce9c6bd76801c709a505d71" have entirely different histories.
main
...
5e5192c9a3
|
@ -1,8 +0,0 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
|
||||
[*.nim]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -1,13 +1,2 @@
|
|||
# binaries
|
||||
**/first
|
||||
**/first.exe
|
||||
**/second
|
||||
**/second.exe
|
||||
**/both
|
||||
**/both.exe
|
||||
|
||||
# input files
|
||||
**/input.txt
|
||||
|
||||
# session.key
|
||||
session.key
|
||||
input.txt
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
import
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let input = adventofcode.getInput(2021, 2)
|
||||
let lines = input.splitLines()
|
||||
|
||||
var horizontalPosition = 0
|
||||
var depth = 0
|
||||
when defined(second):
|
||||
var aim = 0
|
||||
|
||||
for line in lines:
|
||||
var command = line.split(" ")
|
||||
case command[0]:
|
||||
of "forward":
|
||||
horizontalPosition += command[1].parseInt()
|
||||
when defined(second):
|
||||
depth += aim * command[1].parseInt()
|
||||
of "up":
|
||||
when defined(second):
|
||||
aim -= command[1].parseInt()
|
||||
else:
|
||||
depth -= command[1].parseInt()
|
||||
of "down":
|
||||
when defined(second):
|
||||
aim += command[1].parseInt()
|
||||
else:
|
||||
depth += command[1].parseInt()
|
||||
|
||||
echo fmt"Answer: {horizontalPosition * depth}"
|
|
@ -1,57 +0,0 @@
|
|||
import
|
||||
std/math,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils,
|
||||
std/tables
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
type
|
||||
Cycle = int
|
||||
|
||||
let input = adventofcode.getInput(2021, 6)
|
||||
|
||||
var days = 0
|
||||
var fishes: Table[Cycle, int]
|
||||
for i in 0 .. 8:
|
||||
fishes[i] = 0
|
||||
|
||||
proc parseInput() =
|
||||
let cycles = input.split(",").mapIt(it.parseInt())
|
||||
for cycle in cycles:
|
||||
fishes[cycle] += 1
|
||||
|
||||
proc newDay() =
|
||||
days += 1
|
||||
|
||||
var temporaryBox: Table[Cycle, int]
|
||||
for i in 0 .. 8:
|
||||
temporaryBox[i] = 0
|
||||
|
||||
for cycle in [8, 7, 6, 5, 4, 3, 2, 1]:
|
||||
let count = fishes[cycle]
|
||||
fishes[cycle] -= count
|
||||
temporaryBox[cycle - 1] += count
|
||||
|
||||
block cycle0:
|
||||
let count = fishes[0]
|
||||
fishes[0] -= count
|
||||
temporaryBox[6] += count
|
||||
temporaryBox[8] += count
|
||||
|
||||
for cycle in temporaryBox.keys():
|
||||
fishes[cycle] += temporaryBox[cycle]
|
||||
|
||||
when isMainModule:
|
||||
const simulateDays = block:
|
||||
when defined(second): 256
|
||||
else: 80
|
||||
|
||||
parseInput()
|
||||
for i in 1 .. simulateDays:
|
||||
newDay()
|
||||
|
||||
echo fmt"{days} days passed."
|
||||
echo fmt"Answer: {math.sum toSeq fishes.values()}"
|
|
@ -1,29 +0,0 @@
|
|||
import
|
||||
std/options,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let input = adventofcode.getInput(2021, 7)[0 .. ^2]
|
||||
#let input = "16,1,2,0,4,2,7,1,2,14" # Example given
|
||||
let crabs = input.split(",").mapIt(it.parseInt())
|
||||
let minPos = min(crabs)
|
||||
let maxPos = max(crabs)
|
||||
|
||||
var bestPosResult = none int
|
||||
var bestFuelResult = none int
|
||||
|
||||
for pos in minPos .. maxPos:
|
||||
var fuel = 0
|
||||
for crab in crabs:
|
||||
fuel += max(crab, pos) - min(crab, pos)
|
||||
|
||||
if bestFuelResult.isNone() or fuel < bestFuelResult.get():
|
||||
bestPosResult = some pos
|
||||
bestFuelResult = some fuel
|
||||
|
||||
echo fmt"Position : {bestPosResult.get()}"
|
||||
echo fmt"Fuel | Answer: {bestFuelResult.get()}"
|
|
@ -1,22 +0,0 @@
|
|||
import
|
||||
std/math,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let input = adventofcode.getInput(2021, 7)
|
||||
#let input = "16,1,2,0,4,2,7,1,2,14" # Example given
|
||||
let crabs = input.split(",").mapIt(it.parseInt())
|
||||
|
||||
let avg = (math.sum crabs) div crabs.len()
|
||||
|
||||
var fuel = 0
|
||||
for crab in crabs:
|
||||
let distance = max(crab, avg) - min(crab, avg)
|
||||
fuel += sum toSeq 1 .. distance
|
||||
|
||||
echo fmt"Position : {avg}"
|
||||
echo fmt"Fuel | Answer: {fuel}"
|
|
@ -1,26 +0,0 @@
|
|||
import
|
||||
std/math,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils,
|
||||
std/tables
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let lines = adventofcode.getInput(2021, 8).splitLines()
|
||||
var decodedDigits = newTable[int, int]()
|
||||
for i in [2, 3, 4, 7]:
|
||||
decodedDigits[i] = 0
|
||||
|
||||
for line in lines:
|
||||
let lineParts = line.split(" | ")
|
||||
|
||||
# We only consider output digits for now
|
||||
let outputDigits = lineParts[1].split(" ")
|
||||
|
||||
for outputDigit in outputDigits:
|
||||
if decodedDigits.hasKey outputDigit.len():
|
||||
decodedDigits[outputDigit.len()] += 1
|
||||
|
||||
echo fmt"Answer: {math.sum toSeq decodedDigits.values()}"
|
|
@ -1,40 +0,0 @@
|
|||
import
|
||||
std/math,
|
||||
std/options,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
type
|
||||
Grid = seq[seq[int]]
|
||||
|
||||
proc at(g: Grid; x, y: int): Option[int] =
|
||||
try: result = some g[y][x]
|
||||
except IndexDefect: discard
|
||||
|
||||
let input = adventofcode.getInput(2021, 9)
|
||||
let grid = Grid input.splitLines().mapIt(toSeq(it).mapIt(($it).parseInt()))
|
||||
|
||||
var lowPoints = newSeq[int]()
|
||||
|
||||
for y in 0 .. grid.high():
|
||||
for x in 0 .. grid[y].high():
|
||||
let p = grid.at(x, y).get()
|
||||
|
||||
let adjA = grid.at(x - 1, y)
|
||||
if adjA.isSome() and p >= adjA.get(): continue
|
||||
let adjB = grid.at(x, y - 1)
|
||||
if adjB.isSome() and p >= adjB.get(): continue
|
||||
let adjC = grid.at(x + 1, y)
|
||||
if adjC.isSome() and p >= adjC.get(): continue
|
||||
let adjD = grid.at(x, y + 1)
|
||||
if adjD.isSome() and p >= adjD.get(): continue
|
||||
|
||||
lowPoints.add p
|
||||
|
||||
var riskLevels = lowPoints.mapIt(it + 1)
|
||||
|
||||
echo fmt"Answer: {math.sum riskLevels}"
|
|
@ -1,13 +1,11 @@
|
|||
import
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
../../adventofcode,
|
||||
sequtils,
|
||||
strformat,
|
||||
strutils
|
||||
|
||||
let input = adventofcode.getInput(2021, 1)
|
||||
let lines = input.splitLines().mapIt(it.parseInt())
|
||||
let lines = input.splitLines()[0 .. ^2].mapIt(it.parseInt())
|
||||
|
||||
var depths = 0
|
||||
var prevResult = lines[0]
|
|
@ -1,13 +1,11 @@
|
|||
import
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
../../adventofcode,
|
||||
sequtils,
|
||||
strformat,
|
||||
strutils
|
||||
|
||||
let input = adventofcode.getInput(2021, 1)
|
||||
let lines = input.splitLines().mapIt(it.parseInt())
|
||||
let lines = input.splitLines()[0 .. ^2].mapIt(it.parseInt())
|
||||
|
||||
var depths = 0
|
||||
var prevSum = lines[0] + lines[1] + lines[2]
|
|
@ -1,83 +0,0 @@
|
|||
import
|
||||
std/strformat,
|
||||
std/strutils,
|
||||
std/tables
|
||||
|
||||
when defined(second):
|
||||
import std/algorithm
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let input = adventofcode.getInput(2021, 10)
|
||||
let lines = input.splitLines()
|
||||
|
||||
const chunkSymbols = (
|
||||
open: {
|
||||
'(': ')',
|
||||
'[': ']',
|
||||
'{': '}',
|
||||
'<': '>'
|
||||
}.toTable(),
|
||||
close: {
|
||||
')': '(',
|
||||
']': '[',
|
||||
'}': '{',
|
||||
'>': '<'
|
||||
}.toTable()
|
||||
)
|
||||
|
||||
when not defined(second):
|
||||
const chunkScores = {
|
||||
')': 3,
|
||||
']': 57,
|
||||
'}': 1197,
|
||||
'>': 25137
|
||||
}.toTable()
|
||||
else:
|
||||
const chunkScores = {
|
||||
')': 1,
|
||||
']': 2,
|
||||
'}': 3,
|
||||
'>': 4
|
||||
}.toTable()
|
||||
|
||||
var score = 0
|
||||
when defined(second):
|
||||
var lineScores: seq[int]
|
||||
|
||||
for line in lines:
|
||||
var chunks: seq[char]
|
||||
|
||||
block abortLine:
|
||||
for it in line:
|
||||
if chunkSymbols.open.hasKey it:
|
||||
chunks.add it
|
||||
|
||||
if chunkSymbols.close.hasKey it:
|
||||
let expectedSymbol = chunkSymbols.open[chunks[^1]]
|
||||
if it == expectedSymbol:
|
||||
discard chunks.pop()
|
||||
else:
|
||||
# Line is corrupted.
|
||||
when not defined(second):
|
||||
score += chunkScores[it]
|
||||
break abortLine
|
||||
|
||||
# Complete line by closing chunks
|
||||
when defined(second):
|
||||
var lineScore = 0
|
||||
|
||||
for idx in 0 .. chunks.high():
|
||||
let it = chunks[chunks.high() - idx]
|
||||
let closeSym = chunkSymbols.open[it]
|
||||
lineScore *= 5
|
||||
lineScore += chunkScores[closeSym]
|
||||
|
||||
lineScores.add lineScore
|
||||
|
||||
when defined(second):
|
||||
lineScores.sort()
|
||||
score = lineScores[lineScores.len() div 2]
|
||||
|
||||
echo fmt"Answer: {score}"
|
|
@ -1,67 +0,0 @@
|
|||
import
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let input = adventofcode.getInput(2021, 11)
|
||||
var grid: seq[seq[int]] = block:
|
||||
input.splitLines().mapIt(it.mapIt(parseInt $it))
|
||||
|
||||
var steps = 0
|
||||
var flashes = 0
|
||||
|
||||
proc inc(row, col: int)
|
||||
proc flash(row, col: int)
|
||||
|
||||
proc inc(row, col: int) =
|
||||
try:
|
||||
grid[row][col] += 1
|
||||
if grid[row][col] == 10:
|
||||
flash(row, col)
|
||||
except IndexDefect: return
|
||||
|
||||
proc flash(row, col: int) =
|
||||
flashes += 1
|
||||
inc(row, col - 1)
|
||||
inc(row, col + 1)
|
||||
inc(row - 1, col)
|
||||
inc(row + 1, col)
|
||||
inc(row - 1, col - 1)
|
||||
inc(row + 1, col + 1)
|
||||
inc(row - 1, col + 1)
|
||||
inc(row + 1, col - 1)
|
||||
|
||||
proc resetFlashes() =
|
||||
for row in 0 .. grid.high():
|
||||
for col in 0 .. grid[row].high():
|
||||
if grid[row][col] > 9:
|
||||
grid[row][col] = 0
|
||||
|
||||
when defined(second):
|
||||
proc areTheyAllFlashing(): bool =
|
||||
result = true
|
||||
for row in 0 .. grid.high():
|
||||
for col in 0 .. grid[row].high():
|
||||
if grid[row][col] != 0:
|
||||
return false
|
||||
|
||||
proc forwardStep() =
|
||||
steps += 1
|
||||
for row in 0 .. grid.high():
|
||||
for col in 0 .. grid[row].high():
|
||||
inc(row, col)
|
||||
resetFlashes()
|
||||
|
||||
when not defined(second):
|
||||
while steps < 100:
|
||||
forwardStep()
|
||||
|
||||
echo fmt"Answer: {flashes}"
|
||||
else:
|
||||
while not areTheyAllFlashing():
|
||||
forwardStep()
|
||||
|
||||
echo fmt"Answer: {steps}"
|
|
@ -0,0 +1,22 @@
|
|||
import
|
||||
../../adventofcode,
|
||||
strutils,
|
||||
strformat
|
||||
|
||||
let input = adventofcode.getInput(2021, 2)
|
||||
let lines = input.splitLines()[0 .. ^2]
|
||||
|
||||
var horizontalPosition = 0
|
||||
var depth = 0
|
||||
|
||||
for line in lines:
|
||||
var command = line.split(" ")
|
||||
case command[0]:
|
||||
of "forward":
|
||||
horizontalPosition += command[1].parseInt()
|
||||
of "up":
|
||||
depth -= command[1].parseInt()
|
||||
of "down":
|
||||
depth += command[1].parseInt()
|
||||
|
||||
echo fmt"Answer: {horizontalPosition * depth}"
|
|
@ -0,0 +1,24 @@
|
|||
import
|
||||
../../adventofcode,
|
||||
strutils,
|
||||
strformat
|
||||
|
||||
let input = adventofcode.getInput(2021, 2)
|
||||
let lines = input.splitLines()[0 .. ^2]
|
||||
|
||||
var horizontalPosition = 0
|
||||
var depth = 0
|
||||
var aim = 0
|
||||
|
||||
for line in lines:
|
||||
var command = line.split(" ")
|
||||
case command[0]:
|
||||
of "forward":
|
||||
horizontalPosition += command[1].parseInt()
|
||||
depth += aim * command[1].parseInt()
|
||||
of "up":
|
||||
aim -= command[1].parseInt()
|
||||
of "down":
|
||||
aim += command[1].parseInt()
|
||||
|
||||
echo fmt"Answer: {horizontalPosition * depth}"
|
|
@ -1,13 +1,11 @@
|
|||
import
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
../../adventofcode,
|
||||
sequtils,
|
||||
strutils,
|
||||
strformat
|
||||
|
||||
let input = adventofcode.getInput(2021, 3)
|
||||
let lines = input.splitLines()
|
||||
let lines = input.splitLines()[0 .. ^2]
|
||||
|
||||
var gammaRateBinary = ""
|
||||
var epsilonRateBinary = ""
|
|
@ -1,13 +1,11 @@
|
|||
import
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
../../adventofcode,
|
||||
sequtils,
|
||||
strutils,
|
||||
strformat
|
||||
|
||||
let input = adventofcode.getInput(2021, 3)
|
||||
let lines = input.splitLines()
|
||||
let lines = input.splitLines()[0 .. ^2]
|
||||
|
||||
var oxygenGenRateValues = lines
|
||||
var co2ScrubberRateValues = lines
|
|
@ -1,15 +1,15 @@
|
|||
import
|
||||
std/math,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode,
|
||||
./x/board
|
||||
math,
|
||||
sequtils,
|
||||
strutils,
|
||||
strformat
|
||||
|
||||
import
|
||||
x/board
|
||||
|
||||
let input = adventofcode.getInput(2021, 4)
|
||||
let lines = input.splitLines()
|
||||
let lines = input.splitLines()[0 .. ^2]
|
||||
|
||||
let drawn = lines[0].split(",").mapIt(it.parseInt())
|
||||
var currentlyDrawn: seq[int] = @[]
|
|
@ -1,15 +1,15 @@
|
|||
import
|
||||
std/math,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode,
|
||||
./x/board
|
||||
math,
|
||||
sequtils,
|
||||
strutils,
|
||||
strformat
|
||||
|
||||
import
|
||||
x/board
|
||||
|
||||
let input = adventofcode.getInput(2021, 4)
|
||||
let lines = input.splitLines()
|
||||
let lines = input.splitLines()[0 .. ^2]
|
||||
|
||||
let drawn = lines[0].split(",").mapIt(it.parseInt())
|
||||
var currentlyDrawn: seq[int] = @[]
|
|
@ -1,18 +1,16 @@
|
|||
import
|
||||
std/hashes,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils,
|
||||
std/tables
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
../../adventofcode,
|
||||
hashes,
|
||||
sequtils,
|
||||
strutils,
|
||||
strformat,
|
||||
tables
|
||||
|
||||
type
|
||||
Grid = TableRef[Point, int]
|
||||
|
||||
HydrothermalVent = object
|
||||
x1, y1, x2, y2: int
|
||||
x1, x2, y1, y2: int
|
||||
|
||||
Point = object
|
||||
x, y: int
|
||||
|
@ -24,10 +22,10 @@ B = b >= 0 ? 2 * b : -2 * b - 1;
|
|||
A >= B ? A * A + A + B : A + B * B;
|
||||
]#
|
||||
proc hash(p: Point): Hash =
|
||||
let A = block:
|
||||
let A =
|
||||
if p.x >= 0: 2 * p.x
|
||||
else: -2 * p.x - 1
|
||||
let B = block:
|
||||
let B =
|
||||
if p.y >= 0: 2 * p.y
|
||||
else: -2 * p.y - 1
|
||||
return
|
||||
|
@ -35,10 +33,11 @@ proc hash(p: Point): Hash =
|
|||
else: A + B * B
|
||||
|
||||
proc getPoints(v: HydrothermalVent): seq[Point] =
|
||||
let xOffset = v.x2 - v.x1
|
||||
let yOffset = v.y2 - v.y1
|
||||
let xd = xOffset.abs()
|
||||
let yd = yOffset.abs()
|
||||
let xd = max(v.x1, v.x2) - min(v.x1, v.x2)
|
||||
let yd = max(v.y1, v.y2) - min(v.y1, v.y2)
|
||||
when defined(second):
|
||||
let xoffset = v.x2 - v.x1
|
||||
let yoffset = v.y2 - v.y1
|
||||
|
||||
if xd != 0 and v.y1 == v.y2:
|
||||
for i in 0 .. xd:
|
||||
|
@ -50,25 +49,33 @@ proc getPoints(v: HydrothermalVent): seq[Point] =
|
|||
|
||||
else:
|
||||
when defined(second):
|
||||
assert xd == yd
|
||||
|
||||
for i in 0 .. xd:
|
||||
result.add Point(
|
||||
x:
|
||||
if xOffset > 0: min(v.x1, v.x2) + i
|
||||
else: max(v.x1, v.x2) - i,
|
||||
y:
|
||||
if yOffset > 0: min(v.y1, v.y2) + i
|
||||
else: max(v.y1, v.y2) - i
|
||||
)
|
||||
# TODO:
|
||||
if xoffset < 0:
|
||||
for i in 0 .. xd:
|
||||
result.add Point(
|
||||
x: min(v.x1, v.x2) + i,
|
||||
y: max(v.y1, v.y2) - i
|
||||
)
|
||||
|
||||
else:
|
||||
for i in 0 .. yd:
|
||||
result.add Point(
|
||||
x: max(v.x1, v.x2) + i,
|
||||
y: min(v.y1, v.y2) + i
|
||||
)
|
||||
|
||||
proc parseInput(input: string): seq[HydrothermalVent] =
|
||||
for line in input.splitLines():
|
||||
for line in input.splitLines()[0 .. ^2]:
|
||||
let coords = line.split(" -> ").mapIt(it.split(",").mapIt(it.parseInt()))
|
||||
result.add HydrothermalVent(
|
||||
x1: coords[0][0], y1: coords[0][1], x2: coords[1][0], y2: coords[1][1]
|
||||
)
|
||||
|
||||
static:
|
||||
let dummyVent = HydrothermalVent(x1: 9, y1: 7, x2: 7, y2: 9)
|
||||
for point in dummyVent.getPoints():
|
||||
echo $point
|
||||
|
||||
let input = adventofcode.getInput(2021, 5)
|
||||
let vents = input.parseInput()
|
||||
let grid = Grid()
|
|
@ -1,38 +0,0 @@
|
|||
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}"
|
|
@ -1,43 +0,0 @@
|
|||
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}"
|
|
@ -1,60 +0,0 @@
|
|||
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}"
|
|
@ -1,50 +0,0 @@
|
|||
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}"
|
|
@ -1,41 +0,0 @@
|
|||
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}"
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
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}"
|
|
@ -1,35 +0,0 @@
|
|||
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}"
|
105
2022/07/both.nim
105
2022/07/both.nim
|
@ -1,105 +0,0 @@
|
|||
import
|
||||
std/strutils,
|
||||
std/strformat,
|
||||
std/tables
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
proc `/`(base, tail: string): string =
|
||||
if tail == "..":
|
||||
let sep = base.rfind('/')
|
||||
if sep > 0: return base[0 ..< sep]
|
||||
else: return "/"
|
||||
else:
|
||||
if base[^1] == '/':
|
||||
return base & tail
|
||||
else:
|
||||
return base & "/" & tail
|
||||
|
||||
type
|
||||
PseudoFileKind = enum
|
||||
pfFile, pfDir
|
||||
PseudoFile = ref object
|
||||
case kind: PseudoFileKind
|
||||
of pfFile:
|
||||
size: Natural
|
||||
of pfDir:
|
||||
fileNames: seq[string]
|
||||
proc newPseudoFile(size: Natural = 0): PseudoFile =
|
||||
result = PseudoFile(kind: pfFile, size: size)
|
||||
proc newPseudoDir(): PseudoFile =
|
||||
result = PseudoFile(kind: pfDir)
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
var files = initTable[string, PseudoFile]()
|
||||
var dirSizes = initTable[string, Natural]()
|
||||
var cwd = "/"
|
||||
var cwdObj = newPseudoDir()
|
||||
files["/"] = cwdObj
|
||||
|
||||
proc computeSize(path: string): Natural =
|
||||
if not files.hasKey path: return
|
||||
let file = files[path]
|
||||
case file.kind
|
||||
of pfFile: return file.size
|
||||
of pfDir:
|
||||
if dirSizes.hasKey path:
|
||||
return dirSizes[path]
|
||||
for name in file.fileNames:
|
||||
result += computeSize(path / name)
|
||||
dirSizes[path] = result
|
||||
|
||||
for line in input.splitLines:
|
||||
let args = line.splitWhitespace()
|
||||
if args[0] == "$":
|
||||
if args[1] == "cd":
|
||||
if args[2][0] == '/':
|
||||
cwd = args[2]
|
||||
else:
|
||||
cwd = cwd / args[2]
|
||||
when not defined(release):
|
||||
echo fmt"{cwd = }"
|
||||
|
||||
if files.hasKey cwd:
|
||||
cwdObj = files[cwd]
|
||||
else:
|
||||
cwdObj = newPseudoDir()
|
||||
files[cwd] = cwdObj
|
||||
else:
|
||||
if args[1] notin cwdObj.fileNames:
|
||||
cwdObj.fileNames.add args[1]
|
||||
if args[0] == "dir":
|
||||
let dir = newPseudoDir()
|
||||
files[cwd / args[1]] = dir
|
||||
else:
|
||||
let file = newPseudoFile(size=parseInt args[0])
|
||||
files[cwd / args[1]] = file
|
||||
|
||||
when not defined(second):
|
||||
var sum = 0
|
||||
|
||||
discard computeSize "/"
|
||||
for path, dirSize in dirSizes:
|
||||
if dirSize < 100_000:
|
||||
sum += dirSize
|
||||
|
||||
echo fmt"Answer: {sum}"
|
||||
else:
|
||||
import
|
||||
std/algorithm,
|
||||
std/sequtils
|
||||
|
||||
const maxFsSize = 70_000_000
|
||||
const updateSize = 30_000_000
|
||||
|
||||
let currFsSize = computeSize "/"
|
||||
let requiredSize = currFsSize - (maxFsSize - updateSize)
|
||||
when not defined(release):
|
||||
echo fmt"{requiredSize = }"
|
||||
|
||||
let dirSizesSeq = sorted toSeq dirSizes.values()
|
||||
for size in dirSizesSeq:
|
||||
if size > requiredSize:
|
||||
echo fmt"Answer: {size}"
|
||||
break
|
|
@ -1,65 +0,0 @@
|
|||
import
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
type
|
||||
Map = seq[seq[int]]
|
||||
proc `[]`(m: Map; x, y: Natural): int =
|
||||
result = m[y][x]
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
var map: seq[seq[int]] = @[]
|
||||
|
||||
let lines = input.splitLines()
|
||||
for y in 0 ..< lines.len():
|
||||
map.add(@[])
|
||||
for x in 0 ..< lines[y].len():
|
||||
map[y].add parseInt($lines[y][x])
|
||||
|
||||
var visibleTrees = 0
|
||||
|
||||
for y in 0 ..< map.len():
|
||||
for x in 0 ..< map[y].len():
|
||||
if (x == 0) or (y == 0) or (x == map[y].high()) or (y == map.high()):
|
||||
visibleTrees.inc()
|
||||
continue
|
||||
|
||||
let height = map[x, y]
|
||||
block check:
|
||||
|
||||
block left:
|
||||
for x2 in countdown(x - 1, 0):
|
||||
let h = map[x2, y]
|
||||
if h >= height:
|
||||
break left
|
||||
visibleTrees.inc()
|
||||
break check
|
||||
|
||||
block right:
|
||||
for x3 in countup(x + 1, high map[y]):
|
||||
let h = map[x3, y]
|
||||
if h >= height:
|
||||
break right
|
||||
visibleTrees.inc()
|
||||
break check
|
||||
|
||||
block top:
|
||||
for y2 in countdown(y - 1, 0):
|
||||
let h = map[x, y2]
|
||||
if h >= height:
|
||||
break top
|
||||
visibleTrees.inc()
|
||||
break check
|
||||
|
||||
block bottom:
|
||||
for y3 in countup(y + 1, high map):
|
||||
let h = map[x, y3]
|
||||
if h >= height:
|
||||
break bottom
|
||||
visibleTrees.inc()
|
||||
break check
|
||||
|
||||
echo fmt"Answer: {visibleTrees}"
|
|
@ -1,63 +0,0 @@
|
|||
import
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
type
|
||||
Map = seq[seq[int]]
|
||||
proc `[]`(m: Map; x, y: Natural): int =
|
||||
result = m[y][x]
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
var map: seq[seq[int]] = @[]
|
||||
|
||||
let lines = input.splitLines()
|
||||
for y in 0 ..< lines.len():
|
||||
map.add(@[])
|
||||
for x in 0 ..< lines[y].len():
|
||||
map[y].add parseInt($lines[y][x])
|
||||
|
||||
var highestScore: int = 0
|
||||
|
||||
for y in 0 ..< map.len():
|
||||
for x in 0 ..< map[y].len():
|
||||
if (x == 0) or (y == 0) or (x == map[y].high()) or (y == map.high()):
|
||||
continue
|
||||
|
||||
let height = map[x, y]
|
||||
|
||||
var leftScore = 0
|
||||
for x2 in countdown(x - 1, 0):
|
||||
let h = map[x2, y]
|
||||
leftScore.inc()
|
||||
if h >= height:
|
||||
break
|
||||
|
||||
var rightScore = 0
|
||||
for x3 in countup(x + 1, high map[y]):
|
||||
let h = map[x3, y]
|
||||
rightScore.inc()
|
||||
if h >= height:
|
||||
break
|
||||
|
||||
var topScore = 0
|
||||
for y2 in countdown(y - 1, 0):
|
||||
let h = map[x, y2]
|
||||
topScore.inc()
|
||||
if h >= height:
|
||||
break
|
||||
|
||||
var bottomScore = 0
|
||||
for y3 in countup(y + 1, high map):
|
||||
let h = map[x, y3]
|
||||
bottomScore.inc()
|
||||
if h >= height:
|
||||
break
|
||||
|
||||
var score = leftScore * rightScore * topScore * bottomScore
|
||||
if score > highestScore:
|
||||
highestScore = score
|
||||
|
||||
echo fmt"Answer: {highestScore}"
|
|
@ -1,49 +0,0 @@
|
|||
import
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
type
|
||||
Position = tuple[x, y: int]
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
|
||||
var knots: seq[Position] = @[]
|
||||
const knotCount =
|
||||
when not defined(second): 2
|
||||
else: 10
|
||||
for i in 0 ..< knotCount:
|
||||
knots.add (0, 0)
|
||||
|
||||
var visitedByLastKnot: seq[Position] = @[(0, 0)]
|
||||
|
||||
for line in input.splitLines():
|
||||
let direction = line[0]
|
||||
let moves = parseInt line[2 .. ^1]
|
||||
for i in 0 ..< moves:
|
||||
case direction
|
||||
of 'L': knots[0].x -= 1
|
||||
of 'R': knots[0].x += 1
|
||||
of 'U': knots[0].y -= 1
|
||||
of 'D': knots[0].y += 1
|
||||
else: discard
|
||||
|
||||
for i in 1 ..< len knots:
|
||||
let dx = knots[i - 1].x - knots[i].x
|
||||
let dy = knots[i - 1].y - knots[i].y
|
||||
let tension = abs(dx) > 1 or abs(dy) > 1
|
||||
if tension:
|
||||
if abs(dx) > 0:
|
||||
let moveKnotX = if dx > 0: 1 else: -1
|
||||
knots[i].x += moveKnotX
|
||||
if abs(dy) > 0:
|
||||
let moveKnotY = if dy > 0: 1 else: -1
|
||||
knots[i].y += moveKnotY
|
||||
|
||||
if i == high knots:
|
||||
if knots[i] notin visitedByLastKnot:
|
||||
visitedByLastKnot.add knots[i]
|
||||
|
||||
echo fmt"Answer: {len visitedByLastKnot}"
|
|
@ -1,36 +0,0 @@
|
|||
import
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
type
|
||||
Position = tuple[x, y: int]
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
|
||||
var lastHead: Position = (0, 0)
|
||||
var head: Position = (0, 0)
|
||||
var tail: Position = (0, 0)
|
||||
var visited: seq[Position] = @[(0, 0)]
|
||||
|
||||
for line in input.splitLines():
|
||||
let direction = line[0]
|
||||
let moves = parseInt line[2 .. ^1]
|
||||
for i in 0 ..< moves:
|
||||
lastHead = head
|
||||
case direction
|
||||
of 'L': head.x -= 1
|
||||
of 'R': head.x += 1
|
||||
of 'U': head.y -= 1
|
||||
of 'D': head.y += 1
|
||||
else: discard
|
||||
|
||||
var tension = abs(head.x - tail.x) > 1 or abs(head.y - tail.y) > 1
|
||||
if tension:
|
||||
tail = lastHead
|
||||
if tail notin visited:
|
||||
visited.add tail
|
||||
|
||||
echo fmt"Answer: {len visited}"
|
|
@ -1,77 +0,0 @@
|
|||
import
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
when not defined(second):
|
||||
import
|
||||
std/strformat
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
let instructions = input.splitLines()
|
||||
|
||||
var registerX = 1
|
||||
var currOpIdx = 0
|
||||
var currOp = ""
|
||||
var currOpArg = 0
|
||||
var sameOpN = 0
|
||||
proc endOp() =
|
||||
reset currOp
|
||||
reset currOpArg
|
||||
reset sameOpN
|
||||
currOpIdx.inc()
|
||||
|
||||
when not defined(second):
|
||||
const rangeEnd = 220
|
||||
var answer = 0
|
||||
else:
|
||||
const rangeEnd = high(int)
|
||||
var crtOutput = ""
|
||||
|
||||
for n in 1 .. rangeEnd:
|
||||
when not defined(second):
|
||||
if (n + 20) mod 40 == 0:
|
||||
when not defined(release):
|
||||
echo fmt"{ n = }, { registerX = }"
|
||||
answer += n * registerX
|
||||
else:
|
||||
# Because the cycle count `n` starts at 1
|
||||
let a = n - 1
|
||||
|
||||
# Only generate a 40x6 image
|
||||
if a < 40 * 6:
|
||||
if a mod 40 == 0:
|
||||
crtOutput.add '\n'
|
||||
|
||||
if a mod 40 in registerX - 1 .. registerX + 1:
|
||||
crtOutput.add '#'
|
||||
else:
|
||||
crtOutput.add '.'
|
||||
|
||||
if currOp == "":
|
||||
if currOpIdx > high instructions:
|
||||
break
|
||||
let opArgs = splitWhitespace instructions[currOpIdx]
|
||||
currOp = opArgs[0]
|
||||
if opArgs.len() == 2:
|
||||
currOpArg = parseInt opArgs[1]
|
||||
|
||||
case currOp
|
||||
of "addx":
|
||||
if sameOpN == 1:
|
||||
registerX += currOpArg
|
||||
endOp()
|
||||
of "noop":
|
||||
endOp()
|
||||
else:
|
||||
discard
|
||||
|
||||
if currOp != "":
|
||||
sameOpN.inc()
|
||||
|
||||
|
||||
when not defined(second):
|
||||
echo fmt"Answer: {answer}"
|
||||
else:
|
||||
echo crtOutput
|
|
@ -1,39 +0,0 @@
|
|||
import
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
var sum = 0
|
||||
|
||||
for line in input.splitLines():
|
||||
var digitsInLine: seq[char] = @[]
|
||||
for i in 0 .. line.high:
|
||||
if line[i].isDigit():
|
||||
digitsInLine.add line[i]
|
||||
when defined(second):
|
||||
# We can't use multiReplace() as numbers can overlap
|
||||
# e.g.: eighthree, twone, ...
|
||||
proc matches(pattern: string): bool =
|
||||
if i + pattern.high <= line.high:
|
||||
return line[i .. i + pattern.high] == pattern
|
||||
for (a, b) in [
|
||||
("one", '1'),
|
||||
("two", '2'),
|
||||
("three", '3'),
|
||||
("four", '4'),
|
||||
("five", '5'),
|
||||
("six", '6'),
|
||||
("seven", '7'),
|
||||
("eight", '8'),
|
||||
("nine", '9'),
|
||||
]:
|
||||
if matches a:
|
||||
digitsInLine.add b
|
||||
|
||||
# Take the first and the last digits of the current line
|
||||
sum += parseInt(digitsInLine[0] & digitsInLine[^1])
|
||||
|
||||
echo fmt"Answer: {sum}"
|
|
@ -1,39 +0,0 @@
|
|||
import
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
const maxRedCubes = 12
|
||||
const maxGreenCubes = 13
|
||||
const maxBlueCubes = 14
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
var sum = 0
|
||||
|
||||
for line in input.splitLines():
|
||||
let colonIdx = line.find(':')
|
||||
let gameID = parseInt line[len("Game ") ..< colonIdx]
|
||||
let gameSets = line[colonIdx + 2 .. ^1].split("; ")
|
||||
block verifyGameSet:
|
||||
for gameSet in gameSets:
|
||||
for cubeTypeAndCount in gameSet.split(", "):
|
||||
let cubeCountAndTypeSplit = cubeTypeAndCount.split(' ')
|
||||
let cubeCount = parseInt cubeCountAndTypeSplit[0]
|
||||
let cubeType = cubeCountAndTypeSplit[1]
|
||||
case cubeType:
|
||||
of "red":
|
||||
if cubeCount > maxRedCubes:
|
||||
break verifyGameSet
|
||||
of "green":
|
||||
if cubeCount > maxGreenCubes:
|
||||
break verifyGameSet
|
||||
of "blue":
|
||||
if cubeCount > maxBlueCubes:
|
||||
break verifyGameSet
|
||||
else:
|
||||
discard
|
||||
sum += gameID
|
||||
|
||||
echo fmt"Answer: {sum}"
|
|
@ -1,44 +0,0 @@
|
|||
import
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
var sum = 0
|
||||
|
||||
var schematic: seq[seq[char]] = input.splitLines().mapIt(toSeq it)
|
||||
|
||||
for y in 0 .. schematic.high():
|
||||
var numStr = ""
|
||||
for x in 0 .. schematic[y].high():
|
||||
block wholeChara:
|
||||
let chara = schematic[y][x]
|
||||
if not chara.isDigit():
|
||||
numStr.reset()
|
||||
continue
|
||||
numStr &= chara
|
||||
|
||||
if x == schematic[y].high() or not schematic[y][x + 1].isDigit():
|
||||
# x = end index
|
||||
var adjacentPositions: seq[(int, int)] = @[]
|
||||
for i in 0 .. numStr.high():
|
||||
# up, down
|
||||
adjacentPositions.add (x - numStr.high() + i, y - 1)
|
||||
adjacentPositions.add (x - numStr.high() + i, y + 1)
|
||||
for dy in -1 .. 1:
|
||||
# left, right
|
||||
adjacentPositions.add (x - numStr.high() - 1, y + dy)
|
||||
adjacentPositions.add (x + 1, y + dy)
|
||||
|
||||
for pos in adjacentPositions:
|
||||
if pos[0] < 0 or pos[0] > schematic[y].high(): continue
|
||||
if pos[1] < 0 or pos[1] > schematic.high(): continue
|
||||
let charaToCheck = schematic[pos[1]][pos[0]]
|
||||
if not charaToCheck.isDigit() and charaToCheck != '.':
|
||||
sum += numStr.parseInt()
|
||||
break wholeChara
|
||||
|
||||
echo fmt"Answer: {sum}"
|
|
@ -1,54 +0,0 @@
|
|||
import
|
||||
std/math,
|
||||
std/sequtils,
|
||||
std/strformat,
|
||||
std/strutils
|
||||
|
||||
import
|
||||
../../adventofcode
|
||||
|
||||
let input = adventofcode.getInput()
|
||||
|
||||
when not defined(second):
|
||||
var points = 0
|
||||
else:
|
||||
var additionalCards: seq[Natural] = @[]
|
||||
|
||||
let lines = input.splitLines()
|
||||
for i in 0 .. lines.high():
|
||||
let line = lines[i]
|
||||
when defined(second):
|
||||
if additionalCards.high() < i:
|
||||
additionalCards.add 0
|
||||
let instances = 1 + additionalCards[i]
|
||||
let winningNumsStart = line.find(':') + 1
|
||||
let winningNumsEnd = line.find('|')
|
||||
let winningNums = line[winningNumsStart ..< winningNumsEnd]
|
||||
.split(' ')
|
||||
.filterIt(it != "")
|
||||
.mapIt(parseInt it)
|
||||
let elfNums = line[winningNumsEnd + 1 .. ^1]
|
||||
.split(' ')
|
||||
.filterIt(it != "")
|
||||
.mapIt(parseInt it)
|
||||
|
||||
var duplicata = 0
|
||||
for n in elfNums:
|
||||
if n in winningNums:
|
||||
duplicata.inc()
|
||||
|
||||
when not defined(second):
|
||||
if duplicata > 0:
|
||||
points += 2 ^ (duplicata - 1)
|
||||
else:
|
||||
for j in 1 .. duplicata:
|
||||
if additionalCards.high() < i + j:
|
||||
additionalCards.add 0
|
||||
additionalCards[i + j] += instances
|
||||
|
||||
when not defined(second):
|
||||
echo fmt"Answer: {points}"
|
||||
else:
|
||||
var originalCardCount = len(lines)
|
||||
var additionalCardSum = sum(additionalCards)
|
||||
echo fmt"Answer: {originalCardCount + additionalCardSum}"
|
|
@ -1,63 +1,24 @@
|
|||
#[
|
||||
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
|
||||
httpclient,
|
||||
os,
|
||||
strformat
|
||||
|
||||
proc getInput*(year, day: int): string =
|
||||
## 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'})
|
||||
else:
|
||||
echo "adventofcode> Missing input.txt. Downloading..."
|
||||
let session = os.getEnv("SESSION")
|
||||
if session == "":
|
||||
echo "Missing SESSION environment variable."
|
||||
quit 1
|
||||
|
||||
proc getInput*(year, day: int): string =
|
||||
try:
|
||||
let input = readFile(getCurrentDir() / "input.txt")
|
||||
|
||||
return input
|
||||
except IOError:
|
||||
let client = newHttpClient()
|
||||
client.headers = newHttpHeaders({ "Cookie": fmt"session={sessionKey}" })
|
||||
client.headers = newHttpHeaders({ "Cookie": fmt"session={session}" })
|
||||
|
||||
let input = client.getContent fmt"https://adventofcode.com/{year}/day/{day}/input"
|
||||
|
||||
writeFile(inputPath, input)
|
||||
writeFile(getCurrentDir() / "input.txt", input)
|
||||
|
||||
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)
|
||||
return input
|
21
license.txt
21
license.txt
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Danny Harpigny
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1 +0,0 @@
|
|||
Rename this file to `session.key` and put your session key in it.
|
Loading…
Reference in New Issue