[SW Expert] [모의 SW 역량테스트] 5650번 핀볼 게임 (Java)
Algorithm/SW Expert Academy

[SW Expert] [모의 SW 역량테스트] 5650번 핀볼 게임 (Java)

728x90

SW Expert [모의 SW 역량테스트] 5650번 핀볼 게임 :

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRF8s6ezEDFAUo

 

 

모의 SW 역량테스트 중 하나인 핀볼 게임이다.

어렸을 때 핀볼 게임을 해봤던 사람이라면 문제 이해하는 것은 쉬울 것이다.

게임판 안에는 총 5가지의 블록과 웜홀, 블랙홀이 들어 있다.

5가지의 블록 종류

장애물에 부딪히며 움직이다가 블랙홀에 빠지거나 제자리로 돌아오면 게임이 끝나게 된다.

 

모든 경우의 수를 다 따져봐야 하는 브루트 포스 문제이다.

장애물이 없는 모든 구역에서 상하좌우로 핀볼을 움직여야 한다.

이번 문제에서 주요 함수로는 방향을 바꿔주는 changeDir 함수와 핀볼이 움직이기 시작하는 start 함수가 있다.

 

changeDir 함수는 매개변수로 장애물(wall)의 번호와 방향(dir)을 받는다. 방향은 동쪽부터 시계방향으로 0, 1, 2, 3을 지정했다.

장애물과 기존 방향에 따라 변경되는 방향이 달라진다.

각각의 모든 경우에 맞춰서 changeDir 함수에서 그다음 방향을 반환하도록 구현했다.

 

start 함수는 핀볼이 시작 방향으로 출발해서 벽을 몇 번 부딪히는지 count 하는 함수이다.

핀볼의 움직임은 while문으로 반복적으로 이동할 수 있게 하였다.

변수 nx, ny와 ndir은 그다음 핀볼의 위치와 방향을 나타낸다.

그다음 핀볼의 위치가 만약 장애물이라면 ndir은 앞서 만들어 놓았던 changeDir 함수를 사용해 정해준다.

웜홀의 위치는 값을 입력받을 때 index 값을 따로 저장해놓고,

만약 웜홀에 도착했다면 해당 웜홀에 대응되는 반대편 웜홀로 이동하게끔 구현했다.

 

문제를 푸는 데 사소한 팁이 있다면,

핀볼이 가장자리의 벽을 만난다면 방향이 반대방향으로 바뀌게 된다.

이를 쉽게 처리해주려면 map의 크기를 +2씩 해준 뒤, 값을 입력받을 때 가장자리의 값을 5로 처리해준다.

5는 항상 반대방향으로 가기 때문에 앞서 만들었던 changeDir 함수를 적용할 수 있다.

 

코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    private static int n, max;
    private static int[][] map;
    private static Index[][] wormhall;
    private static int[] dx = {0, 1, 0, -1};
    private static int[] dy = {1, 0, -1, 0};

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        int T = Integer.parseInt(br.readLine());
        for (int t = 1; t <= T; t++) {
            n = Integer.parseInt(br.readLine());
            map = new int[n + 2][n + 2];
            wormhall = new Index[5][2];
            max = Integer.MIN_VALUE;

            for (int i = 0; i < n + 2; i++) {
                if (i == 0 || i == n + 1) {
                    for (int j = 0; j < n + 2; j++) {
                        map[i][j] = 5;
                    }
                } else {
                    map[i][0] = 5;
                    map[i][n + 1] = 5;
                    st = new StringTokenizer(br.readLine());
                    for (int j = 1; j <= n; j++) {
                        map[i][j] = Integer.parseInt(st.nextToken());
                        if (6 <= map[i][j] && map[i][j] <= 10) {
                            int index = map[i][j] - 6;
                            if (wormhall[index][0] == null)
                                wormhall[index][0] = new Index(i, j);
                            else
                                wormhall[index][1] = new Index(i, j);
                        }
                    }
                }
            }
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    if (map[i][j] == 0) pinball(i, j);
                }
            }
            System.out.println("#" + t + " " + max);
        }
    }

    private static void pinball(int x, int y) {
        for (int i = 0; i < 4; i++) { // 동서남북
            start(x, y, i);
        }
    }

    private static void start(int x, int y, int dir) {
        int nx = x, ny = y, ndir = dir;
        int count = 0;
        while (true) {
            nx = nx + dx[ndir];
            ny = ny + dy[ndir];
            
            if (nx == x && ny == y) break;

            int num = map[nx][ny]; // 다음 위치의 번호

            if (num == 0) continue;
            else if (num == -1) break; // 블랙홀
            else if (1 <= num && num <= 5) { // 벽 만남
                ndir = changeDir(num, ndir);
                count++;
            } else if (6 <= num && num <= 10) { // 웜홀 만남
                Index[] hall = wormhall[num - 6];
                if (hall[0].x == nx && hall[0].y == ny) {
                    nx = hall[1].x;
                    ny = hall[1].y;
                } else {
                    nx = hall[0].x;
                    ny = hall[0].y;
                }
            }
        }
        if (max < count) max = count;
    }

    private static int changeDir(int wall, int dir) {
        int ndir = (dir + 2) % 4; // 반대 방향
        switch (wall) {
            case 1:
                if (dir == 1) ndir = 0;
                if (dir == 2) ndir = 3;
                break;
            case 2:
                if (dir == 2) ndir = 1;
                if (dir == 3) ndir = 0;
                break;
            case 3:
                if (dir == 0) ndir = 1;
                if (dir == 3) ndir = 2;
                break;
            case 4:
                if (dir == 1) ndir = 2;
                if (dir == 0) ndir = 3;
                break;
        }
        return ndir;
    }
}

class Index {
    int x;
    int y;

    public Index(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

 

728x90