HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Action dispatch for a combat class

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
combatdispatchactionforclass

Problem

My problem is that I have a piece of code logic that I'm having trouble fitting into an OO approach, and I was looking for design patterns so that the following code would no longer rely on the ugly


if class is of type A do X else do Y

In Python, we can say I have three "fighting method" classes, class Fight, class Manoeuvre, and class Dodge.

I also have a control class that takes two inputs, attackMode and defendMode. The inputs will always be objects whose classes extend from or are of one of the above three.

The piece of script causing issue is as follows:

```
from random import Random

# Following are example "Action" objects which are to be compared
# For results

class Action:
"Base Action all others inherit from"
__random = Random()

def __init__(self):
self.health = 100

@classmethod
def getSuccess(cls):
return cls.__random.randint(-2,3)

class Dodge(Action):
def __init__(self):
super(Dodge, self).__init__()
class Attack(Action):
def __init__(self):
super(Attack, self).__init__()

def performActionOn(self, subject, sucessLevel=0):
damage = 5 if successLevel > 1 else 3
subject.health -= damage

class Manoeuvre(Action):
def __init__(self):
super(Manoeuvre, self).__init__()

def performActionOn(self, subject, successLevel=0):
pass

# Following is the results configuration

class CombatControl:
def fight(self, actionAttack, actionDefend):

if isinstance(actionDefend, Dodge):
__attackDodge(actionAttack, actionDefend)
else:
__attackAttack(actionAttack, actionDefend)

def __attackAttack(self, attack, defend):
"""
" Defender Attacks back
"""
resultAttack = attack.getSuccess()
resultDefend = defend.getSuccess()

# Both failed. No action.
if resultAttack = resultDefend:
attack.performActionOn(defend, successLevel=resultAttack)

Solution

The first thing that came to mind was further encapsulation of the fight mechanics. One thing I did have to change was how success was handled; now it's a member of each action subclass and is given a new value each time Controller.fight is called.

The other part necessary to this approach was the implementation of a action mode (offensive or defensive) so that actions like Dodge would know what to do.

import random

OFFENSIVE = 0
DEFENSIVE = 1

class Action(object):

    def __init__(self):
        super(Action, self).__init__()
        self.health = 100
        self.success = 0
        self.nextSuccess()

    def nextSuccess(self):
        self.success = random.randint(-2, 3)

    def performOn(self, subject, success):
        pass

class Dodge(Action):

    def __init__(self):
        super(Dodge, self).__init__()

    def performOn(self, subject):
        if mode == DEFENSIVE and subject.success > self.success:
            subject.performOn(subject, success=subject.success)

class Attack(Action):

    def __init__(self):
        super(Attack, self).__init__()

    def performOn(self, subject, mode):
        if self.success = subject.success:
            subject.health -= 5 if success > 1 else 3
        elif mode == DEFENSIVE and self.success > subject.success:
            subject.health -= 3

class Manoeuvre(Action):

    def __init__(self):
        super(Attack, self).__init__()

class Controller:

    def fight(offense, defense):
        offensive = offense.nextSuccess()
        defensive = defense.nextSuccess()
        offense.performOn(defense, OFFENSIVE)
        defense.performOn(offense, DEFENSIVE)


As far as I can tell this does what the original script did. If there are any tweaks that need to be made, let me know!

Code Snippets

import random

OFFENSIVE = 0
DEFENSIVE = 1


class Action(object):

    def __init__(self):
        super(Action, self).__init__()
        self.health = 100
        self.success = 0
        self.nextSuccess()

    def nextSuccess(self):
        self.success = random.randint(-2, 3)

    def performOn(self, subject, success):
        pass


class Dodge(Action):

    def __init__(self):
        super(Dodge, self).__init__()

    def performOn(self, subject):
        if mode == DEFENSIVE and subject.success > self.success:
            subject.performOn(subject, success=subject.success)


class Attack(Action):

    def __init__(self):
        super(Attack, self).__init__()

    def performOn(self, subject, mode):
        if self.success < 0 and subject.success < 0:
            return
        if mode == OFFENSIVE and self.success >= subject.success:
            subject.health -= 5 if success > 1 else 3
        elif mode == DEFENSIVE and self.success > subject.success:
            subject.health -= 3


class Manoeuvre(Action):

    def __init__(self):
        super(Attack, self).__init__()


class Controller:

    def fight(offense, defense):
        offensive = offense.nextSuccess()
        defensive = defense.nextSuccess()
        offense.performOn(defense, OFFENSIVE)
        defense.performOn(offense, DEFENSIVE)

Context

StackExchange Code Review Q#96598, answer score: 2

Revisions (0)

No revisions yet.