상호는 전차로 시가전을 하는 것을 테마로 한 새로운 게임 “배틀 필드”를 개발하기로 했다.
그래서 먼저 간단하게 프로토 타입 게임을 만들었다.
이 프로토 타입에서 등장하는 전차는 사용자의 전차 하나뿐이며, 적이나 아군으로 만들어진 전차는 등장하지 않는다.
사용자의 전차는 사용자의 입력에 따라 격자판으로 이루어진 게임 맵에서 다양한 동작을 한다.
다음 표는 게임 맵의 구성 요소를 나타낸다.
| 문자 | 의미 |
|---|---|
| . | 평지(전차가 들어갈 수 있다.) |
| * | 벽돌로 만들어진 벽 |
| # | 강철로 만들어진 벽 |
| - | 물(전차는 들어갈 수 없다.) |
| ^ | 위쪽을 바라보는 전차(아래는 평지이다.) |
| v | 아래쪽을 바라보는 전차(아래는 평지이다.) |
| > | 왼쪽을 바라보는 전차(아래는 평지이다.) |
| < | 오르쪽을 바라보는 전차(아래는 평지이다.) |
다음 표는 사용자가 넣을 수 있는 입력의 종류를 나타낸다.
| 문자 | 동작 |
|---|---|
U : Up | 전차가 바라보는 방향을 위쪽으로 바꾸고, 한 칸 위의 칸이 평지라면 위 그 칸으로 이동한다. |
D : Down | 전차가 바라보는 방향을 아래쪽으로 바꾸고, 한 칸 아래의 칸이 평지라면 그 칸으로 이동한다. |
L : Left | 전차가 바라보는 방향을 왼쪽으로 바꾸고, 한 칸 왼쪽의 칸이 평지라면 그 칸으로 이동한다. |
R : Right | 전차가 바라보는 방향을 오른쪽으로 바꾸고, 한 칸 오른쪽의 칸이 평지라면 그 칸으로 이동한다. |
S : Shoot | 전차가 현재 바라보고 있는 방향으로 포탄을 발사한다. |
전차가 이동을 하려고 할 때, 만약 게임 맵 밖이라면 전차는 당연히 이동하지 않는다.
전차가 포탄을 발사하면, 포탄은 벽돌로 만들어진 벽 또는 강철로 만들어진 벽에 충돌하거나 게임 맵 밖으로 나갈 때까지 직진한다.
만약 포탄이 벽에 부딪히면 포탄은 소멸하고, 부딪힌 벽이 벽돌로 만들어진 벽이라면 이 벽은 파괴되어 칸은 평지가 된다.
강철로 만들어진 벽에 포탄이 부딪히면 아무 일도 일어나지 않는다.
게임 맵 밖으로 포탄이 나가면 아무런 일도 일어나지 않는다.
초기 게임 맵의 상태와 사용자가 넣을 입력이 순서대로 주어질 때, 모든 입력을 처리하고 나면 게임 맵의 상태가 어떻게 되는지 구하는 프로그램을 작성하라.
첫 번째 줄에 테스트 케이스의 수 T가 주어진다.
각 테스트 케이스의 첫 번째 줄에는 두 정수 H, W (2 ≤ H, W ≤ 20) 이 공백으로 구분되어 주어진다.
이는 게임 맵의 높이가 H, 너비가 W임을 나타낸다.
즉, 게임 맵은 H x W크기의 격자판이다.
다음 H개의 각각의 줄에는 길이가 W인 문자열이 주어진다.
각각의 문자는 위의 게임 맵 구성 요소 표에 있는 문자들만 포함하며, 전차는 단 하나만 있다.
다음 줄에는 사용자가 넣을 입력의 개수를 나타내는 정수 N(0 < N ≤ 100) 이 주어진다.
다음 줄에는 길이가 N인 문자열이 주어진다.
각각의 문자는 위의 사용자가 넣을 수 있는 입력의 종류를 나타내는 표에 있는 문자들만 포함된다.
각 테스트 케이스마다 ‘#x’(x는 테스트케이스 번호를 의미하며 1부터 시작한다)를 출력하고 한 칸을 띄운 후, 모든 입력을 처리하고 난 후의 게임 맵을 H개의 줄에 걸쳐 출력한다.
1
4 6
*.*..*
*.....
..-...
^.*#..
#1 *....*
......
..-...
..>#..
package live06._02_상호의_배틀필드;
import java.util.*;
import java.io.*;
public class Solution {
static int H, W;
static char[][] map;
static int tankR, tankC, dir;
static int[] dr = { -1, 1, 0, 0 };
static int[] dc = { 0, 0, -1, 1 };
static char[] tankDir = { '^', 'v', '<', '>' };
public static void main(String[] args) throws IOException {
System.setIn(new FileInputStream("src/live06/_02_상호의_배틀필드/input.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
for (int tc = 1; tc <= T; tc++) {
st = new StringTokenizer(br.readLine());
H = Integer.parseInt(st.nextToken());
W = Integer.parseInt(st.nextToken());
map = new char[H][W];
tankR = 0;
tankC = 0;
dir = 0;
for (int i = 0; i < H; i++) {
String road = br.readLine();
for (int j = 0; j < W; j++) {
map[i][j] = road.charAt(j);
if (map[i][j] == '^' || map[i][j] == 'v' || map[i][j] == '<' || map[i][j] == '>') {
tankR = i;
tankC = j;
switch (map[i][j]) {
case '^': dir = 0; break;
case 'v': dir = 1; break;
case '<': dir = 2; break;
case '>': dir = 3; break;
}
}
}
}
int N = Integer.parseInt(br.readLine());
String cmdLine = br.readLine();
for (int i = 0; i < N; i++) {
char cmd = cmdLine.charAt(i);
switch (cmd) {
case 'U': move(0); break;
case 'D': move(1); break;
case 'L': move(2); break;
case 'R': move(3); break;
case 'S': shoot(); break;
}
}
StringBuilder sb = new StringBuilder();
sb.append("#").append(tc).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());
}
br.close();
bw.close();
}
static void move(int nextDir) {
dir = nextDir;
map[tankR][tankC] = tankDir[dir];
int nr = tankR + dr[dir];
int nc = tankC + dc[dir];
if (nr < 0 || nc < 0 || nr >= H || nc >= W) return;
if (map[nr][nc] != '.') return;
map[tankR][tankC] = '.';
tankR = nr;
tankC = nc;
map[tankR][tankC] = tankDir[dir];
}
static void shoot() {
int nr = tankR + dr[dir];
int nc = tankC + dc[dir];
while (nr >= 0 && nc >= 0 && nr < H && nc < W) {
if (map[nr][nc] == '*') {
map[nr][nc] = '.';
return;
}
if (map[nr][nc] == '#') return;
nr += dr[dir];
nc += dc[dir];
}
}
}
전역 변수
- 아래 함수들에서 사용할 전역 변수들을 선언한다.
- 이 때
dr & dc와tankDir를 상하좌우로 꼭 매칭해줘야한다.
static int H, W; // 맵의 가로, 세로 크기
static char[][] map; // 맵의 정보를 받을 변수
static int tankR, tankC, dir; // 몇 번째 행렬에 있고, 어느 방향을 바라보는지
static int[] dr = { -1, 1, 0, 0 }; // 행 좌표 이동
static int[] dc = { 0, 0, -1, 1 }; // 열 좌표 이동
static char[] tankDir = { '^', 'v', '<', '>' }; // 상하좌우
main
- 초기화와 함수 사용을 담당한다.
- 매 테스트 케이스마다 다음의 변수들을 초기화해야한다.
H, W, map, tankR, tankC, dir- 또한, 초기값도 다시 대입해야한다.
if (map[i][j] == '^' || map[i][j] == 'v'
|| map[i][j] == '<' || map[i][j] == '>')
{
tankR = i; // 탱크 시작 좌표 Row
tankC = j; // 탱크 시작 좌표 Col
// 탱크가 바라보는 방향 초기화
switch (map[i][j]) {
case '^':
dir = 0;
break;
case 'v':
dir = 1;
break;
case '<':
dir = 2;
break;
case '>':
dir = 3;
break;
}
}
- 변수들을 초기화했으니 이제 움직이고 포탄을 발사할 차례
- 들어오는 명령에 따라
Switch을 적용시킨다.- 아래
int N = Integer.parseInt(br.readLine()); // 명령어 갯수
String cmdLine = br.readLine(); // 명령어 줄
for (int i = 0; i < N; i++) {
char cmd = cmdLine.charAt(i); // 명령어
switch (cmd) {
case 'U': // 위로 돌고 평지면 이동
move(0);
break;
case 'D': // 아래로 돌고 평지면 이동
move(1);
break;
case 'L': // 좌로 돌고 평지면 이동
move(2);
break;
case 'R': // 우로 돌고 평지면 이동
move(3);
break;
case 'S': // 포탄 발사
shoot();
break;
}
}
- 위 코드까지 진행되면,
map은 값이 변해있고, 출력만하면 되는 상태가 된다.
StringBuilder sb = new StringBuilder();
sb.append("#").append(tc).append(" ");
// 값이 변경된 map 입력받기
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()); // 출력
move 함수
- 현재 전차 방향
dir을 명령으로 들어온 방향으로 변경- 방향 변경하고 이동, 이 때 이동이 실패하더라도 방향은 변경되어야함
- 맵 밖이거나, 평지가 아닌 경우 예외 처리
- 전차가 지나가는 영역을 초기화
- 전차가 있던 칸을 평지로 초기화
- 전차 좌표 이동 후 그 위치의 전차 방향 표시
static void move(int nextDir) {
dir = nextDir;
// 이동이 실패해도 방향은 바뀜
map[tankR][tankC] = tankDir[dir];
int nr = tankR + dr[dir]; // 탱크 다음 행 좌표
int nc = tankC + dc[dir]; // 탱크 다음 열 좌표
// 맵 밖이거나 평지가 아닐 때
if (nr < 0 || nc < 0 || nr >= H || nc >= W) return;
if (map[nr][nc] != '.') return;
map[tankR][tankC] = '.'; // 평지 초기화
tankR = nr; // 다음 행으로 이동할 준비
tankC = nc; // 다음 열로 이동할 준비
map[tankR][tankC] = tankDir[dir]; // 다음 좌표에 탱그 방향 표시
}
shoot 함수
- 현재 탱크가 바라보는 방향으로 포탄 발사
- 포탄이 처음 위치할 행렬 좌표 설정
- 포탄이 맵 안에 있는 동안 계속 직진
- 벽돌 벽이거나, 강철 벽이거나, 벽을 만나지 않았거나 예외 처리
static void shoot() {
int nr = tankR + dr[dir];
int nc = tankC + dc[dir];
while (nr >= 0 && nc >= 0 && nr < H && nc < W) {
// 벽돌 벽 만나면 평지로 바꾸고 이동 끝
if (map[nr][nc] == '*') {
map[nr][nc] = '.';
return;
}
// 강철 벽 만나면 이동 끝
if (map[nr][nc] == '#') return;
// 뭔가 만날 때까지 게속 이동
nr += dr[dir];
nc += dc[dir];
}
}