본문 바로가기
일반 스터디/코딩 테스트

[프로그래머스] 붕대 감기

by StelthPark 2025. 10. 7.

문제 개요

밴디지(붕대) 시스템을 구현하는 문제로, 다음과 같은 요소들이 있다:

  • bandage: [연속 성공 시간, 초당 회복량, 추가 회복량]
  • health: 최대 체력
  • attacks: 공격 정보 배열 [[시간, 데미지], ...]

핵심 로직

  1. 공격이 있으면 데미지를 받고 연속 성공 카운트 리셋
  2. 공격이 없으면 초당 회복량만큼 체력 회복
  3. 연속 성공 시간을 달성하면 추가 회복량을 받음
  4. 체력이 0 이하가 되면 -1 반환

내가 놓친 핵심 포인트

잘못된 이해

if (hp + hpsec <= health) {
  hp += hpsec;
}

잘못된 생각: "체력이 최대치보다 낮을 때만 회복해야 한다"

올바른 이해

hp = Math.min(hp + hpsec, health);

올바른 로직: "항상 회복하되, 최대치를 초과하지 않도록 제한한다"

문제가 된 케이스

예시 1: 정상 케이스

  • 현재 체력: 90, 최대 체력: 100, 회복량: 10
  • 기존 로직: 90 + 10 <= 100 → true → 회복 (맞음)

예시 2: 문제 케이스

  • 현재 체력: 95, 최대 체력: 100, 회복량: 10
  • 기존 로직: 95 + 10 <= 100 → false → 회복 안함 (틀림)
  • 수정 로직: Math.min(95 + 10, 100) → 100 → 올바르게 회복 (맞음)

교훈

1. 조건문의 의미를 정확히 파악하기

  • hp + hpsec <= health는 "회복 후에도 최대치를 넘지 않는다"는 의미
  • 하지만 이는 "회복을 시도할지 말지"를 결정하는 조건이 아님

2. 체력 회복의 올바른 로직

  • 체력이 부족하면 회복을 시도
  • 단, 최대치를 초과하지 않도록 제한
  • Math.min()을 사용하면 이 두 조건을 모두 만족

3. 엣지 케이스 고려

  • 체력이 거의 최대치에 가까울 때의 동작
  • 회복량이 남은 체력보다 클 때의 동작

최종 코드

function solution(bandage, health, attacks) {
  let maxAttackTime = attacks[attacks.length - 1][0];
  let attackInfo = {};
  attacks.forEach((el) => {
    attackInfo[el[0]] = el[1];
  });
  let seqCnt = 0;
  let [seqChk, hpsec, addHp] = bandage;
  let hp = health;

  for (let i = 1; i <= maxAttackTime; i++) {
    if (attackInfo[i] !== undefined) {
      seqCnt = 0;
      hp -= attackInfo[i];
      if (hp <= 0) {
        hp = -1;
        break;
      }
    } else {
      seqCnt += 1;
      hp = Math.min(hp + hpsec, health); // 핵심 수정!

      if (seqCnt >= seqChk) {
        if (hp + addHp <= health) {
          hp += addHp;
        }
        seqCnt = 0;
      }
    }
  }
  return hp;
}

결론

간단해 보이는 조건문이지만, 실제로는 체력 회복의 근본적인 로직을 잘못 이해했던 것이 문제였다. 항상 엣지 케이스와 경계값을 고려해야 한다는 교훈을 얻었다.

댓글