POTATO THAT WANT TO BE HUMAN

[알고리즘/javascript] 백준 2503번: 숫자야구 본문

알고리즘

[알고리즘/javascript] 백준 2503번: 숫자야구

녜힝 2024. 8. 15. 17:58
반응형

문제 바로가기

https://www.acmicpc.net/problem/2503

 

✏️ Problem

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

  • 영수는 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, 이렇게 두 가지이다.

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

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

 

🧑‍💻 Solution

[ 설계 ]

삼중 반복문을 통해 각 자리 수를 돌면서 세자리 수를 조합한다.

숫자가 같은 경우를 제외하기 때문에 123 ~ 987까지 반복된다.

반복문을 통해 조합된 수를 curr 변수에 저장하고,

입력받은 세자리 수를 새로운 반복문으로 돌면서 조합된 수(curr)에서의 strike와 ball을 확인한다.

 

예를 들어, 입력받은 수(number)는 123 이고 새로 조합된 curr 변수가 124 일 경우 2 strike이다.

그렇다면 count는 {strike: 2, ball: 0}이 될 것이다.

strike와 ball의 수를 모두 센 후 입력값으로 들어온 스트라이크와 볼과 같은 지 비교한다.

만약 값이 같다면 정답이 될 수 있는 수 이므로 resNumArr에 저장한다.

 

마지막으로 res의 길이가 0일 경우 resNumArr 자체를 저장하고, 아닐 경우 res에 있는 값과 중복되는 값만을 저장한다.

모든 질문 횟수를 돌면 res에는 정답이 될 수 있는 수만 남게 된다.

 

[ 작성한 코드 ]

const [N, ...nums] = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
let res = [];

for(let i = 0; i < Number(N); i++) {
    findBaseBallCnt(nums[i]);
}
console.log(res.length);  // 결과 출력

function findBaseBallCnt(numInfo) {
    const [number, strike, ball] = numInfo.split(' ').map(Number);
    const resNumArr = [];
    
    for(let i = 1; i < 10; i++) {
        for(let j = 1; j < 10; j++) {
            for(let k = 1; k < 10; k++) {
            	// 111, 323 과 같이 숫자가 같은 경우를 제외
                if(i === j || j === k || k === i) continue;
                
                const curr = String(i) + String(j) + String(k);
                const count = {strike: 0, ball: 0};
               
                for(let l = 0; l < String(number).length; l++) {
                    // input으로 받은 수와 현재 조합된 curr에서 겹치는 수의 인덱스를 구함
                    const idx = curr.indexOf(number.toString()[l]);
                    
                    // 인덱스가 반복문 변수 l과 같을 때 숫자와 자리가 모두 같은 strike이며
                    // -1이 아닌 경우 숫자는 일치하지만 자리가 다를 경우인 ball에 해당함
                    if(idx === l) count.strike += 1;
                    else if(idx !== -1) count.ball += 1;
                }
                
                if(strike === count.strike && ball === count.ball) resNumArr.push(curr);
            }
        }
    }
    // res에서 중복된 요소만 담기
    if(res.length === 0) res = [...resNumArr];
    else res = resNumArr.filter(ele => res.includes(ele));
}

 

 

두 개의 배열에서 중복된 요소 찾기

const arr1 = [1, 4, 6, 12];
const arr2 = [4, 7, 10, 12];

const res = arr1.filter(ele => arr2.includes(ele));
console.log(res);  // [4, 12]

다음과 같은 두 개의 배열이 있다. 

이 두 배열에서 중복되는 요소만을 찾고 싶은 경우 filterincludes 메서드를 활용해 찾을 수 있다.

includes 메서드는 배열이 특정 값을 포함하고 있는 지의 여부를 boolean 값으로 반환하는 메서드이다.

 

반응형
Comments