생략
구현 문제이다.
각각에 해당하는 부분은 함수로 나누어서 작성해 주는 게 좋다.
초록색 보드를 돌려놓으면 파란색 보드가 되는 것을 알 수 있다. 그렇기에 파란색 보드에는 돌려놓은 값을 대입하면 된다.
한 줄이 가득 차 있는 경우를 확인할 때 위에서부터 확인해 준 뒤 (왜냐하면 블록은 위에서부터 내려오니까) 가득 찬 경우에는 지워주고 해당 줄 위에서부터 내려오게 해주면 된다.
연한 칸에 값이 존재할 때는 밑을 지우고 위에 있는 값들을 내려오게 하면 된다.
각각의 블록은 줄이 사라지면서 분리되지 않는 한 같이 내려와야 한다. 또한 같은 타입이어도 따로 생성된 것이라면 다른 블록이기에 구분해 주는 값을 대입해 줘야 한다.
같은 타입+같은 블록을 묶어서 내려오게 해주는 것이 중요한 것이다.
도중에 줄이 삭제되면서 1칸으로 되는 경우가 존재한다. 그런 경우에는 타입을 변경하면 된다.
#include <iostream>
using namespace std;
int map[2][6][4]; // false은 초록, true은 파랑
int ret;
// 타입 확인 (끊기는 경우도 있음 그럴 경우 1로 반환)
int checkType(bool isBlue, int x, int y)
{
if (y + 1 < 4 && map[isBlue][x][y] == map[isBlue][x][y + 1])
return 2;
else if (x - 1 >= 0 && map[isBlue][x][y] == map[isBlue][x - 1][y])
return 3;
else
return 1;
}
// 블록 설치해주기
void setBlock(bool isBlue, int x, int y, int t, int idx)
{
map[isBlue][x][y] = idx;
if (t == 2)
map[isBlue][x][y + 1] = idx;
else if (t == 3)
map[isBlue][x - 1][y] = idx;
}
// 밑으로 내려가기
void drop(bool isBlue, int x, int y, int t, int idx)
{
for (int i = x; i < 6; ++i)
{
if (map[isBlue][i][y]) // 해당 위치에 블럭이 있다면 이전 높이에 설치
{
setBlock(isBlue, i - 1, y, t, idx);
return;
}
else if (t == 2 && map[isBlue][i][y + 1]) // 가로가 긴 경우
{
setBlock(isBlue, i - 1, y, t, idx);
return;
}
}
setBlock(isBlue, 5, y, t, idx);
}
// 삭제 후 위의 블럭들 타입 유지하여 밑으로 내리기
void remove(bool isBlue, int x)
{
for (int i = 0; i < 4; ++i)
map[isBlue][x][i] = 0;
for (int i = x - 1; i >= 0; --i)
{
for (int j = 0; j < 4; ++j)
{
if (!map[isBlue][i][j])
continue;
int idx = map[isBlue][i][j];
int type = checkType(isBlue, i, j);
map[isBlue][i][j] = 0;
if (type == 2)
map[isBlue][i][j + 1] = 0;
else if (type == 3)
map[isBlue][i - 1][j] = 0;
drop(isBlue, i, j, type, idx);
}
}
}
// 한 줄이 가득찬지 확인
void checkFull(bool isBlue)
{
for (int i = 0; i < 6; ++i)
{
int cnt = 0;
for (int j = 0; j < 4; ++j)
if (map[isBlue][i][j])
++cnt;
if (cnt == 4)
{
++ret;
remove(isBlue, i);
}
}
}
// 확인 후 가장 밑에 값 삭제
void checkLimit(bool isBlue)
{
for (int i = 0; i <= 1; ++i)
for (int j = 0; j < 4; ++j)
if (map[isBlue][i][j])
remove(isBlue, 5);
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
int N, t, x, y, idx = 0, cnt = 0;
cin >> N;
while (N--)
{
cin >> t >> x >> y;
drop(false, 0, y, t, ++idx);
if (t == 1)
drop(true, 0, x, 1, idx);
else if (t == 2)
drop(true, 0, x, 3, idx);
else
drop(true, 0, x, 2, idx);
checkFull(false);
checkFull(true);
checkLimit(false);
checkLimit(true);
}
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 6; ++j)
for (int k = 0; k < 4; ++k)
if (map[i][j][k])
++cnt;
cout << ret << "\n"
<< cnt;
return 0;
}
어떤 식으로 접근해야 할 진 알겠는데 그대로 구현하면 너무 하드코딩일 것 같아서 다른 사람의 풀이를 참고했다.
처음엔 지도에 타입을 기재해도 될 거로 생각했다. 하지만 타입의 경우 다른 블록과 구분이 안 된다는 점에서 문제가 발생할 수 있다. 그렇기에 고유한 식별 값을 넣어주는 것이 중요하다.