計算機科学のブログ

inheritance - Your object's family tree - abstract class, abstract method, override

Head First C Sharp: A Learner’s Guide to Real-World Programming with C Sharp and .NET (Andrew Stellman(著)、Jennifer Greene(著)、O’Reilly Media)の Chapter 6(inheritance - Your object’s family tree)、p.339(Exercise)の解答を求めてみる。

コード

Program.cs

Random random = new Random();
int RollDice(int numberOfRolls)
{
    int roll = 0;
    for (int i = 0; i < numberOfRolls; i++)
    {
        roll += random.Next(1, 7);
    }
    return roll;
}
SwordDamage swordDamage = new SwordDamage(RollDice(3));
ArrowDamage arrowDamage = new ArrowDamage(RollDice(1));
while (true)
{
    Console.Write("0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: ");
    char key = Console.ReadKey(false).KeyChar;
    if (key < '0' || '3' < key)
    {
        break;
    }
    Console.Write("\nS for sword, A for arrow, anything else to quit: ");
    char weaponKey = Char.ToUpper(Console.ReadKey().KeyChar);
    switch (weaponKey)
    {
        case 'S':
            swordDamage.Roll = RollDice(3);
            swordDamage.Magic = key == '1' || key == '3';
            swordDamage.Flaming = key == '2' || key == '3';
            Console.WriteLine($"\nRolled {swordDamage.Roll} for {swordDamage.Damage} HP\n");
            break;
        case 'A':
            arrowDamage.Roll = RollDice(1);
            arrowDamage.Magic = key == '1' || key == '3';
            arrowDamage.Flaming = key == '2' || key == '3';
            Console.WriteLine($"\nRolled {arrowDamage.Roll} for {arrowDamage.Damage} HP\n");
            break;
        default:
            return;
    }
}

abstract class WeaponDamage
{
    private int roll;
    public int Roll
    {
        get { return roll; }
        set
        {
            roll = value;
            CalculateDamage();
        }
    }
    private bool magic;
    public bool Magic
    {
        get { return magic; }
        set
        {
            magic = value;
            CalculateDamage();
        }
    }
    private bool flaming;
    public bool Flaming
    {
        get { return flaming; }
        set
        {
            flaming = value;
            CalculateDamage();
        }
    }
    public int Damage { get; protected set; }
    protected abstract void CalculateDamage();
    public WeaponDamage(int roll)
    {
        this.roll = roll;
        CalculateDamage();
    }
}
class SwordDamage : WeaponDamage
{
    private const int BASE_DAMAGE = 3;
    private const int FLAME_DAMAGE = 2;
    public SwordDamage(int roll) : base(roll) { }
    protected override void CalculateDamage()
    {
        Damage = BASE_DAMAGE;
        if (Magic)
        {

            Damage = (int)(Roll * 1.75M) + BASE_DAMAGE;
        }
        else
        {
            Damage = Roll + BASE_DAMAGE;
        }
        if (Flaming)
        {
            Damage += FLAME_DAMAGE;
        }
    }
}
class ArrowDamage : WeaponDamage
{
    private const decimal BASE_MULTIPLIER = 0.35M;
    private const decimal MAGIC_MULTIPLIER = 2.5M;
    private const decimal FLAME_DAMAGE = 1.25M;
    public ArrowDamage(int roll) : base(roll) { }

    protected override void CalculateDamage()
    {
        decimal baseDamage = Roll * BASE_MULTIPLIER;
        if (Magic)
        {

            baseDamage *= MAGIC_MULTIPLIER;
        }
        if (Flaming)
        {
            Damage += (int)Math.Ceiling(baseDamage + FLAME_DAMAGE);
        }
        else
        {
            Damage = (int)Math.Ceiling(baseDamage);
        }
    }
}

入出力結果(Terminal, Zsh)

% dotnet run
0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 0
S for sword, A for arrow, anything else to quit: s
Rolled 9 for 12 HP

0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 0
S for sword, A for arrow, anything else to quit: a
Rolled 4 for 2 HP

0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 1
S for sword, A for arrow, anything else to quit: s
Rolled 10 for 20 HP

0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 1
S for sword, A for arrow, anything else to quit: a
Rolled 3 for 3 HP

0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 2
S for sword, A for arrow, anything else to quit: s
Rolled 6 for 11 HP

0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 2
S for sword, A for arrow, anything else to quit: a
Rolled 3 for 5 HP

0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 3
S for sword, A for arrow, anything else to quit: s
Rolled 9 for 20 HP

0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 3
S for sword, A for arrow, anything else to quit: a
Rolled 4 for 18 HP

0 fur no magic/flaming, 1 for magic, 2 for flaming, 3 for both, anything else to quit: 4%