-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
- BFS 탐색 (그룹들 구하기)
- 배열에 중력 작용해 떨어뜨리기
- 배열 90도 반시계 회전
# 블록의 종류
# 검은색 / 무지개 / 일반(M 가지 색상)
# -1 0 1 ~ M
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
n, m = map(int, input().split())
a = [list(map(int, input().split())) for _ in range(n)]
# for line in a:
# print(line)
# 블록 그룹 : 연결된 블록의 집합
# <조건>
# 1. 일반 블록이 적어도 1개 (색은 모두 같아야 함 !!)
# 2. 검은색 블록 있으면 X
# (3. 무지개 블록은 얼마나 들어있든 상관없다.)
# 4. 그룹에 속한 블록의 개수는 2보다 크거나 같아야 (-> len(그룹) == 1 이면 continue ??)
# <기준 블록> : 무지개 블록(0) 이 아닌 블록 중에서 행의 번호가 가장 작은 블록 => 열의 번호가 가장 작은 블록
## 왼쪽 반시계 90도 수행
def rotate(a):
n = len(a)
m = len(a[0])
b = [[0]*n for _ in range(m)]
for i in range(m):
for j in range(n):
b[i][j] = a[j][m - i - 1]
return b
## 오토 플레이 수행 (블록 그룹이 존재하지 않으면 게임 종료)
from collections import deque
score = 0
colors = [num for num in range(1, m+1)]
turn = 0
while True:
ok = False
turn += 1
## 1 단계. 크기가 가장 큰 블록 그룹 찾기
### (블록 그룹의 크기 up / 무지개 블록의 개수 up / 기준 블록의 행 up / 기준 블록의 열 up)
### len(temp) cnt row col
check = [[False]*n for _ in range(n)]
groups = []
# for line in check:
# print(line)
for i in range(n):
for j in range(n):
if a[i][j] in [num for num in range(1, m+1)] and check[i][j] == False:
# 해당 블록을 기준으로 탐색 시작
check[i][j] = True
idx = a[i][j] # 해당 블록의 색깔 번호
q = deque([(i, j)])
temp = []
temp.append((i, j))
cnt = 0
row = i
col = j
while q:
x, y = q.popleft()
for k in range(4):
nx, ny = x+dx[k], y+dy[k]
if 0<=nx<n and 0<=ny<n:
if a[nx][ny] == -1: # 검은색 블록
continue
if a[nx][ny] == idx and check[nx][ny] == False: # 일반 블록
q.append((nx, ny))
check[nx][ny] = True ###
temp.append((nx, ny))
# <기준 블록> : 무지개 블록(0) 이 아닌 블록 중에서 행의 번호가 가장 작은 블록 => 열의 번호가 가장 작은 블록
if row > nx: row = nx
if col > ny: col = ny
elif a[nx][ny] == 0 and (nx, ny) not in temp: # (아직 해당 그룹에서는 방문한 적 없는) 무지개 블록
q.append((nx, ny))
temp.append((nx, ny))
cnt += 1 ###
if len(temp) >= 2:
ok = True
groups.append([len(temp), cnt, row, col, temp])
if ok == False:
break
## 2 단계. 해당 블록 그룹의 모든 블록 제거 + len(그룹) ** 2 만큼 점수획득
groups.sort(reverse = True)
best_group = groups[0]
score += (best_group[0] ** 2)
for (remove_x, remove_y) in best_group[4]:
a[remove_x][remove_y] = -8 # 제거
# for line in a:
# print(line)
## (격자에 중력이 작용하면 검은색 블록을 제외한 모든 블록이 행의 번호가 큰 칸으로 이동한다.
# 이동은 다른 블록이나 격자의 경계를 만나기 전까지 계속 된다.)
## 3 단계. 격자에 중력 작용
for col in range(0, n):
## <1. 이동 대상(블록) 선정>
row = n-1 ###
while row > -1:
##if col == 0: print(row, col, n, a[row][col])
if a[row][col] == -1 or a[row][col] == -8: # 검은색 or 빈칸
row -= 1
continue
else:
## <2. 중력 이동 수행>
idx = row ### (이동시킬 블록의 행 실시간 위치)
for standard in range(row+1, n):
if a[standard][col] != -8: # 이동할 칸에 다른 블록이 있으면(=빈칸이 아니면)
break
else: # SWAP
a[standard][col], a[idx][col] = a[idx][col], a[standard][col]
idx += 1
row -= 1
# print('### 결과 ###')
# for line in a:
# print(line)
## 4 단계. 격자 90도 반시계 회전
a = rotate(a)
# print('### 결과 ###')
# for line in a:
# print(line)
## 5 단계. 격자에 다시 중력 작용
for col in range(0, n):
## <1. 이동 대상(블록) 선정>
row = n-1 ###
while row > -1:
##if col == 0: print(row, col, n, a[row][col])
if a[row][col] == -1 or a[row][col] == -8: # 검은색 or 빈칸
row -= 1
continue
else:
## <2. 중력 이동 수행>
idx = row ### (이동시킬 블록의 행 실시간 위치)
for standard in range(row+1, n):
if a[standard][col] != -8: # 이동할 칸에 다른 블록이 있으면(=빈칸이 아니면)
break
else: # SWAP
a[standard][col], a[idx][col] = a[idx][col], a[standard][col]
idx += 1
row -= 1
# print('### 결과 ###')
# for line in a:
# print(line)
print(score)
Metadata
Metadata
Assignees
Labels
No labels
