프렌즈4블록
블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은 "프렌즈4블록".
같은 모양의 카카오프렌즈 블록이 2×2 형태로 4개가 붙어있을 경우 사라지면서 점수를 얻는 게임이다.

만약 판이 위와 같이 주어질 경우, 라이언이 2×2로 배치된 7개 블록과 콘이 2×2로 배치된 4개 블록이 지워진다. 같은 블록은 여러 2×2에 포함될 수 있으며, 지워지는 조건에 만족하는 2×2 모양이 여러 개 있다면 한꺼번에 지워진다.

블록이 지워진 후에 위에 있는 블록이 아래로 떨어져 빈 공간을 채우게 된다.

만약 빈 공간을 채운 후에 다시 2×2 형태로 같은 모양의 블록이 모이면 다시 지워지고 떨어지고를 반복하게 된다.

위 초기 배치를 문자로 표시하면 아래와 같다.
TTTANT
RRFACC
RRRFCC
TRRRAA
TTMMMF
TMMTTJ
각 문자는 라이언(R), 무지(M), 어피치(A), 프로도(F), 네오(N), 튜브(T), 제이지(J), 콘(C)을 의미한다
입력으로 블록의 첫 배치가 주어졌을 때, 지워지는 블록은 모두 몇 개인지 판단하는 프로그램을 제작하라.
입력 형식
- 입력으로 판의 높이 m, 폭 n과 판의 배치 정보 board가 들어온다.
- 2 ≦ n, m ≦ 30
- board는 길이 n인 문자열 m개의 배열로 주어진다. 블록을 나타내는 문자는 대문자 A에서 Z가 사용된다.
출력 형식
입력으로 주어진 판 정보를 가지고 몇 개의 블록이 지워질지 출력하라.
입출력 예제
m n board answer4 | 5 | ["CCBDE", "AAADE", "AAABF", "CCBBF"] | 14 |
6 | 6 | ["TTTANT", "RRFACC", "RRRFCC", "TRRRAA", "TTMMMF", "TMMTTJ"] | 15 |
예제에 대한 설명
- 입출력 예제 1의 경우, 첫 번째에는 A 블록 6개가 지워지고, 두 번째에는 B 블록 4개와 C 블록 4개가 지워져, 모두 14개의 블록이 지워진다.
- 입출력 예제 2는 본문 설명에 있는 그림을 옮긴 것이다. 11개와 4개의 블록이 차례로 지워지며, 모두 15개의 블록이 지워진다.
풀이 및 소스코드
초기화) 반복 정보를 true 처리한다.(아래 설명)
1. x와 y의 좌표는 m - 2, n -2까지 이동한다. 왜냐하면 검사하는 과정에서 m+1, y+1을 검사하기 때문이다.
5라면 index는 4까지 있는데, 3까지만 직접 좌표를 이동하고 4는 검사 과정에서 자동으로 체크가 된다.
2. map[x][y], map[x][y+1], map[x+1][y+1], map[x+1][y] 가 모두 같다면 네모다. 따라서 맵을 한번 다 훑고 check 배열에 체크를 해 놨다가 맵 전체를 순회하면 그 때에 카운트를 해준다. 그리고 아직 네모가 남아있을 수 있다는 뜻이므로 반복정보를 false로 저장한다.
예제를 1회 체크한 배열의 상태
[false, false, false, false, false, false]
[true, true, false, false, true, true]
[true, true, true, false, true, true]
[false, true, true, false, false, false]
[false, false, false, false, false, false]
[false, false, false, false, false, false]
반드시 1회전이 끝나고 후 처리를 해야함.
3. 체크 배열의 true에 해당하는 위치를 "~"로 변환하고 count한다.
4. 네모가 체크되어 사라진 공간을 체크해야 하는데, 네모인지 검사할때와 반대로 아래서 위로 이동한다.
x좌표를 아래에서 위로 이동하며 빈 공간("~")를 만다면 x좌표가 0이 될 때 까지 -1하여(위로 올라가서) "~"이 아닌 위치를 찾아서 빈공간 위치와 "~" 이 아닌 위치를 교체한다.
5. 반복정보가 false인동안 초기화 ~ 5)를 반복한다. 만약 반복정보가 2번에서 false로 바뀌지 않았다면 다음회전 초기화때 true로 남게되므로 한 바퀴 회전하고 끝이난다
// m = 높이, n = 폭
func solution(_ m:Int, _ n:Int, _ board:[String]) -> Int {
var x = 0, y = 0
var end = false
var map = [[Character]]()
var count = 0
for i in board{
map.append(Array(i))
}
while end != true{
end = true
//네모인지 체크 할 2중배열
var check = [[Bool]](repeating: [Bool](repeating: false, count: n), count: m)
//x, y좌표로 시작
for x_idx in 0..<m-1{
x = x_idx
for y_idx in 0..<n-1{
y = y_idx
//현재 좌표의 값, 현재 좌표가 ("~")가 아니면 네모의 값을 읽어옴
let now = map[x][y]
if now != Character("~"){
let r = map[x][y+1]
let dr = map[x+1][y+1]
let d = map[x+1][y]
//네모면 check배열에 체크
if now == r && r == dr && dr == d{
end = false
check[x][y] = true
check[x][y+1] = true
check[x+1][y+1] = true
check[x+1][y] = true
}
}
}
}
//체크배열의 네모위치에 해당하는 위치를 count 하고 ~로 바꿈
for x in 0..<m{
for y in 0..<n{
if check[x][y] == true{
map[x][y] = Character("~")
count += 1
}
}
}
//빈 공간 채우기
for x in (0..<m).reversed(){
for y in 0..<n{
if map[x][y] == Character("~"){
var x_find = x
while x_find != 0{
x_find -= 1
if map[x_find][y] != Character("~"){
map[x][y] = map[x_find][y]
map[x_find][y] = Character("~")
break
}
}
}
}
}
}
return count
}