Skip to content

Commit

Permalink
unify day18 solutions
Browse files Browse the repository at this point in the history
  • Loading branch information
2bjake committed Dec 18, 2020
1 parent 8679cdd commit 537c020
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 50 deletions.
100 changes: 53 additions & 47 deletions day18/Sources/day18/Expr.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,61 +28,67 @@ extension Expr {
}

extension Expr {
private typealias ParseResult = (expr: Expr, remainingTokens: ArraySlice<Character>)
struct Builder {
let leftToRightPrecedence: Bool

static func build(_ tokens: [Character]) -> Expr {
return build(tokens[...])
}
static func build(_ tokens: ArraySlice<Character>) -> Expr {
var remainingTokens = tokens
var expr: Expr?
while !remainingTokens.isEmpty {
(expr, remainingTokens) = subBuild(remainingTokens, stashed: expr)
private typealias ParseResult = (expr: Expr, remainingTokens: ArraySlice<Character>)

func build(_ tokens: [Character]) -> Expr {
return build(tokens[...])
}
return expr!
}

private static func getParenSlice(_ slice: ArraySlice<Character>) -> ArraySlice<Character> {
guard slice.first == "(" else { return [] }
var current = slice
var parenCount = 1
while parenCount != 0 {
current = current.dropFirst()
switch current.first! {
case "(": parenCount += 1
case ")": parenCount -= 1
default: break
private func build(_ tokens: ArraySlice<Character>) -> Expr {
var remainingTokens = tokens
var expr: Expr?
while !remainingTokens.isEmpty {
(expr, remainingTokens) = subBuild(remainingTokens, stashed: expr)
}
return expr!
}
return slice[slice.startIndex+1..<current.startIndex]
}

private static func subBuild(_ tokens: ArraySlice<Character>, stashed: Expr? = nil) -> ParseResult {
guard let first = tokens.first else { fatalError("empty token stream") }
switch first {
case "+":
guard let left = stashed else { fatalError("missing left for '+'" ) }
let (right, remainingTokens) = subBuild(tokens.dropFirst())
return (.plus(left, right), remainingTokens)
case "*":
guard let left = stashed else { fatalError("missing left for '*'" ) }
var (right, remainingTokens) = subBuild(tokens.dropFirst())
private func getParenSlice(_ slice: ArraySlice<Character>) -> ArraySlice<Character> {
guard slice.first == "(" else { return [] }
var current = slice
var parenCount = 1
while parenCount != 0 {
current = current.dropFirst()
switch current.first! {
case "(": parenCount += 1
case ")": parenCount -= 1
default: break
}
}
return slice[slice.startIndex+1..<current.startIndex]
}

// // perform lookahead for +
// while remainingTokens.first == "+" {
// (right, remainingTokens) = subBuild(remainingTokens, stashed: right)
// }
private func subBuild(_ tokens: ArraySlice<Character>, stashed: Expr? = nil) -> ParseResult {
guard let first = tokens.first else { fatalError("empty token stream") }
switch first {
case "+":
guard let left = stashed else { fatalError("missing left for '+'" ) }
let (right, remainingTokens) = subBuild(tokens.dropFirst())
return (.plus(left, right), remainingTokens)
case "*":
guard let left = stashed else { fatalError("missing left for '*'" ) }
var (right, remainingTokens) = subBuild(tokens.dropFirst())

return (.multiply(left, right), remainingTokens)
case "(":
let parenSlice = getParenSlice(tokens)
let expr = build(parenSlice)
return (.parens(expr), tokens.dropFirst(parenSlice.count + 2))
case ")":
fatalError("didn't expect to see ')'")
default:
guard let value = Int(String(first)) else { fatalError("could not parse '\(first)'") }
return (.digit(value), tokens.dropFirst())
if !leftToRightPrecedence {
// perform lookahead for +
while remainingTokens.first == "+" {
(right, remainingTokens) = subBuild(remainingTokens, stashed: right)
}
}
return (.multiply(left, right), remainingTokens)
case "(":
let parenSlice = getParenSlice(tokens)
let expr = build(parenSlice)
return (.parens(expr), tokens.dropFirst(parenSlice.count + 2))
case ")":
fatalError("didn't expect to see ')'")
default:
guard let value = Int(String(first)) else { fatalError("could not parse '\(first)'") }
return (.digit(value), tokens.dropFirst())
}
}
}
}
13 changes: 10 additions & 3 deletions day18/Sources/day18/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ let tokens = input.split(separator: "\n").map { line in
line.compactMap { $0 == " " ? nil : $0 }
}

print(tokens.map { Expr.build($0).eval() }.reduce(0, +))
// part 1: 4491283311856
// part 2: 68852578641904
func evaluate(_ tokens: [[Character]], leftToRightPrecedence: Bool) -> Int {
let builder = Expr.Builder(leftToRightPrecedence: leftToRightPrecedence)
return tokens.map { builder.build($0).eval() }.reduce(0, +)
}

let partOne = evaluate(tokens, leftToRightPrecedence: true)
print("answer to part one: \(partOne)") // 4491283311856

let partTwo = evaluate(tokens, leftToRightPrecedence: false)
print("answer to part two: \(partTwo)") // 68852578641904

0 comments on commit 537c020

Please sign in to comment.