Be concise for no reason

This commit is contained in:
Daniel Flanagan 2020-12-03 11:42:18 -06:00
parent f1f5b2f57c
commit 7419eccd05
Signed by: lytedev
GPG key ID: 5B2020A0F9921EF4
5 changed files with 33 additions and 51 deletions

View file

@ -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 = proc part1*(s: Stream): int =
var targets = initHashSet[int]() let (n1, n2) = findComplement(toSeq(asInts(s))).get; n1 * n2
for n in asInts(s):
if targets.contains(day1TargetSum - n):
return (day1TargetSum - n) * n
else:
targets.incl n
proc part2*(strm: Stream): int = proc part2*(s: Stream): int =
# this works exactly the same as the previous algorithm, except we simply let nums = toSeq(asInts(s))
# 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
for n in nums: for n in nums:
var iset = initHashSet[int]() let comp = findComplement(nums, targetSum - n)
let nTargetSum = day1TargetSum - n if comp.isSome:
for n2 in nums: let (n1, n2) = comp.get; return n * n1 * n2
if iset.contains(nTargetSum - n2):
return n * n2 * (nTargetSum - n2)
iset.incl n2

View file

@ -2,6 +2,15 @@ import streams, strutils, re
type PasswordPolicy = tuple[min: int, max: int, keyChar: char] 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 = proc isValidPassword(str: string, pp: PasswordPolicy): bool =
let count = str.count pp.keyChar let count = str.count pp.keyChar
(pp.min <= count) and (count <= pp.max) (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 = proc isValidPasswordPart2(str: string, pp: PasswordPolicy): bool =
(str[pp.min - 1] == pp.keyChar) xor (pp.keyChar == str[pp.max - 1]) (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 = proc part1*(s: Stream): int =
for (pp, pw) in asPasswordPolicies(s): for (pp, pw) in s.asPasswordPolicies:
if isValidPassword(pw, pp): if isValidPassword(pw, pp): inc result
result += 1
proc part2*(s: Stream): int = proc part2*(s: Stream): int =
for (pp, pw) in asPasswordPolicies(s): for (pp, pw) in s.asPasswordPolicies:
if isValidPasswordPart2(pw, pp): if isValidPasswordPart2(pw, pp): inc result
result += 1

View file

@ -3,15 +3,12 @@ import streams
proc sled(s: Stream, velx: int, vely: int): int = proc sled(s: Stream, velx: int, vely: int): int =
var xpos, ypos: int var xpos, ypos: int
for line in s.lines(): for line in s.lines():
ypos += 1 inc ypos
if (ypos - 1) mod vely > 0: if (ypos - 1) mod vely > 0: continue
continue if line[xpos mod line.len()] == '#': inc result
if line[xpos mod line.len()] == '#':
result += 1
xpos += velx xpos += velx
proc part1*(s: Stream): int = proc part1*(s: Stream): int = sled(s, 3, 1)
sled(s, 3, 1)
proc part2*(s: Stream): int = proc part2*(s: Stream): int =
result = part1(s) result = part1(s)

View file

@ -10,7 +10,7 @@ macro loadDays(): untyped =
# TODO: do I "need" to close these streams? # TODO: do I "need" to close these streams?
solver_str = solver_str & &""" solver_str = solver_str & &"""
{day}: proc(): tuple[part1: int, part2: int] = {day}: proc(): tuple[part1: int, part2: int] =
echo "Day {day}" stdout.write "Day {day}: "
( (
{module}.part1(getInputFileStreamForDay({day})), {module}.part1(getInputFileStreamForDay({day})),
{module}.part2(getInputFileStreamForDay({day})) {module}.part2(getInputFileStreamForDay({day}))

View file

@ -1,9 +1,7 @@
import streams, strutils, sugar import streams, strutils, sugar
iterator mapStream*[T](s: Stream, cb: (string) -> T): T = iterator mapStream*[T](s: Stream, cb: (string) -> T): T =
for line in s.lines(): for line in s.lines(): yield cb line
yield cb line
iterator asInts*(s: Stream): int = iterator asInts*(s: Stream): int =
for i in mapStream[int](s, parseInt): for i in mapStream[int](s, parseInt): yield i
yield i