'The optimal moveset is the combination of two moves, one quick move
and one charge move, that deals the most damage over time.
Because each quick move gains a certain amount of energy (different
for different moves) and each charge move requires a different amount
of energy to use, sometimes, a quick move with lower DPS will be
better since it charges the charge move faster.  On the same note,
sometimes a charge move that has lower DPS will be more optimal since
it may require less energy or it may last for a longer period of time.
Attacker have STAB (Same-type attack bonus - x1.25) pokemon have the
same type as attack. So we add it to the "Combo DPS" of the moveset.
The defender attacks in intervals of 1 second for the first 2 attacks,
and then in intervals of 2 seconds for the remainder of the attacks.
This explains why we see two consecutive quick attacks at the beginning
of the match.  As a result, we add +2 seconds to the DPS calculation
for defender DPS output.
So to determine an optimal defensive moveset, we follow the same  method
as we did for optimal offensive movesets, but instead calculate  the
highest "Combo DPS" with an added 2 seconds to the quick move cool down.
Note: critical hits have not yet been implemented in the game
See http://pokemongo.gamepress.gg/optimal-moveset-explanation
See http://pokemongo.gamepress.gg/defensive-tactics'

def _process_movesets(self):

    movesets = []
    for fm in self.fast_attacks:
        for chm in self.charged_attack:
            movesets.append(Moveset(fm, chm, self.types, self.id))
    assert (len(movesets) > 0)
    movesets = sorted(movesets, key=(lambda m: m.dps_attack))
    worst_dps = movesets[0].dps_attack
    best_dps = movesets[(-1)].dps_attack
    if (best_dps > worst_dps):
        for moveset in movesets:
            current_dps = moveset.dps_attack
            moveset.attack_perfection = ((current_dps - worst_dps) / (best_dps - worst_dps))
    movesets = sorted(movesets, key=(lambda m: m.dps_defense))
    worst_dps = movesets[0].dps_defense
    best_dps = movesets[(-1)].dps_defense
    if (best_dps > worst_dps):
        for moveset in movesets:
            current_dps = moveset.dps_defense
            moveset.defense_perfection = ((current_dps - worst_dps) / (best_dps - worst_dps))
    return sorted(movesets, key=(lambda m: m.dps), reverse=True)
