Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make this C++ code more DRY?

I have these two methods on a class that differ only in one method call. Obviously, this is very un-DRY, especially as both use the same formula.

int PlayerCharacter::getAttack() {
    int attack;
    attack = 1 + this->level;
    for(int i = 0; i < this->current_equipment; i++) {
        attack += this->equipment[i].getAttack();
    }
    attack *= sqrt(this->level);
    return attack;
}
int PlayerCharacter::getDefense() {
    int defense;
    defense = 1 + this->level;
    for(int i = 0; i < this->current_equipment; i++) {
        defense += this->equipment[i].getDefense();
    }
    defense *= sqrt(this->level);
    return defense;
}

How can I tidy this up in C++?

like image 683
Macha Avatar asked Apr 19 '10 18:04

Macha


People also ask

How do you DRY programming?

"Don't repeat yourself" (DRY) is a principle of software development aimed at reducing repetition of software patterns, replacing it with abstractions or using data normalization to avoid redundancy.

What does it mean to make code DRY?

DRY, which stands for 'don't repeat yourself,' is a principle of software development that aims at reducing the repetition of patterns and code duplication in favor of abstractions and avoiding redundancy.

WHAT IS DRY principle in C?

The DRY (don't repeat yourself) principle is a best practice in software development that recommends software engineers to do something once, and only once.


2 Answers

One easy way is to represent all of a piece of equipment's attributes in an array, indexed by an enum.

enum Attributes {
  Attack, 
  Defense,
  AttributeMAX
};

class Equipment {
  std::vector<int> attributes;

  Equipment(int attack, int defense): attributes(AttributeMAX)
  {
    attributes[ATTACK] = attack;
    attributes[DEFENSE] = defense;
  }

};

Then you change your function to

int PlayerCharacter::getAttribute(int& value, Attribute attribute) {
    value = 1 + this->level;
    for(int i = 0; i <= current_equipment; i++) {
        value += this->equipment[i].attributes[attribute];
    }
    value *= sqrt(this->level);
    return value;
}

And you can call it like so

  player.getAttribute(player.attack, Attack);
like image 151
Bill Prin Avatar answered Oct 08 '22 13:10

Bill Prin


In my opinion, what you have is fine, as it will allow you to tweak attack/defense more than if you represented both of them with one function. Once you start testing your game, you'll begin balancing attack/defense formulas, so having separate functions for them is fine.

The whole concept of DRY [don't repeat yourself] is [hopefully] to prevent your code from becoming a huge copy & paste fest. In your situation, the defense/attack formulas will change over time [for example, what if characters have buffs/status-ailment? A specific status ailment might cut defense in half, while increasing attack by 2 (Berserk, FF reference, heh)]

like image 24
Warty Avatar answered Oct 08 '22 13:10

Warty