ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준]12100: 2048(Easy)(java)
    Algorithm/백준 2022. 5. 5. 23:40
    728x90

    https://www.acmicpc.net/problem/12100

     

    12100번: 2048 (Easy)

    첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2

    www.acmicpc.net

    문제

    2048 게임은 4×4 크기의 보드에서 혼자 즐기는 재미있는 게임이다. 이 링크를 누르면 게임을 해볼 수 있다.

    이 게임에서 한 번의 이동은 보드 위에 있는 전체 블록을 상하좌우 네 방향 중 하나로 이동시키는 것이다. 이때, 같은 값을 갖는 두 블록이 충돌하면 두 블록은 하나로 합쳐지게 된다. 한 번의 이동에서 이미 합쳐진 블록은 또 다른 블록과 다시 합쳐질 수 없다. (실제 게임에서는 이동을 한 번 할 때마다 블록이 추가되지만, 이 문제에서 블록이 추가되는 경우는 없다)


    <그림 1> <그림 2> <그림 3>

    <그림 1>의 경우에서 위로 블록을 이동시키면 <그림 2>의 상태가 된다. 여기서, 왼쪽으로 블록을 이동시키면 <그림 3>의 상태가 된다.

    <그림 4> <그림 5> <그림 6> <그림 7>

    <그림 4>의 상태에서 블록을 오른쪽으로 이동시키면 <그림 5>가 되고, 여기서 다시 위로 블록을 이동시키면 <그림 6>이 된다. 여기서 오른쪽으로 블록을 이동시켜 <그림 7>을 만들 수 있다.

    <그림 8> <그림 9>

    <그림 8>의 상태에서 왼쪽으로 블록을 옮기면 어떻게 될까? 2가 충돌하기 때문에, 4로 합쳐지게 되고 <그림 9>의 상태가 된다.

    <그림 10> <그림 11> <그림 12> <그림 13>

    <그림 10>에서 위로 블록을 이동시키면 <그림 11>의 상태가 된다. 

    <그림 12>의 경우에 위로 블록을 이동시키면 <그림 13>의 상태가 되는데, 그 이유는 한 번의 이동에서 이미 합쳐진 블록은 또 합쳐질 수 없기 때문이다.

    <그림 14> <그림 15>

    마지막으로, 똑같은 수가 세 개가 있는 경우에는 이동하려고 하는 쪽의 칸이 먼저 합쳐진다. 예를 들어, 위로 이동시키는 경우에는 위쪽에 있는 블록이 먼저 합쳐지게 된다. <그림 14>의 경우에 위로 이동하면 <그림 15>를 만든다.

    이 문제에서 다루는 2048 게임은 보드의 크기가 N×N 이다. 보드의 크기와 보드판의 블록 상태가 주어졌을 때, 최대 5번 이동해서 만들 수 있는 가장 큰 블록의 값을 구하는 프로그램을 작성하시오.

    입력

    첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2보다 크거나 같고, 1024보다 작거나 같은 2의 제곱꼴이다. 블록은 적어도 하나 주어진다.

    출력

    최대 5번 이동시켜서 얻을 수 있는 가장 큰 블록을 출력한다.

    예제 입력 1 

    3
    2 2 2
    4 4 4
    8 8 8
    

    예제 출력 1 

    16

    풀이

    가능한 모든 경우의수를 해본 뒤 최댓값을 구한다.

    현재 배열의 깊은 복사를 통해 현재 배열이 바뀌지 않아야 하는게 핵심이다.

    로직 순서는 다음과 같다.

    1) 왼쪽, 오른쪽, 아래, 위로 민다

    2) 왼쪽, 오른쪽, 아래, 위로 민다 > 무한으로 뎁스를 내려가며 민다.

     

    1) 전체적으로 뎁스를 내려가며 미는 함수

    public static void playGame(int[][] map, int cnt) {
        if(cnt == 5) {
            int maxNum = 0;
            for(int i=0; i<N; i++) {
                for(int j=0; j<N; j++) {
                    if(map[i][j] > maxNum) {
                        maxNum = map[i][j];
                    }
                }
            }
            if(max < maxNum) max =maxNum;
            return;
        }
        int[][] tmp = copyMap(map);
    
        moveUp(tmp);
    
        playGame(tmp, cnt+1);
        tmp = copyMap(map);
        moveDown(tmp);
        playGame(tmp, cnt+1);
        tmp = copyMap(map);
        moveRight(tmp);
        playGame(tmp, cnt+1);
        tmp = copyMap(map);
        moveLeft(tmp);
        playGame(tmp, cnt+1);
    }

    - 총 5번 밀었다면 최대값을 갱신한다.

     

    2) 위로 미는 함수

    public static void moveUp(int[][] map) {
        ArrayList<Integer> list;
        for(int j=0; j<N; j++) {
            list = new ArrayList<>();
            for(int i=0; i<N; i++) {
                if(map[i][j] !=0) {
                    list.add(map[i][j]);
                    map[i][j] = 0;
                }
            }
    
            if(list.size() == 0) continue;
            ArrayList<Integer> result =  sumBlock(list);
            for(int i=0; i<result.size(); i++) {
                map[i][j] = result.get(i);
            }
        }
    }

    위로 밀어야하는 숫자를 세로로 한줄 리스트에 넣는다. 이 때 0은 넣지 않는다.

    list에서 연산이 가능한 수들을 연산한다.

    public static ArrayList<Integer> sumBlock(ArrayList<Integer> list) {
        ArrayList<Integer> sumBlock = new ArrayList<>();
    
        for(int i=0; i<list.size(); i++) {
            if(i+1 >= list.size()) {
                sumBlock.add(list.get(i));
            }
            else if(list.get(i).equals(list.get(i+1))) {
                sumBlock.add(list.get(i) * 2);
                i++;
            } else {
                sumBlock.add(list.get(i));
            }
        }
        return sumBlock;
    }

    이 과정의 무한 반복이다.

     

    전체 코드

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.StringTokenizer;
    
    public class BJ_G2_12100_2048Easy {
        static int N;
        static int max = 0;
        public static void main(String[] args) throws Exception {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st;
            N = Integer.parseInt(br.readLine());
    
            int[][] map = new int[N][N];
            for(int i=0; i<N; i++) {
                st = new StringTokenizer(br.readLine());
                for(int j=0; j<N; j++) {
                    map[i][j] = Integer.parseInt(st.nextToken());
                }
            }
    
            playGame(map, 0);
            System.out.println(max);
        }
    
        public static void playGame(int[][] map, int cnt) {
            if(cnt == 5) {
                int maxNum = 0;
                for(int i=0; i<N; i++) {
                    for(int j=0; j<N; j++) {
                        if(map[i][j] > maxNum) {
                            maxNum = map[i][j];
                        }
                    }
                }
                if(max < maxNum) max =maxNum;
                return;
            }
            int[][] tmp = copyMap(map);
    
            moveUp(tmp);
            playGame(tmp, cnt+1);
            tmp = copyMap(map);
            moveDown(tmp);
            playGame(tmp, cnt+1);
            tmp = copyMap(map);
            moveRight(tmp);
            playGame(tmp, cnt+1);
            tmp = copyMap(map);
            moveLeft(tmp);
            playGame(tmp, cnt+1);
        }
    
        public static ArrayList<Integer> sumBlock(ArrayList<Integer> list) {
            ArrayList<Integer> sumBlock = new ArrayList<>();
    
            for(int i=0; i<list.size(); i++) {
                if(i+1 >= list.size()) {
                    sumBlock.add(list.get(i));
                }
                else if(list.get(i).equals(list.get(i+1))) {
                    sumBlock.add(list.get(i) * 2);
                    i++;
                } else {
                    sumBlock.add(list.get(i));
                }
            }
            return sumBlock;
        }
    
        public static void moveUp(int[][] map) {
            ArrayList<Integer> list;
            for(int j=0; j<N; j++) {
                list = new ArrayList<>();
                for(int i=0; i<N; i++) {
                    if(map[i][j] !=0) {
                        list.add(map[i][j]);
                        map[i][j] = 0;
                    }
                }
    
                if(list.size() == 0) continue;
                ArrayList<Integer> result =  sumBlock(list);
                for(int i=0; i<result.size(); i++) {
                    map[i][j] = result.get(i);
                }
            }
        }
    
        public static void moveDown(int[][] map) {
            ArrayList<Integer> list;
            for(int j=0; j<N; j++) {
                list = new ArrayList<>();
                for(int i=N-1; i>=0; i--) {
                    if(map[i][j] !=0) {
                        list.add(map[i][j]);
                        map[i][j] = 0;
                    }
                }
    
                if(list.size() == 0) continue;
                ArrayList<Integer> result =  sumBlock(list);
                for(int i=0; i<result.size(); i++) {
                    map[N-i-1][j] = result.get(i);
                }
            }
        }
    
        public static void moveLeft(int[][] map) {
            ArrayList<Integer> list;
            for(int i=0; i<N; i++) {
                list = new ArrayList<>();
                for(int j=0; j<N; j++) {
                    if(map[i][j] !=0) {
                        list.add(map[i][j]);
                        map[i][j] = 0;
                    }
                }
    
                if(list.size() == 0) continue;
                ArrayList<Integer> result =  sumBlock(list);
                for(int j=0; j<result.size(); j++) {
                    map[i][j] = result.get(j);
                }
            }
        }
    
        public static void moveRight(int[][] map) {
            ArrayList<Integer> list;
            for(int i=0; i<N; i++) {
                list = new ArrayList<>();
                for(int j=N-1; j>=0; j--) {
                    if(map[i][j] !=0) {
                        list.add(map[i][j]);
                        map[i][j] = 0;
                    }
                }
    
                if(list.size() == 0) continue;
                ArrayList<Integer> result =  sumBlock(list);
                for(int j=0; j<result.size(); j++) {
                    map[i][N-j-1] = result.get(j);
                }
            }
        }
    
    
        public static int[][] copyMap(int[][] map) {
            int[][] tmp = new int[N][N];
            for(int i=0; i<N; i++) {
                for(int j=0; j<N; j++) {
                    tmp[i][j] = map[i][j];
                }
            }
            return tmp;
        }
    }
    
    728x90

    'Algorithm > 백준' 카테고리의 다른 글

    [백준]16197: 두 동전(java)  (0) 2022.05.08
    [백준]2109: 순회강연(java)  (0) 2022.05.07
    [백준]6416: 트리인가?  (0) 2022.05.03
    [백준]20437: 문자열 게임2(java)  (0) 2022.05.02
    [백준]2933: 미네랄(java)  (0) 2022.05.01

    댓글

Designed by Tistory.