Last active
February 7, 2025 04:50
-
-
Save Natetnosova/621674b06ba9a02a4ec57c4c532ab837 to your computer and use it in GitHub Desktop.
ДЗ: Гладиаторские бои
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
namespace Colosseum | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
ColosseumGame game = new ColosseumGame(); | |
game.Run(); | |
} | |
} | |
public interface IDamageable | |
{ | |
void TakeDamage(int damage); | |
bool IsAlive { get; } | |
} | |
public abstract class Fighter : IDamageable | |
{ | |
public const int MinDamage = 0; | |
public const int MinHealth = 0; | |
private readonly string _name; | |
protected int _health; | |
private readonly int _damage; | |
private readonly int _defense; | |
protected Fighter(string name, int health, int damage, int defense) | |
{ | |
_name = name; | |
_health = health; | |
_damage = damage; | |
_defense = defense; | |
} | |
public string Name => _name; | |
public int Health => _health; | |
public int Damage => _damage; | |
public int Defense => _defense; | |
public bool IsAlive => _health > MinHealth; | |
public virtual void Attack(IDamageable opponent) | |
{ | |
Console.WriteLine($"{Name} атакует {opponent}."); | |
opponent.TakeDamage(Damage); | |
} | |
public virtual void TakeDamage(int damage) | |
{ | |
int actualDamage = Math.Max(damage - Defense, MinDamage); | |
_health = Math.Max(_health - actualDamage, MinHealth); | |
Console.WriteLine($"{Name} получил {actualDamage} урона, здоровье: {Health}"); | |
} | |
public abstract Fighter Clone(); | |
public override string ToString() | |
{ | |
return $"{Name} (Здоровье: {Health}, Урон: {Damage}, Защита: {Defense})"; | |
} | |
} | |
public class Berserker : Fighter | |
{ | |
private const int DamageMultiplier = 2; | |
private const int DoubleDamageChance = 20; | |
public Berserker(string name, int health, int damage, int defense) | |
: base(name, health, damage, defense) { } | |
public override void Attack(IDamageable opponent) | |
{ | |
const int ChanceMin = 0; | |
const int ChanceMax = 100; | |
bool doubleDamage = RandomProvider.Next(ChanceMin, ChanceMax) < DoubleDamageChance; | |
int attackDamage = doubleDamage ? Damage * DamageMultiplier : Damage; | |
string attackMessage = doubleDamage | |
? $"{Name} наносит удвоенный урон!" | |
: $"{Name} атакует {opponent} и наносит {attackDamage} урона."; | |
Console.WriteLine(attackMessage); | |
opponent.TakeDamage(attackDamage); | |
} | |
public override Fighter Clone() | |
{ | |
return new Berserker(Name, Health, Damage, Defense); | |
} | |
} | |
public class DualAttacker : Fighter | |
{ | |
private const int AttackInterval = 3; | |
private const int DoubleAttackMultiplier = 2; | |
private int _attackCount = 0; | |
public DualAttacker(string name, int health, int damage, int defense) | |
: base(name, health, damage, defense) { } | |
public override void Attack(IDamageable opponent) | |
{ | |
_attackCount++; | |
int attackDamage = Damage; | |
if (_attackCount % AttackInterval == 0) | |
{ | |
attackDamage *= DoubleAttackMultiplier; | |
Console.WriteLine($"{Name} наносит двойную атаку!"); | |
} | |
else | |
{ | |
Console.WriteLine($"{Name} атакует {opponent} и наносит {attackDamage} урона."); | |
} | |
opponent.TakeDamage(attackDamage); | |
} | |
public override Fighter Clone() | |
{ | |
return new DualAttacker(Name, Health, Damage, Defense); | |
} | |
} | |
public class RageFighter : Fighter | |
{ | |
private const int MaxRage = 100; | |
private const int RageGain = 25; | |
private const int HealAmount = 20; | |
private int _rage = 0; | |
public RageFighter(string name, int health, int damage, int defense) | |
: base(name, health, damage, defense) { } | |
public override void TakeDamage(int damage) | |
{ | |
base.TakeDamage(damage); | |
_rage += RageGain; | |
if (_rage >= MaxRage) | |
{ | |
Heal(HealAmount); | |
_rage = 0; | |
} | |
} | |
private void Heal(int amount) | |
{ | |
_health += amount; | |
Console.WriteLine($"{Name} исцеляется на {amount} здоровья, текущее здоровье: {Health}"); | |
} | |
public override Fighter Clone() | |
{ | |
return new RageFighter(Name, Health, Damage, Defense); | |
} | |
} | |
public class Mage : Fighter | |
{ | |
private const int ManaCost = 30; | |
private const int SpellDamage = 40; | |
private int _mana = 100; | |
public Mage(string name, int health, int damage, int defense) | |
: base(name, health, damage, defense) { } | |
public override void Attack(IDamageable opponent) | |
{ | |
if (_mana >= ManaCost) | |
{ | |
_mana -= ManaCost; | |
Console.WriteLine($"{Name} применяет заклинание 'Огненный шар' и наносит {SpellDamage} урона."); | |
opponent.TakeDamage(SpellDamage); | |
} | |
else | |
{ | |
Console.WriteLine($"{Name} не хватает маны для заклинания. Выполняется обычная атака."); | |
base.Attack(opponent); | |
} | |
} | |
public override Fighter Clone() | |
{ | |
return new Mage(Name, Health, Damage, Defense); | |
} | |
} | |
public class Dodger : Fighter | |
{ | |
private const int DodgeChance = 30; | |
private const int ChanceMin = 0; | |
private const int ChanceMax = 100; | |
public Dodger(string name, int health, int damage, int defense) | |
: base(name, health, damage, defense) { } | |
public override void TakeDamage(int damage) | |
{ | |
if (RandomProvider.Next(ChanceMin, ChanceMax) < DodgeChance) | |
{ | |
Console.WriteLine($"{Name} уклоняется от атаки!"); | |
} | |
else | |
{ | |
base.TakeDamage(damage); | |
} | |
} | |
public override Fighter Clone() | |
{ | |
return new Dodger(Name, Health, Damage, Defense); | |
} | |
} | |
public static class RandomProvider | |
{ | |
private static readonly Random _random = new Random(); | |
public static int Next(int minValue, int maxValue) => _random.Next(minValue, maxValue); | |
} | |
public class ColosseumGame | |
{ | |
private const string MenuOptionFight = "1"; | |
private const string MenuOptionExit = "2"; | |
private readonly List<Fighter> _fighters = new List<Fighter>(); | |
public void Run() | |
{ | |
Console.WriteLine("Добро пожаловать на арену Колизея!"); | |
InitializeFighters(); | |
ShowMainMenu(); | |
} | |
private void InitializeFighters() | |
{ | |
_fighters.Add(new Berserker("Берсерк", 100, 20, 5)); | |
_fighters.Add(new DualAttacker("Двойной атакующий", 120, 15, 7)); | |
_fighters.Add(new RageFighter("Разъярённый", 110, 18, 6)); | |
_fighters.Add(new Mage("Маг", 90, 10, 3)); | |
_fighters.Add(new Dodger("Уворотчик", 80, 12, 5)); | |
} | |
private void ShowMainMenu() | |
{ | |
bool isRunning = true; | |
while (isRunning) | |
{ | |
Console.WriteLine("\nГлавное меню:"); | |
Console.WriteLine($"{MenuOptionFight}. Посмотреть бой"); | |
Console.WriteLine($"{MenuOptionExit}. Выйти из программы"); | |
string choice = Console.ReadLine(); | |
switch (choice) | |
{ | |
case MenuOptionFight: | |
RunFight(); | |
break; | |
case MenuOptionExit: | |
Console.WriteLine("Выход из программы..."); | |
isRunning = false; | |
break; | |
default: | |
Console.WriteLine("Неверный ввод. Попробуйте снова."); | |
break; | |
} | |
} | |
} | |
private void RunFight() | |
{ | |
Fighter fighter1 = ChooseFighter("Выберите первого бойца:", null)?.Clone(); | |
Fighter fighter2 = ChooseFighter("Выберите второго бойца:", fighter1)?.Clone(); | |
if (fighter1 == null || fighter2 == null) | |
{ | |
Console.WriteLine("Бой не может начаться, один из бойцов не выбран."); | |
return; | |
} | |
Console.WriteLine($"\nБой начинается между {fighter1.Name} и {fighter2.Name}!"); | |
while (fighter1.IsAlive && fighter2.IsAlive) | |
{ | |
fighter1.Attack(fighter2); | |
if (fighter2.IsAlive) | |
{ | |
fighter2.Attack(fighter1); | |
} | |
} | |
Console.WriteLine(fighter1.IsAlive ? $"{fighter1.Name} одержал победу!" : $"{fighter2.Name} одержал победу!"); | |
} | |
private Fighter ChooseFighter(string message, Fighter excludeFighter) | |
{ | |
Console.WriteLine(message); | |
for (int i = 0; i < _fighters.Count; i++) | |
{ | |
Console.WriteLine($"{i + 1}. {_fighters[i]}"); | |
} | |
int selectedIndex; | |
if (!int.TryParse(Console.ReadLine(), out selectedIndex) || selectedIndex < 1 || selectedIndex > _fighters.Count) | |
{ | |
Console.WriteLine("Неверный выбор. Попробуйте снова."); | |
return ChooseFighter(message, excludeFighter); | |
} | |
Fighter chosenFighter = _fighters[selectedIndex - 1]; | |
return chosenFighter == excludeFighter ? null : chosenFighter.Clone(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment