Pokemon Damage Calculator<6 kyu>

jjanmo·2020년 1월 22일
0

Codewars에서 뒹굴기

목록 보기
21/32

문제링크

문제

1️⃣
It's a Pokemon battle! Your task is to calculate the damage that a particular move would do using the following formula (not the actual one from the game):

damage = 50 * (attack / defense) * effectiveness

Where:

  • attack = your attack power
  • defense = the opponent's defense
  • effectiveness = the effectiveness of the attack based on the matchup (see explanation below)

2️⃣
Effectiveness:

Attacks can be super effective, neutral, or not very effective depending on the matchup. For example, water would be super effective against fire, but not very effective against grass.

  • Super effective: 2x damage
  • Neutral: 1x damage
  • Not very effective: 0.5x damage

To prevent this kata from being tedious, you'll only be dealing with four types: fire, water, grass, and electric. Here is the effectiveness of each matchup:

  • fire > grass
  • fire < water
  • fire = electric
  • water < grass
  • water < electric
  • grass = electric

For this kata, any type against itself is not very effective. Also, assume that the relationships between different types are symmetric (if A is super effective against B, then B is not very effective A).

3️⃣
The function you must implement takes in:

  1. your type
  2. the opponent's type
  3. your attack power
  4. the opponent's defense

🚩문제해석
1️⃣
포켓몬 간의 배틀에서 어떻게 데미지가 들어가는지에 대한 공식(formula)을 정의하고 있다.

damage = 50 * (attack / defense) * effectiveness

여기서 damage는 피해량, attack은 내 포켓몬의 공격력, defence는 상대 포켓몬의 방어력, effectiveness에 대해선 2️⃣에서 설명을 하고 있다.

2️⃣
effectiveness는 말그대로 포켓몬 전투간의 효율성을 따지는 지표가 된다. 즉 쉽게 말해 포켓몬 간의 상성을 의미하는 것! 상성이 좋다 (Super effective), 똑같다(Neutral), 나쁘다(Not very effective) 이렇게 3종류로 나눌 수 있고, 이에 따라서 상대에게 입히는 데미지의 효율성이 달라지게 된다.(2x, 1x, 0.5x)
같은 상성 간의 대전은 항상 not very effective (0.5x damage)이다. 그리고 모든 상성은 항상 대칭적이다.(A가 B와 비교하여 좋은 상성이라면, B는 A와 비교하여 좋지 않은 상성이라는 것!)

3️⃣
이 문제의 함수에서 parameter로서 주어지는 것, 4가지에 대한 설명이다. 이 함수를 통해서 최종적으로 포켓몬의 데미지를 리턴하면 된다.

문제 접근

Codewars에는 이렇게 게임, 퍼즐 같은 문제들이 많이 있다. 내용은 상당히 길지만 포켓몬이라는 게임에 익숙한 사람이라면 금방 이해할 수 있는 내용들이다.
가장 쉬운 풀이로 접근하였다. 조건에 따라서 경우의 수를 나눈다. 이 문제에서는 상성을 4종류로 주어줬기 때문에 조건을 따지는 것이 어렵지 않다. 또한 effectiveness가 달라지는 경우만을 찾으면 된다.

function calculateDamage(yourType, opponentType, attack, defense){
      let effectiveness = 1;
      if(yourType === 'fire' &&  opponentType === 'grass'){
        effectiveness = 2;
      }
      else if(yourType === 'fire' &&  opponentType === 'water'){
        effectiveness = 0.5;
      }
      else if(yourType === 'water' &&  opponentType === 'fire'){
        effectiveness = 2;
      }
      else if(yourType === 'water' &&  opponentType === 'grass'){
        effectiveness = 0.5;
      }
      else if(yourType === 'water' &&  opponentType === 'electric'){
        effectiveness = 0.5;
      }
      else if(yourType === 'grass' &&  opponentType === 'water'){
        effectiveness = 2;
      }
      else if(yourType === 'grass' &&  opponentType === 'fire'){
        effectiveness = 0.5;
      }
      else if(yourType === 'electric' &&  opponentType === 'water'){
        effectiveness = 2;
      }
      else if(yourType === opponentType){
        effectiveness = 0.5;
      }
      return 50 * (attack / defense) * effectiveness;
}

Best Solution

  • Solution1
  var effects = {
    fire : {
      fire : 0.5,
      grass : 2,
      water : 0.5,
      electric : 1
    },
    grass : {
      fire : 0.5,
      grass : 0.5,
      water : 2,
      electric : 1
    },
    water : {
      fire : 2,
      grass : 0.5,
      water : 0.5,
      electric : 0.5
    },
    electric : {
      fire : 1,
      grass : 1,
      water : 2,
      electric : 0.5
    }
  };

  function calculateDamage(yourType, opponentType, attack, defense){
    return Math.ceil(50 * (attack/defense) * effects[yourType][opponentType]);
  }

이 문제를 봤을때 처음으로 생각했던 풀이는 조건에 따라 나누는 것이 아니라 뭔가 형식(포맷)을 만들어서 거기에 맞는 조건이 parameter로 들어왔을때, 그에 따라서 계산이 가능 하도록 만드는 것이였다. 그런데 effectiveness1이 아닌 경우만 따로 빼서 만들려고 하니 뭔가 통일성이 없는 것 같고, 객체나 배열로서 어떤식으로 표현해야할지 감이 오지 않아서 if문을 사용하여 접근 하였다. 이 풀이는 모든 상성의 관계를 객체로서 표현한 풀이이다. 마치 조건문 안에 조건문을 넣은 것처럼 객체 안에 객체를 넣어서 접근하여각각의 effectiveness에 접근할 수 있게 하였다. 가독성이 아주 좋았다. 😎

✅ 여기서 알아야 할 개념(?)은 **객체에 접근하는 방식**이다. 객체의 접근하는 방식에는 2가지가 있다. **점(.) 접근과 []접근**이다. 일반적으로 점 접근을 많이 사용한다. 하지만 이렇게 **변수로 접근할 때는 []를 사용**해야 한다.
effects[yourType][opponentType]

예전에 이것 때문에 고민한 적이 있어서 다시 한 번 상기해보는 의미에서 적어본다.

  • Solution2

    ```javascript
    function calculateDamage(yourType, opponentType, attack, defense) {
      var strength = { fire: 'grass', water: 'fire', grass: 'water', electric: 'water' };
      var effectiveness = 1;
      if (yourType == opponentType || yourType == strength[opponentType]) {
        effectiveness = 0.5;
      } else if (opponentType == strength[yourType]) {
        effectiveness = 2;
      }
      return Math.ceil(50 * effectiveness * attack / defense);
    }
    이 풀이는 전체를 비교/분류하여 객체를 만든 것(Solution1)이 아니라 `effectiveness`에 따라서 분류하여 객체를 생성하였다. 나의 풀이를 좀 더 일반화한 풀이라고 볼 수 있다. 또한 문제의 조건인 `symmetric(대칭적)` 이라는 말을 잘 구현한 코드라고 생각한다. 
    좀 더 자세히 살펴보자.
    `effectiveness`가 `1`이 아닌 경우는 나와 상대의 타입이 같은 경우일 때와 나와 상대 타입이 다를 경우에는 상대 타입과 나의 타입이 무엇인지에 관계 없이 4가지 경우(아래)가 존재한다. 
    	```
      1. fire ↔ grass
    	2. water ↔ fire
    	3. grass ↔ water
    	4. electric ↔ water
또한 위의 관계는 대칭적이다. 나의 타입을 기준으로 `effectiveness`가 `2`인 경우가 4가지이면 `effectiveness`가 `0.5`인 경우도 4가지가 된다. 이를 이용해서 상성에 관련된 객체인 `strength`를 만들어서 객체 안의 속성에 위의 관계를 표현하였다. 그 속성에 아래와 같이 접근하면 `effectiveness`가 `2`인 경우와 `effectiveness`가 `0.5`인 경우를 모두 표현이 가능해진다.

yourType == strength[opponentType]
opponentType == strength[yourType]

이 코드는 보면 이해하기 쉽지만 쉽게 떠오르지 않은 코드이다. 콜럼버스의 달걀이랄까. 

## 결론
**대칭적이다**라는 말은 어떻게 코드로 구현할 수 있을까에 대해서 고민하였지만, 스스로 해결하지 못하였다. 그런데 그것을 객체를 생성하여 객체에 어떻게 접근하느냐에 따라서 대칭을 만들어가는 과정에 대해서 알게 되었다. 개념적으로 어렵고, 보지 못한 문법을 사용하고 그런 것들이 아니다. 생각하는 방법의 차이, 발상의 전환(?) 그런 것이라고 생각한다. 많이 보다 보면 익숙해지고, 많이 사용하다 보면 내 것이 될 것이다. 다음에는 이러한 생각을 할 수 있길 바랄 뿐... 😅


> 🚀 문제를 풀어나갈 때 생각의 흐름을 정리합니다. 또한 새로운 풀이에 대한 코드를 분석하고 모르는 부분에 대해서 정리합니다. 생각이 다른 부분에 대한 피드백은 언제나 환영합니다. 틀린 내용에 대한 피드백 또한 항상 감사합니다.




  
  
profile
눈길을 걸어갈 때 어지럽게 걷지 말기를.

0개의 댓글