Files
aoc24/day12/d12p1.swift
2024-12-14 20:43:38 -08:00

79 lines
2.2 KiB
Swift

import Foundation
struct Plot : Hashable, CustomStringConvertible {
let x: Int
let y: Int
var description: String { return "Plot(\(x), \(y))" }
}
struct Map : CustomStringConvertible {
let map: [[Character]]
let (w, h): (Int, Int)
var visited: [[Bool]]
var description: String {
var ret: String = "\(w)x\(h):\n"
for i in 0..<map.count {
for j in 0..<map[i].count {
ret.append(map[i][j])
ret.append(visited[i][j] ? "." : " ")
}
ret.append("\n")
}
return ret
}
init(_ map: [[Character]]) {
self.map = map
self.visited = map.map { $0.map { _ in false } }
self.h = map.count
self.w = map[0].count
}
// visits a plot; returns its perimeter contribution & unvisited neighbors
mutating func visit(_ plot: Plot) -> (Int, [Plot]) {
let (x, y) = (plot.x, plot.y)
visited[x][y] = true
let all_nbs = [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]
let peri = all_nbs.filter { i, j in
i < 0 || j < 0 || i >= h || j >= w || map[i][j] != map[x][y]
}.count
let nbs = all_nbs.filter { i, j in
i >= 0 && j >= 0 && i < h && j < w &&
map[i][j] == map[x][y] &&
!visited[i][j]
}.map { i, j in Plot(x: i, y: j) }
return (peri, nbs)
}
mutating func visitAll(from plot: Plot) -> Int {
var q: Set<Plot> = [plot]
var peri = 0
var area = 0
while !q.isEmpty {
let currentPlot = q.removeFirst()
let (newPeri, newNBs) = visit(currentPlot)
peri += newPeri
area += 1
q.formUnion(newNBs)
}
return peri * area
}
}
func readInput(_ filePath: String) throws -> Map {
let content = try String(contentsOfFile: filePath, encoding: .ascii)
return Map(content.split(separator: "\n").map(Array.init))
}
var map = try readInput(CommandLine.arguments[1])
print(map)
var answer = 0
for i in 0..<map.h {
for j in 0..<map.w {
if !map.visited[i][j] {
answer += map.visitAll(from: Plot(x: i, y: j))
}
}
}
print(answer)