-
[백준]12100: 2048(Easy)(java)Algorithm/백준 2022. 5. 5. 23:40728x90
https://www.acmicpc.net/problem/12100
문제
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