백준 17837 새로운 게임 2(Java,자바)

jonghyukLee·2021년 11월 3일
0

이번에 풀어본 문제는
백준 17837번 새로운 게임 2 입니다.

📕 문제 링크

❗️코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

class Piece
{
    int x,y,dir;

    public Piece(int x, int y, int dir)
    {
        this.x = x;
        this.y = y;
        this.dir = dir;
    }
}
public class Main {
    static int N,K;
    static List<Integer>[][] map;
    static Piece [] piece;
    static int [] dx = {0,0,-1,1};
    static int [] dy = {1,-1,0,0}; //우 좌 상 하

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());

        map = new List[N][N];
        piece = new Piece[K+1];

        for(int i = 0; i < N; ++i) // 0흰 1빨 2파
        {
            st = new StringTokenizer(br.readLine());
            for(int j = 0; j < N; ++j)
            {
                map[i][j] = new ArrayList<>();
                map[i][j].add(Integer.parseInt(st.nextToken()));
            }
        }

        for(int i = 1; i <= K; ++i)
        {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken())-1;
            int y = Integer.parseInt(st.nextToken())-1;
            int dir = Integer.parseInt(st.nextToken())-1;
            piece[i] = new Piece(x,y,dir);
            map[x][y].add(i);
        }

        int t = 0;
        boolean flag = false;
        loop : while(t++ < 1000)
        {
            for(int i = 1; i <= K; ++i)
            {
                flag = next(piece[i],i);
                if(flag) break loop;
            }

        }
        int answer = t == 1001 ? -1 : t;
        System.out.print(answer);
    }
    static boolean next(Piece p,int n)
    {
        int cur_x = p.x;
        int cur_y = p.y;
        int level = 0;
        int size = map[cur_x][cur_y].size();
        for(int i = 1; i < size; ++i)
        {
            if(map[cur_x][cur_y].get(i) == n)
            {
                level = i;
                break;
            }
        }
        int mx = cur_x + dx[p.dir];
        int my = cur_y + dy[p.dir];
        int nextBlock = 2;

        if(isValid(mx,my)) nextBlock = map[mx][my].get(0);

        if(nextBlock == 2) // 범위벗어났거나 파란블록
        {
            if(p.dir == 0) p.dir = 1;
            else if(p.dir == 1) p.dir = 0;
            else if(p.dir == 2) p.dir = 3;
            else p.dir = 2;

            mx = cur_x + dx[p.dir];
            my = cur_y + dy[p.dir];

            if(!isValid(mx,my) || map[mx][my].get(0) == 2) return false;
            else
            {
                return move(map[mx][my].get(0),level,size,cur_x,cur_y,mx,my);
            }
        }
        else
        {
            return move(nextBlock,level,size,cur_x,cur_y,mx,my);
        }
    }
    static boolean move(int color,int start, int end, int x, int y, int mx,int my)
    {
        List<Integer> tmp_list = map[x][y].subList(start,end);
        int start_size = tmp_list.size();
        int end_size = map[mx][my].size();
        if(start_size + end_size > 4) return true;
        if(color == 0) 
        {
            for(int i : tmp_list)
            {
                map[mx][my].add(i);
                piece[i].x = mx;
                piece[i].y = my;
            }
        }
        else
        {
            for(int i = start_size-1; i >= 0; --i)
            {
                int num = tmp_list.get(i);
                map[mx][my].add(num);
                piece[num].x = mx;
                piece[num].y = my;
            }
        }
        map[x][y].subList(start,end).clear();
        return false;
    }
    static boolean isValid(int x, int y)
    {
        return x >= 0 && y >= 0 && x < N && y < N;
    }
}

📝 풀이

이동할 블록의 색상에 따라 다른 조건을 수행하는 게임입니다. 우선 이동시 블록이 탑처럼 쌓이므로 List형태의 2차원 배열을 맵으로 사용했고, 각 리스트의 0번째 인덱스는 입력값으로 주어진 발판의 색상입니다. piece 배열은 각 번호의 좌표값과 방향을 지니고 있으며, 인덱스 값이 각 번호를 뜻합니다. 따라서 1부터 K번까지 순차적으로 next함수로 보내주어 이동을 수행합니다. next 함수에서는 다음 이동할 발판의 색상을 판단하여 move함수로 보내줍니다. 범위를 벗어난 것 또한 파란 발판으로 판단했고, 흰색 또는 빨간색 발판일 경우 move함수를 통해 이동을 수행해줍니다. move함수에서는 먼저 이동하는 리스트의 크기와 목적지에 쌓여진 리스트 크기를 더해 4가 넘는다면, 0번 인덱스를 제외하고 쌓인 탑의 크기가 4이상이므로 즉시 true를 리턴하여 반복을 벗어날 수 있도록 했습니다. 그 이외에는 다음 발판으로 리스트를 넘겨주며 주어진 조건을 수행합니다.

📜 후기

주어진 조건이 복잡했고, 테스트를 직관적으로 만들기 조금 까다로운 구조여서 생각보다 시간이 오래걸렸습니다. 그래도 나름 재밌게 풀었던 문제입니다 ^^

profile
머무르지 않기!

0개의 댓글