이 포스팅은 프로그래머스 시리즈 28 편 중 27 번째 글 입니다.
목차
풀이
하라는 대로 구현했다. 일단, board에서는 빈칸을 찾아야 하고, table에서는 채워진 조각을 찾아야 한다. 각각에서 그 빈 구석을 모두 도려낸 뒤에, 그 조각들이 맞는지를 완전탐색했다. 이 때, table에 있는 조각중, 사용을 마친 경우는 최종 결과물에 더해지면 안된다.
Code
import Foundation
let blocked = 2
struct Position {
let y: Int
let x: Int
init(_ y: Int, _ x: Int) {
self.y = y
self.x = x
}
}
class Block {
var rowSize: Int
var colSize: Int
let fillCount: Int
var isInserted: Bool = false
var value: [[Int]]
init(_ rowSize: Int, _ colSize: Int, _ fillCount: Int, _ value: [[Int]]) {
self.rowSize = rowSize
self.colSize = colSize
self.fillCount = fillCount
self.value = value
}
private func rotate(){
var rotated = [[Int]]()
for j in 0..<value[0].count {
rotated.append(value.map({ $0[j] }).reversed())
}
self.value = rotated
self.rowSize = rotated.count
self.colSize = rotated[0].count
}
func isOk(_ rotated: Block, other block: Block) -> Bool {
return rotated.rowSize == block.rowSize && rotated.colSize == block.colSize && rotated.fillCount == block.fillCount && rotated.isInserted == false && block.isInserted == false
}
func match(with block: Block) -> Int? {
for _ in 0..<4 {
self.rotate()
if isOk(self, other: block) {
if self.value == block.value {
self.isInserted = true
block.isInserted = true
return self.fillCount
}
}
}
return nil
}
}
func BFS(start: Position, in board: inout [[Int]], with num: Int) -> Block? {
let n = board.count
func isOk(_ y: Int, _ x: Int) -> Bool {
return (0..<n).contains(y) && (0..<n).contains(x) && board[y][x] == num
}
let d = [[1, 0], [0, 1], [-1, 0], [0, -1]]
var q = Array([start])
var positions = Array([start])
board[start.y][start.x] = blocked
while !q.isEmpty {
guard let now = q.first else { return nil }
q.removeFirst()
let y = now.y, x = now.x
for i in 0..<4 {
let ny = y + d[i][0], nx = x + d[i][1]
if isOk(ny, nx) {
let position = Position(ny, nx)
q.append(position)
positions.append(position)
board[ny][nx] = blocked
}
}
}
// 모인 positions에 대해서 row 상한 하한, col 상한 하한을 체크한다.
let rowLowerBound = positions.map { $0.y }.min()!
let rowUpperBound = positions.map { $0.y }.max()!
let colLowerBound = positions.map { $0.x }.min()!
let colUpperBound = positions.map { $0.x }.max()!
var slicedBoard = board[rowLowerBound...rowUpperBound].map { Array($0[colLowerBound...colUpperBound]) }
slicedBoard = slicedBoard.map({ $0.map( { $0 == blocked ? 1 : 0 })})
return Block(slicedBoard.count, slicedBoard[0].count, positions.count, slicedBoard)
}
func detach(in board: inout [[Int]], with num: Int) -> [Block] {
let n = board.count
var blocks = [Block]()
for i in 0..<n {
for j in 0..<n {
if board[i][j] == num {
guard let block = BFS(start: Position(i, j), in: &board, with: num) else { continue }
blocks.append(block)
}
}
}
return blocks
}
func solution(_ gameBoard:[[Int]], _ table:[[Int]]) -> Int {
var board = gameBoard, table = table
let boardBlocks = detach(in: &board, with: 0)
let tableBlocks = detach(in: &table, with: 1)
var count = 0
for tBlock in tableBlocks {
for bBlock in boardBlocks {
if let matchCount = tBlock.match(with: bBlock) {
count += matchCount
}
}
}
return count
}