다희의 코딩 성장일기
[SWEA] 5650. 핀볼게임 (자바 JAVA) 본문
[ 문제 ] [SWEA] 5650. 핀볼게임 (자바 JAVA)
# 접근 방법 및 풀이
- 구현 시뮬레이션 문제다. 생각보다 정말 오랜시간 걸려서 풀었다.. 댓글이 가장 많길래 논란이 있는 문젠가 싶었더니 역시 고려해주어야 할 부분이 많아 까다로웠다.
- 근데 쉽게 생각하면 정말 문제 그 대 로 구현하면 된다.
- 러프한 로직은 다음과 같이 생각했다.
- 1. 출발지 선택
- 2. 이동처리
- 2-1. 웜홀 빠졌을 때
- 2-2. 벽을 만났을 때
- 2-3. 블럭을 만났을 때
- 2-4. 블랙홀 or 출발점으로 돌아왔을때 -> 게임종료
- 생각보다 쉽네~! 하고 막 풀었더니 역시 무한루프를 도는 상황 발생.. 진짜 이 문제는 디버깅 한참했다. 예시로 주어진 테케 5개중 1번으로만 해도 정확히 푼다면 통과한다.
- 먼저, 문제에서 임의의 출발지와 방향을 선택한다고 되어있다. 따라서 출발지 선택은 빈공간 0일경우, departList에 r, c 좌표를 담았다.
- departList의 모든 출발 좌표를 탐색하고, 좌표에서 4가지 방향을 다 보아야하므로 2중 for문을 사용했다.
- "출발 좌표"와 "방향"을 선택했다면, go()메소드를 통해 핀볼을 쭉 이동시켜보고 점수를 반환한다. 반환한 점수의 최대값이 정답이 된다.
- 이동처리는 go메소드로 따로 로직을 뺐다.
- 여기서 중요한건, "현재 내위치", "다음으로 갈 곳" 두가지 상태에서 생각해야한다. 다음으로 갈 곳 기준만 한다면 벽밖으로 나갔다 오는거 고려해야되는데 그렇게는 안 짰다!
- 처음엔 다음에 갈곳이 "벽이면, 블록이면, 웜홀이면, 종료조건"이면 이렇게 다음에 갈 곳만 생각해서 짰는데 이렇게 하면 안된다.
- 현재 내가 있는 위치가 "빈공간", "블록"에 따라 다음에 갈 방향이 나뉘어지고, 다음 갈 곳이 달라지기 때문에 현재 내 위치가 무엇인지도 파악해야한다.
- 따라서 현재 내 위치 map[r][c]가 빈공간, 블록인지 나누어 다음에 갈 곳을 정해준다.
- 빈공간이라면 현재 내 방향 그대로 다음 위치 nr, nc를 정해주면 되지만, 블록일 경우 방향을 블록에 따라 바꾸고, 그 방향으로 다음위치 nr, nc를 구해야한다.
- 블록은 1~5로 표현하므로, 1 <= map[r][c] <= 5일 경우, 방향 d를 문제 조건에 맞게 바꿔주면된다.
- 나는 1~5블록마다 switch문을 통해 분기를 해주었는데, 각각의 블록은 수직일때와 수평일때로 나누어 방향 값을 변경했다. 여기서 실수하면 ^^.......최악이다. 그리고 블록일 경우 점수 cnt를 증가시켜준다.
- 이렇게 다음에 갈 위치(nr, nc)를 정해주었다면, nr, nc가 "벽일 경우", "웜홀일 경우", "종료할 경우" 3가지로 나누어 분기해주면 된다.
- 벽일경우 (범위밖), 방향을 반대로 바꾸어주고, 다음에 갈 위치는 원래 위치로 바꾼다. nr = r, nc = c 그리고 벽도 마찬가지로 점수를 증가시켜준다.
- 종료조건일 경우, 블랙홀 일 때와 첫 출발좌표일 경우 종료
- 웜홀을 만났을 경우, 짝 웜홀 위치로 nr, nc를 변경해주면 된다.
- 그리고 최종적으로 r = nr, c = nc로 다음갈 위치로 현재 위치 좌표를 변경해주고 종료조건 만나기 전까지 while문으로 반복돌면 끝!
- 자세한건 코드참조
# 주의할 점
- 현재 내 위치가 빈공간인지, 블록인지에 따라 다음에 갈 방향이 달라지므로 nr, nc 좌표가 달라짐.
- 혹시 로직에서 웜홀 무한루프를 돌고 있지 않은지 체크
- 벽에서 방향 반대로 바꿨는데, 현재 위치가 블록일 경우 블록의 수직 수평에 따라 다른 방향으로 설정해서 잘 가는지 체크
JAVA 코드
package 모의SW역량테스트;
import java.awt.Point;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class swea_5650_핀볼게임 {
static int ans = 0, N;
static int map[][];
static int dr[] = { -1, 0, 1, 0 };
static int dc[] = { 0, -1, 0, 1 };
static List<Point>[] warm;
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int T = Integer.parseInt(in.readLine());
for (int tc = 1; tc <= T; tc++) {
ans = 0;
N = Integer.parseInt(in.readLine());
map = new int[N][N];
List<Point> departList = new ArrayList<Point>();
warm = new ArrayList[11];
for (int i = 6; i <= 10; i++) {
warm[i] = new ArrayList<>();
}
for (int i = 0; i < map.length; i++) {
st = new StringTokenizer(in.readLine());
for (int j = 0; j < map.length; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
if (map[i][j] == 0) {
departList.add(new Point(i, j));
}
if (map[i][j] >= 6) {
warm[map[i][j]].add(new Point(i, j));
}
}
} // 입력끝
for (Point point : departList) {
for (int d = 0; d < 4; d++) {
int cnt = go(point.x, point.y, d);
ans = Math.max(ans, cnt);
}
}
System.out.println("#" + tc + " " + ans);
}
}
private static int go(int startR, int startC, int d) {
int cnt = 0;
boolean flag = false;
int r = startR;
int c = startC;
while (true) {
int nr = 0;
int nc = 0;
int num = map[r][c];
// 블록
if (1 <= num && num <= 5) {
cnt++;
switch (num) {
case 1: {
if (d == 0 || d == 3) {
d = (d % 2 == 0) ? 2 - d : 4 - d;
} else {
d = (d == 1) ? 0 : 3;
}
break;
}
case 2: {
if (d == 2 || d == 3) {
d = (d % 2 == 0) ? 2 - d : 4 - d;
} else {
d = (d == 0) ? 3 : 2;
}
break;
}
case 3: {
if (d == 1 || d == 2) {
d = (d % 2 == 0) ? 2 - d : 4 - d;
} else {
d = (d == 0) ? 1 : 2;
}
break;
}
case 4: {
if (d == 0 || d == 1) {
d = (d % 2 == 0) ? 2 - d : 4 - d;
} else {
d = (d == 2) ? 1 : 0;
}
break;
}
case 5: {
d = (d % 2 == 0) ? 2 - d : 4 - d;
break;
}
}
}
nr = r + dr[d];
nc = c + dc[d];
// 벽
if (nr < 0 || nr >= N || nc < 0 || nc >= N) {
d = (d % 2 == 0) ? 2 - d : 4 - d;
cnt++;
nr = r;
nc = c;
}
// 종료조건
if (map[nr][nc] == -1 || (nr == startR && nc == startC)) {
break;
}
if (map[nr][nc] >= 6) {// 웜홀
int warmNum = map[nr][nc];
for (int i = 0; i < 2; i++) {
if (warm[warmNum].get(i).x == nr && warm[warmNum].get(i).y == nc) {
nr = (i == 0) ? warm[warmNum].get(1).x : warm[warmNum].get(0).x;
nc = (i == 0) ? warm[warmNum].get(1).y : warm[warmNum].get(0).y;
break;
}
}
}
r = nr;
c = nc;
}
return cnt;
}
}
REVIEW
'Algorithm > SWEA' 카테고리의 다른 글
[SWEA] 5658. 보물상자 비밀번호 (자바 JAVA) (0) | 2021.10.04 |
---|---|
[SWEA] 1953. 탈주범 검거(자바 JAVA) (0) | 2021.09.10 |
[SWEA] 4012. 요리사 (자바 JAVA) (0) | 2021.09.09 |
Comments