[백준] 2621 카드게임 JavaScript

·2024년 10월 23일

문제

근우는 오늘 재미있는 카드 게임을 배우고 있다. 카드는 빨간색, 파란색, 노란색, 녹색의 네 가지 색이 있고, 색깔별로 1부터 9까지 숫자가 쓰여진 카드가 9장씩 있다. 카드는 모두 36(=4x9)장이다. 근우가 배운 카드 게임은 36장의 카드에서 5장을 뽑고, 아래와 같은 규칙으로 정수를 계산하는 것이다.

각 카드는 다음과 같이 나타낸다. 카드의 색깔은 영어 대문자 R, B, Y, G로 나타내는데, R은 빨간색, B는 파란색, Y는 노란색, G는 녹색을 뜻한다. 예를 들어서 Y8은 노란색 8을 나타내고, B5는 파란색 5를 나타낸다.

<점수를 정하는 규칙>

  1. 카드 5장이 모두 같은 색이면서 숫자가 연속적일 때, 점수는 가장 높은 숫자에 900을 더한다. 예를 들어, 카드가 Y4, Y3, Y2, Y5, Y6 일 때 점수는 906(=6+900)점이다.
  2. 카드 5장 중 4장의 숫자가 같을 때 점수는 같은 숫자에 800을 더한다. 예를 들어, 카드가 B3, R3, B7, Y3, G3 일 때 점수는 803(=3+800)점이다.
  3. 카드 5장 중 3장의 숫자가 같고 나머지 2장도 숫자가 같을 때 점수는 3장이 같은 숫자에 10을 곱하고 2장이 같은 숫자를 더한 다음 700을 더한다. 예를 들어, 카드가 R5, Y5, G7, B5, Y7 일 때 점수는 757(=5x10+7+700)점이다.
  4. 5장의 카드 색깔이 모두 같을 때 점수는 가장 높은 숫자에 600을 더한다. 예를 들어, 카드가 Y3, Y4, Y8, Y6, Y7 일 때 점수는 608(=8+600)점이다.
  5. 카드 5장의 숫자가 연속적일 때 점수는 가장 높은 숫자에 500을 더한다. 예를 들어 R7, R8, G9, Y6, B5 일 때 점수는 509(=9+500)점이다.
  6. 카드 5장 중 3장의 숫자가 같을 때 점수는 같은 숫자에 400을 더한다. 예를 들어 R7, Y7, R2, G7, R5 일 때 점수는 407(=7+400)점이다.
  7. 카드 5장 중 2장의 숫자가 같고 또 다른 2장의 숫자가 같을 때 점수는 같은 숫자 중 큰 숫자에 10을 곱하고 같은 숫자 중 작은 숫자를 더한 다음 300을 더한다. 예를 들어, R5, Y5, Y4, G9, B4 일 때 점수는 354(=5X10+4+300)점이다.
  8. 카드 5장 중 2장의 숫자가 같을 때 점수는 같은 숫자에 200을 더한다. 예를 들어, R5, Y2, B5, B3, G4 일 때 점수는 205(=5+200)점이다.
  9. 위의 어떤 경우에도 해당하지 않을 때 점수는 가장 큰 숫자에 100을 더한다. 예를 들어, R1, R2, B4, B8, Y5 일 때 점수는 108(=8+100)점이다.

입력으로 카드 5장이 주어질 때, 카드 게임의 점수를 구하는 프로그램을 작성하시오. 두 가지 이상의 규칙을 적용할 수 있는 경우에는 가장 높은 점수가 카드 게임의 점수이다.

입력

첫째 줄부터 다섯째 줄까지 한 줄에 카드 하나씩 입력된다. 카드의 색깔과 숫자 사이에는 빈 칸이 하나 있다.

출력

한 줄에 카드의 점수를 출력한다.

예제 입력

B 3
B 7
R 1
B 2
Y 7

예제 출력

207

내가 했던 풀이 방법

  1. 입력받은 카드를 색깔과 숫자를 기준으로 Map에 저장한다. 예를 들어 colorMap에는 key가 color가 되고, 해당 color를 가진 num을 value의 배열에 담아준다.
  2. numberMap의 key 값을 배열로 만들어준다. 만들어진 배열을 오름차순 정렬을 하고, isConsecutive를 true로 초기화한다음 가장 작은 수부터 순차적으로 반복하며 이전 요소보다 1만큼 큰지를 확인해준다. 모든 요소를 검사했을 때 조건에 해당하는 경우가 없었다면, 뽑은 카드는 순차적임을 알 수 있다.
  3. sameNum 배열을 초기화해준다. sameNum은 [가장 많이 존재하는 숫자 중 큰 값, 가장 많이 존재하는 경우의 수]가 담기게 된다. 예를 들어 R5, Y5, Y4, G9, B4를 입력으로 받을 때 가장 많이 존재하는 경우는 2이다. 같은 숫자가 2개 존재하는 경우는 5와 4가 있는데 이 중 더 큰 값인 5가 선택된다. 즉 sameNum은 [5, 2]가 될 것이다.
  4. 1번부터 9번 조건은 점수가 겹치는 경우가 존재하지 않는다. 즉, 두 가지 이상의 규칙을 적용할 수 있는 경우에는 가장 높은 점수가 카드 게임의 점수이다.에서 1번 규칙에 해당한다면 2번 규칙에 해당한다고 해도 1번 규칙보다 점수가 클 수 없다. 그렇기 때문에 if/elseif/else 형태로 구현해주면 된다.
  5. 1번 규칙은 colorMap의 size가 1이고 isConsecutive가 true일 때 해당된다. 모두 같은 색이므로 map에는 하나만 생성되기 때문이다. 가장 큰 수는 이미 number를 오름차순 정렬해두었기 때문에 가장 마지막 요소가 가장 큰 수가 된다.
  6. 2번 규칙은 colorMap의 size가 4이고, sameNum[1]이 4일 때 해당된다. 물론 sameNum[1]이 4이어도 충분히 판별 가능하다. 4장의 숫자가 같다는 의미는 네 가지 색상의 카드가 존재한다는 의미이기 때문에 같다. 이때는 sameNum[0]을 추가로 더해주면 된다.
  7. 3번 규칙은 sameNum[1]이고 numberMap의 size가 2일 때 해당된다. sameNum[1]을 통해 5장 중 3장의 숫자가 같다는 것을 알 수 있고, numberMap의 size가 2라면 남은 2장이 같다는 것이기 때문이다. (다르다면 size가 3이 되어야 한다.) 이때는 기본점수에 sameNum[0]*10을 더해주고, number 중에 sameNum[0]과 같지 않은 수를 찾아 더해주면 된다.
  8. 4번 규칙은 colorMap의 size가 1일 때 해당된다.
  9. 5번 규칙은 numberMap의 size가 5이고 isConsecutive가 true일 때 해당된다. numberMap의 size가 5이기 때문에 5장 모두 다른 숫자를 가지고 있다는 것을 알 수 있고 그 수가 연속적이므로 해당된다.
  10. 6번 규칙은 sameNum[1]이 3일 때 해당된다.
  11. 7번 규칙은 sameNum[1]이 2이고, numberMap의 size가 3일 때 해당된다. 7번 규칙에 의해 숫자는 2장/2장/1장이 같은 수를 가지게 된다. 그러므로 숫자가 3개가 존재해야 한다. sameNum[0]*10을 더해주고 number 중에 sameNum[0]이 아니면서 해당 수의 개수가 2개인 경우의 수를 더해준다.
  12. 8번 규칙은 sameNum[1]이 2일 때 해당된다.
  13. 그 외의 모든 경우는 9번에 해당된다.

코드

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

let colorMap = new Map();
let numberMap = new Map();
for (let i = 0; i < 5; i++) {
  cards[i] = cards[i].trim().split(' ');
  if (colorMap.has(cards[i][0])) {
    colorMap.set(cards[i][0], [...colorMap.get(cards[i][0]), Number(cards[i][1])]);
  } else {
    colorMap.set(cards[i][0], [Number(cards[i][1])]);
  }

  if (numberMap.has(Number(cards[i][1]))) {
    numberMap.set(Number(cards[i][1]), [...numberMap.get(Number(cards[i][1])), cards[i][0]]);
  } else {
    numberMap.set(Number(cards[i][1]), [cards[i][0]]);
  }
}

let number = Array.from(numberMap.keys());
number.sort((a, b) => a - b);
let isConsecutive = true;
for (let i = 1; i < number.length; i++) {
  if (number[i] - number[i - 1] !== 1) {
    isConsecutive = false;
    break;
  }
}

let sameNum = [0, 0];
for (let num of numberMap) {
  if (sameNum[1] <= num[1].length && sameNum[0] < num[0]) {
    sameNum = [num[0], num[1].length];
  }
}

let score = 0;
if (colorMap.size === 1 && isConsecutive) {
  score += 900 + number[number.length - 1];
} else if (colorMap.size === 4 && sameNum[1] === 4) {
  score += sameNum[0] + 800;
} else if (sameNum[1] === 3 && numberMap.size === 2) {
  let two = 0;
  for (let num of numberMap) {
    if (sameNum[0] !== num[0]) two = num[0];
  }
  score += 700 + 10 * sameNum[0] + two;
} else if (colorMap.size === 1) {
  score += 600 + number[number.length - 1];
} else if (numberMap.size === 5 && isConsecutive) {
  score += 500 + number[number.length - 1];
} else if (sameNum[1] === 3) {
  score += 400 + sameNum[0];
} else if (sameNum[1] === 2 && numberMap.size === 3) {
  let second = 0;
  for (let num of numberMap) {
    if (num[0] !== sameNum[0] && num[1].length === 2) second = num[0];
  }
  score += 300 + 10 * sameNum[0] + second;
} else if (sameNum[1] === 2) {
  score += 200 + sameNum[0];
} else {
  score += 100 + number[number.length - 1];
}

console.log(score);

회고

규칙이 많아서 구현하기 귀찮기는 하지만, 점수가 위에서 순차적으로 검사만 하면 겹칠 일이 없어서 그래도 너무 복잡하지 않게 풀기는 했다. 계속 map이랑 배열을 추가하다보니 조금 더 알아보기 쉽게 풀이가 가능했을 것 같은데 그게 그거 같긴 하다..

profile
Frontend🍓

0개의 댓글