붕대 감기
프로그래머스 문제
문제 설명 어떤 게임에는 붕대 감기라는 기술이 있습니다.
붕대 감기는 t초 동안 붕대를 감으면서 1초마다 x만큼의 체력을 회복합니다. t초 연속으로 붕대를 감는 데 성공한다면 y만큼의 체력을 추가로 회복합니다. 게임 캐릭터에는 최대 체력이 존재해 현재 체력이 최대 체력보다 커지는 것은 불가능합니다.
기술을 쓰는 도중 몬스터에게 공격을 당하면 기술이 취소되고, 공격을 당하는 순간에는 체력을 회복할 수 없습니다. 몬스터에게 공격당해 기술이 취소당하거나 기술이 끝나면 그 즉시 붕대 감기를 다시 사용하며, 연속 성공 시간이 0으로 초기화됩니다.
몬스터의 공격을 받으면 정해진 피해량만큼 현재 체력이 줄어듭니다. 이때, 현재 체력이 0 이하가 되면 캐릭터가 죽으며 더 이상 체력을 회복할 수 없습니다.
당신은 붕대감기 기술의 정보, 캐릭터가 가진 최대 체력과 몬스터의 공격 패턴이 주어질 때 캐릭터가 끝까지 생존할 수 있는지 궁금합니다.
붕대 감기 기술의 시전 시간, 1초당 회복량, 추가 회복량을 담은 1차원 정수 배열 bandage와 최대 체력을 의미하는 정수 health, 몬스터의 공격 시간과 피해량을 담은 2차원 정수 배열 attacks가 매개변수로 주어집니다. 모든 공격이 끝난 직후 남은 체력을 return 하도록 solution 함수를 완성해 주세요. 만약 몬스터의 공격을 받고 캐릭터의 체력이 0 이하가 되어 죽는다면 -1을 return 해주세요.
제한사항 bandage는 [시전 시간, 초당 회복량, 추가 회복량] 형태의 길이가 3인 정수 배열입니다. 1 ≤ 시전 시간 = t ≤ 50 1 ≤ 초당 회복량 = x ≤ 100 1 ≤ 추가 회복량 = y ≤ 100 1 ≤ health ≤ 1,000 1 ≤ attacks의 길이 ≤ 100 attacks[i]는 [공격 시간, 피해량] 형태의 길이가 2인 정수 배열입니다. attacks는 공격 시간을 기준으로 오름차순 정렬된 상태입니다. attacks의 공격 시간은 모두 다릅니다. 1 ≤ 공격 시간 ≤ 1,000 1 ≤ 피해량 ≤ 100
느낀 점
군대 전역후에 코딩문제를 처음 접해 보았다 문제를 읽는 것도 낯설어 조건을 해석하는 것도 조금 오래 걸렸다.
어찌저찌 naive하게 테스트 케이스 3개를 통과하게 코드를 작성하는데 성공하여, 맞았겠지 생각하였는데 실제 채점해보니 정확도 33%로 틀렸다고 한다.
레벨 1문제는 맞히고 싶었지만 이미 코드를 볼때 생각이 굳어져서 원인을 못찾을 것 같다 생각하여 쪽팔리지만 다른 사람의 답을 보았다.
그리고 그 원인은 다음과 같았다.
회복을 다 했을 때 최대 체력보다 크면 최대체력까지 증가해야하는데, 그냥 if문을 if(현재체력+회복량<=최대회복량) 체력회복; 처럼 해버려서 틀렸던 것이었다.
손코딩이라도 해보아야 했는데, 반성하게 되었다.
그리고 다른 사람들의 코드를 살펴보니
- 문제의 조건을 다시 새로운 변수로 할당하여 가독성이 좋다.
- 정수의 나눗셈 연산을 잘 이용한다. ex) int a = b/c; 한뒤 수식 aBC 처럼 이를 응용
- 나는 time이라는 변수로 ‘초’라는 프레임을 성정해 접근했는데, 다른 사람들은 그럴 필요없이 심플하게 공격이 들어온 간격을 구해서접근했다. 한마디로 더 효율적인 코드를 작성한 것을 보고 많이 배워야겠다고 느꼇다.
- 가독성을 높이자. 진짜 고급지게 코드를 짠 사람은 전처리문으로 define 함수까지 썻더라. 그리고 카멜식 명명법 채택하자.
앞으로 나만의 답을 게시해서 올릴 정도의 실력을 갖치기 위해 노력해야겠으며, 코딩문제를 그동안 가까이 하지 못한걸 반성한다.
내 코드
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
// bandage_len은 배열 bandage의 길이입니다.
// attacks_rows는 2차원 배열 attacks의 행 길이, attacks_cols는 2차원 배열 attacks의 열 길이입니다.
int solution(int bandage[], size_t bandage_len, int health, int** attacks, size_t attacks_rows, size_t attacks_cols) {
int currentHealth = health;
int continuous_success=0;
for(int time=0;time<=attacks[attacks_rows-1][0];time++){
bool isAttacked=false;
for(int i=0;i<attacks_rows;i++){
if(attacks[i][0]==time) { // 몬스터가 해당 time에 공격했을 경우
continuous_success=0;
isAttacked=true;
currentHealth-=attacks[i][1];
if(currentHealth<=0) return -1;
}
}
if(isAttacked) continue;
currentHealth+=bandage[1];
if(currentHealth>health) currentHealth=health;
continuous_success++;
if(continuous_success==bandage[0]){ // 추가 체력회복
currentHealth+=bandage[2];
continuous_success=0;
if(currentHealth>health) currentHealth=health;
}
}
return currentHealth;
}
다른 사람 코드 ‘김민영’님
가독성, 명료성에서 그만 감탄했다 내가 본 답중에 가장 휼륭하다고 생각했다.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define MIN(x, y) ((x) < (y) ? (x) : (y))
// bandage_len은 배열 bandage의 길이입니다.
// attacks_rows는 2차원 배열 attacks의 행 길이, attacks_cols는 2차원 배열 attacks의 열 길이입니다.
int solution(int bandage[], size_t bandage_len, int health, int** attacks, size_t attacks_rows, size_t attacks_cols) {
int answer = 0;
int last_attacked_time = 0;
int current_health = health;
for (int attack = 0; attack < attacks_rows; attack++) {
int *current_attack = attacks[attack];
int duration = current_attack[0] - last_attacked_time - 1;
last_attacked_time = current_attack[0];
int additional_healing_count = duration / bandage[0];
int basic_healing = duration * bandage[1];
int healing = basic_healing + additional_healing_count * bandage[2];
current_health += healing;
current_health = MIN(current_health, health);
// printf("HEALED!== HP: %d(+%d)\n", current_health, healing);
current_health -= current_attack[1];
// printf("[%d]ATTACK!== HP: %d, attack: %d\n", current_attack[0], current_health, current_attack[1]);
if (current_health <= 0) {
return -1;
}
}
return current_health;
}
Leave a comment