[백준] 2503 숫자 야구 JavaScript

·2024년 5월 23일

문제

정보문화진흥원 정보 영재 동아리에서 동아리 활동을 하던 영수와 민혁이는 쉬는 시간을 틈타 숫자야구 게임을 하기로 했다.

영수는 1에서 9까지의 서로 다른 숫자 세 개로 구성된 세 자리 수를 마음속으로 생각한다. (예: 324)
민혁이는 1에서 9까지의 서로 다른 숫자 세 개로 구성된 세 자리 수를 영수에게 묻는다. (예: 123)
민혁이가 말한 세 자리 수에 있는 숫자들 중 하나가 영수의 세 자리 수의 동일한 자리에 위치하면 스트라이크 한 번으로 센다. 숫자가 영수의 세 자리 수에 있긴 하나 다른 자리에 위치하면 볼 한 번으로 센다.
예) 영수가 324를 갖고 있으면

429는 1 스트라이크 1 볼이다.
241은 0 스트라이크 2 볼이다.
924는 2 스트라이크 0 볼이다.
영수는 민혁이가 말한 수가 몇 스트라이크 몇 볼인지를 답해준다.
민혁이가 영수의 세 자리 수를 정확하게 맞추어 3 스트라이크가 되면 게임이 끝난다. 아니라면 민혁이는 새로운 수를 생각해 다시 영수에게 묻는다.
현재 민혁이와 영수는 게임을 하고 있는 도중에 있다. 민혁이가 영수에게 어떤 수들을 물어보았는지, 그리고 각각의 물음에 영수가 어떤 대답을 했는지가 입력으로 주어진다. 이 입력을 바탕으로 여러분은 영수가 생각하고 있을 가능성이 있는 수가 총 몇 개인지를 알아맞혀야 한다.

아래와 같은 경우를 생각해보자.

민혁: 123
영수: 1 스트라이크 1 볼.
민혁: 356
영수: 1 스트라이크 0 볼.
민혁: 327
영수: 2 스트라이크 0 볼.
민혁: 489
영수: 0 스트라이크 1 볼.
이때 가능한 답은 324와 328, 이렇게 두 가지이다.

영수는 동아리의 규율을 잘 따르는 착한 아이라 민혁이의 물음에 곧이곧대로 정직하게 답한다. 그러므로 영수의 답들에는 모순이 없다.

민혁이의 물음들과 각각의 물음에 대한 영수의 답이 입력으로 주어질 때 영수가 생각하고 있을 가능성이 있는 답의 총 개수를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에는 민혁이가 영수에게 몇 번이나 질문을 했는지를 나타내는 1 이상 100 이하의 자연수 N이 주어진다. 이어지는 N개의 줄에는 각 줄마다 민혁이가 질문한 세 자리 수와 영수가 답한 스트라이크 개수를 나타내는 정수와 볼의 개수를 나타내는 정수, 이렇게 총 세 개의 정수가 빈칸을 사이에 두고 주어진다.

출력

첫 줄에 영수가 생각하고 있을 가능성이 있는 답의 총 개수를 출력한다.

예제 입력

4
123 1 1
356 1 0
327 2 0
489 0 1

예제 출력

2

내가 했던 풀이 방법

1, possible을 선언해주고, 123부터 987까지 i를 증가시키면서, 아래 반복문을 진행한다. (123부터 987까지하는 이유는 숫자는 0을 포함하지 않고, 서로 다른 숫자 세개로 구성되어 있는 세 자리 수이기 때문이다. 그러므로 나올 수 있는 가장 작은 수는 123, 가장 큰 수는 987이다.) (Set을 사용하는 이유는 코드 상으로는 없다. 초기 구현 계획에는 다를 경우 possible에서 제거해주기 위해 Set으로 초기화했으나 현재는 count를 증가시키는 코드이므로, 삭제가 필요로 하지 않아 배열로 구현 가능하다.)
2. isPossible을 true로 초기화해주고, i를 문자열로 변환해준 값에 0이 포함되어있지 않으면서, 각 자리수에 중복이 없는 경우에 입력으로 받은 테스트 케이스에서 3스트라이크가 아닌 질문된 세 자리 수가 아닌 경우 possible에 i를 문자열로 바꾸어 추가해준다. (이때 쓸데없는 연산을 줄이기 위해 i에 0이 포함되었거나 각 자리 수에 중복된 수가 있는 경우에는 continue를 이용해 바로 다음 i를 검사하도록 해주었다. 테스트 케이스의 수를 2번에서 제거해주지 않아도 된다. 아래 연산을 통해 걸러지기 때문에.)
3. possible에는 현재 가능한 숫자들이 저장되어 있다. 이 수를 테스트케이스의 경우와 비교하여 가능한 경우의 수를 체크해줄 것이다. 아래 연산을 수행하며 possible을 순회한다.
4. isPossible을 true로 바꾸어주고, 테스트케이스만큼 반복해준다.
5. 테스트케이스에서 질문된 수를 문자열로 바꿔 num에 저장해주고, strike와 ball을 0으로 초기화해준다. possible의 현재 수(value)와 테스트 케이스의 수(num)은 모두 문자열이므로, charAt을 통해 자릿수마다 비교해주고, 같은 위치에 같은 수가 있는 경우 strike를 1증가시켜주고, 같은 위치는 아니지만 num에 value의 현재 자릿수가 존재하는 경우 ball을 1증가시켜준다. (중복된 수가 없으므로, 다음과 같이 구현해도 문제가 없다.) 이를 세 자리 모두 검사해주고, strike와 ball을 테스트케이스와 비교해서 같을 경우, 다음 테스트케이스를 검사해주고, 다를 경우 isPossible을 false로 바꾸고, 반복문을 탈출한다.
6. 반복문이 끝났거나 탈출했을 경우 isPossible이 true인 경우에만 count를 1 증가시켜준다.
7. count를 출력한다.

코드

const fs = require('fs');
let [N, ...input] = fs.readFileSync(0, 'utf-8').toString().trim().split('\n');

N = Number(N);
for (let i = 0; i < N; i++) {
  input[i] = input[i].trim().split(' ').map(Number);
}

let isPossible = true;
let possible = new Set();
for (let i = 123; i <= 987; i++) {
  isPossible = true;
  if ((i + '').indexOf('0') === -1) {
    if (
      (i + '').charAt(0) !== (i + '').charAt(1) &&
      (i + '').charAt(0) !== (i + '').charAt(2) &&
      (i + '').charAt(1) !== (i + '').charAt(2)
    ) {
      for (let j = 0; j < N; j++) {
        if (i === input[j][0] && input[j][1] < 3) isPossible = false;
      }
      if (isPossible) possible.add(i + '');
    } else continue;
  } else continue;
}

let strike = 0;
let ball = 0;
let num = '';
let count = 0;
possible.forEach((value) => {
  isPossible = true;
  for (let i = 0; i < N; i++) {
    num = input[i][0].toString();
    strike = 0;
    ball = 0;
    if (num.charAt(0) === value.charAt(0)) strike++;
    else if (num.indexOf(value.charAt(0)) >= 0) ball++;
    if (num.charAt(1) === value.charAt(1)) strike++;
    else if (num.indexOf(value.charAt(1)) >= 0) ball++;
    if (num.charAt(2) === value.charAt(2)) strike++;
    else if (num.indexOf(value.charAt(2)) >= 0) ball++;
    if (strike === input[i][1] && ball === input[i][2]) {
    } else {
      isPossible = false;
      break;
    }
  }
  if (isPossible) {
    count++;
  }
});

console.log(count);

회고

방법을 알고나서는 구현 자체가 어렵지는 않았으나 방법을 떠올리기까지 정말....너무 오래걸렸다. 처음에는 스트라이크가 1일 때 2일 때... 이렇게 경우의 수를 나눠주어야 하나 했지만 그럼 너무 복잡해지기에...... 한동안 프로젝트를 하면서 문제풀이를 많이 못했더니 어색한건지 코드 작성이 잘 안 된다. 심지어 이 코드는 부등호 하나 잘못 써서 또 한참 고민하게 했다....

profile
Frontend🍓

0개의 댓글