[구름톤 챌린지] 10일차 미션 GameJam - JavaScript
문제 출처
문제 설명
플레이어는 GmaeJam에 참가했다. GameJam은 현장에서 즉석으로 팀을 꾸려 게임의 규칙을 만든 뒤, 생각한 규칙을 코드로 옮겨서 게임을 만들어내는 대회이다.
플레이어가 속한 팀은 보드로 즐길 수 있는 간단한 보드게임을 만들었다. 게임의 진행 방법과 규친은 다음과 같다.
- 게임은 한 변의 길이가 N인 격자 보드 위에서 진행한다. 보드는 한 변의 길이가 1인 N^2개의 칸으로 나누어져 있다.
- 각 칸에는 command에 해당하는 방향으로 count 칸만큼 한 칸씩 이동하라는 지시가 적혀있다.
- 플레이하는 사람은 처음에 보드의 칸 중 하나에 말을 올려놓는다.
- 각 칸에 적힌 지시대로 말을 이동한다. 만약 이동 중에 보드 밖으로 나가게 된다면 반대쪽의 첫 번째 칸으로 이동한다.
- 만약 이동하다가 자신의 말이 이미 방문한 칸을 다시 지나야 할 경우에는 게임이 종료된다. 그 외의 경우 게임이 종료될 때까지 위의 4번 단계를 반복한다.
- 게임 점수는 시작칸을 포함한 말이 방문한 칸의 개수이다.
플레이어는 GameJam의 최종 발표 때 게임을 시연해 보기 위해, 구름이와 미리 연습게임을 진행해 보려고 한다. 플레이어와 구름이가 각각의 게임에서 처음에 말을 올려둔 칸이 주어졌을 때, 두 사람 중 누가 더 높은 점수를 흭득했는지를 구해보자.
구름이가 게임에서 승리하면 goorm과 구름이가 얻은 점수를 공백을 두고 출력하고, 플레이어가 승리하면 player와 플레이어가 얻은 점수를 공백을 두고 출력한다. 두 사람이 비기는 테스트 케이스는 주어지지 않는다.
제한 조건
- 첫째 줄에 격자 보드의 크기 N이 주어진다.
- 둘째 줄에는 구름이가 말을 올려둔 칸의 좌표가 공백을 두고 주어진다.
- 셋째 줄에는 플레이어가 말을 올려둔 칸의 좌표가 공백을 두고 주어진다.
- 다음 N개의 줄에는 보드의 각 칸에 적혀있는 지시 사항이 주어진다.
- command는 U, D, R, L 중 하나이다. 각각 위, 아래, 오른쪽, 왼쪽을 의미한다.
- 3 <= N <= 200
예시
입력 예
3
1 1
3 3
1L 2L 1D
2U 3R 1D
2R 2R 1U
출력 예
goorm 4
풀이
const readline = require("readline");
let rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
let input = [];
rl.on("line", (line) => {
input.push(line);
});
rl.on("close", () => {
// 격자 보드의 크기
const N = Number(input[0]);
// 구름이 좌표 [1, 1]
let gxy = input[1].split(" ").map((n) => Number(n) - 1);
// 플레이어 좌표 [3, 3]
let pxy = input[2].split(" ").map((n) => Number(n) - 1);
// 보드
const board = input.slice(3).map((b) => b.split(" "));
// 각 점수를 구하는 함수
const goormScore = playGame(N, board, gxy);
const playerScore = playGame(N, board, pxy);
console.log(
goormScore > playerScore ? "goorm " + goormScore : "player " + playerScore
);
});
// 게임 점수를 구하는 함수
function playGame(N, board, xy) {
// 보드 크기와 같은 크기의 체크 배열 생성
const check = Array.from({ length: N }, () => Array(N).fill(0));
// 상 하 좌 우
const command = {
U: [-1, 0],
D: [1, 0],
R: [0, 1],
L: [0, -1],
};
// 받아온 좌표
let [x, y] = xy;
// 게임을 종료시키는 플레그
let flag = true;
while (flag) {
// 지시사항 분리
// (N이 200까지라 200R의 경우 split으로 분리 불가)
const len = board[x][y].length - 1;
const cnt = Number(board[x][y].substring(0, len));
const cmd = board[x][y].substring(len);
// 위에 선언해 둔 이동할 좌표
const [tx, ty] = command[cmd];
// 구한 count만큼 for문을 통해 이동한다.
for (let i = 0; i < cnt; i++) {
// 이동하려는 장소가 이미 방문한 장소라면 종료
if (check[x][y] === 1) {
flag = false;
break;
}
// 방문 체크
check[x][y] = 1;
// 이동
x += tx;
y += ty;
// 칸이 넘어갔을 경우 반대 쪽으로 이동
if (x < 0) x = N - 1;
if (x === N) x = 0;
if (y < 0) y = N - 1;
if (y === N) y = 0;
}
}
// 점수 구함
return check.flat().filter((n) => n === 1).length;
}
정리
현재 구름톤 챌린지가 진행중인데 하루에 한 문제를 풀면서 머리를 굴려보아요.
피드백은 언제나 환영입니다. 😊
사용한 메서드
split() 메서드 - MDN
slice() 메서드 - MDN
map() 메서드 - MDN
flat() 메서드 - MDN
filter() 메서드 - MDN
substring() 메서드 - MDN
구조 분해 할당 - MDN