Menu
Coddy logo textTech

System postaci w grze

Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 107 z 107.

challenge icon

Wyzwanie

Łatwy

Stwórzmy system postaci do gry, który łączy osadzanie struktur, interfejsy i wzorzec Strategia, aby tworzyć elastyczne mechaniki walki! Zaprojektujesz różne typy postaci, które mogą atakować i bronić się na wyjątkowe sposoby, a ich zdolności będzie można zmieniać w czasie działania programu.

Rozmieścisz kod w pięciu plikach:

  • character.go: Zdefiniuj bazową strukturę Character ze wspólnymi polami: Name (string), Health (int) i MaxHealth (int). Dodaj konstruktor NewCharacter oraz metody:
    • IsAlive() bool: zwraca true, jeśli zdrowie jest większe niż 0
    • Status() string: zwraca format: [Name]: [Health]/[MaxHealth] HP
  • interfaces.go: Zdefiniuj interfejsy walki umożliwiające polimorfizm:
    • Interfejs Attacker z metodą Attack() int: zwraca zadane obrażenia
    • Interfejs Defender z metodą TakeDamage(damage int) int: zmniejsza obrażenia i zwraca faktycznie otrzymane obrażenia
    • Interfejs Ability z metodą Use() string: zwraca opis efektu zdolności
  • characters.go: Utwórz trzy typy postaci, które osadzają Character i implementują zarówno Attacker, jak i Defender:

    Warrior: ma pola Strength (int) i Armor (int). Attack zwraca Strength jako zadawane obrażenia. TakeDamage zmniejsza otrzymywane obrażenia o Armor (otrzymane obrażenia wynoszą co najmniej 1).

    Mage: ma pola Intelligence (int) i MagicResist (int). Attack zwraca Intelligence * 2 jako zadawane obrażenia. TakeDamage zmniejsza otrzymywane obrażenia o MagicResist / 2 (otrzymane obrażenia wynoszą co najmniej 1).

    Archer: ma pola Agility (int) i Evasion (int). Attack zwraca Agility + 5 jako zadawane obrażenia. TakeDamage: jeśli Evasion > 10, zmniejsza obrażenia o 25% (dzielenie całkowitoliczbowe); w przeciwnym razie postać otrzymuje pełne obrażenia (otrzymane obrażenia wynoszą co najmniej 1).

    Dodaj konstruktory dla każdego typu: NewWarrior, NewMage, NewArcher, które przyjmują imię, zdrowie i wartości odpowiednich statystyk.

  • abilities.go: Zaimplementuj wzorzec Strategia z wymiennymi zdolnościami:

    Struktura FireSpell z polem Power (int). Jej metoda Use() zwraca: Casts fireball for [Power] damage

    Struktura IceSpell z polem Power (int). Jej metoda Use() zwraca: Casts ice shard for [Power] damage

    Struktura PowerStrike z polem Multiplier (int). Jej metoda Use() zwraca: Performs power strike at [Multiplier]x damage

    Dodaj do struktury Mage pole ability (typu Ability) oraz metody SetAbility(a Ability) i UseAbility() string. UseAbility zwraca No ability set, jeśli ability ma wartość nil.

  • main.go: Utwórz postacie i pokaż mechanikę walki.

    Wczytaj typ postaci (warrior, mage lub archer), a następnie imię postaci, zdrowie i statystyki właściwe dla danego typu. Utwórz odpowiednią postać.

    Następnie wczytaj liczbę akcji. Każda akcja jest jednym z poniższych poleceń:

    • status: wypisz status postaci
    • attack: wypisz [Name] attacks for [damage] damage
    • defend [amount]: zastosuj obrażenia i wypisz [Name] takes [actual] damage
    • setability [type] [power]: tylko dla magów, ustaw zdolność (type to fire, ice lub strike)
    • useability: tylko dla magów, wypisz wynik metody Use()

Podane zostaną następujące dane wejściowe:

  • Typ postaci, imię, zdrowie i statystyki właściwe dla danego typu
  • Liczba akcji, a następnie każda akcja w osobnym wierszu

Na przykład dla danych:

warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100

Wynik powinien wyglądać następująco:

Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damage

A dla danych:

mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40

Wynik powinien wyglądać następująco:

Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damage

A dla danych:

archer
Legolas
90
18
15
4
status
attack
defend 24
status

Wynik powinien wyglądać następująco:

Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HP

Zwróć uwagę, że osadzanie struktur pozwala każdemu typowi postaci współdzielić pola i metody bazowego Character, a interfejsy umożliwiają polimorficzną walkę, w której każdy Attacker może zadawać obrażenia, a każdy Defender może je otrzymywać. Wzorzec Strategia doskonale sprawdza się w przypadku wymiennych zdolności Maga: ta sama postać może używać różnych zaklęć bez zmieniania swojej podstawowej implementacji!

Spróbuj swoich sił

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// Odczytaj typ postaci
	scanner.Scan()
	charType := strings.TrimSpace(scanner.Text())

	// Odczytaj imię postaci
	scanner.Scan()
	name := strings.TrimSpace(scanner.Text())

	// Odczytaj punkty zdrowia
	scanner.Scan()
	health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Odczytaj pierwszą statystykę właściwą dla danego typu
	scanner.Scan()
	stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Odczytaj drugą statystykę właściwą dla danego typu
	scanner.Scan()
	stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// TODO: Utwórz odpowiednią postać na podstawie charType
	// Użyj zmiennych: charType, name, health, stat1, stat2
	// Dla wojownika: stat1 = Strength, stat2 = Armor
	// Dla maga: stat1 = Intelligence, stat2 = MagicResist
	// Dla łucznika: stat1 = Agility, stat2 = Evasion

	// Odczytaj liczbę akcji
	scanner.Scan()
	numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Przetwórz każdą akcję
	for i := 0; i < numActions; i++ {
		scanner.Scan()
		line := strings.TrimSpace(scanner.Text())
		parts := strings.Fields(line)
		action := parts[0]

		// TODO: Obsłuż każdy typ akcji:
		// - "status": wypisz wynik Status() postaci
		// - "attack": wypisz "[Name] attacks for [damage] damage"
		// - "defend [amount]": zastosuj obrażenia i wypisz "[Name] takes [actual] damage"
		// - "setability [type] [power]": dla magów ustaw zdolność (fire, ice lub strike)
		// - "useability": dla magów wypisz wynik UseAbility()

		_ = action // Usuń tę linię podczas implementacji
		_ = fmt.Println // Usuń tę linię podczas implementacji
	}
}

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Go online