블록에서 빈 칸을 찾으려면...
y축이나 x축 중 한 축은 같은 값이 (3번, 1번), 다른 축은 (2번, 1번, 1번) 나온다.
값이 3번 나오게 되는 축에서 나머지 1번 나오는 값과, 다른 축에서 1번 씩만 나오는 값들의 product 연산이 바로 빈 칸이다.
예를 들어 y축(a:3, b:1), x축(c:2, d:1, e:1)이라고 할 때
값이 3번 나오게 되는 축(y)에서 나머지 1번 나오는 값 = b,
다른 축(x)에서 1번 씩만 나오는 값들 = (d, e)
의 product 연산 => (b, d), (b, e) 가 바로 빈 칸이다.
이때 축을 잘 봐야 한다. 만약 b가 x축이었다면 (d, b), (e, b)였을 것이다.
from collections import Counter, defaultdict
def solution(board):
global N
N = len(board)
pos = init_pos(board)
answer = 0
while True:
popped = pop_blocks(board, pos)
if popped == 0:
break
answer += popped
return answer
def init_pos(board):
pos = defaultdict(lambda: [])
for i in range(N):
for j in range(N):
if board[i][j] != 0:
pos[board[i][j]].append((i, j))
return pos
def get_blanks(blocks):
counts = [sorted(Counter([block[i] for block in blocks]).items(), key=lambda x: -x[1]) for i in range(2)]
target_idx = [i for i in range(2) if counts[i][0][1] == 3][0]
axis = counts[target_idx][1][0]
counter_idx = (target_idx + 1) % 2
counter_axis = [counts[counter_idx][i][0] for i in range(3) if counts[counter_idx][i][1] == 1]
blanks = []
for c in counter_axis:
temp = [0, 0]
temp[target_idx] = axis
temp[counter_idx] = c
blanks.append(temp)
return blanks
def is_fillable(board, blanks):
for blank in blanks:
for i in range(blank[0], -1, -1):
if board[i][blank[1]] != 0:
return False
return True
def pop_blocks(board, pos):
cnt = 0
popped = []
for n, p in pos.items():
blanks = get_blanks(p)
if is_fillable(board, blanks):
cnt += 1
for py, px in p:
board[py][px] = 0
popped.append(n)
for p in popped:
pos.pop(p)
return cnt
get_blanks
함수는 블록의 위치값 리스트를 넣어주면 블록을 반환한다.
y축과 x축에 구애받지 않고 한 번에 구할 수 있는 로직으로 작성하였다.