Initial commit
This commit is contained in:
commit
dae7c34265
17 changed files with 2001 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.xcodeproj/**/xcuserdata/
|
1236
AdventOfCode2020.xcodeproj/project.pbxproj
Normal file
1236
AdventOfCode2020.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load diff
7
AdventOfCode2020.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
AdventOfCode2020.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
30
common/LoadData.swift
Normal file
30
common/LoadData.swift
Normal file
|
@ -0,0 +1,30 @@
|
|||
import Foundation
|
||||
|
||||
func loadData(day: Int) -> String {
|
||||
guard let session = getenv("SESSION") else {
|
||||
fatalError("Missing session env var")
|
||||
}
|
||||
|
||||
var request = URLRequest(url: URL(string: "https://adventofcode.com/2020/day/\(day)/input")!)
|
||||
request.setValue("session=\(String(cString: session))", forHTTPHeaderField: "Cookie")
|
||||
|
||||
var result: String? = nil
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
group.enter()
|
||||
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
|
||||
guard error == nil, let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 else {
|
||||
fatalError("Cannot get input from server")
|
||||
}
|
||||
|
||||
result = String(data: data, encoding: .utf8)
|
||||
group.leave()
|
||||
}
|
||||
|
||||
task.resume()
|
||||
|
||||
group.wait()
|
||||
|
||||
return result!
|
||||
}
|
26
common/Scanner+Extensions.swift
Normal file
26
common/Scanner+Extensions.swift
Normal file
|
@ -0,0 +1,26 @@
|
|||
import Foundation
|
||||
|
||||
extension Scanner {
|
||||
@discardableResult
|
||||
func string(_ string: String) -> Bool {
|
||||
return scanString(string) != nil
|
||||
}
|
||||
|
||||
func integers() -> [Int]? {
|
||||
var numbers: [Int] = []
|
||||
while !isAtEnd {
|
||||
guard let num = scanInt() else { return nil }
|
||||
numbers.append(num)
|
||||
}
|
||||
return numbers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension String {
|
||||
func lines() -> [String] {
|
||||
var result: [String] = []
|
||||
enumerateLines { line, _ in result.append(line) }
|
||||
return result
|
||||
}
|
||||
}
|
21
day1/main.swift
Normal file
21
day1/main.swift
Normal file
|
@ -0,0 +1,21 @@
|
|||
import Foundation
|
||||
|
||||
let input = Scanner(string: loadData(day: 1)).integers()!
|
||||
|
||||
for i in 0..<input.count {
|
||||
for j in i..<input.count {
|
||||
for k in j..<input.count {
|
||||
let a = input[i]
|
||||
let b = input[j]
|
||||
let c = input[k]
|
||||
|
||||
if k == j && a + b == 2020 {
|
||||
print("1st", a * b)
|
||||
}
|
||||
|
||||
if a + b + c == 2020 {
|
||||
print("2nd", a * b * c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
day10/main.swift
Normal file
64
day10/main.swift
Normal file
|
@ -0,0 +1,64 @@
|
|||
import Foundation
|
||||
|
||||
let input = loadData(day: 10)
|
||||
let scanner = Scanner(string: input)
|
||||
|
||||
var adapters = scanner.integers()!.sorted { $0 > $1 }
|
||||
adapters.append(0)
|
||||
|
||||
|
||||
let device = adapters[0] + 3
|
||||
|
||||
var current = device
|
||||
var ones = 0
|
||||
var threes = 0
|
||||
|
||||
for adapter in adapters {
|
||||
let step = current - adapter
|
||||
if step == 3 {
|
||||
threes += 1
|
||||
} else if step == 1 {
|
||||
ones += 1
|
||||
} else if step != 2 {
|
||||
print("fail")
|
||||
}
|
||||
current = adapter
|
||||
}
|
||||
|
||||
print("part 1", ones * threes)
|
||||
|
||||
struct Key: Hashable {
|
||||
var start: Int
|
||||
var max: Int
|
||||
}
|
||||
var memo: [Key: Int] = [:]
|
||||
|
||||
func findPaths(start: Int, max: Int) -> Int {
|
||||
if let value = memo[Key(start: start, max: max)] {
|
||||
return value
|
||||
}
|
||||
|
||||
let diff = max - adapters[start]
|
||||
if diff > 3 || diff < 1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if start == adapters.count - 1 {
|
||||
return 1
|
||||
}
|
||||
|
||||
var result = 0
|
||||
for n in (start + 1)..<(adapters.count) {
|
||||
let next = findPaths(start: n, max: adapters[start])
|
||||
if next == 0 {
|
||||
break
|
||||
}
|
||||
result += next
|
||||
}
|
||||
|
||||
memo[Key(start: start, max: max)] = result
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
print(findPaths(start: 0, max: device))
|
116
day11/main.swift
Normal file
116
day11/main.swift
Normal file
|
@ -0,0 +1,116 @@
|
|||
import Foundation
|
||||
|
||||
let input = loadData(day: 11)
|
||||
|
||||
enum Spot: Equatable {
|
||||
case empty
|
||||
case occupied
|
||||
case floor
|
||||
}
|
||||
typealias Map = [[Spot]]
|
||||
|
||||
var map: Map = []
|
||||
|
||||
input.enumerateLines { (line, _) in
|
||||
map.append(line.map {
|
||||
switch $0 {
|
||||
case ".": return .floor
|
||||
case "#": return .occupied
|
||||
case "L": return .empty
|
||||
default: fatalError("Invalid input")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
let adjacents = [
|
||||
(-1, -1),
|
||||
(0, -1),
|
||||
(1, -1),
|
||||
(-1, 0),
|
||||
(1, 0),
|
||||
(-1, 1),
|
||||
(0, 1),
|
||||
(1, 1)
|
||||
]
|
||||
|
||||
/*
|
||||
func step(map: Map) -> Map {
|
||||
var result = map
|
||||
let width = map[0].count
|
||||
|
||||
for i in 0..<map.count {
|
||||
for j in 0..<width where map[i][j] != .floor {
|
||||
let occupieds = adjacents.reduce(0) { count, offset in
|
||||
let (x, y) = (offset.0 + j, offset.1 + i)
|
||||
guard 0..<map.count ~= y, 0..<width ~= x else { return count }
|
||||
return count + (map[y][x] == .occupied ? 1 : 0)
|
||||
}
|
||||
switch (map[i][j], occupieds) {
|
||||
case (.empty, 0): result[i][j] = .occupied
|
||||
case (.occupied, let n) where n >= 4: result[i][j] = .empty
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
func occupiedInDirection(at pos: (Int, Int), map: Map, direction: (Int, Int)) -> Int {
|
||||
var pos = pos
|
||||
|
||||
let yRange = 0..<map.count
|
||||
let xRange = 0..<map[0].count
|
||||
|
||||
while true {
|
||||
var (i, j) = pos
|
||||
i+=direction.1
|
||||
j += direction.0
|
||||
pos = (i, j)
|
||||
|
||||
guard yRange ~= pos.0, xRange ~= pos.1 else { break }
|
||||
|
||||
let state = map[i][j]
|
||||
switch state {
|
||||
case .floor: break
|
||||
case .occupied: return 1
|
||||
case .empty: return 0
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func step(map: Map) -> Map {
|
||||
var result = map
|
||||
let width = map[0].count
|
||||
|
||||
for i in 0..<map.count {
|
||||
for j in 0..<width where map[i][j] != .floor {
|
||||
let occupieds = adjacents.reduce(0) { count, offset in
|
||||
count + occupiedInDirection(at: (i, j), map: map, direction: offset)
|
||||
}
|
||||
switch (map[i][j], occupieds) {
|
||||
case (.empty, 0): result[i][j] = .occupied
|
||||
case (.occupied, let n) where n >= 5: result[i][j] = .empty
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
while true {
|
||||
let next = step(map: map)
|
||||
if next == map {
|
||||
break
|
||||
}
|
||||
map = next
|
||||
}
|
||||
|
||||
let totalOccupieds = map.lazy.flatMap { $0 }.filter { $0 == .occupied }.count
|
||||
print(totalOccupieds)
|
39
day2/main.swift
Normal file
39
day2/main.swift
Normal file
|
@ -0,0 +1,39 @@
|
|||
import Foundation
|
||||
|
||||
let input = loadData(day: 2)
|
||||
|
||||
var valids = 0
|
||||
var valid2 = 0
|
||||
|
||||
var scanner = Scanner(string: input)
|
||||
while !scanner.isAtEnd {
|
||||
guard let min = scanner.scanInt(),
|
||||
scanner.scanString("-") != nil,
|
||||
let max = scanner.scanInt(),
|
||||
let character = scanner.scanCharacter(),
|
||||
scanner.scanString(":") != nil,
|
||||
let password = scanner.scanUpToCharacters(from: .newlines)
|
||||
else {
|
||||
fatalError("Invalid input");
|
||||
}
|
||||
|
||||
|
||||
let count = password.lazy.filter { $0 == character }.count
|
||||
|
||||
if min <= count && count <= max {
|
||||
print("valid", min, max, character, password)
|
||||
valids += 1
|
||||
}
|
||||
|
||||
let first = password.index(password.startIndex, offsetBy: min - 1, limitedBy: password.endIndex).map { password[$0] }
|
||||
let second = password.index(password.startIndex, offsetBy: max - 1, limitedBy: password.endIndex).map { password[$0] }
|
||||
|
||||
if (first == character || second == character) && first != second {
|
||||
print("valid 2", password)
|
||||
valid2 += 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
print("Valid old", valids)
|
||||
print("Valid new", valid2)
|
32
day3/main.swift
Normal file
32
day3/main.swift
Normal file
|
@ -0,0 +1,32 @@
|
|||
let input = loadData(day: 3).lines()
|
||||
|
||||
/// - returns true if a tree is at that position, false if it is empty
|
||||
func get(x: Int, y: Int) -> Bool {
|
||||
let line = input[y]
|
||||
let index = line.index(line.startIndex, offsetBy: x % line.count)
|
||||
return line[index] == "#"
|
||||
}
|
||||
|
||||
func calculate(dx: Int, dy: Int) -> Int {
|
||||
var x = 0
|
||||
var y = 0
|
||||
|
||||
var trees = 0
|
||||
|
||||
while y < input.count {
|
||||
if get(x: x, y: y) {
|
||||
trees += 1
|
||||
}
|
||||
|
||||
x += dx
|
||||
y += dy
|
||||
}
|
||||
|
||||
return trees
|
||||
}
|
||||
|
||||
let trees = calculate(dx: 3, dy: 1)
|
||||
print("trees", trees)
|
||||
|
||||
|
||||
print("combined", calculate(dx: 1, dy: 1) * calculate(dx: 3, dy: 1) * calculate(dx: 5, dy: 1) * calculate(dx: 7, dy: 1) * calculate(dx: 1, dy: 2))
|
99
day4/main.swift
Normal file
99
day4/main.swift
Normal file
|
@ -0,0 +1,99 @@
|
|||
import Foundation
|
||||
|
||||
let input = loadData(day: 4)
|
||||
|
||||
let scanner = Scanner(string: input)
|
||||
scanner.charactersToBeSkipped = nil
|
||||
|
||||
extension Scanner {
|
||||
func field() -> (String, String)? {
|
||||
guard let name = scanUpToString(":"),
|
||||
scanString(":") != nil,
|
||||
let value = scanUpToCharacters(from: .whitespacesAndNewlines)
|
||||
else { return nil }
|
||||
return (name, value)
|
||||
}
|
||||
|
||||
func passport() -> [String: String]? {
|
||||
var fields = [(String, String)]()
|
||||
while !isAtEnd && scanString("\n\n") == nil {
|
||||
_ = scanner.scanCharacters(from: .whitespacesAndNewlines)
|
||||
guard let field = field() else { return nil }
|
||||
fields.append(field)
|
||||
}
|
||||
return try? Dictionary(fields, uniquingKeysWith: { _, _ in throw NSError(domain: "error", code: 1, userInfo: nil) })
|
||||
}
|
||||
}
|
||||
|
||||
var valids = 0
|
||||
var valid2 = 0
|
||||
|
||||
let requiredFields = [
|
||||
"byr",
|
||||
"iyr",
|
||||
"eyr",
|
||||
"hgt",
|
||||
"hcl",
|
||||
"ecl",
|
||||
"pid",
|
||||
]
|
||||
|
||||
func validHeight(_ height: String) -> Bool {
|
||||
let scanner = Scanner(string: height)
|
||||
guard let number = scanner.scanInt() else { return false }
|
||||
if scanner.scanString("cm") != nil, 150...193 ~= number {
|
||||
return true
|
||||
}
|
||||
|
||||
if scanner.scanString("in") != nil, 59...76 ~= number {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func validHairColor(_ hcl: String) -> Bool {
|
||||
let scanner = Scanner(string: hcl)
|
||||
guard scanner.scanString("#") != nil else { return false }
|
||||
guard scanner.scanCharacters(from: CharacterSet(charactersIn: "0123456789abcdef"))?.count == 6 else { return false }
|
||||
return scanner.isAtEnd
|
||||
}
|
||||
|
||||
let validEyeColors: Set<String> = [
|
||||
"amb",
|
||||
"blu",
|
||||
"brn",
|
||||
"gry",
|
||||
"grn",
|
||||
"hzl",
|
||||
"oth"
|
||||
]
|
||||
|
||||
func isValidPassportId(_ pid: String) -> Bool {
|
||||
return pid.count == 9 && Int(pid) != nil
|
||||
}
|
||||
|
||||
while !scanner.isAtEnd {
|
||||
guard let passport = scanner.passport() else { fatalError() }
|
||||
print(passport)
|
||||
|
||||
let valid = requiredFields.allSatisfy { passport.keys.contains($0) }
|
||||
if valid {
|
||||
valids += 1
|
||||
}
|
||||
|
||||
guard let year = passport["byr"].flatMap(Int.init), 1920...2002 ~= year else { continue }
|
||||
guard let issueYear = passport["iyr"].flatMap(Int.init), 2010...2020 ~= issueYear else { continue }
|
||||
guard let expireYear = passport["eyr"].flatMap(Int.init), 2020...2030 ~= expireYear else { continue }
|
||||
guard let height = passport["hgt"], validHeight(height) else { continue }
|
||||
guard let hairColor = passport["hcl"], validHairColor(hairColor) else { continue }
|
||||
guard let eyeColor = passport["ecl"], validEyeColors.contains(eyeColor) else { continue }
|
||||
guard let pid = passport["pid"], isValidPassportId(pid) else { continue }
|
||||
|
||||
valid2 += 1
|
||||
|
||||
}
|
||||
|
||||
print("valids", valids)
|
||||
print("valid2", valid2)
|
||||
|
35
day5/main.swift
Normal file
35
day5/main.swift
Normal file
|
@ -0,0 +1,35 @@
|
|||
let input = loadData(day: 5).lines()
|
||||
|
||||
func decode(_ s: Substring, lower: Character, upper: Character, range: Range<Int>) -> (Int, Substring)
|
||||
{
|
||||
var range = range
|
||||
var start = s.startIndex
|
||||
while start != s.endIndex && (s[start] == lower || s[start] == upper) {
|
||||
let mid = (range.lowerBound + range.upperBound) / 2
|
||||
if s[start] == lower {
|
||||
range = range.lowerBound..<mid
|
||||
} else if s[start] == upper {
|
||||
range = mid..<range.upperBound
|
||||
}
|
||||
start = s.index(after: start)
|
||||
}
|
||||
|
||||
return (range.lowerBound, s[start...])
|
||||
}
|
||||
|
||||
func decodeSeat(_ s: String) -> Int {
|
||||
let (row, rest) = decode(s[...], lower: "F", upper: "B", range: 0..<128)
|
||||
let (column, _) = decode(rest, lower: "L", upper: "R", range: 0..<8)
|
||||
let id = row * 8 + column
|
||||
print(s, row, column, id)
|
||||
return id
|
||||
}
|
||||
|
||||
let foundSeats = Set(input.map { decodeSeat($0) })
|
||||
print("max seat id", foundSeats.max() ?? -1)
|
||||
|
||||
let allSeats = Set(0...(7+127*8))
|
||||
let freeSeats = allSeats.subtracting(foundSeats)
|
||||
|
||||
let yours = freeSeats.first(where: { foundSeats.contains($0 + 1) && foundSeats.contains($0 - 1)})
|
||||
print("yours", yours ?? -1)
|
34
day6/main.swift
Normal file
34
day6/main.swift
Normal file
|
@ -0,0 +1,34 @@
|
|||
import Foundation
|
||||
|
||||
var input = loadData(day: 6)
|
||||
|
||||
let scanner = Scanner(string: input)
|
||||
scanner.charactersToBeSkipped = nil
|
||||
|
||||
var count = 0
|
||||
var countB = 0
|
||||
var currentGroup: [Character:Int] = [:]
|
||||
var peopleInGroup = 0
|
||||
|
||||
repeat {
|
||||
guard let answers = scanner.scanUpToString("\n") else { fatalError() }
|
||||
peopleInGroup += 1
|
||||
_ = scanner.scanString("\n")
|
||||
|
||||
for answer in answers {
|
||||
currentGroup[answer, default: 0] += 1
|
||||
}
|
||||
|
||||
if scanner.isAtEnd || scanner.scanString("\n") != nil {
|
||||
count += currentGroup.count
|
||||
|
||||
countB += currentGroup.lazy.filter { $1 == peopleInGroup }.count
|
||||
|
||||
currentGroup.removeAll(keepingCapacity: true)
|
||||
peopleInGroup = 0
|
||||
}
|
||||
|
||||
} while !scanner.isAtEnd
|
||||
|
||||
print("count", count)
|
||||
print("part 2", countB)
|
74
day7/main.swift
Normal file
74
day7/main.swift
Normal file
|
@ -0,0 +1,74 @@
|
|||
import Foundation
|
||||
|
||||
let input = loadData(day: 7)
|
||||
|
||||
|
||||
let scanner = Scanner(string: input)
|
||||
|
||||
struct Rule {
|
||||
var count: Int
|
||||
var color: String
|
||||
}
|
||||
|
||||
extension Scanner {
|
||||
func scanRule() -> Rule? {
|
||||
guard let count = scanInt(),
|
||||
let color = scanUpToString(count == 1 ? " bag" : " bags"),
|
||||
scanString(count == 1 ? "bag" : "bags") != nil
|
||||
else { return nil }
|
||||
return Rule(count: count, color: color)
|
||||
}
|
||||
|
||||
func scanRuleSet() -> (String, [Rule])? {
|
||||
guard
|
||||
let color = scanUpToString(" bags contain"),
|
||||
scanString("bags contain") != nil else { return nil }
|
||||
if scanString("no other bags.") != nil {
|
||||
return (color, [])
|
||||
}
|
||||
|
||||
var rules: [Rule] = []
|
||||
repeat {
|
||||
guard let rule = scanRule() else { return nil }
|
||||
rules.append(rule)
|
||||
} while scanString(",") != nil
|
||||
|
||||
guard scanString(".") != nil else { return nil }
|
||||
|
||||
return (color, rules)
|
||||
}
|
||||
|
||||
func scanAllRules() -> [String: [Rule]]? {
|
||||
var result: [String: [Rule]] = [:]
|
||||
while !isAtEnd {
|
||||
guard let (color, rules) = scanRuleSet() else { return nil }
|
||||
result[color] = rules
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
guard let rules = scanner.scanAllRules() else { fatalError() }
|
||||
//print(rules)
|
||||
|
||||
func findPath(rules: [String: [Rule]], from: String, to: String) -> Bool {
|
||||
guard let from = rules[from] else { return false }
|
||||
if from.contains(where: { $0.color == to }) {
|
||||
return true
|
||||
}
|
||||
|
||||
return from.contains(where: { findPath(rules: rules, from: $0.color, to: to) })
|
||||
}
|
||||
|
||||
let count = rules.lazy.filter { findPath(rules: rules, from: $0.key, to: "shiny gold") }.count
|
||||
|
||||
print("count", count)
|
||||
|
||||
func bagsInside(rules: [String: [Rule]], color: String) -> Int {
|
||||
guard let from = rules[color] else { return 0 }
|
||||
return from.reduce(0) { accum, bag in
|
||||
accum + bag.count + bag.count * bagsInside(rules: rules, color: bag.color)
|
||||
}
|
||||
}
|
||||
|
||||
print("total bags", bagsInside(rules: rules, color: "shiny gold"))
|
134
day8/main.swift
Normal file
134
day8/main.swift
Normal file
|
@ -0,0 +1,134 @@
|
|||
import Foundation
|
||||
|
||||
let input = loadData(day: 8)
|
||||
|
||||
let scanner = Scanner(string: input)
|
||||
|
||||
enum Instruction: String {
|
||||
case nop
|
||||
case acc
|
||||
case jmp
|
||||
}
|
||||
|
||||
struct Line {
|
||||
var instruction: Instruction
|
||||
var argument: Int
|
||||
}
|
||||
|
||||
extension Scanner {
|
||||
func instruction() -> Instruction? {
|
||||
guard let string = scanUpToCharacters(from: .whitespaces),
|
||||
let instruction = Instruction(rawValue: string)
|
||||
else { return nil }
|
||||
return instruction
|
||||
}
|
||||
|
||||
func line() -> Line? {
|
||||
guard let ins = instruction(),
|
||||
let argument = scanInt()
|
||||
else { return nil }
|
||||
return Line(instruction: ins, argument: argument)
|
||||
}
|
||||
|
||||
func program() -> [Line]? {
|
||||
var program = [Line]()
|
||||
while !isAtEnd {
|
||||
guard let line = self.line() else { return nil }
|
||||
program.append(line)
|
||||
}
|
||||
return program
|
||||
}
|
||||
}
|
||||
|
||||
class Computer {
|
||||
var program: [Line]
|
||||
var ip: Int = 0
|
||||
var acc: Int = 0
|
||||
|
||||
init(program: [Line]) {
|
||||
self.program = program
|
||||
}
|
||||
|
||||
var visited: Set<Int> = []
|
||||
|
||||
func runLine() {
|
||||
let line = program[ip]
|
||||
switch line.instruction {
|
||||
case .nop:
|
||||
ip += 1
|
||||
|
||||
case .acc:
|
||||
acc += line.argument
|
||||
ip += 1
|
||||
|
||||
case .jmp:
|
||||
ip += line.argument
|
||||
}
|
||||
}
|
||||
|
||||
func run() {
|
||||
ip = 0
|
||||
acc = 0
|
||||
|
||||
while ip < program.count {
|
||||
let (inserted, _) = visited.insert(ip)
|
||||
if !inserted {
|
||||
print("Repeated instruction", acc)
|
||||
return
|
||||
}
|
||||
|
||||
runLine()
|
||||
}
|
||||
print("Finished", acc)
|
||||
}
|
||||
|
||||
func find(ip: Int, acc: Int, changed: Bool, visited: Set<Int>) -> Int?
|
||||
{
|
||||
if ip >= program.count {
|
||||
return acc
|
||||
}
|
||||
|
||||
if (visited.contains(ip)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
let newVisited = visited.union([ip])
|
||||
|
||||
let line = program[ip]
|
||||
switch line.instruction {
|
||||
case .acc:
|
||||
return find(ip: ip + 1, acc: acc + line.argument, changed: changed, visited: newVisited)
|
||||
|
||||
case .nop:
|
||||
if let result = find(ip: ip + 1, acc: acc, changed: changed, visited: newVisited) {
|
||||
return result
|
||||
}
|
||||
|
||||
if !changed, let result = find(ip: ip + line.argument, acc: acc, changed: true, visited: newVisited) {
|
||||
print("Found result by changing nop to jmp at", ip)
|
||||
return result
|
||||
}
|
||||
|
||||
case .jmp:
|
||||
if let result = find(ip: ip + line.argument, acc: acc, changed: changed, visited: newVisited) {
|
||||
return result
|
||||
}
|
||||
|
||||
if !changed, let result = find(ip: ip + 1, acc: acc, changed: true, visited: newVisited) {
|
||||
print("Found result by changing jmp to nop at", ip)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
guard let program = scanner.program() else { fatalError() }
|
||||
let computer = Computer(program: program)
|
||||
computer.run()
|
||||
if let found = computer.find(ip: 0, acc: 0, changed: false, visited: []) {
|
||||
print("found solution", found)
|
||||
}
|
||||
|
||||
|
45
day9/main.swift
Normal file
45
day9/main.swift
Normal file
|
@ -0,0 +1,45 @@
|
|||
import Foundation
|
||||
|
||||
let input = loadData(day: 9)
|
||||
let scanner = Scanner(string: input)
|
||||
|
||||
let numbers = scanner.integers()!
|
||||
|
||||
var weakness: Int? = nil
|
||||
outer: for i in 25..<numbers.count {
|
||||
let search = numbers[i]
|
||||
|
||||
for j in (i - 25)..<i {
|
||||
for k in j..<i {
|
||||
if search == numbers[j] + numbers[k] {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print("first which is not sum", i, search)
|
||||
weakness = search
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
guard let weakness = weakness else { fatalError("No weakness found") }
|
||||
|
||||
outer: for i in 0..<numbers.count {
|
||||
var sum = 0
|
||||
var min = Int.max
|
||||
var max = Int.min
|
||||
for j in (i+1)..<numbers.count {
|
||||
let n = numbers[j]
|
||||
sum += n
|
||||
if n < min { min = n }
|
||||
if n > max { max = n }
|
||||
if sum == weakness {
|
||||
print(min + max)
|
||||
break outer
|
||||
}
|
||||
if sum > weakness {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue