Be concise for no reason
This commit is contained in:
parent
f1f5b2f57c
commit
7419eccd05
5 changed files with 33 additions and 51 deletions
|
@ -1,29 +1,19 @@
|
|||
import sets, streams, strutils, input_helpers
|
||||
import sets, streams, input_helpers, sequtils, options
|
||||
|
||||
# Day 1
|
||||
let targetSum = 2020
|
||||
|
||||
let day1TargetSum = 2020
|
||||
proc findComplement(nums: seq[int], complement = targetSum): Option[(int, int)] =
|
||||
var targets = initHashSet[int]()
|
||||
for n in nums:
|
||||
if targets.contains(complement - n): return some(((complement - n), n))
|
||||
else: targets.incl n
|
||||
|
||||
proc part1*(s: Stream): int =
|
||||
var targets = initHashSet[int]()
|
||||
for n in asInts(s):
|
||||
if targets.contains(day1TargetSum - n):
|
||||
return (day1TargetSum - n) * n
|
||||
else:
|
||||
targets.incl n
|
||||
let (n1, n2) = findComplement(toSeq(asInts(s))).get; n1 * n2
|
||||
|
||||
proc part2*(strm: Stream): 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
|
||||
proc part2*(s: Stream): int =
|
||||
let nums = toSeq(asInts(s))
|
||||
for n in nums:
|
||||
var iset = initHashSet[int]()
|
||||
let nTargetSum = day1TargetSum - n
|
||||
for n2 in nums:
|
||||
if iset.contains(nTargetSum - n2):
|
||||
return n * n2 * (nTargetSum - n2)
|
||||
iset.incl n2
|
||||
let comp = findComplement(nums, targetSum - n)
|
||||
if comp.isSome:
|
||||
let (n1, n2) = comp.get; return n * n1 * n2
|
||||
|
|
|
@ -2,6 +2,15 @@ import streams, strutils, re
|
|||
|
||||
type PasswordPolicy = tuple[min: int, max: int, keyChar: char]
|
||||
|
||||
let parsePasswordLineRe = re"^(\d+)-(\d+) (.): (.*)$"
|
||||
proc parsePasswordLine(str: string): (PasswordPolicy, string) =
|
||||
var matches: array[4, string]
|
||||
if match(str, parsePasswordLineRe, matches):
|
||||
return ((min: parseInt(matches[0]), max: parseInt(matches[1]), keyChar: matches[2][0]), matches[3])
|
||||
|
||||
iterator asPasswordPolicies(s: Stream): (PasswordPolicy, string) =
|
||||
for line in s.lines(): yield parsePasswordLine line
|
||||
|
||||
proc isValidPassword(str: string, pp: PasswordPolicy): bool =
|
||||
let count = str.count pp.keyChar
|
||||
(pp.min <= count) and (count <= pp.max)
|
||||
|
@ -9,22 +18,10 @@ proc isValidPassword(str: string, pp: PasswordPolicy): bool =
|
|||
proc isValidPasswordPart2(str: string, pp: PasswordPolicy): bool =
|
||||
(str[pp.min - 1] == pp.keyChar) xor (pp.keyChar == str[pp.max - 1])
|
||||
|
||||
let parsePasswordPolicyRe = re"^(\d+)-(\d+) (.): (.*)$"
|
||||
proc parsePasswordPolicy(str: string): (PasswordPolicy, string) =
|
||||
var matches: array[4, string]
|
||||
if match(str, parsePasswordPolicyRe, matches):
|
||||
return ((min: parseInt(matches[0]), max: parseInt(matches[1]), keyChar: matches[2][0]), matches[3])
|
||||
|
||||
iterator asPasswordPolicies(s: Stream): (PasswordPolicy, string) =
|
||||
for line in s.lines():
|
||||
yield parsePasswordPolicy line
|
||||
|
||||
proc part1*(s: Stream): int =
|
||||
for (pp, pw) in asPasswordPolicies(s):
|
||||
if isValidPassword(pw, pp):
|
||||
result += 1
|
||||
for (pp, pw) in s.asPasswordPolicies:
|
||||
if isValidPassword(pw, pp): inc result
|
||||
|
||||
proc part2*(s: Stream): int =
|
||||
for (pp, pw) in asPasswordPolicies(s):
|
||||
if isValidPasswordPart2(pw, pp):
|
||||
result += 1
|
||||
for (pp, pw) in s.asPasswordPolicies:
|
||||
if isValidPasswordPart2(pw, pp): inc result
|
||||
|
|
|
@ -3,15 +3,12 @@ import streams
|
|||
proc sled(s: Stream, velx: int, vely: int): int =
|
||||
var xpos, ypos: int
|
||||
for line in s.lines():
|
||||
ypos += 1
|
||||
if (ypos - 1) mod vely > 0:
|
||||
continue
|
||||
if line[xpos mod line.len()] == '#':
|
||||
result += 1
|
||||
inc ypos
|
||||
if (ypos - 1) mod vely > 0: continue
|
||||
if line[xpos mod line.len()] == '#': inc result
|
||||
xpos += velx
|
||||
|
||||
proc part1*(s: Stream): int =
|
||||
sled(s, 3, 1)
|
||||
proc part1*(s: Stream): int = sled(s, 3, 1)
|
||||
|
||||
proc part2*(s: Stream): int =
|
||||
result = part1(s)
|
||||
|
|
|
@ -10,7 +10,7 @@ macro loadDays(): untyped =
|
|||
# TODO: do I "need" to close these streams?
|
||||
solver_str = solver_str & &"""
|
||||
{day}: proc(): tuple[part1: int, part2: int] =
|
||||
echo "Day {day}"
|
||||
stdout.write "Day {day}: "
|
||||
(
|
||||
{module}.part1(getInputFileStreamForDay({day})),
|
||||
{module}.part2(getInputFileStreamForDay({day}))
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import streams, strutils, sugar
|
||||
|
||||
iterator mapStream*[T](s: Stream, cb: (string) -> T): T =
|
||||
for line in s.lines():
|
||||
yield cb line
|
||||
for line in s.lines(): yield cb line
|
||||
|
||||
iterator asInts*(s: Stream): int =
|
||||
for i in mapStream[int](s, parseInt):
|
||||
yield i
|
||||
for i in mapStream[int](s, parseInt): yield i
|
||||
|
|
Loading…
Reference in a new issue