(JAVA) 5650. [모의 SW 역량테스트] 핀볼 게임

Standard

문제 링크: https://www.swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRF8s6ezEDFAUo

솔직히 한 번에 문제를 어떻게 풀어야 할지 구상이 안 되서 엄청 복잡하게 짜다가 갈아엎고 단순화해서 구현함. (그래도 소스는 복잡해 보임)
– 처음에 map을 만들 때, 블랙홀과 웜홀들 (웜홀 별로)의 위치를 기록함
– 경우의 수는 NXN의 위치, 상하좌우의 방향 (4가지)해서 4*N2 가지의 경우가 성립한다.
(단, 웜홀, 블랙홀, 특수 블록들은 시작 위치가 될 수 없으므로 제외)
– 현재 방향은 윗 방향/아랫 방향/왼쪽 방향/오른쪽 방향 총 4가지 이고
각 방향에서 가장 edge에 (순서대로 맨 윗줄, 맨 아랫줄, 맨 왼쪽 줄, 맨 오른쪽 줄) 있는 경우와 그 외의 경우로 크게 나눴다.
edge에 있는 경우는 각 블록 별로 몇 번 부딪히고 방향은 어디로 바뀌는지 미리 계산하고 (부딪히고 돌아오는 것으로 보고 위치는 수정하지 않음) / 이외의 경우는 블록에 따라 원하는 방향으로 가지 못하는 경우 (부딪히고 방향 바뀜), 원하는 방향으로 가는 경우 (부딪히고 방향 바뀜 or 위치만 이동)로 나누어 구현. (주석은 귀찮아서 윗 방향일 때만 full로 달았음)
– 아무래도 현재 위치/현재 블록/다음 블록 과 같이 조건의 조합이 많아서 좀 복잡했는데, 차분하게 디버깅하면서 짜니 결국은 원하는 답이 나옴.

import java.io.*;
import java.util.*;

public class Solution {
	public static void main(String[] args) throws IOException {
		//System.setIn(new FileInputStream("./src/sample_input.txt"));
		
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
		
		try {
			int numCases = Integer.parseInt(reader.readLine());
	
			for (int num = 0; num < numCases; num++) {
				writer.write("#" + String.valueOf(num + 1) + " ");
				int numN = Integer.parseInt(reader.readLine()); // map 크기
				
				int[][] map = new int[numN][numN];
				Map<Integer, List<String>> wormhole = new HashMap<Integer, List<String>>(); // 웜홀 (6~10)
				List<String> blackhole = new ArrayList<String>();		// 블랙홀
				
				// 맵 만들기
				for (int i = 0; i < numN; i++) {
					String[] tmp = reader.readLine().split(" ");
					
					for (int j = 0; j < tmp.length; j++) {
						map[j][i] = Integer.parseInt(tmp[j]);

						int tmp_ = map[j][i];
						
						if (tmp_ >= 6 || tmp_ == -1) {
							switch (tmp_) {
							case -1: // 블랙홀
								blackhole.add(j + "/" + i);
								break;
							case 6:  // 웜홀 6
							case 7:  // 웜홀 7
							case 8:  // 웜홀 8
							case 9:  // 웜홀 9
							case 10: // 웜홀 10
								if (wormhole.containsKey(tmp_) == false)
									wormhole.put(tmp_, new ArrayList<String>());
								
								wormhole.get(tmp_).add(j + "/" + i);
								break;
							}
						}
					}
				}
				
				// 실제 진행
				int startX = 0, startY = 0;
				int X = 0, Y = 0, direction = 0; // 현재 X, Y, 방향
				int maxScore = 0;
				
				for (int i = 0; i < numN; i++) { 
					for (int j = 0; j < numN; j++) {
						// 블록, 웜홀, 블랙홀: 시작점이 될 수 없음
						if (map[i][j] != 0)
							continue;
						
						startX = i; // 시작점 
						startY = j; // 끝점
						
						// 방향별 / 0: 위, 1: 아래, 2: 왼쪽, 3: 오른쪽 
						for (int k = 0; k < 4; k++) {
							X = startX; // 초기화 (X)
							Y = startY; // 초기화 (Y)
							direction = k; // 초기화 (방향)
							int score = 0; // 초기화 (점수)
							
							boolean isFirst = true;

							// 조건이 될 때까지 진행
							while (true) {
								if (isFirst == true) // 처음인 경우 (최초는 X==startX 이고 Y==startY이므로 한 번 진행한 후 확인)
									isFirst = false;
								else if ((X == startX && Y == startY)) // 시작 위치로 돌아오는 경우 (블랙홀은 아래 이동 후 루틴에서 처리)
									break;
								
								int currentBlock = map[X][Y]; // 현재 블록

								// 실제 이동 수행
								switch (direction) {
								case 0: // 위 
									if (Y == 0) { // 맨 윗줄
										if (currentBlock == 0) { // 아무 것도 없는 블록: 벽에 부딪히고 나서 아래로
											score++;
											direction = 1; 
										}
										else if (currentBlock == 1) { // 좌하 직각삼각형:벽에 부딪히고, 블록에 부딪히고 오른쪽으로
											score += 2;
											direction = 3;
										}
										else if (currentBlock == 4) { // 우하 직각삼각형:벽에 부딪히고, 블록에 부딪히고 왼쪽으로
											score += 2;
											direction = 2;
										}
										else if (currentBlock == 2) { // 좌상 직각삼각형: 블록에 부딪히고 오른쪽으로
											score++;
											direction = 3;
										}
										else if (currentBlock == 3) { // 우상 직각삼각형: 블록에 부딪히고 왼쪽으로
											score++;
											direction = 2;
										} // 웜홀: 아무 것도 없는 경우와 동일 
										else if (currentBlock >= 6 && currentBlock <= 10) {
											score++; 
											direction = 1; 
										}
									}
									else { // 이외의 경우
										if (currentBlock == 2) { // 위로 갈 수 없으므로, 부딪힌 후 오른쪽으로 변경되는 것 반영
											score++;
											direction = 3;
										}
										else if (currentBlock == 3) { // 위로 갈 수 없으므로, 부딪힌 후 왼쪽으로 변경되는 것 반영
											score++;
											direction = 2;
										}
										else { // 위로 갈 수 있는 경우 다음 블록 체크
											int nextMap = map[X][Y-1];
											if (nextMap == 1 || nextMap == 4 || nextMap == 5) { // 위로 못 올라오는 경우, 부딪히고 방향 변경
												score++;
												direction = 1;
											}
											else if (nextMap == 2) { // 위로 올라와서 부딪히고 오른쪽으로 향함
												score++;
												direction = 3;
												Y--;
											}
											else if (nextMap == 3) { // 위로 올라와서 부딪히고 왼쪽으로 향함
												score++;
												direction = 2;
												Y--;
											}
											else // 일반블럭, 웜홀, 블랙홀은 위치만 이동 (웜홀, 블랙홀은 차후 처리) 
												Y--;
										}
									}
									break;
								case 1: // 아래 
									if (Y == numN - 1) { // 맨 아랫줄
										if (currentBlock == 0) {
											score++;
											direction = 0; 
										}
										else if (currentBlock == 2) {
											score += 2;
											direction = 3;
										}
										else if (currentBlock == 3) {
											score += 2;
											direction = 2;
										}
										else if (currentBlock == 1) { // 위에 부딪혀서 내려온 경우 
											score++;
											direction = 3;
										}
										else if (currentBlock == 4) { // 위에 부딪혀서 내려온 경우 
											score++;
											direction = 2;											
										}
										else if (currentBlock >= 6 && currentBlock <= 10) {
											score++;
											direction = 0; 
										}
									}
									else { // 이외의 경우
										if (currentBlock == 1) {
											score++;
											direction = 3;
										}
										else if (currentBlock == 4) {
											score++;
											direction = 2;
										}
										else {
											int nextMap = map[X][Y+1];
											if (nextMap == 2 || nextMap == 3 || nextMap == 5) { // 아래로 못 내려가는 경우
												score++;
												direction = 0;
											}
											else if (nextMap == 1) {
												score++;
												direction = 3;
												Y++;
											}
											else if (nextMap == 4) {
												score++;
												direction = 2;
												Y++;
											}
											else
												Y++;
										}
									}
									break;
								case 2: // 왼쪽 
									if (X == 0) { // 맨 왼쪽줄
										if (currentBlock == 0) {
											score++;
											direction = 3; 
										}
										else if (currentBlock == 3) {
											score += 2;
											direction = 1;
										}
										else if (currentBlock == 4) {
											score += 2;
											direction = 0;
										}
										else if (currentBlock == 1) {
											score++;
											direction = 0;
										}
										else if (currentBlock == 2) {
											score++;
											direction = 1;
										}
										else if (currentBlock >= 6 && currentBlock <= 10) {
											score++;
											direction = 3; 
										}
									}
									else { // 이외의 경우
										if (currentBlock == 1) {
											score++;
											direction = 0;
										}
										else if (currentBlock == 2) {
											score++;
											direction = 1;
										}
										else {
											int nextMap = map[X-1][Y];
											if (nextMap == 3 || nextMap == 4 || nextMap == 5) { // 왼쪽으로 못 가는 경우
												score++;
												direction = 3;
											}
											else if (nextMap == 1) {
												score++;
												direction = 0;
												X--;
											}
											else if (nextMap == 2) {
												score++;
												direction = 1;
												X--;
											}
											else
												X--;
										}
									}
									break;
								case 3: // 오른쪽
									if (X == numN - 1) { // 맨 오른쪽줄
										if (currentBlock == 0) {
											score++;
											direction = 2; 
										}
										else if (currentBlock == 1) {
											score += 2;
											direction = 0;
										}
										else if (currentBlock == 2) {
											score += 2;
											direction = 1;
										}	
										else if (currentBlock == 3) {
											score++;
											direction = 1;
										}
										else if (currentBlock == 4) {
											score++;
											direction = 0;
										}
										else if (currentBlock >= 6 && currentBlock <= 10) {
											score++;
											direction = 2; 
										}
									}
									else { // 이외의 경우
										if (currentBlock == 3) { 
											score++;
											direction = 1;
										}
										else if (currentBlock == 4) {
											score++;
											direction = 0;
										}
										else {
											int nextMap = map[X+1][Y];
											if (nextMap == 1 || nextMap == 2 || nextMap == 5) { // 오른쪽으로 못 가는 경우
												score++;
												direction = 2;
											}
											else if (nextMap == 3) {
												score++;
												direction = 1;
												X++;
											}
											else if (nextMap == 4) {
												score++;
												direction = 0;
												X++;
											}
											else
												X++;
										}
									}
									break;
								}
									
								// 웜홀 처리
								if (map[X][Y] >= 6 && map[X][Y] <= 10) {
									List<String> wormholePair = wormhole.get(map[X][Y]);
									for (String pos: wormholePair) {
										if (pos.equals(X + "/" + Y) == false) { // 지금 웜홀과 다른 웜홀을 발견하면 그 곳으로 이동
											String[] tmp__ = pos.split("/");
											X = Integer.parseInt(tmp__[0]);
											Y = Integer.parseInt(tmp__[1]);
											break;												
										}
									}
								}
								// 블랙홀 처리 
								else if (map[X][Y] == -1)
									break;
							}
							
							if (maxScore < score) {
								maxScore = score;
							}
						}						
					}					
				}	
				
				writer.write(maxScore + System.lineSeparator());
				writer.flush();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.