[프로그래머스 1레벨] [1차] 다트게임

이민선(Jasmine)·2023년 1월 11일
1
post-thumbnail

이 문제는 통과하고 나서 며칠 후 다시 풀어보았다.
첫 번째 코드가 억지의 스멜을 많이 풍겼기 때문이다. ㅋㅋㅋ

첫번째 억지 코드 공개

function solution(dartResult) {
  const withPrize = dartResult
    .split("S")
    .join("|")
    .split("D")
    .join("|")
    .split("T")
    .join("|")
    .split("|");
  console.log(withPrize);
  const elimPrize = dartResult.split("*").join("").split("#").join("");

  const elimSDT = elimPrize
    .split("S")
    .join("|")
    .split("D")
    .join("|")
    .split("T")
    .join("|")
    .split("|");
  elimSDT.pop();

  const SDT = elimPrize
    .split("")
    .filter((v) => v === "S" || v === "D" || v === "T");

  const totalBeforePrize = elimSDT.map((v, i) =>
    SDT[i] === "D"
      ? Math.pow(v, 2)
      : SDT[i] === "T"
      ? Math.pow(v, 3)
      : Number(v)
  );
  if (elimPrize === dartResult)
    return totalBeforePrize.reduce((s, v) => (s += v), 0);

  const starCurrentRoundApplied = totalBeforePrize.map((v, i) =>
    withPrize[i + 1][0] === "*" ? 2 * v : v
  );

  let arr = [];
  for (let v of withPrize) v[0] === "*" ? arr.push(2) : arr.push(1);
  arr.shift();
  arr.shift();

  const starWholeRoundsApplied = starCurrentRoundApplied.map((v, i) =>
    arr[i] === 2 ? 2 * v : v
  );

  const sharpApplied = starWholeRoundsApplied.map((v, i) =>
    withPrize[i + 1][0] === "#" ? v * -1 : v
  );

  return sharpApplied.reduce((s, v) => (s += v), 0);
}

ㅋㅋㅋㅋㅋㅋㅋ
split과 join을 몇 번을 쓰는거야 ㅋㅋㅋㅋㅋㅋㅋ
아놔 보고 또 봐도 흥겨운 코드 ㅋㅋㅋㅋㅋ
변수명 조차도 한번에 와닿지 않아서 마음에 안들었다.

그래서 좀 더 깔끔하게 다시 풀어보았다.

function solution(dartResult) {
  const d = dartResult.split("");
  const nums = d
    .map((v) => Number(v))
    .join("")
    .split(NaN)
    .filter((w) => w !== "");
  const SDT = d.filter((v) => v === "S" || v === "D" || v === "T");
  const prize = [...d, " "]
    .map((v, i, a) =>
      SDT.includes(a[i - 1]) ? (!isNaN(v) ? "no prize" : v) : null
    )
    .filter((v) => v);
  const appliedSDT = nums.map((v, i) =>
    SDT[i] === "S"
      ? Number(v)
      : SDT[i] === "D"
      ? Math.pow(v, 2)
      : Math.pow(v, 3)
  );
  const acha = appliedSDT.map((v, i) => (prize[i] === "#" ? v * -1 : v));
  const starThisRound = acha.map((v, i) => (prize[i] === "*" ? v * 2 : v));
  const starNextRound = starThisRound.map((v, i) =>
    prize[i + 1] === "*" ? v * 2 : v
  );

  return starNextRound.reduce((s, v) => s + v, 0);
}

map무새 답게 map을 많이도 사용하였지만, 첫번째 코드보다는 훨씬 깔끔한 거 같다.

내가 선언한 변수

- nums : 라운드 별로 숫자만 추출한 배열. ex) [1, 2, 3]

dartResult를 한 글자 씩 쪼갠 배열에서 모든 원소를 Number 타입으로 바꾼 뒤, 10이 있음을 고려하여 join. NaN으로 split()하여 숫자만 남도록 만듦.

- SDT : 라운드 별로 S, D, T만 추출한 배열. ex) ["S", "D", "T"]

filter 사용.

- prize : 라운드 별로 *, #만 추출한 배열. 상을 받지 않은 경우 no prize. ex) ["no prize", "*" , "no prize"]

dartResult.split('')의 원소 중 바로 이전의 글자가 S,D,T이면, 현재 * 또는 #이거나 다음 라운드 점수임을 이용. 현재 글자가 *이나 #이 아닌 숫자라면 no prize. 이 때, 배열의 마지막 원소에 빈 글자를 추가하여 3라운드에 상을 받지 못하더라도 3라운드에 no prize 표시할 수 있게 함.

- appliedSDT : S일 경우 nums 변수에 1제곱, D일 경우 nums 변수에 2제곱, T일 경우 nums 변수에 3제곱

S일 경우 Number 형태로만 변환. D 또는 T일 경우 각각 Math.pow로 2제곱 또는 3제곱.

- acha : 아차상 받은 경우 해당 라운드 점수 음수값으로 변환

prize 배열의 각 원소 인덱스가 appliedSDT의 각 원소 인덱스와 같은 라운드를 가리킴을 이용하여 map 사용.

- starThisRound : 스타상을 받은 경우 이번 라운드 점수 2배로 변환

acha와 동일한 논리

- starNextRound : 다음 라운드에서 스타상을 받은 경우 이번 라운드 점수 2배로 변환

starThisRound와 달리 다음 라운드 상이 *인지 확인해야 하므로 prize[i+1]==="*" 확인.

첫번째보다 나은 점은 nums, SDT, Prize의 원소 개수를 3으로 통일해서 map에서 index 사용하기가 훨씬 편해졌다는 것이다. 상을 받을 때도 있고 안 받을 때도 있어서 어떻게 표시할지 고민을 많이 했는데, 원소 개수를 게임 라운드 수와 통일시키기 위해 no prize를 표시한 점이 좋았던 것 같다.

그런데 다른 사람 코드를 확인해보니 정규표현식을 많이 사용해서 푸는 것 같았다.
그래서 미루고 미뤄왔던 정규표현식을 조금씩 익혀보기로 했다.

const dart = "10S2D*3T";

const num = dart.replace(/[^0-9]/g, " ");
const str = dart.replace(/[0-9]/g, "");
const reg = dart.split(/[SDT*#]/g);

console.log(num); //10 2  3 
console.log(str); //SD*T
console.log(reg); //[ '10', '2', '', '3', '' ]

정규표현식을 처음 본 나의 표정

"이게 뭐람?"

드림코딩 유튜브를 보니 정규표현식을 하루만에 다 익히는 건 무리일 것 같다. ㅋㅋㅋㅋㅋ 각각의 글자가 무엇을 의미하는지 그때그때 조금씩 살펴보기루!
드림코딩 정규표현식:
https://www.youtube.com/watch?v=t3M6toIflyQ&t=553s

정규표현식: /regex/i
/ /안에 찾고자 하는 패턴을 작성
i : option을 나타내는 flag

마지막 글자인 g는 flag이다.
g: Global search. retain the index of the last match, allowing iterative searches.
즉, 매칭되는 다수의 결과값을 기억.
[]: 문자셋, 괄호 안의 어떤 문자든
[^]: 부정문자셋, 괄호 안의 문자가 아닌 어떤 것이든
0-9: 숫자 0부터 9까지

기괴해보였던 코드가 이제 안 기괴해보이는 magic~
[0-9] 0~9까지 숫자는 모두 찾아줌.
[^0-9] 0~9까지 숫자가 아닌 것들은 모두 찾아줌.
/[0-9]/ 내가 숫자 패턴이다!
/[0-9]/g 숫자 여러개 찾으므로 g라는 flag 사용.

괜히 거부감 들어서 미루고 미뤄왔는데
막상 해보니 그리 어렵지는 않아보인다 ^^
어쩌면 다트게임 출제자의 의도는 정규표현식 아니었을까
앞으로도 거부하지말고 조금씩 알아가보자!

profile
기록에 진심인 개발자 🌿

0개의 댓글