[Lv.1][1차] 다트 게임

Jihyun-Jeon·2022년 4월 16일
0

문제 : https://programmers.co.kr/learn/courses/30/lessons/17682

🔶 내가 한 방법

function solution(dartResult) {
  const result = [0, 0, 0];
  const bonus = { S: 1, D: 2, T: 3 };

  // 0. 점수|보너스|[옵션] 대로 각각 배열의 요소로 만든다.
  const rx2 = /\d{1,2}[A-Z]["*"|"#"]?/g;
  const arr = dartResult.match(rx2).map((el) => el); // ['1D', '2S#', '10S']

  for (let i = 0; i < arr.length; i += 1) {
    // arr의 각 요소를 돌면서 요소마다
    // 1. 숫자만 찾아, result 배열에 담는다.
    result[i] = +arr[i].match(/\d{1,2}/g); // 1, 2, 10

    // 2. S,D,T를 찾아 제곱한다
    const b = arr[i].match(/[A-Z]/g); // D, S, S
    result[i] **= bonus[b[0]];

    // 3.옵션 있으면, *(직전 점수와 해당점수에 2곱하고), #(해당점수 -1 곱한다)
    const op = arr[i].match(/["*"|"#"]$/g); // null, # , null
    if (op) {
      // *
      if (op[0] === '*') {
        result[i] *= 2;
        if (result[i - 1]) {
          result[i - 1] *= 2;
        }
      }
      // #
      if (op[0] === '#') {
        result[i] *= -1;
      }
    }
  }

  return result.reduce((acc, cur) => acc + cur);
}

// 실행코드
console.log('1:', solution('1S2D*3T')); // 37 ←11 * 2 + 22 * 2 + 33
console.log('2:', solution('1D2S#10S')); // 9 ←12 + 21 * (-1) + 101
console.log('3:', solution('1D2S0T')); // 3 ←12 + 21 + 03
console.log('4:', solution('1S*2T*3S')); // 23 ←-11 * 2 * 2 + 23 * 2 + 31
console.log('5:', solution('1D#2S*3S')); // 5 ←12 * (-1) * 2 + 21 * 2 + 31
console.log('6:', solution('1T2D3D#')); // -4 ←13 + 22 + 32 * (-1)
console.log('7:', solution('1D2S3T*')); // 59 ←12 + 21 * 2 + 33 * 2

🔶 다른 사람 풀이

function solution(dartResult) {
  const bonus = { S: 1, D: 2, T: 3 };
  const options = { '*': 2, '#': -1, '': 1 };

 // 1.정규식으로 ['1S', '2D*', '3T'] 만들기
  const darts = dartResult.match(/\d{1,}[SDT][*#]?/g); // 방법1 -\d{1,}(한자리 수 이상 숫자 추출함), [SDT](S,D,T 중 문자하나), [*#](*,# 중 문자하나), ?(있을수도 없을수도 있음)
  // const darts = dartResult.match(/\d.\D?/g); // 방법2 - \d(0-9숫자 다 추출함), .(any sigle character), \D( 숫자가 아닌 문자), ?(있을수도 없을수도 있음)

  for (let i = 0; i < darts.length; i += 1) {
 // 2. 각 요소를 돌면서 숫자,문자,특수문자를 각각 변수로 만듦.
    const [, digit, b, op] = darts[i].match(/(\d{1,})([SDT])([*#]?)/);
    // ['1S', '1', 'S', '', index: 0, input: '1S', groups: undefined]
    // console.log(digit, b, op); // digit :1, S / b :2 D * / op:3 T
    const score = digit ** bonus[b] * options[op];
// 3. option이 *이면 직전 점수도 2곱해줌
    if (op === '*' && darts[i - 1]) {
      darts[i - 1] *= options['*'];
    }

    darts[i] = score;
  }

  return darts.reduce((a, b) => a + b);
}
function solution(dartResult) {
  const reg = /[\d]+[SDT][*#]*/g;
  // [\d](0-9중 숫자 한개), +(한개 이상), [SDT](S,D,T 중 한개) , [*#](*,#중 한개), *(0개 이상)
  // +(1개 이상) *(0개 이상)
  const darts = dartResult.match(reg); // ['1D', '2S#', '10S']
  const result = [];

  for (let i = 0; i < darts.length; i += 1) {
    let number = darts[i].match(/[\d]+/g)[0];
    const bonus = darts[i].match(/[SDT]/g)[0];
    const option = darts[i].match(/[*#]/g);

    switch (bonus) {
      case 'S':
        number **= 1;
        break;
      case 'D':
        number **= 2;
        break;
      default:
        number **= 3;
    }

    result[i] = number;

    if (option) {
      switch (option[0]) {
        case '*':
          result[i - 1] *= 2;
          result[i] *= 2;
          break;
        default:
          result[i] *= -1;
      }
    }
  }

  return result.reduce((acc, cur) => acc + cur);
}

🔶 피드백

1. 정규식, 문자 추출(캡쳐그룹) 잘 몰랐음.

  • 캡쳐그룹 이란?
    1) 정규식 또는 matches 배열 내의 ID로 나중에 참조될 전체 일치의 일부를 분리합니다.
    2) ID는 1부터 시작합니다. ←[전체패턴, 1번그룹매치($1), 2번그룹 매치($2) ...] 이런 식으로 나옴
    3) 정규식에 글로벌(/g) 플래그가 포함되어있지 않으면 캡쳐그룹이 안됨.

  • 설명

1)match는 유사배열로 반환됨(배열안에 내용의 자료형은 "문자"[""])
-첫 번째 요소는 정규식에 매치된 "전체 문자열", 두번째부터는 괄호로 "추출된 문자열"~이 나옴.

2)() 괄호는 String.prototype.match 호출 시 RegExpMatchArray로 유사배열로 "추출됨".

3)괄호를 추출하지 않고 싶다면 (?:...) 를 사용해서 무시할 수 있음.
const arr = "abcdef00".match(/ab(?:cd|ef)(e)(f)(00)/); 
console.log(arr); // ["abcdef00", "e", "f", "00"] ← ?:를 붙여 cd또는 ef를 추출하지 않음.

4)global에서는 추출이 안됨.(mdn :캡처된 그룹은 반환되지 않습니다.)
 :g쓰면 괄호 추출은 의미가 사라지고, 그냥 정규식 패턴에 맞는 텍스트를 모두 찾아
  유사배열로 반환함(그냥 ()없이 쓰는거랑 똑같이 됨.)
console.log("a12bc3a1".match(/a(\d)/)); //["a1", "1"] ←() 지정된게 1개 추출됨
console.log("a12bc3a1".match(/a(\d)/g)); //["a1", "a1"] ←()가 추출되지 않음.★

2. 정규식으로 1D2S#10S → ['1D', '2S#', '10S'] 만드는 법 - 방법3개

// <방법1>
const dartResult = '1D2S#10S';
const darts = dartResult.match(/\d{1,}[SDT][*#]?/g); 
// \d(0-9 중 한개), {1,}(한개 이상 숫자 추출함), 
// [SDT](S,D,T 중 문자하나), [*#](*,# 중 문자하나), ?(있을수도 없을수도 있음) 
// <방법2>
const dartResult = '1D2S#10S';
const darts = dartResult.match(/\d.\D?/g); 
// \d(0-9 중 한개), .(문자 중 하나),  <- 1D, 2S, 10 나옴
// \D('0' ~ '9'가 아닌 문자 즉,숫자가 아닌 문자), ?(있을수도 없을수도 있음) <- "", # , S
// <방법3>
const dartResult = '1D2S#10S';
const reg = /[\d]+[SDT][*#]*/g;
const darts = dartResult.match(reg);
// [\d](0-9중 숫자 한개), +(한개 이상), [SDT](S,D,T 중 한개) ,
// [*#](*,#중 한개), *(0개 이상)
// +(1개 이상) *(0개 이상)

3. 예제

  • '880925-1184015' → '1988 남자'으로 반환하기
function jumin(str) {
  let year = '';
  let gender = '';

  let [, second, third] = str.match(/(^\d{2})\d{4}-(\d)/); // ["880925-1", "88(추출)", "1(추출)"] ["940207-2", "94(추출)", "2(추출)"]

  year = second[0] <= '2' ? `20${second}` : `19${second}`; // second는 88임, second[0]은 8
  gender = third === '1' ? '남자' : '여자';

  console.log(`${year} ${gender}`);
}

jumin('880925-1184015'); // 1988 남자;
jumin('100207-2188107'); // 1994 여자;

0개의 댓글