Skip to content

Instantly share code, notes, and snippets.

@mkuliszkiewicz
Last active December 14, 2022 19:42
Show Gist options
  • Save mkuliszkiewicz/a293e73cbb47de8012ce8728dd45e828 to your computer and use it in GitHub Desktop.
Save mkuliszkiewicz/a293e73cbb47de8012ce8728dd45e828 to your computer and use it in GitHub Desktop.
AoC Day 14
struct Point: Hashable, CustomStringConvertible {
let x: Int; let y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
init(_ str: String) {
// x represents distance to the right and y represents distance down.
let el = str.components(separatedBy: ",").map { Int($0)! }
self.x = el[0]
self.y = el[1]
}
var description: String { "Point(x: \(x), y: \(y))" }
func makeAllPoints(to otherPoint: Point) -> [Point] {
guard self != otherPoint else { return [] }
if x != otherPoint.x {
var minX = min(x, otherPoint.x)
var maxX = max(x, otherPoint.x)
return (minX...maxX).map { Point(x: $0, y: y) }
} else {
var minY = min(y, otherPoint.y)
var maxY = max(y, otherPoint.y)
return (minY...maxY).map { Point(x: x, y: $0) }
}
}
func adjustX(by val: Int) -> Point {
Point(x: x + val, y: y)
}
func adjustY(by val: Int) -> Point {
Point(x: x, y: y + val)
}
func flipY() -> Point {
Point(x: x, y: y * -1)
}
}
final class Sand {
var position = Point(x: 0, y: 0)
}
func task1(input: String) -> Int {
let rawRows = input
.components(separatedBy: .newlines)
.filter { !$0.isEmpty }
.map { $0.components(separatedBy: " -> ").map(Point.init) }
var rawRockPoints: Set<Point> = []
for row in rawRows where !row.isEmpty {
for i in (1..<row.count) {
let current = row[i]
let previous = row[i - 1]
previous
.makeAllPoints(to: current)
.forEach {
rawRockPoints.insert($0)
}
}
}
var rocksPoints = rawRockPoints.map { $0.adjustX(by: -500).flipY() }
var lowestRockPoint = rocksPoints.min(by: { $0.y < $1.y })!
var sandBuffer: Set<Point> = []
var sandCounter = 0
var hasFallenDown = false
while !hasFallenDown {
sandCounter += 1
var currentSand = Sand()
func nextMove() -> Point? {
var currentPosition = currentSand.position
let oneDown = currentPosition.adjustY(by: -1)
let oneDownLeft = currentPosition.adjustY(by: -1).adjustX(by: -1)
let oneDownRight = currentPosition.adjustY(by: -1).adjustX(by: 1)
if !rocksPoints.contains(oneDown) && !sandBuffer.contains(oneDown) {
return oneDown
}
if !rocksPoints.contains(oneDownLeft) && !sandBuffer.contains(oneDownLeft) {
return oneDownLeft
}
if !rocksPoints.contains(oneDownRight) && !sandBuffer.contains(oneDownRight) {
return oneDownRight
}
return nil
}
while let next = nextMove(), !hasFallenDown {
currentSand.position = next
hasFallenDown = currentSand.position.y < lowestRockPoint.y
if hasFallenDown {
print("Has fallen down")
}
}
print("Settled at \(currentSand.position)")
sandBuffer.insert(currentSand.position)
}
return sandCounter - 1
}
func task2(input: String) -> Int {
let rawRows = input
.components(separatedBy: .newlines)
.filter { !$0.isEmpty }
.map {
$0.components(separatedBy: " -> ")
.map(Point.init)
.map {
$0.adjustX(by: -500)
.flipY()
}
}
var rawRockPoints: Set<Point> = []
for row in rawRows where !row.isEmpty {
for i in (1..<row.count) {
let current = row[i]
let previous = row[i - 1]
previous
.makeAllPoints(to: current)
.forEach {
rawRockPoints.insert($0)
}
}
}
var rocksPoints = rawRockPoints
let lowestRockPoint = rocksPoints.min(by: { $0.y < $1.y })!
let floorLevel = lowestRockPoint.y - 2
print("Floor level \(floorLevel)")
var sandCounter = 0
while true {
sandCounter += 1
var currentSand = Point(x: 0, y: 0)
func nextMove() -> Point? {
let oneDown = currentSand.adjustY(by: -1)
let oneDownLeft = currentSand.adjustY(by: -1).adjustX(by: -1)
let oneDownRight = currentSand.adjustY(by: -1).adjustX(by: 1)
if oneDown.y == floorLevel {
return nil
}
if !rocksPoints.contains(oneDown) {
return oneDown
}
if !rocksPoints.contains(oneDownLeft) {
return oneDownLeft
}
if !rocksPoints.contains(oneDownRight) {
return oneDownRight
}
return nil
}
while let next = nextMove() {
currentSand = next
}
rocksPoints.insert(currentSand)
if currentSand == .init(x: 0, y: 0) {
return sandCounter
}
}
fatalError()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment