JavaScript

[구름톤 챌린지] 2주차_폭탄 구현하기

김꼬알 2023. 8. 25. 12:18

 

 필요한 개념


  • 시뮬레이션
  • list 메소드

 

 

문제 분석


문제를 풀기 위해서는 2차원 배열에서의 탐색이 필요하다.

이후에는 주어지는 폭탄 데이터를 입력 받아 문제의 요구 사항대로 구현하면 된다.

모든 폭탄이 떨어진 이후에, 배열에서 가장 큰 값을 찾아야 한다.

반복문으로 찾을 수 있지만, 배열의 단계를 낮춰주는 메소드를 사용해서 해결할 수 있다.

 

  • 폭탄이 떨어지면, 떨어진 위치를 기준으로 십자가 영역의 폭탄 값이 조건에 따라서 증가
    • # 는 폭탄 값의 영향을 받지 않음
    • 0 이면 폭탄 값이 1만큼 증가
    • @ 라면 폭탄 값이 2만큼 증가
  • 모든 폭탄이 떨어진 이후에 폭탄 앖이 가장 높은 값을 출력

 

 

데이터의 입력


// 입력

4 4
0 0 @ 0
0 0 0 0
0 # 0 0
0 0 0 @
2 2
2 3
1 4
1 4

이 문제는 위의 데이터를 입력 받아야 하기 때문에 복잡하다.

입력을 받으면서 바로 변수를 갱신해줘야 한다.

기존에 선언된 N, K를 입력과 동시에 할당해주고, 입력의 길이가 N + M + 1만큼 되면 rl.close() 를 호출한다.

 

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

let input = [];
let N, K;
rl.on('line', (line) => {
	if (input.length === 0){
		input.push(line);
		[N, K] = input[0].split(' ').map(Number)
	}else{
		input.push(line.trim());
	}
	if (input.length === N + K + 1){
		rl.close();	
	}
})

 

 

점수 행렬 만들기


특정 값으로 채워져 있는 행렬을 선언하는 이유는 현재 땅의 상태를 수정할 수 없기 때문에 점수만 기록할 행렬을 따로 선언해준다.

이 행렬의 모든 초기 값은 0이므로, 한 변의 길이가 N이고 0으로 채워져 있는 배열을 만든다.

 

  • Array.from
let score = Array.from({ length: N }, () => Array(N).fill(0));

 

  • 반복문 사용
let score = new Array(N);
for(let i = 0; i < N; i++) {
    score[i] = new Array(N).fill(0);
}

 

 

탐색 구현하기


우선 폭탄을 한 번 떨어트리는 코드가 필요하다.

하나의 폭탄이 떨어지면 상하좌우에 폭탄의 영향을 끼치고, 영향을 받은 위치의 값에 따라서 영향을 끼치는 정도가 달라진다.

그리고 폭탄의 영향은 떨어진 위치도 받기 때문에, dx/dy 기법에서는 원래 위치와 더불어 상하좌우를 탐색할 수 있도록 코드를 작성한다.

// 원래 위치와 상하좌우
let dx = [0, 0, 0, 1, -1];
let dy = [0, 1, -1, 0, 0];

 

구현과 탐색을 할 때 중요한 점은 탐색을 해도 되는 부분인지 확인해야 한다.

이 문제에서 행렬의 범위를 넘어가는 경우와, 행렬의 값이 # 이라면 탐색하지 않아도 문제가 없다.

그래서 현재의 (x, y)에서 탐색을 진행했을 때, 범위를 나가거나 matrix[nx][ny] 의 값이 # 이라면 탐색을 하지 않도록 한다.

rl.on('close', () => {
	// matrix, score 행렬 선언 부분
	..code
	
	// 탐색 및 구현 부분
	for (let i = N+1; i <= N+K ; i++){
		// 떨어지는 폭탄의 위치를 [x, y]에 할당
		let [x, y] = input[i].trim().split(' ').map(Number);
		// 인덱스 조정
		x -= 1;
		y -= 1;
		// dx/dy가 5곳을 탐색하기 때문에 반복문의 길이도 5
		for ( let j = 0 ; j < 5 ; j++){
			let nx = x + dx[j];
			let ny = y + dy[j];
			// 행렬의 범위를 나가거나, 탐색할 행렬의 값이 #이라면 탐색하지 않음
			if (nx >= 0 && nx < N && ny >= 0 && ny < N && matrix[nx][ny] !== '#') {
				// 폭탄 값의 영향을 받는 경우의 구현
		}
	}
	process.exit();
}

 

 

폭탄 구현하기


마지막으로 구현할 부분은 아래와 같다.

  • 땅의 상태가 0 이라면 폭탄 값은 1 증가한다.
  • 땅의 상태가 @ 이라면 폭탄 값은 2 증가한다.

 

땅의 상태는 matrix 에서 조회하고, 폭탄 값은 score 에서 조회하면 된다.

  • matirx[nx][ny] 의 값이 @ 일 때, score[nx][ny] 의 값을 2 추가합니다.
  • matirx[nx][ny] 의 값이 0일 때, score[nx][ny] 의 값을 1 추가합니다.
rl.on('close', () => {
	..code
	for (let i = N+1; i <= N+K ; i++){
		let [x, y] = input[i].trim().split(' ').map(Number);
		x -= 1;
		y -= 1;
		for ( let j = 0 ; j < 5 ; j++){
			let nx = x + dx[j];
			let ny = y + dy[j];
			if (nx >= 0 && nx < N && ny >= 0 && ny < N && matrix[nx][ny] !== '#') {
				//matrix[nx][ny]의 값이 @ 일때, score[nx][ny] 값을 +2 을 한다.
				if (matrix[nx][ny] === '@') {
					score[nx][ny] += 2;
				}
				// matrix[nx][ny]값이 @가 아니라면, score[nx][ny] 값을 +1 을 한다.
				} else {
					score[nx][ny] += 1;
				}
			}
		}
	}
	console.log(score);
	process.exit();
})

 

 

행렬을 배열로


score 행렬에 모든 폭탄 값들이 저장되어 있는데, 최대 폭탄 값을 찾는 방법은 두 가지 이다.

 

  • 배열을 순회하면서 찾기
let max = -1; // 초기 최대값을 가장 작은 수로 설정
for (let i = 0; i < score.length; i++) {
  for (let j = 0; j < score[i].length; j++) {
    if (score[i][j] > max) {
      max = score[i][j];
    }
  }
}
const result = max

 

  • list.flat() 사용

list.flat() 은 행렬을 배열로 바꿔준다.

배열의 요소로 또 다른 배열이 있다면, 그 배열을 한 단계 낮춰준다.

그리고 나서 Math.max() 를 사용하면 배열의 요소 중 최대 값을 간단하게 찾을 수 있다.

let arr1 = [1, 2, [3, 4]];
arr1.flat(); 
// [1, 2, 3, 4]

let arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

const result = Math.max(...score.flat())

 

 

 

dx/dy 문제를 한 번 풀어봤는데도 막상 구현하려고 하니 아직은 쉽지 않았다.

그리고 이번엔, 조건에 맞게 점수를 바꿔줘야 해서 더 어렵게 느껴졌다.

어떤 것을 구현해야 할지 정리하고 하나씩 해나가는 과정을 정리하고 나니 어렵지 않은데, 아직은 문제를 분석하는 연습이 부족하다고 느껴진다.

구름톤 챌린지를 하면서 문제를 풀어보고 해설을 자세히 확인할 수 있어 복습하고 정리하면서 도움이 되는 것 같다.