상호의 배틀 필드

Huisu·2024년 8월 25일
0

Coding Test Practice

목록 보기
113/119
post-thumbnail

문제

문제 설명

상호는 전차로 시가전을 하는 것을 테마로 한 새로운 게임 “배틀 필드”를 개발하기로 했다.

그래서 먼저 간단하게 프로토 타입 게임을 만들었다.

이 프로토 타입에서 등장하는 전차는 사용자의 전차 하나뿐이며, 적이나 아군으로 만들어진 전차는 등장하지 않는다.

사용자의 전차는 사용자의 입력에 따라 격자판으로 이루어진 게임 맵에서 다양한 동작을 한다.

다음 표는 게임 맵의 구성 요소를 나타낸다.

문자의미
.평지(전차가 들어갈 수 있다.)
*벽돌로 만들어진 벽
#강철로 만들어진 벽
-물(전차는 들어갈 수 없다.)
^위쪽을 바라보는 전차(아래는 평지이다.)
v아래쪽을 바라보는 전차(아래는 평지이다.)
<왼쪽을 바라보는 전차(아래는 평지이다.)
>오른쪽을 바라보는 전차(아래는 평지이다.)

다음 표는 사용자가 넣을 수 있는 입력의 종류를 나타낸다.

문자동작
UUp : 전차가 바라보는 방향을 위쪽으로 바꾸고, 한 칸 위의 칸이 평지라면 위 그 칸으로 이동한다.
DDown : 전차가 바라보는 방향을 아래쪽으로 바꾸고, 한 칸 아래의 칸이 평지라면 그 칸으로 이동한다.
LLeft : 전차가 바라보는 방향을 왼쪽으로 바꾸고, 한 칸 왼쪽의 칸이 평지라면 그 칸으로 이동한다.
RRight : 전차가 바라보는 방향을 오른쪽으로 바꾸고, 한 칸 오른쪽의 칸이 평지라면 그 칸으로 이동한다.
SShoot : 전차가 현재 바라보고 있는 방향으로 포탄을 발사한다.

전차가 이동을 하려고 할 때, 만약 게임 맵 밖이라면 전차는 당연히 이동하지 않는다.

전차가 포탄을 발사하면, 포탄은 벽돌로 만들어진 벽 또는 강철로 만들어진 벽에 충돌하거나 게임 맵 밖으로 나갈 때까지 직진한다.

만약 포탄이 벽에 부딪히면 포탄은 소멸하고, 부딪힌 벽이 벽돌로 만들어진 벽이라면 이 벽은 파괴되어 칸은 평지가 된다.

강철로 만들어진 벽에 포탄이 부딪히면 아무 일도 일어나지 않는다.

게임 맵 밖으로 포탄이 나가면 아무런 일도 일어나지 않는다.

초기 게임 맵의 상태와 사용자가 넣을 입력이 순서대로 주어질 때, 모든 입력을 처리하고 나면 게임 맵의 상태가 어떻게 되는지 구하는 프로그램을 작성하라.

제한 사항

첫 번째 줄에 테스트 케이스의 수 T가 주어진다.

각 테스트 케이스의 첫 번째 줄에는 두 정수 H, W (2 ≤ H, W ≤ 20) 이 공백으로 구분되어 주어진다.

이는 게임 맵의 높이가 H, 너비가 W임을 나타낸다.

즉, 게임 맵은 H x W크기의 격자판이다.

다음 H개의 각각의 줄에는 길이가 W인 문자열이 주어진다.

각각의 문자는 위의 게임 맵 구성 요소 표에 있는 문자들만 포함하며, 전차는 단 하나만 있다.

다음 줄에는 사용자가 넣을 입력의 개수를 나타내는 정수 N(0 < N ≤ 100) 이 주어진다.

다음 줄에는 길이가 N인 문자열이 주어진다.

각각의 문자는 위의 사용자가 넣을 수 있는 입력의 종류를 나타내는 표에 있는 문자들만 포함된다.

각 테스트 케이스마다 ‘#x’(x는 테스트케이스 번호를 의미하며 1부터 시작한다)를 출력하고 한 칸을 띄운 후, 모든 입력을 처리하고 난 후의 게임 맵을 H개의 줄에 걸쳐 출력한다.

입출력 예

입력출력
1
3 7
***....
*-..#**#1 **....v
#<.****.-..#..
23#......
SURSSSSUSLSRSSSURRDSRDS

입출력 예 설명

아이디어

switch문 써서 시뮬레이션 실행하자

제출 코드


package com.example.javacodingtest.swea;

import java.io.*;
import java.util.StringTokenizer;

/*
 @author ranuinclulus
 @since 2024.08.23
 @link
 @timecomplex
 @performance 18332KB, 123MS
 @category
 @note
 */
public class three1873 {
    class Tank {
        int row;
        int col;
        int direction;

        public Tank(int row, int col, char direction) {
            this.row = row;
            this.col = col;
            switch(direction) {
                case '^':
                    this.direction = 0;
                    break;
                case 'v':
                    this.direction = 1;
                    break;
                case '<':
                    this.direction = 2;
                    break;
                case '>':
                    this.direction = 3;
                    break;
            }
        }
    }
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static StringBuilder sb = new StringBuilder();
    static StringTokenizer st;
    static int testNum;
    static int h;
    static int w;
    static char[][] map;
    static int n;
    static char[] operations;
    static Tank tank;
    static int[][] deltas = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 상 하 좌 우
    public void solution() throws IOException {
        testNum = Integer.parseInt(br.readLine());
        for (int test = 1; test <= testNum; test++) {
            // 입력
            st = new StringTokenizer(br.readLine());
            h = Integer.parseInt(st.nextToken());
            w = Integer.parseInt(st.nextToken());
            map = new char[h][w];
            for (int i = 0; i < h; i++) {
                map[i] = br.readLine().toCharArray();
            }
            
            for (int i = 0; i < h; i++) {
                for (int j = 0; j < w; j++) {
                    if (map[i][j] == '^' ||
                        map[i][j] == 'v' ||
                        map[i][j] == '<' ||
                        map[i][j] == '>') {
                        tank = new Tank(i, j, map[i][j]);
                    }
                }
            }
            n = Integer.parseInt(br.readLine());
            operations = br.readLine().toCharArray();
            
            for(char operation : operations) {
                switch(operation) {
                    case 'U':
                        tank.direction = 0;
                        map[tank.row][tank.col] = '^';
                        moveOne();
                        break;
                    case 'D':
                        tank.direction = 1;
                        map[tank.row][tank.col] = 'v';
                        moveOne();
                        break;
                    case 'L':
                        tank.direction = 2;
                        map[tank.row][tank.col] = '<';
                        moveOne();
                        break;
                    case 'R':
                        tank.direction = 3;
                        map[tank.row][tank.col] = '>';
                        moveOne();
                        break;
                    case 'S':
                        shooting();
                        break;
                }
            }

            sb.append("#").append(test).append(" ");
            for (int i = 0; i < h; i++) {
                for (int j = 0; j < w; j++) {
                    sb.append(map[i][j]);
                }
                sb.append("\n");
            }

        }
        bw.write(sb.toString());
        bw.flush();
    }

    private void shooting() {
        int nextRow = tank.row + deltas[tank.direction][0];
        int nextCol = tank.col + deltas[tank.direction][1];
        while (nextRow >= 0 && nextRow < h && nextCol >= 0 && nextCol < w) {
            if (map[nextRow][nextCol] != '.' && map[nextRow][nextCol] != '-') break;
            nextRow += deltas[tank.direction][0];
            nextCol += deltas[tank.direction][1];
        }

        if (nextRow < 0 || nextRow >= h || nextCol < 0 || nextCol >= w) return;
        if (map[nextRow][nextCol] == '#') return;
        if (map[nextRow][nextCol] == '*') map[nextRow][nextCol] = '.';

    }

    private void moveOne() {
        int nextRow = tank.row + deltas[tank.direction][0];
        int nextCol = tank.col + deltas[tank.direction][1];
        
        if (nextRow < 0 || nextRow >= h || nextCol < 0 || nextCol >= w) return;
        if (map[nextRow][nextCol] != '.') return;
        map[nextRow][nextCol] = map[tank.row][tank.col];
        map[tank.row][tank.col] = '.';
        tank.row = nextRow;
        tank.col = nextCol;
    }

    public static void main(String[] args) throws IOException {
        new three1873().solution();
    }
}

전략

Tank 객체 생성

  • 탱크의 현재 위치와 방향을 가지는 객체 생성
  • 방향은 deltas의 인덱스와 일치

입력부

  • h * w 사이즈의 지도에 대해 값을 입력받음
  • 만약 ^ v < > 로 입력된 값이 있다면 탱크를 생성

  • 해야 할 작업들을 operations에 저장

연산 수행 껍데기 부분

  • U D L R
    • 탱크의 방향 바꾸기
    • 맵에 표시된 탱크의 방향도 바꾸기
    • 한 칸 이동하는 함수 실행
  • S
    • 슈팅 함수 실행

moveOne

  • 탱크가 현재 바라보는 방향으로 이동했을 시의 좌표를 받아서
  • 맵 밖이라면 패스
  • 뚫린 길이 아니라면 패스
  • 이동하려는 칸에 탱크를 두고 원래 탱크가 있던 칸은 . 으로 바꾸기
  • 탱크의 위치 재설정

shooting

  • 탱크가 현재 바라보는 방향으로 이동했을 시의 좌표를 계속 받아옴
  • 지도 안 경우일 때만 와일문 실행
  • 만약 뚫린 길인 .이 아니고 강인 -가 아닌, 즉 강철이든 벽돌이든 막힌 곳을 만나면 nextRow, nextCol 갱신 중단
  • 마지막으로 갱신된 위치가 맵 안인지 확인
  • 강철을 만난 거라면 패스
  • 벽돌을 만난 거라면 뿌셔서 . 만들기

느낀 점

  • direction과 ^ v < >과의 변환이 많아서 이걸 해시맵으로 선언한 뒤에 관리했다면 조금 더 편하지 않았을까
  • U D L R 과 S이 나뉘는 기분임
    • 따라서 U D L R에 반복되는 코드를 많이 짠 것 같은데.. 현재는 이 반복 작업을 더 단순화할 방법이 생각나지 않음 ㅜ

0개의 댓글