Skip to content

About

CS 1410 Inheritance Example

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Monster Battle Arena - CS 1410 OOP Demo

A fun teaching project demonstrating inheritance, abstract classes, and method overriding in C#.

Quick Start

# Build and run tests
dotnet build
dotnet test

# Run the Blazor web app
dotnet run --project MonsterArena.Web

Then open https://localhost:5001 (or the port shown in terminal).


Project Structure

MonsterArena/
├── MonsterArena.Logic/     # Class library (the OOP concepts)
│   ├── Monster.cs          # Abstract base class
│   ├── Dragon.cs           # Derived class - overrides everything
│   ├── Goblin.cs           # Derived class - minimal overrides
│   ├── Wizard.cs           # Derived class - calls base methods
│   └── Arena.cs            # Polymorphism demo
│
├── MonsterArena.Tests/     # Unit tests
│   ├── MonsterTests.cs     # Tests for inheritance behavior
│   └── ArenaTests.cs       # Tests for polymorphism
│
└── MonsterArena.Web/       # Blazor Server UI
    └── Components/Pages/Home.razor  # Interactive monster battles

Teaching Walkthrough

Part 1: Abstract Classes (15 min)

Open Monster.cs and discuss:

  1. Why abstract class?

    public abstract class Monster
    • We want a base type that defines common behavior
    • But it doesn't make sense to create a generic "Monster"
    • Every monster must be a specific type (Dragon, Goblin, etc.)
  2. Try to instantiate it (show the error):

    var m = new Monster("Test", 100);  // COMPILE ERROR!
    • Uncomment the test in MonsterTests.cs line 14-19 to demonstrate
  3. Common properties stay in the base class:

    public string Name { get; protected set; }
    public int Health { get; protected set; }
    public bool IsAlive => Health > 0;
    • All monsters have these - no need to repeat them

Part 2: Abstract Methods (15 min)

Still in Monster.cs:

  1. What are abstract methods?

    public abstract int Attack();
    public abstract string GetBattleCry();
    • No implementation body - just a signature
    • FORCES derived classes to provide their own implementation
    • "Every monster attacks, but each attacks differently"
  2. Compare implementations across monsters:

    Monster Attack() GetBattleCry()
    Dragon 20-35 damage "ROOOAAAR! Feel my flames!"
    Goblin 5-15 damage "Hehehe! Stab stab!"
    Wizard 15-30 (uses mana) "By the power of the arcane!"
  3. What happens if you forget to override?

    • Comment out Attack() in Goblin.cs
    • Show the compile error: "Goblin does not implement inherited abstract member"

Part 3: Virtual Methods (15 min)

Compare virtual vs abstract:

Keyword Has Implementation? Override Required?
abstract No Yes - must override
virtual Yes (default) No - optional

Examples in Monster.cs:

// Virtual method WITH a default implementation
public virtual int Defend(int incomingDamage)
{
    return (int)(incomingDamage * 0.75);  // Take 75% damage
}

// Virtual method that returns null by default
public virtual string? SpecialAbility()
{
    return null;  // No special ability
}

Show the three patterns:

  1. Goblin - Uses defaults (doesn't override):

    • Defend() → uses base class (75% damage)
    • SpecialAbility() → returns null
  2. Dragon - Overrides with better behavior:

    public override int Defend(int incomingDamage)
    {
        return incomingDamage / 2;  // Dragon scales - only 50% damage!
    }
  3. Wizard - Conditionally calls base:

    public override int Defend(int incomingDamage)
    {
        if (_mana >= 5)
        {
            _mana -= 5;
            return (int)(incomingDamage * 0.2);  // Magic shield!
        }
        return base.Defend(incomingDamage);  // Out of mana - use default
    }

Part 4: Run the Unit Tests (10 min)

dotnet test --logger "console;verbosity=detailed"

Walk through key tests:

Test Demonstrates
CannotCreateAbstractMonster Abstract class restriction
EachMonsterHasUniqueBattleCry Abstract method overrides
GoblinUsesDefaultDefend Virtual method - using default
DragonOverridesDefendWithBetterArmor Virtual method - override
WizardDefendUsesBaseWhenOutOfMana Calling base.Method()
PolymorphismAllMonstersCanAttack Polymorphism in action

Part 5: Polymorphism Demo (10 min)

Open Arena.cs and show:

public void AddFighter(Monster monster)  // Accepts ANY Monster type!
{
    Fighters.Add(monster);
}

Key insight: The Arena doesn't know or care if it's a Dragon, Goblin, or Wizard. It just knows it's a Monster with an Attack() method.

public int PerformAttack(Monster attacker, Monster defender, ...)
{
    int damage = attacker.Attack();  // Polymorphism picks the right override!
    ...
}

Part 6: Run the Blazor App (15 min)

dotnet run --project MonsterArena.Web

Interactive demo:

  1. Create one of each monster type
  2. Show their different battle cries (abstract override)
  3. Show special abilities (some have them, some don't - virtual override)
  4. Have monsters attack each other
  5. Click "Defender Blocks" to show different Defend() implementations:
    • Goblin takes 75% damage (default)
    • Dragon takes 50% damage (override)

Student Exercises

Exercise 1: Create a New Monster

Add a Skeleton.cs that:

  • Has 50 health
  • Does 8-12 damage
  • Says "Rattle rattle..."
  • Has NO special ability (use default)
  • Takes FULL damage when defending (override to return incomingDamage)

Exercise 2: Add a New Abstract Method

Add public abstract string GetMonsterType(); to Monster.cs

  • Should return "Fire", "Melee", "Magic", etc.
  • Update all derived classes
  • Add a test that verifies each type

Exercise 3: Add New Virtual Method

Add public virtual bool CanFly() => false; to Monster.cs

  • Override only in Dragon to return true
  • Display this in the Blazor UI

Key Vocabulary

Term Definition Example in Project
Abstract Class A class that cannot be instantiated Monster
Concrete Class A class that can be instantiated Dragon, Goblin, Wizard
Abstract Method Method with no body, must be overridden Attack(), GetBattleCry()
Virtual Method Method with default body, can be overridden Defend(), SpecialAbility()
Override Replacing a virtual/abstract method in derived class public override int Attack()
Polymorphism Treating derived objects through base type List<Monster> holding Dragons and Goblins
Base Keyword to call parent class implementation base.Defend(damage)

Common Student Mistakes

  1. Forgetting override keyword:

    // WRONG - this creates a NEW method, doesn't override!
    public int Attack() { ... }
    
    // RIGHT
    public override int Attack() { ... }
  2. Trying to instantiate abstract class:

    Monster m = new Monster("X", 100);  // COMPILE ERROR
  3. Not implementing all abstract methods:

    • If you inherit from an abstract class, you MUST implement all abstract methods
    • Or make your class abstract too
  4. Confusing virtual and abstract:

    • virtual = "here's a default, override if you want"
    • abstract = "no default, you MUST provide implementation"

Enjoy teaching with Monster Arena!

About

CS 1410 Inheritance Example

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages