오늘은 2018 카카오 1차 기출인 프로그래머스 프렌즈 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 | answer |
---|---|---|---|
4 | 5 | ["CCBDE", "AAADE", "AAABF", "CCBBF"] | 14 |
6 | 6 | ["TTTANT", "RRFACC", "RRRFCC", "TRRRAA", "TTMMMF", "TMMTTJ"] | 15 |
입력 값의 크기가 최대 900 이기 때문에 쉽게 접근해서 정확히 푸는 문제가 아닐까 생각했다.
문제를 크게 두 과정으로 나누어서 진행할 수 있는데 4개의 문자가 동일한 블록을 확인하는 과정과 블록이 사라지고 난 뒤 위에 있던 블록들이 아래로 내려오도록 조정하는 과정이다.
지워질 수 있는 블록들을 확인하는 과정에서 중복되는 블록이 없도록 하는 방법을 조금 고민했는데, 다른 블로그 글을 참고해 set
자료형을 사용할 수 있음을 참고했다. (1,1) - (m-1,n-1) 을 탐색하면서 4개의 블록이 빈칸이 아니고 모두 같은지 확인하고 해당 블록 위치를 쌍으로 묶어서 set
에 저장했다. 이후 탐색이 끝나면 set
의 크기가 지워질 수 있는 블록의 수로 반환되고 해당 값이 0보다 크면 반복해서 탐색할 수 있도록 했다.
위에 있던 블록들을 아래로 내리는 과정도 역시 고민 했지만, 그냥 무식하게 하는게 좋을 것 같았다. 1열부터 n열까지 밑에서부터 빈칸이 아닌 블록 문자만 vector
에 담아두고 이것을 다시 m 행부터 위쪽으로 빈칸없이 입력 후 남은 칸들은 모두 빈칸으로 처리 할 수 있도록 했다.
어렵지 않은 것 같은데 왜 까다롭지..? 싶었는데 기출 해설을 보니 난이도가 상으로 표시되어 있어서 의외면서도 약간 끄덕여졌다. 고민 없이 바로 정확하게 풀 수 있는 능력을 보는 문제였던 것 같다.
#include <string>
#include <vector>
#include <set>
// 프로그래머스 프렌즈4블록, level2
using namespace std;
vector<vector<char>> matrix;
int countRemovable(int m, int n){
set<pair<int, int>> check;
vector<vector<char>> removed = matrix;
for (int i = 1; i <= m-1; ++i) {
for (int j = 1; j <= n-1; ++j) {
if ( matrix[i][j]!='-' && matrix[i][j] == matrix[i][j+1] && matrix[i][j] == matrix[i+1][j] && matrix[i][j] == matrix[i+1][j+1]) {
removed[i][j] = '-';
if (check.find({i, j}) == check.end()) check.insert({i, j});
removed[i][j + 1] = '-';
if (check.find({i, j + 1}) == check.end()) check.insert({i, j + 1});
removed[i + 1][j] = '-';
if (check.find({i + 1, j}) == check.end()) check.insert({i + 1, j});
removed[i + 1][j + 1] = '-';
if (check.find({i + 1, j + 1}) == check.end()) check.insert({i + 1, j + 1});
}
}
}
matrix = removed;
return check.size();
}
void arrangeBlock(int m, int n){
for (int j = 1; j <= n; ++j) {
vector<char> col;
for (int i = m; i >= 1; --i) {
if (matrix[i][j] != '-') col.push_back(matrix[i][j]);
}
for (int i = 0; i < col.size(); ++i) {
matrix[m-i][j] = col[i];
}
if (col.size() == m) continue;
for (int i = m-col.size(); i >= 1; --i) matrix[i][j] = '-';
}
}
int solution(int m, int n, vector<string> board) {
int answer = 0;
matrix.assign(m+1, vector<char>(n+1, ' '));
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) matrix[i][j] = board[i-1][j-1];
}
int removable = countRemovable(m,n);
answer += removable;
while (removable > 0){
arrangeBlock(m,n);
removable = countRemovable(m,n);
answer += removable;
}
return answer;
}