본문 바로가기
백준

[백준, JAVA]17780번, 새로운 게임

by 열정적인 이찬형 2022. 7. 3.

문제 링크

 

17780번: 새로운 게임

재현이는 주변을 살펴보던 중 체스판과 말을 이용해서 새로운 게임을 만들기로 했다. 새로운 게임은 크기가 N×N인 체스판에서 진행되고, 사용하는 말의 개수는 K개이다. 말은 원판모양이고, 하

www.acmicpc.net


주의사항

  • JAVA를 사용하여 프로그램을 사용하였습니다.
  • 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{ 	
	public static void main(String[] args){
    }
}

문제 설명


접근 방법

이 문제에 핵심

1. 한 번의 턴에 1~K번의 말이 차례대로 이동합니다.

2. 이동하려는 칸에 색에 따라 말의 상태를 변경해줍니다.

3. 한 칸에 말이 4개 이상있을 때까지 진행됩니다.

4. 1000턴이 넘어갈 경우 -1을 결과로 출력합니다.

5.1000턴 이전에 한 칸에 4개 이상의 말이 존재하는 최소 턴을 결과로 출력합니다.

 

한 번의 턴마다 각 말들을 방향대로 이동하는 시뮬레이션이 되도록 구현하였습니다.

 

※해당 칸에 첫 번째 말만 이동이 가능합니다.

 

이동하려는 칸에 색에 따라 말의 상태가 변경됩니다.

 

흰색(0)

해당 칸으로 말을 이동, 이미 칸에 말이 있을 경우 해당 말 위에 순서대로 쌓인다.

 

빨간색(1)

해당 칸으로 말을 이동, 이미 칸에 말이 있는 경우 해당 말 위에 역순으로 쌓인다.

 

파란색(2) | 체스판에 벗어날 경우

해당 말 방향을 반대로 바꾸고 이동, 반대로 바꾸고 이동할 칸도 파란색이나 벗어난 경우일 때는 이동X

 

체스판에 말이 쌓일 수 있으므로 ArrayList<>형태의 배열로 만들었습니다.

 

문제에서는 예제입력 1이 진행되는 과정을 참고하시면서 제 코드를 살펴보시면 이해가 잘 될 것입니다.

 

  • BufferedReader를 사용하여 입력 값을 받았습니다.
  • StringTokenizer을 이용하여 체스판과 말에 대한 정보를 저장하였습니다.
  • 게임을 진행하여 말이 4개 쌓이는 최소 턴을 구하는 gameStart함수를 실행하였습니다.
  • 말이 4개 쌓이지 못하면 -1, 쌓이면 최소 턴을 BufferedWriter에 저장합니다.
  • BufferedWriter에 저장된 결과값을 출력하였습니다.
  • gameStart는 각 턴마다 각 말들을 이동하도록 시뮬레이션을 진행하는 함수입니다.
  • outBoard는 이동하려는 칸이 체스판에 벗어나는지 확인하는 함수입니다. 
  • redMove 이동하려는 칸이 빨간 칸일 때 해당 칸에 역순으로 말이 쌓이는 함수입니다.
  • whiteMove는 이동하려는 칸이 하얀 칸일 때 해당 칸에 차례대로 말이 쌓이는 함수입니다.
  • directionChange는 파란칸에 만났을 때 방향을 반대로 바꾸는 함수입니다.
import java.util.*;
import java.io.*;

public class Main {
	//말 관련 정보 클래스
    static class pieces{
        int x, y, direction;
        public pieces(int x, int y, int direction) {
            this.x = x;
            this.y = y;
            this.direction = direction;
        }
    }
    static int N,K;
    static ArrayList<Integer>[][] board;	//체스판에 쌓인 말 정보 저장 배열
    static pieces[] chessPieces;	//말에 대한 정보 저장 배열
    static int[][] chessBoard;		//체스판 정보 저장 배열
    static int[] dx = {1, -1, 0, 0};	//좌우상하 x값 변경
    static int[] dy = {0, 0, -1, 1};	//좌우상하 y값 변경
    static public void  main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //입력값 처리하는 BufferedReader
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        //결과값 출력하는 BufferedWriter
        StringTokenizer st = new StringTokenizer(br.readLine()," ");
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
        board = new ArrayList[N][N];
        chessBoard = new int[N][N];
        chessPieces = new pieces[K];
        //입력된 체스판 정보 저장
        for(int i=0;i<N;i++){
            st = new StringTokenizer(br.readLine(), " ");
            for(int j=0;j<N;j++)
                chessBoard[i][j] = Integer.parseInt(st.nextToken());
        }
       
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++)
                board[i][j] = new ArrayList();
        }
        //말에 대한 정보 저장
        for(int i=0;i<K;i++){
            st = new StringTokenizer(br.readLine()," ");
            int y = Integer.parseInt(st.nextToken())-1;
            int x = Integer.parseInt(st.nextToken())-1;
            int direction = Integer.parseInt(st.nextToken());
            chessPieces[i] = new pieces(x,y,direction-1);
            board[y][x].add(i);
        }
        int result = gameStart();	//게임 시작 함수 실행
        bw.write(result + "\n");	//턴 BufferedWriter 저장
        bw.flush();		//결과 출력
        bw.close();
        br.close();
    }
    //게임을 진행하는 함수
    static int gameStart(){
        int turn = 0;
        while(true){
            turn++;
            if(turn>1000)		//턴이 1000을 넘어갔을 때
                return -1;
            for(int i=0;i<K;i++){
                int x = chessPieces[i].x;
                int y = chessPieces[i].y;
                int direction = chessPieces[i].direction;
                if(board[y][x].get(0) != i)	//해당 칸 첫 번째 말이 아닌 경우 이동 X
                    continue;
                //해당 방향으로 이동
                int tempX = x + dx[direction];
                int tempY = y + dy[direction];
                if(outBoard(tempX,tempY) || chessBoard[tempY][tempX]==2){//파란 칸일 때
                    int tempDirection = directionChange(direction);	//방향 바꾸기
                    chessPieces[i].direction = tempDirection;
                    //방향 바꾸고 한 칸 이동해보기
                    tempX = x + dx[tempDirection];
                    tempY = y + dy[tempDirection];
                    //이동한 칸이 파란색일 때, 이동 X
                    if(outBoard(tempX,tempY) || chessBoard[tempY][tempX]==2){
                        continue;
                    }else if(chessBoard[tempY][tempX] == 1){	//이동한 칸이 빨간 칸일 때
                        redMove(x,y,tempX,tempY);
                    }else		//이동한 칸이 흰 칸일 때
                        whiteMove(x,y,tempX,tempY);

                }else if(chessBoard[tempY][tempX] == 1){	//빨간칸일 때
                    redMove(x,y,tempX,tempY);
                }else{		//하얀칸일 때
                    whiteMove(x,y,tempX,tempY);
                }
                if(board[tempY][tempX].size() >= 4)	//이동한 칸에 말이 4개 이상 쌓일 때
                    return turn;	//현재 턴 반환
            }
        }
    }
    //체스판에 벗어나는지 확인하는 함수
    static boolean outBoard(int x, int y){
        return x < 0 || y < 0 || x >= N || y >= N;
    }
    //이동하려는 칸이 빨간색일 때 역순으로 해당 칸에 말을 쌓는 함수
    static void redMove(int x, int y, int tempX, int tempY){
        for(int i=board[y][x].size()-1;i>=0;i--){
            int temp = board[y][x].get(i);
            board[tempY][tempX].add(temp);
            chessPieces[temp].x = tempX;
            chessPieces[temp].y = tempY;
        }
        board[y][x].clear();
    }
    //이동하려는 칸이 하얀색일 때 해당 칸에 말을 쌓는 함수
    static void  whiteMove(int x, int y, int tempX, int tempY){
        for(int i=0;i<board[y][x].size();i++){
            int temp = board[y][x].get(i);
            board[tempY][tempX].add(temp);
            chessPieces[temp].x = tempX;
            chessPieces[temp].y = tempY;
        }
        board[y][x].clear();
    }
    //말의 방향 반대로 바꾸는 함수
    static int directionChange(int direction){
        if(direction==0)	//좌
            return 1;
        else if(direction==1)	//우
            return 0;
        else if(direction==2)	//상
            return 3;
        else		//하
            return 2;
    }
}

댓글