From c47dee812e64b72101400c97afe61a778062a67c Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Wed, 14 Dec 2022 20:58:42 +0100 Subject: [PATCH] 2022 Day 14 --- 2022/day14.swift | 155 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 2022/day14.swift diff --git a/2022/day14.swift b/2022/day14.swift new file mode 100644 index 0000000..b039dba --- /dev/null +++ b/2022/day14.swift @@ -0,0 +1,155 @@ +import Foundation +import Darwin + + +struct Point: Hashable { + var x: Int + var y: Int +} + +extension Scanner { + func point() -> Point? { + guard let x = scanInt(), scanString(",") != nil, let y = scanInt() else { + return nil + } + + return Point(x: x, y: y) + } + + func line() -> [Point] { + var result: [Point] = [] + while let point = point() { + result.append(point) + guard scanString("->") != nil else { + break + } + } + return result + } +} + +let input = try String(contentsOf: URL(fileURLWithPath: "day14.input")) +let scanner = Scanner(string: input) + +var map: Set = [] + +func range(_ a: Int, _ b: Int) -> ClosedRange { + min(a, b)...max(a, b) +} + +var maxY = 0 +var minY = Int.max +var maxX = 0 +var minX = Int.max + +while !scanner.isAtEnd { + let line = scanner.line() + var current = line[0] + for point in line.dropFirst() { + if current.x == point.x { + for y in range(current.y, point.y) { + map.insert(Point(x: current.x, y: y)) + if y > maxY { + maxY = y + } + if y < minY { + minY = y + } + } + maxX = max(current.x, maxX) + minX = min(current.x, minX) + } else if current.y == point.y { + for x in range(current.x, point.x) { + map.insert(Point(x: x, y: current.y)) + if x > maxX { + maxX = x + } + if x < minX { + minX = x + } + } + maxY = max(current.y, maxY) + minY = min(current.y, minY) + } else { + fatalError("Not horizontal/vertical") + } + current = point + } +} +let walls = map + +func blocked(_ point: Point) -> Bool { + if map.contains(point) { + return true + } + + return point.y >= maxY + 2 +} + +extension Point { + func down() -> Point? { + var copy = self + copy.y += 1 + if !blocked(copy) { + return copy + } + + copy.x -= 1 + if !blocked(copy) { + return copy + } + + copy.x = x + 1 + if !blocked(copy) { + return copy + } + + return nil + } +} + +let inlet = Point(x: 500, y: 0) +var part1: Int? = nil + +func simulate() { + var position = inlet + + while let next = position.down() { + position = next + if position.y >= maxY, part1 == nil { + part1 = count + } + } + + map.insert(position) +} + + +var count = 0 +while !map.contains(inlet) { + simulate() + count += 1 + show() + usleep(3000) +} + +print("Part 2:", count) + +func show() { + var line = "\u{1b}[2J\u{1b}[H" + for y in 0...(maxY + 2) { + for x in (minX-30)...(maxX+30) { + let point = Point(x:x, y:y) + let isWall = walls.contains(point) || y >= maxY + 2 + let sand = map.contains(point) + line += isWall ? "#" : sand ? "o" : " " + } + line += "\n" + } + line += "\n" + if let part1 { + line += "Part 1: \(part1)\n" + } + var data = Array(line.utf8) + write(STDOUT_FILENO, &data, data.count) +}