CodeKata/Codewars

[CK] Greed is Good

anothel 2021. 10. 27.

Greed is a dice game played with five six-sided dice. Your mission, should you choose to accept it, is to score a throw according to these rules. You will always be given an array with five six-sided dice values.

 

 Three 1's => 1000 points
 Three 6's =>  600 points
 Three 5's =>  500 points
 Three 4's =>  400 points
 Three 3's =>  300 points
 Three 2's =>  200 points
 One   1   =>  100 points
 One   5   =>   50 point

 

A single die can only be counted once in each roll. For example, a given "5" can only count as part of a triplet (contributing to the 500 points) or as a single 50 points, but not both in the same roll.

 

Example scoring

 Throw       Score
 ---------   ------------------
 5 1 3 4 1   250:  50 (for the 5) + 2 * 100 (for the 1s)
 1 1 1 3 1   1100: 1000 (for three 1s) + 100 (for the other 1)
 2 4 4 5 4   450:  400 (for three 4s) + 50 (for the 5)

 

In some languages, it is possible to mutate the input to the function. This is something that you should never do. If you mutate the input, you will not be able to pass all the tests.

 

Solution

#include <vector>
#include <map>

using namespace std;

int score(const std::vector<int>& dice) {
  int result = 0;
  std::map<int, int> score;
  for(auto i : dice) score[i]++;
  
  for(auto x : dice) {
    switch(x) {
        case 1:{
          if(3 <= score[x]) {
            result += 1000;
            score[x] -= 3;
          } else if (0 < score[x]) {
            result += (100 * score[x]);
            score[x] = 0;
          } else {
            // Do nothing            
          }
          break;
        }
        case 2:{
          if(3 <= score[x]) {
            result += 200;
            score[x] = 0;
          } else {
            // Do nothing            
          }
          break;
        }
        case 3:{
          if(3 <= score[x]) {
            result += 300;
            score[x] = 0;
          } else {
            // Do nothing            
          }
          break;
        }
        case 4:{
          if(3 <= score[x]) {
            result += 400;
            score[x] = 0;
          } else {
            // Do nothing            
          }
          break;
        }
        case 5:{
          if(3 <= score[x]) {
            result += 500;
            score[x] -= 3;
          } else if (0 < score[x]) {
            result += (50 * score[x]);
            score[x] = 0;
          } else {
            // Do nothing            
          }
          break;
        }
        case 6:{
          if(3 <= score[x]) {
            result += 600;
            score[x] = 0;
          } else {
            // Do nothing            
          }
          break;
        }
        default: {
          // Do nothing
          break;
        }
    }
    
  }
  
  return result;
}

 

Unnamed의 코드

#include <vector>

int score(const std::vector<int>& dice) {
  unsigned cs[7] = {};
  for (auto d : dice)
    cs[d]++;
  return
    cs[1] / 3 * 1000 + cs[6] / 3 * 600 + cs[5] / 3 * 500 +
    cs[4] / 3 * 400 + cs[3] / 3 * 300 + cs[2] / 3 * 200 +
    cs[1] % 3 * 100 + cs[5] % 3 * 50;
}

 

reflake의 코드

#include <algorithm>
#include <iostream>
#include <vector>

const int sidesCount = 6;

struct DiceCounterGenerator {
  std::vector<int> dices;
  int index;
  
  DiceCounterGenerator(std::vector<int> dices) : dices(dices) { index = 0; }
  
  int operator()() { return std::count(dices.begin(), dices.end(), ++index); }
  
};

struct PointCounter {
  int total;
  int index;
  int* triple_points;
  int* single_points;
  
  PointCounter(int* triple_points, int* single_points) :
    triple_points(triple_points),
    single_points(single_points)
  {
    total = 0;
    index = 0;
  }
  
  void operator()(int n) {
    total += (n / 3) * triple_points[index];
    total += (n % 3) * single_points[index];
    
    ++index;
  }
};

int score(const std::vector<int>& dice) {

  std::vector<int> values(sidesCount);
  std::generate(values.begin(), values.end(), DiceCounterGenerator(dice));

  int triple_points[] = { 1000, 200, 300, 400, 500, 600 };
  int single_points[] =  { 100, 0, 0, 0, 50, 0 };

  auto points = std::for_each(values.begin(), values.end(), PointCounter(triple_points, single_points));
  
  return points.total;

}

 

후기

강철멘털이라고 생각한다. 하지만 문제를 푼 후 남의 코드를 봤을 때 조금 멘털이 흔들렸다. 대체 이 Greed dice 문제를 놓고 어떻게하면 깔끔하게 풀 수 있을까? 고민하다가 내놓은 결과이다. 그렇게 내가 짜 놓은 코드는 회사에서 내가 제일 보기 싫어하는 코드들보다 살짝 나아진 코드이다. 그래봐야 else if에서 switch case문으로 바뀌었다는 것?

첫 번째 남의 코드는 잘 이해가 안간다. 어떻게 저런 공식을 찾아낼 수 있지?라는 의문으로 마음을 가라 앉히고 문제와 코드를 번갈아 가며 다시 보니 그럴 수 있다..

두 번째 남의 코드는 전형적인 C++의 코드를 보여주었다. 내가 맨날 공부하려고 하는 그 문법들이 다 들어가 있는 듯 하다. 아직 공부가 조금 부족한듯 하니 공부를 다시 하고 코드를 분석해보아야겠다.

 

(url: https://www.codewars.com/kata/5270d0d18625160ada0000e4)

 

'CodeKata > Codewars' 카테고리의 다른 글

[CK] Human Readable Time  (0) 2021.10.28
[CK] Product of consecutive Fib numbers  (0) 2021.10.28
[CK] Greed is Good  (0) 2021.10.27
[CK] Decode the Morse code  (0) 2021.10.27
[CK] Mexican Wave  (0) 2021.10.25
[CK] Rectangle into Squares  (0) 2021.10.25

댓글0