Hoppa till huvudinnehåll

Objektorienterad Programmering - Bygg Mini Battle Arena ⚔️

I detta projekt får ni träna på OOP-relaterade koncept som ännu inte täcks av webserverprogrammeringen med SvelteKit & Prisma.

Ditt uppdrag 🎯

Bemästra objektorienterad programmering genom att bygga en CLI battle arena:

  • Förstå klasser och objekt genom Fighter-system
  • Implementera arv med olika fighter-typer (Warrior, Mage, Archer)
  • Skapa interfaces för battle behaviors
  • Hantera inkapsling för stats och health
  • Bygga generisk Arena för tournaments

Mål: Skapa ett fungerande battle system där olika fighters kan mötas i epic duels!

Setup för CLI Battle Arena 🚀
mkdir battle-arena
cd battle-arena
npm init -y
npm install -D typescript @types/node ts-node
npx tsc --init

Kör ditt spel med: npx ts-node arena.ts

Fas 1: Grundläggande Fighter-klass 🥊

Steg 1: Analysera vad en fighter behöver

Tänk innan du kodar:

// Vad behöver alla fighters ha gemensamt?
// - Namn för att identifiera dem
// - Health för att veta när de förlorar
// - Attack power för skada
// - Någon form av special ability?

// Din uppgift 1: Lista 5 properties som alla fighters bör ha
// 1.
// 2.
// 3.
// 4.
// 5.

Steg 2: Skapa bas Fighter-klassen

Din första klass med utmaningar:

// arena.ts
class Fighter {
// Din uppgift 2: Deklarera properties
// Tips: name (string), health (number), maxHealth (number), attackPower (number)



constructor(name: string, health: number, attackPower: number) {
// Din uppgift 3: Initialisera alla properties
// Kom ihåg att sätta maxHealth = health




}

// Din uppgift 4: Implementera attack() metoden
// Ska returnera en string som beskriver attacken
// Använd fighter's namn i meddelandet
attack(): string {
// Din kod här

}

// Din uppgift 5: Implementera takeDamage()
// Parameter: damage (number)
// Minska health med damage
// Health kan aldrig gå under 0
// Returnera true om fightern fortfarande lever, false om död
takeDamage(damage: number): boolean {
// Din logik här




}

// Din uppgift 6: Implementera isAlive()
// Returnera true om health > 0
isAlive(): boolean {
// Din kod här

}

// Din uppgift 7: Implementera getStatus()
// Returnera string med namn och health, ex: "Warrior Bob: 75/100 HP"
getStatus(): string {
// Din kod här

}
}

Steg 3: Testa din bas-klass

Verifiera att allt fungerar:

// Din uppgift 8: Skapa två fighters och testa alla metoder
// Skapa fighter1 och fighter2
// Låt dem attackera varandra
// Kolla status efter varje attack


// Test kod här:






console.log("Första testet klart!");

Steg 4: Basic battle loop

Enkel stridsmekanism:

// Din uppgift 9: Implementera en enkel battle funktion
// Parametrar: fighter1 och fighter2
// Loop tills någon dör
// Alternera vem som attackerar
// Skriv ut vad som händer varje runda
// Returnera vinnaren

function battle(fighter1: Fighter, fighter2: Fighter): Fighter {
console.log(`🥊 BATTLE BEGINS: ${fighter1.getStatus()} vs ${fighter2.getStatus()}`);

let round = 1;
// Din logik här - while loop som fortsätter tills någon dör
// Tips: använd fighter1.isAlive() && fighter2.isAlive()







// Vem vann?

}

// Din uppgift 10: Testa battle funktionen
// Skapa fighters och låt dem slåss


Fas 2: Interfaces för Battle Behaviors 🎭

Steg 1: Identifiera olika beteenden

Tänk på vad fighters kan göra:

// Vilka olika "abilities" kan fighters ha?
// - Vissa kan försvara sig (block/shield)
// - Vissa kan heal
// - Vissa har special attacks
// - Vissa kan buff/debuff

// Din uppgift 11: Vilka interfaces behöver vi?
// Föreslå 3 interfaces med deras metoder:

// Interface 1:
// Metod:

// Interface 2:
// Metod:

// Interface 3:
// Metod:

Steg 2: Definiera interfaces

Skapa kontrakt för beteenden:

// Din uppgift 12: Definiera Defensive interface
// Metod: defend() som returnerar number (damage reduction)
interface Defensive {
// Din kod här

}

// Din uppgift 13: Definiera Magical interface
// Metod: castSpell() som returnerar string (spell description)
// Metod: getMana() som returnerar number
interface Magical {
// Din kod här


}

// Din uppgift 14: Definiera Ranged interface
// Metod: rangedAttack() som returnerar number (damage)
// Metod: getAmmo() som returnerar number
interface Ranged {
// Din kod här


}

Steg 3: Testa interface thinking

Planera innan implementering:

// Din uppgift 15: Vilka fighter-typer ska implementera vilka interfaces?
//
// Warrior: implementerar Defensive (kan blockera)
// Mage: implementerar Magical (kan casta spells)
// Archer: implementerar Ranged (kan skjuta pilar)
//
// Skriv ner dina tankar om varför denna kombination gör sense:
/*




*/

Fas 3: Specialiserade Fighter-typer 🛡️🔮🏹

Steg 1: Warrior klassen

Den defensiva fightern:

class Warrior extends Fighter implements Defensive {
// Din uppgift 16: Lägg till armor property


constructor(name: string, health: number = 120, attackPower: number = 25, armor: number = 10) {
// Din uppgift 17: Anropa super() och sätt armor


}

// Din uppgift 18: Override attack() metoden
// Warriors gör mer damage: attackPower + (armor / 2)
// Returnera beskrivande meddelande
attack(): string {
// Din kod här - beräkna total damage och returnera meddelande


}

// Din uppgift 19: Implementera defend() från Defensive interface
// Returnera armor värde som damage reduction
defend(): number {
// Din kod här

}

// Din uppgift 20: Skapa getDamageReduction() metod
// Beräkna hur mycket damage som blockeras baserat på armor
getDamageReduction(incomingDamage: number): number {
// Din logik - t.ex. armor reducerar damage med armor/2 men max 50%


}
}

Steg 2: Mage klassen

Den magiska fightern:

class Mage extends Fighter implements Magical {
// Din uppgift 21: Lägg till mana property


constructor(name: string, health: number = 80, attackPower: number = 15, mana: number = 100) {
// Din uppgift 22: Implementera constructor


}

// Din uppgift 23: Override attack()
// Mages gör magic damage som kostar mana
// Om mana < 10: gör weak physical attack
// Om mana >= 10: gör strong magic attack och minska mana
attack(): string {
// Din kod här



}

// Din uppgift 24: Implementera castSpell()
// Kostar 30 mana, gör extra damage (attackPower * 2)
// Returnera spell description eller "Not enough mana"
castSpell(): string {
// Din kod här



}

// Din uppgift 25: Implementera getMana()
getMana(): number {

}

// Din uppgift 26: Skapa healSelf() metod
// Kostar 20 mana, healar 30 HP (up to maxHealth)
healSelf(): string {
// Din kod här




}
}

Steg 3: Archer klassen

Den långdistans fightern:

class Archer extends Fighter implements Ranged {
// Din uppgift 27: Lägg till arrows property


constructor(name: string, health: number = 100, attackPower: number = 20, arrows: number = 30) {
// Din uppgift 28: Implementera constructor


}

// Din uppgift 29: Override attack()
// Om arrows > 0: använd pil och gör normal damage
// Om arrows = 0: melee attack med reducerad damage (attackPower / 2)
attack(): string {
// Din kod här



}

// Din uppgift 30: Implementera rangedAttack()
// Kostar 2 arrows, gör extra damage (attackPower * 1.5)
// Returnera damage eller 0 om inte enough arrows
rangedAttack(): number {
// Din kod här



}

// Din uppgift 31: Implementera getAmmo()
getAmmo(): number {

}
}

Steg 4: Polymorfism test

Testa att alla typer fungerar som Fighter:

// Din uppgift 32: Skapa array med olika fighter-typer
const fighters: Fighter[] = [
// Din kod - skapa en av varje typ

];

// Din uppgift 33: Loop genom alla och visa polymorfism
// Anropa attack() för alla och se olika beteenden
console.log("=== POLYMORFISM TEST ===");
fighters.forEach(fighter => {
// Din kod här

});

// Din uppgift 34: Type checking challenge
// Loop igen men använd instanceof för att anropa specifika metoder
// Exempel: endast Warriors kan defend(), endast Mages kan castSpell()
console.log("=== SPECIAL ABILITIES ===");
fighters.forEach(fighter => {
// Din kod med instanceof checks



});

Fas 4: Inkapsling och Stats Management 🔒

Steg 1: Problem med nuvarande design

Vad kan gå fel?

// Vad är problemet med denna kod?
const warrior = new Warrior("Conan", 100, 25, 10);
warrior.health = 999999; // Cheat!
warrior.attackPower = -50; // Nonsense!

// Din uppgift 35: Lista 3 problem med öppen data access
// 1.
// 2.
// 3.

Steg 2: Säker Fighter bas-klass

Refactorera med proper inkapsling:

class Fighter {
private _name: string;
private _health: number;
private _maxHealth: number;
private _attackPower: number;

constructor(name: string, health: number, attackPower: number) {
// Din uppgift 36: Validera input och sätt private fields
// Namn får inte vara tomt
// Health och attackPower måste vara positiva





}

// Din uppgift 37: Skapa getters (read-only access)
get name(): string { }
get health(): number { }
get maxHealth(): number { }
get attackPower(): number { }

// Din uppgift 38: Skapa protected setter för health
// (endast subklasser ska kunna ändra)
// Validera: inte negativt, inte över maxHealth
protected setHealth(value: number): void {
// Din validering här



}

// Din uppgift 39: Uppdatera takeDamage() för att använda private fields
takeDamage(damage: number): boolean {
// Använd setHealth() för validering


}

// Din uppgift 40: Skapa healthPercentage getter
get healthPercentage(): number {
// Returnera health som procent (0-100)

}

// Uppdatera andra metoder för att använda getters...
}

Steg 3: Säker Warrior implementation

Uppdatera för inkapsling:

class Warrior extends Fighter implements Defensive {
private _armor: number;

constructor(name: string, health: number = 120, attackPower: number = 25, armor: number = 10) {
// Din uppgift 41: Validera armor (måste vara positivt)
// Anropa super med validerade värden



}

get armor(): number {

}

// Din uppgift 42: Säker armor upgrade metod
upgradeArmor(points: number): void {
// Validera att points är positivt
// Max armor = 50
// Skriv ut resultat




}

// Uppdatera andra metoder för nya getters...
}

Steg 4: Stats validation

Testa din säkerhet:

// Din uppgift 43: Försök bryta ditt system
const testWarrior = new Warrior("Test", 100, 20, 15);

// Testa ogiltiga värden:
// testWarrior.health = -50; // Ska inte fungera längre!

// Testa edge cases:


// Skriv ut vad som fungerade/inte fungerade:

Fas 5: Generisk Arena och Tournament System 🏟️

Steg 1: Planera Arena klassen

Vad ska en arena kunna göra?

// Din uppgift 44: Designa Arena funktionalitet
// Vad behöver en arena hantera?
// - Lista av fighters
// - Tournaments (flera battles)
// - Statistik (wins/losses)
// - Different tournament types?

// Skriv ditt design här:
/*




*/

Steg 2: Generisk Arena implementation

Flexibel arena för alla fighter-typer:

// Din uppgift 45: Skapa generisk Arena klass
class Arena<T extends Fighter> {
private fighters: T[] = [];
private battleHistory: /* vilken typ? */ = [];

constructor(private name: string) {

}

// Din uppgift 46: Implementera addFighter()
// Validera att fighter inte redan finns
addFighter(fighter: T): boolean {
// Din kod här - check för duplicates baserat på namn



}

// Din uppgift 47: Implementera removeFighter()
removeFighter(name: string): boolean {
// Din kod här


}

// Din uppgift 48: Implementera listFighters()
listFighters(): void {
// Skriv ut alla fighters med deras status


}

// Din uppgift 49: Implementera randomBattle()
// Välj 2 random fighters och låt dem slåss
// Spara resultatet i battleHistory
randomBattle(): string | null {
// Din kod här




}

// Din uppgift 50: Implementera tournament()
// Round-robin: alla slåss mot alla
// Returnera vinnare (mest wins)
tournament(): T | null {
// Din kod här - detta är en utmaning!




}
}

Steg 3: Battle Statistics

Spåra fighter prestanda:

// Din uppgift 51: Skapa FighterStats klass
class FighterStats {
// Vad vill vi spåra?
// wins, losses, totalDamageDealt, totalDamageTaken, battlesPlayed


constructor(public fighterName: string) {

}

// Din uppgift 52: Implementera update metoder
recordWin(): void { }
recordLoss(): void { }
recordDamage(dealt: number, taken: number): void { }

// Din uppgift 53: Implementera getWinRate()
getWinRate(): number {
// Returnera win percentage

}

// Din uppgift 54: Implementera getSummary()
getSummary(): string {
// Returnera formaterad statistics string

}
}

// Din uppgift 55: Integrera stats i Arena
// Uppdatera Arena för att spåra fighter statistics

Fas 6: CLI Interface och Komplett System 💻

Steg 1: Command Parser

Hantera user input:

// Din uppgift 56: Implementera command parsing
class CommandParser {
// Kommandon vi vill stödja:
// "create warrior Bob" - skapa fighter
// "list" - visa alla fighters
// "battle Alice Bob" - specifik battle
// "random" - random battle
// "tournament" - kör tournament
// "stats Alice" - visa fighter stats
// "quit" - avsluta

static parseCommand(input: string): { command: string; args: string[] } {
// Din kod här - split input och returnera structured data


}
}

Steg 2: Game Controller

Huvudlogik för CLI:

// Din uppgift 57: Implementera GameController
class GameController {
private arena: Arena<Fighter>;
private running: boolean = true;

constructor() {
this.arena = new Arena<Fighter>("Epic Battle Arena");
// Lägg till några default fighters för testing?

}

// Din uppgift 58: Implementera handleCommand()
handleCommand(command: string, args: string[]): void {
switch (command) {
case 'create':
// Din kod - parse fighter type och name, skapa fighter

break;
case 'list':
// Din kod

break;
case 'battle':
// Din kod - hitta fighters och starta battle

break;
case 'random':
// Din kod

break;
case 'tournament':
// Din kod

break;
case 'stats':
// Din kod

break;
case 'quit':
// Din kod

break;
default:
console.log("Unknown command. Try: create, list, battle, random, tournament, stats, quit");
}
}

// Din uppgift 59: Implementera createFighter()
private createFighter(type: string, name: string): Fighter | null {
// Din kod - factory pattern för att skapa rätt fighter type



}

// Din uppgift 60: Implementera main game loop
async run(): Promise<void> {
console.log("🏟️ Welcome to Epic Battle Arena! 🏟️");
console.log("Commands: create <type> <name>, list, battle <name1> <name2>, random, tournament, stats <name>, quit");

// Import readline för user input
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});

while (this.running) {
// Din kod för input loop


}
}
}

Steg 3: Huvudprogram

Starta allt:

// Din uppgift 61: Skapa main function och starta spelet
async function main() {
const game = new GameController();
await game.run();
}

// Din uppgift 62: Error handling
// Wrap main() i try-catch för graceful errors

if (require.main === module) {
// Din kod här

}

Steg 4: Testing och polish

Slutlig validering:

// Din uppgift 63: Skriv test scenarios
// Testa alla commands:
// 1. Skapa fighters av olika typer
// 2. Lista fighters
// 3. Kör battles
// 4. Kör tournament
// 5. Kolla stats
// 6. Edge cases (ogiltiga commands, non-existent fighters, etc.)

// Dokumentera dina test results:
/*




*/

Avslutande Utmaningar 🏆

Om du vill gå längre:

Performance Challenge:

// Din uppgift 64: Optimera för stora tournaments
// Vad händer med 1000 fighters?
// Hur kan du optimera tournament() metoden?

Feature Extensions:

// Din uppgift 65: Lägg till nya features
// - Fighter levels och experience
// - Equipment system (weapons/armor upgrades)
// - Special tournament modes (elimination, team battles)
// - Save/load fighters till fil

Design Patterns:

// Din uppgift 66: Implementera nya patterns
// - Observer: UI updates när battles händer
// - Strategy: Olika AI behaviors för fighters
// - Factory: Mer sofistikerad fighter creation

Reflektion 🤔

Efter implementering, svara på:

Teknisk förståelse:

  1. Vilka OOP-principer hjälpte mest med code organization?

  2. Vad var svårast med generics och varför?

  3. Hur hjälpte interfaces dig att designa flexibla system?

Design insights:

  1. Vilka trade-offs upptäckte du mellan enkelhet och funktionalitet?

  2. När valde du arv vs composition och varför?

  3. Vad lärde dig mest om error handling och validation?

Grattis! 🎉

Du har nu byggt:

  • Komplett CLI-applikation med OOP-principer
  • Flexibel fighter-hierarki med arv och polymorfism
  • Type-safe generisk arena system
  • Robust error handling och data validation
  • Interactive command interface för user interaction

Detta battle arena använder samma patterns som:

  • Game engines (Unity, Unreal)
  • Backend services (REST APIs)
  • Desktop applications
  • Mobile games
Du kan bygga komplexa system! ⚔️

Genom att lösa varje utmaning steg för steg har du utvecklat skills för att tackla stora programmeringsprojekt!

Nästa steg: Använd dessa OOP-skills för webbutveckling med dina SvelteKit-lektioner!