다희의 코딩 성장일기

[SWEA] 5650. 핀볼게임 (자바 JAVA) 본문

Algorithm/SWEA

[SWEA] 5650. 핀볼게임 (자바 JAVA)

ilmiodiario 2021. 9. 9. 17:27

[ 문제 ]  [SWEA] 5650. 핀볼게임 (자바 JAVA)

 

문제 링크 : https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRF8s6ezEDFAUo&categoryId=AWXRF8s6ezEDFAUo&categoryType=CODE 

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com


# 접근 방법 및 풀이 

 

  • 구현 시뮬레이션 문제다. 생각보다 정말 오랜시간 걸려서 풀었다.. 댓글이 가장 많길래 논란이 있는 문젠가 싶었더니 역시 고려해주어야 할 부분이 많아 까다로웠다.
  • 근데 쉽게 생각하면 정말 문제 그 대 로 구현하면 된다.
  • 러프한 로직은 다음과 같이 생각했다.
  • 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

Comments