diff --git a/CourseApp.Tests/DemoTest.cs b/CourseApp.Tests/DemoTest.cs deleted file mode 100644 index cf7cbb1..0000000 --- a/CourseApp.Tests/DemoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace CourseApp.Tests -{ - using Xunit; - - public class DemoTest - { - [Fact] - public void Test1() - { - Assert.True(true); - } - } -} diff --git a/CourseApp.Tests/FightTest.cs b/CourseApp.Tests/FightTest.cs new file mode 100644 index 0000000..87796b1 --- /dev/null +++ b/CourseApp.Tests/FightTest.cs @@ -0,0 +1,117 @@ +namespace CourseApp.Tests; + +using CourseApp.Effects; +using CourseApp.Players; +using Xunit; + +[Collection("Sequential")] +public class FightTest +{ + [Theory] + [InlineData(30, 40)] + [InlineData(20, 50)] + [InlineData(10, 5)] + public void AttackTest(int strength, int health) + { + // Arrange + IPlayer firstPlayer = new Archer("Мax", strength, 40, "Лучник"); + IPlayer secondPlayer = new Mage("Nikita", 20, health, "Маг"); + var healthUnderAttack = secondPlayer.Health; + var result = false; + + // Act + firstPlayer.AttackEnemy(secondPlayer); + + if (secondPlayer.Health < healthUnderAttack) + { + result = true; + } + + // Assert + Assert.True(result); + } + + [Fact] + public void UltimateTest() + { + // Arrange + IPlayer firstPlayer = new Archer("Мax", 30, 40, "Лучник"); + IPlayer secondPlayer = new Mage("Nikita", 20, 40, "Маг"); + IPlayer thirdPlayer = new Knight("Kevin", 20, 40, "Рыцарь"); + + // Act + firstPlayer.Ultimate(firstPlayer, secondPlayer, 1); + secondPlayer.Ultimate(secondPlayer, firstPlayer, 1); + secondPlayer.Ultimate(secondPlayer, thirdPlayer, 1); + + // Assert + Assert.NotEmpty(firstPlayer.MyEffects); + Assert.NotEmpty(secondPlayer.MyEffects); + Assert.NotEmpty(thirdPlayer.MyEffects); + } + + [Fact] + public void StunTest() + { + // Arrange + IPlayer firstPlayer = new Archer("Мax", 30, 40, "Лучник"); + IPlayer secondPlayer = new Mage("Nikita", 20, 40, "Маг"); + var result = false; + + // Act + secondPlayer.Ultimate(secondPlayer, firstPlayer, 1); + if (firstPlayer.MyEffects[0] is Stun) + { + result = true; + } + + // Assert + Assert.True(result); + } + + [Fact] + public void EffectTest() + { + // Arrange + IPlayer firstPlayer = new Archer("Мax", 30, 40, "Лучник"); + IPlayer secondPlayer = new Mage("Nikita", 20, 40, "Маг"); + IPlayer thirdPlayer = new Knight("Kevin", 20, 40, "Рыцарь"); + + int[] firstPlayerUnderUltimate = { firstPlayer.Health, firstPlayer.Strength }; + int[] secondPlayerUnderUltimate = { secondPlayer.Health, secondPlayer.Strength }; + int[] thirdPlayerUnderUltimate = { thirdPlayer.Health, thirdPlayer.Strength }; + + firstPlayer.Ultimate(firstPlayer, secondPlayer, 1); + secondPlayer.Ultimate(secondPlayer, thirdPlayer, 1); + thirdPlayer.Ultimate(thirdPlayer, firstPlayer, 1); + + var firstResult = false; + var secondResult = false; + var thirdResult = false; + + // Act + firstPlayer.Effect(firstPlayer); + secondPlayer.Effect(secondPlayer); + thirdPlayer.Effect(thirdPlayer); + + if (firstPlayer.Strength < firstPlayerUnderUltimate[0] || firstPlayer.Health > firstPlayerUnderUltimate[1]) + { + firstResult = true; + } + + if (secondPlayer.Strength < secondPlayerUnderUltimate[0] || secondPlayer.Health > secondPlayerUnderUltimate[1]) + { + secondResult = true; + } + + if (thirdPlayer.Strength < thirdPlayerUnderUltimate[0] || thirdPlayer.Health > thirdPlayerUnderUltimate[1]) + { + thirdResult = true; + } + + // Assert + Assert.True(firstResult); + Assert.True(secondResult); + Assert.True(thirdResult); + } +} \ No newline at end of file diff --git a/CourseApp.Tests/GameTest.cs b/CourseApp.Tests/GameTest.cs new file mode 100644 index 0000000..d43654f --- /dev/null +++ b/CourseApp.Tests/GameTest.cs @@ -0,0 +1,83 @@ +namespace CourseApp.Tests; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json; +using CourseApp.Base; +using CourseApp.GeneratePlayers; +using CourseApp.Logger; +using CourseApp.Players; +using CourseApp.SelectorGame; +using PlayerNames; +using Xunit; + +[Collection("Sequential")] +public class GameTest +{ + [Fact] + public void DraftTest() + { + // Arrange + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("1"); + stringBuilder.AppendLine("Да"); + stringBuilder.AppendLine("Да"); + stringBuilder.AppendLine("10"); + var stringReader = new StringReader(stringBuilder.ToString()); + Console.SetIn(stringReader); + + Game game = new Game(new GameLogger()); + Selector selector = new Selector(new GameLogger()); + List newClasses = selector.SelectCustomClass(); + int playerNumbers = selector.SelectNumbPlayers(); + + const string filepath = @"/home/kiosk/Develop/Tprogramming_2022/CourseApp/Main/Names.json"; + var json = File.ReadAllText(filepath); + var playerNames = JsonSerializer.Deserialize>(json); + + PlayersGenerator playersGenerator = new PlayersGenerator(playerNumbers, playerNames, newClasses); + + List players = new List(playersGenerator.GeneratePlayersArray()); + + // Act + var playersCopy = new List(players); + game.Draft(players); + + // Assert + Assert.NotSame(players, playersCopy); + } + + [Fact] + public void TourTest() + { + // Arrange + Game game = new Game(new GameLogger()); + List players = new List(); + players.Add(new Archer("Max", 10, 30, "Рыцарь")); + players.Add(new Archer("Max", 10, 30, "Рыцарь")); + players.Add(new Archer("Max", 10, 30, "Рыцарь")); + + // Act + game.Tour(players); + + // Assert + Assert.NotEmpty(players); + } + + [Fact] + public void EndGameTest() + { + // Arrange + Game game = new Game(new GameLogger()); + List players = new List(); + players.Add(new Archer("Max", 40, 30, "Рыцарь")); + + // Act + var result = game.EndGame(players); + + // Assert + Assert.True(result); + } +} \ No newline at end of file diff --git a/CourseApp.Tests/PlayersGeneratorTest.cs b/CourseApp.Tests/PlayersGeneratorTest.cs new file mode 100644 index 0000000..0303c36 --- /dev/null +++ b/CourseApp.Tests/PlayersGeneratorTest.cs @@ -0,0 +1,49 @@ +namespace CourseApp.Tests; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json; +using CourseApp.GeneratePlayers; +using CourseApp.Logger; +using CourseApp.SelectorGame; +using PlayerNames; +using Xunit; + +[Collection("Sequential")] +public class PlayersGeneratorTest +{ + [Theory] + [InlineData("1", "Да", "Да", "10")] + [InlineData("2", "Да", "Да", "12")] + [InlineData("3", "Да", "Да", "14")] + public void GeneratePlayersArrayTest(string number, string isAdd, string startChoicePlayers, string numberPlayers) + { + // Arrange + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine(number); + stringBuilder.AppendLine(isAdd); + stringBuilder.AppendLine(startChoicePlayers); + stringBuilder.AppendLine(numberPlayers); + var stringReader = new StringReader(stringBuilder.ToString()); + Console.SetIn(stringReader); + + Selector selector = new Selector(new GameLogger()); + List newClasses = selector.SelectCustomClass(); + + const string filepath = @"/home/kiosk/Develop/Tprogramming_2022/CourseApp/Main/Names.json"; + var json = File.ReadAllText(filepath); + var playerNames = JsonSerializer.Deserialize>(json); + + int playerNumbers = selector.SelectNumbPlayers(); + + var playersGenerator = new PlayersGenerator(playerNumbers, playerNames, newClasses); + + // Act + var players = playersGenerator.GeneratePlayersArray(); + + // Assert + Assert.NotEmpty(players); + } +} \ No newline at end of file diff --git a/CourseApp.Tests/SelectorTest.cs b/CourseApp.Tests/SelectorTest.cs new file mode 100644 index 0000000..5f706ac --- /dev/null +++ b/CourseApp.Tests/SelectorTest.cs @@ -0,0 +1,77 @@ +namespace CourseApp.Tests; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using CourseApp.Logger; +using CourseApp.SelectorGame; +using Xunit; + +[Collection("Sequential")] +public class SelectorTest +{ + [Theory] + [InlineData("1", "Да", "Да")] + [InlineData("2", "Да", "Да")] + [InlineData("3", "Да", "Да")] + public void SelectCustomClassTest(string number, string isAdd, string startChoicePlayers) + { + // Arrange + var selector = new Selector(new GameLogger()); + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine(number); + stringBuilder.AppendLine(isAdd); + stringBuilder.AppendLine(startChoicePlayers); + var stringReader = new StringReader(stringBuilder.ToString()); + Console.SetIn(stringReader); + + // Act + bool result = false; + List listBool = selector.SelectCustomClass(); + + foreach (var element in listBool) + { + result = element; + + if (result == true) + { + break; + } + } + + // Assert + Assert.True(result); + } + + [Theory] + [InlineData("10")] + [InlineData("11", "12")] + [InlineData("12")] + public void SelectNumbPlayersTest(string number, string secondNumber = "14") + { + // Arrange + var selector = new Selector(new GameLogger()); + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine(number); + + if (!(int.Parse(number) % 2 == 0)) + { + stringBuilder.AppendLine(secondNumber); + } + + var stringReader = new StringReader(stringBuilder.ToString()); + Console.SetIn(stringReader); + + // Act + var result = false; + var player = selector.SelectNumbPlayers(); + if (player % 2 == 0) + { + result = true; + } + + // Assert + Assert.True(result); + } +} \ No newline at end of file diff --git a/CourseApp/Entities/Abilities/FireArrows.cs b/CourseApp/Entities/Abilities/FireArrows.cs new file mode 100644 index 0000000..f422225 --- /dev/null +++ b/CourseApp/Entities/Abilities/FireArrows.cs @@ -0,0 +1,32 @@ +namespace CourseApp.Abilities +{ + using CourseApp.Effects; + using CourseApp.Players; + + public class FireArrows : IAbility + { + public string AbilityName { get; set; } = "Огненные стрелы"; + + public int NumberUses { get; set; } = 0; + + private int MaxUses { get; set; } = 1; + + public void Spell(IPlayer myself, IPlayer enemy, int round) + { + enemy.MyEffects.Add(new LongDamage(5, round)); + NumberUses++; + } + + public bool CanSpell() + { + if (NumberUses < MaxUses) + { + return true; + } + else + { + return false; + } + } + } +} diff --git a/CourseApp/Entities/Abilities/Fireball.cs b/CourseApp/Entities/Abilities/Fireball.cs new file mode 100644 index 0000000..cf7a7f2 --- /dev/null +++ b/CourseApp/Entities/Abilities/Fireball.cs @@ -0,0 +1,36 @@ +namespace CourseApp.Abilities +{ + using CourseApp.Effects; + using CourseApp.Players; + + public class Fireball : IAbility + { + public int NumberUses { get; set; } = 0; + + public string AbilityName { get; set; } = "Фаерболл"; + + private int MaxUses { get; set; } = 2; + + public void Spell(IPlayer myself, IPlayer enemy, int round) + { + IEffect generateBuff = new Buff(2, round); + myself.MyEffects.Add(generateBuff); + int indexEffect = myself.MyEffects.IndexOf(generateBuff); + myself.MyEffects[indexEffect].State(myself); + enemy.Health -= myself.Strength; + NumberUses++; + } + + public bool CanSpell() + { + if (NumberUses < MaxUses) + { + return true; + } + else + { + return false; + } + } + } +} diff --git a/CourseApp/Entities/Abilities/Freeze.cs b/CourseApp/Entities/Abilities/Freeze.cs new file mode 100644 index 0000000..97bc0ba --- /dev/null +++ b/CourseApp/Entities/Abilities/Freeze.cs @@ -0,0 +1,23 @@ +namespace CourseApp.Abilities +{ + using CourseApp.Effects; + using CourseApp.Players; + + public class Freeze : IAbility + { + public int NumberUses { get; set; } = 0; + + public string AbilityName { get; set; } = "Заворожение"; + + public void Spell(IPlayer myself, IPlayer enemy, int round) + { + enemy.MyEffects.Add(new Stun(round)); + NumberUses++; + } + + public bool CanSpell() + { + return true; + } + } +} diff --git a/CourseApp/Entities/Abilities/IAbility.cs b/CourseApp/Entities/Abilities/IAbility.cs new file mode 100644 index 0000000..db6e337 --- /dev/null +++ b/CourseApp/Entities/Abilities/IAbility.cs @@ -0,0 +1,15 @@ +namespace CourseApp.Abilities +{ + using CourseApp.Players; + + public interface IAbility + { + int NumberUses { get; set; } + + string AbilityName { get; set; } + + void Spell(IPlayer myself, IPlayer enemy, int round); + + bool CanSpell(); + } +} diff --git a/CourseApp/Entities/Abilities/IceArrows.cs b/CourseApp/Entities/Abilities/IceArrows.cs new file mode 100644 index 0000000..6a1e028 --- /dev/null +++ b/CourseApp/Entities/Abilities/IceArrows.cs @@ -0,0 +1,32 @@ +namespace CourseApp.Abilities +{ + using CourseApp.Effects; + using CourseApp.Players; + + public class IceArrows : IAbility + { + public int NumberUses { get; set; } = 0; + + public string AbilityName { get; set; } = "Ледяные стрелы"; + + private int MaxUses { get; set; } = 1; + + public void Spell(IPlayer myself, IPlayer enemy, int round) + { + enemy.MyEffects.Add(new LongDamage(10, round)); + NumberUses++; + } + + public bool CanSpell() + { + if (NumberUses < MaxUses) + { + return true; + } + else + { + return false; + } + } + } +} diff --git a/CourseApp/Entities/Abilities/StunStrike.cs b/CourseApp/Entities/Abilities/StunStrike.cs new file mode 100644 index 0000000..cc5589c --- /dev/null +++ b/CourseApp/Entities/Abilities/StunStrike.cs @@ -0,0 +1,23 @@ +namespace CourseApp.Abilities +{ + using CourseApp.Effects; + using CourseApp.Players; + + public class StunStrike : IAbility + { + public int NumberUses { get; set; } = 0; + + public string AbilityName { get; set; } = "Оглушающий удар"; + + public void Spell(IPlayer myself, IPlayer enemy, int round) + { + enemy.MyEffects.Add(new Stun(round)); + NumberUses++; + } + + public bool CanSpell() + { + return true; + } + } +} diff --git a/CourseApp/Entities/Abilities/VengeanceStrike.cs b/CourseApp/Entities/Abilities/VengeanceStrike.cs new file mode 100644 index 0000000..7eb0fe0 --- /dev/null +++ b/CourseApp/Entities/Abilities/VengeanceStrike.cs @@ -0,0 +1,27 @@ +namespace CourseApp.Abilities +{ + using CourseApp.Effects; + using CourseApp.Players; + + public class VengeanceStrike : IAbility + { + public int NumberUses { get; set; } = 0; + + public string AbilityName { get; set; } = "Удар возмездия"; + + public void Spell(IPlayer myself, IPlayer enemy, int round) + { + IEffect generateBuff = new Buff(1.3, round); + myself.MyEffects.Add(generateBuff); + int indexEffect = myself.MyEffects.IndexOf(generateBuff); + myself.MyEffects[indexEffect].State(myself); + enemy.Health -= myself.Strength; + NumberUses++; + } + + public bool CanSpell() + { + return true; + } + } +} diff --git a/CourseApp/Entities/Effects/Buff.cs b/CourseApp/Entities/Effects/Buff.cs new file mode 100644 index 0000000..ac8a8bf --- /dev/null +++ b/CourseApp/Entities/Effects/Buff.cs @@ -0,0 +1,42 @@ +namespace CourseApp.Effects +{ + using System.Linq; + using CourseApp.Players; + + public class Buff : IEffect + { + public Buff(double factor, int round) + { + Factor = factor; + LastUsedRound = round; + } + + public double Factor { get; set; } + + public int LastUsedRound { get; set; } + + public void State(IPlayer player) + { + player.Strength = (int)((double)player.Strength * Factor); + } + + public void DeleteState(IPlayer player, int round, int numberPlayer) + { + if (round - LastUsedRound == 1) + { + if (player.NormalState is Normal normal) + { + normal.RestoreStrength(player); + } + + foreach (var effect in player.MyEffects.ToList()) + { + if (effect is Buff buff) + { + player.MyEffects.Remove(buff); + } + } + } + } + } +} diff --git a/CourseApp/Entities/Effects/IEffect.cs b/CourseApp/Entities/Effects/IEffect.cs new file mode 100644 index 0000000..68aa6b9 --- /dev/null +++ b/CourseApp/Entities/Effects/IEffect.cs @@ -0,0 +1,13 @@ +namespace CourseApp.Effects +{ + using CourseApp.Players; + + public interface IEffect + { + int LastUsedRound { get; set; } + + void State(IPlayer player); + + void DeleteState(IPlayer player, int round, int numberPlayer); + } +} diff --git a/CourseApp/Entities/Effects/LongDamage.cs b/CourseApp/Entities/Effects/LongDamage.cs new file mode 100644 index 0000000..420c9d6 --- /dev/null +++ b/CourseApp/Entities/Effects/LongDamage.cs @@ -0,0 +1,37 @@ +namespace CourseApp.Effects +{ + using System.Linq; + using CourseApp.Players; + + public class LongDamage : IEffect + { + public LongDamage(int factor, int round) + { + Factor = factor; + LastUsedRound = round; + } + + public int Factor { get; set; } + + public int LastUsedRound { get; set; } + + public void State(IPlayer enemy) + { + enemy.Health -= Factor; + } + + public void DeleteState(IPlayer player, int round, int numberPlayer) + { + if ((round - LastUsedRound == 10 && numberPlayer == 2) || (round - LastUsedRound == 11 && numberPlayer == 1)) + { + foreach (var effect in player.MyEffects.ToList()) + { + if (effect is LongDamage longDamage) + { + player.MyEffects.Remove(longDamage); + } + } + } + } + } +} diff --git a/CourseApp/Entities/Effects/Normal.cs b/CourseApp/Entities/Effects/Normal.cs new file mode 100644 index 0000000..2c32ad7 --- /dev/null +++ b/CourseApp/Entities/Effects/Normal.cs @@ -0,0 +1,40 @@ +namespace CourseApp.Effects +{ + using CourseApp.Players; + + public class Normal : IEffect + { + public Normal(int strength, int health) + { + Health = health; + Strength = strength; + } + + public int Health { get; set; } + + public int Strength { get; set; } + + public int LastUsedRound { get; set; } + + public void State(IPlayer myself) + { + myself.Strength = Strength; + myself.Health = Health; + } + + public void RestoreStrength(IPlayer myself) + { + myself.Strength = Strength; + } + + public void RestoreHealth(IPlayer myself) + { + myself.Health = Health; + } + + public void DeleteState(IPlayer player, int round, int numberPlayer) + { + player.MyEffects = null; + } + } +} diff --git a/CourseApp/Entities/Effects/Stun.cs b/CourseApp/Entities/Effects/Stun.cs new file mode 100644 index 0000000..9e97a91 --- /dev/null +++ b/CourseApp/Entities/Effects/Stun.cs @@ -0,0 +1,38 @@ +namespace CourseApp.Effects +{ + using System.Linq; + using CourseApp.Players; + + public class Stun : IEffect + { + public Stun(int round) + { + LastUsedRound = round; + } + + public int LastUsedRound { get; set; } + + public void State(IPlayer player) + { + player.Strength = 0; + } + + public void DeleteState(IPlayer player, int round, int numberPlayer) + { + foreach (var effect in player.MyEffects.ToList()) + { + if (effect is Stun stun) + { + if ((round - effect.LastUsedRound == 1 && numberPlayer == 2) || (round - effect.LastUsedRound == 2 && numberPlayer == 1)) + { + player.MyEffects.Remove(stun); + if (player.NormalState is Normal normal) + { + normal.RestoreStrength(player); + } + } + } + } + } + } +} diff --git a/CourseApp/Entities/Players/Archer.cs b/CourseApp/Entities/Players/Archer.cs new file mode 100644 index 0000000..d0a79dc --- /dev/null +++ b/CourseApp/Entities/Players/Archer.cs @@ -0,0 +1,109 @@ +namespace CourseApp.Players +{ + using System; + using System.Collections.Generic; + using System.Linq; + using CourseApp.Abilities; + using CourseApp.Effects; + + public class Archer : IPlayer + { + public Archer(string name, int strength, int health, string className) + { + Name = name; + Strength = strength; + Health = health; + + ClassName = className; + + Abilities.Add(new FireArrows()); + if (ClassName == "Стрелок") + { + Abilities.Add(new IceArrows()); + } + + NormalState = new Normal(Strength, Health); + } + + public string Name { get; set; } + + public int Strength { get; set; } + + public int Health { get; set; } + + public List Abilities { get; set; } = new List(); + + public int CurrentAbility { get; set; } + + public List MyEffects { get; set; } = new List(); + + public IEffect NormalState { get; set; } + + public string ClassName { get; set; } + + public void TakingDamage(int damage) + { + Health -= damage; + } + + public void AttackEnemy(IPlayer enemy) + { + enemy.TakingDamage(Strength); + } + + public void EnterCurrentAbility() + { + Random random = new Random(); + CurrentAbility = random.Next(0, Abilities.Count); + } + + public bool CanUltimate() + { + return Abilities[CurrentAbility].CanSpell(); + } + + public int Ultimate(IPlayer myself, IPlayer enemy, int round) + { + Abilities[CurrentAbility].Spell(myself, enemy, round); + return CurrentAbility; + } + + public void Effect(IPlayer myself) + { + if (MyEffects.Count != 0) + { + foreach (var effect in MyEffects) + { + effect.State(myself); + } + } + } + + public void DeleteEffect(IPlayer myself, int round, int numberPlayer) + { + if (MyEffects.Count != 0) + { + foreach (var effect in MyEffects.ToList()) + { + effect.DeleteState(myself, round, numberPlayer); + } + } + } + + public void RestoreAfterBattle() + { + if (NormalState is Normal normal) + { + Health = normal.Health; + Strength = normal.Strength; + } + + foreach (var ability in Abilities) + { + ability.NumberUses = 0; + } + + MyEffects.Clear(); + } + } +} diff --git a/CourseApp/Entities/Players/IPlayer.cs b/CourseApp/Entities/Players/IPlayer.cs new file mode 100644 index 0000000..a7f9d2c --- /dev/null +++ b/CourseApp/Entities/Players/IPlayer.cs @@ -0,0 +1,41 @@ +namespace CourseApp.Players +{ + using System.Collections.Generic; + using CourseApp.Abilities; + using CourseApp.Effects; + + public interface IPlayer + { + string Name { get; set; } + + int Strength { get; set; } + + int Health { get; set; } + + List Abilities { get; set; } + + int CurrentAbility { get; set; } + + List MyEffects { get; set; } + + IEffect NormalState { get; set; } + + string ClassName { get; set; } + + void TakingDamage(int damage); + + void AttackEnemy(IPlayer enemy); + + void EnterCurrentAbility(); + + bool CanUltimate(); + + int Ultimate(IPlayer myself, IPlayer enemy, int round); + + void Effect(IPlayer myself); + + void DeleteEffect(IPlayer myself, int round, int numberPlayer); + + void RestoreAfterBattle(); + } +} diff --git a/CourseApp/Entities/Players/Knight.cs b/CourseApp/Entities/Players/Knight.cs new file mode 100644 index 0000000..b9a2c58 --- /dev/null +++ b/CourseApp/Entities/Players/Knight.cs @@ -0,0 +1,110 @@ +namespace CourseApp.Players +{ + using System; + using System.Collections.Generic; + using System.Linq; + using CourseApp.Abilities; + using CourseApp.Effects; + + public class Knight : IPlayer + { + public Knight(string name, int strength, int health, string className) + { + Name = name; + Strength = strength; + Health = health; + + ClassName = className; + + Abilities.Add(new VengeanceStrike()); + + if (ClassName == "Воин") + { + Abilities.Add(new StunStrike()); + } + + NormalState = new Normal(Strength, Health); + } + + public string Name { get; set; } + + public int Strength { get; set; } + + public int Health { get; set; } + + public List Abilities { get; set; } = new List(); + + public int CurrentAbility { get; set; } + + public List MyEffects { get; set; } = new List(); + + public IEffect NormalState { get; set; } + + public string ClassName { get; set; } + + public void TakingDamage(int damage) + { + Health -= damage; + } + + public void AttackEnemy(IPlayer enemy) + { + enemy.TakingDamage(Strength); + } + + public void EnterCurrentAbility() + { + Random random = new Random(); + CurrentAbility = random.Next(0, Abilities.Count); + } + + public bool CanUltimate() + { + return Abilities[CurrentAbility].CanSpell(); + } + + public int Ultimate(IPlayer myself, IPlayer enemy, int round) + { + Abilities[CurrentAbility].Spell(myself, enemy, round); + return CurrentAbility; + } + + public void Effect(IPlayer myself) + { + if (MyEffects.Count != 0) + { + foreach (var effect in MyEffects) + { + effect.State(myself); + } + } + } + + public void DeleteEffect(IPlayer myself, int round, int numberPlayer) + { + if (MyEffects.Count != 0) + { + foreach (var effect in MyEffects.ToList()) + { + effect.DeleteState(myself, round, numberPlayer); + } + } + } + + public void RestoreAfterBattle() + { + if (NormalState is Normal normal) + { + Health = normal.Health; + Strength = normal.Strength; + } + + foreach (var ability in Abilities) + { + ability.NumberUses = 0; + } + + MyEffects.Clear(); + } + } +} diff --git a/CourseApp/Entities/Players/Mage.cs b/CourseApp/Entities/Players/Mage.cs new file mode 100644 index 0000000..1135d63 --- /dev/null +++ b/CourseApp/Entities/Players/Mage.cs @@ -0,0 +1,109 @@ +namespace CourseApp.Players +{ + using System; + using System.Collections.Generic; + using System.Linq; + using CourseApp.Abilities; + using CourseApp.Effects; + + public class Mage : IPlayer + { + public Mage(string name, int strength, int health, string className) + { + Name = name; + Strength = strength; + Health = health; + + ClassName = className; + + Abilities.Add(new Freeze()); + if (ClassName == "Огненный маг") + { + Abilities.Add(new Fireball()); + } + + NormalState = new Normal(Strength, Health); + } + + public string Name { get; set; } + + public int Strength { get; set; } + + public int Health { get; set; } + + public List Abilities { get; set; } = new List(); + + public int CurrentAbility { get; set; } + + public List MyEffects { get; set; } = new List(); + + public IEffect NormalState { get; set; } + + public string ClassName { get; set; } + + public void TakingDamage(int damage) + { + Health -= damage; + } + + public void AttackEnemy(IPlayer enemy) + { + enemy.TakingDamage(Strength); + } + + public void EnterCurrentAbility() + { + Random random = new Random(); + CurrentAbility = random.Next(0, Abilities.Count); + } + + public bool CanUltimate() + { + return Abilities[CurrentAbility].CanSpell(); + } + + public int Ultimate(IPlayer myself, IPlayer enemy, int round) + { + Abilities[CurrentAbility].Spell(myself, enemy, round); + return CurrentAbility; + } + + public void Effect(IPlayer myself) + { + if (MyEffects.Count != 0) + { + foreach (var effect in MyEffects) + { + effect.State(myself); + } + } + } + + public void DeleteEffect(IPlayer myself, int round, int numberPlayer) + { + if (MyEffects.Count != 0) + { + foreach (var effect in MyEffects.ToList()) + { + effect.DeleteState(myself, round, numberPlayer); + } + } + } + + public void RestoreAfterBattle() + { + if (NormalState is Normal normal) + { + Health = normal.Health; + Strength = normal.Strength; + } + + foreach (var ability in Abilities) + { + ability.NumberUses = 0; + } + + MyEffects.Clear(); + } + } +} diff --git a/CourseApp/Logger/GameLogger.cs b/CourseApp/Logger/GameLogger.cs new file mode 100644 index 0000000..de525b0 --- /dev/null +++ b/CourseApp/Logger/GameLogger.cs @@ -0,0 +1,148 @@ +namespace CourseApp.Logger +{ + using System; + using CourseApp.Effects; + using CourseApp.Players; + + public class GameLogger : ILogger + { + public void PrintStart() + { + Console.WriteLine("\nПриветствуем в Akvelon RPG SAGA!"); + } + + public void PrintStartSelectHero() + { + Console.WriteLine("Добавьте персонажей с новыми способностями!"); + } + + public void PrintSelectHero() + { + Console.WriteLine("\n1 - Огненный маг\n2 - Воин\n3 - Стрелок"); + } + + public void PrintWrongNumber() + { + Console.WriteLine("Неправильное число!"); + } + + public void PrintAddAbility(int heroChoice) + { + if (heroChoice == 1) + { + Console.WriteLine("Фаербол - наносит 2 * сила урона"); + Console.WriteLine("Добавить? Да - Нет"); + } + else if (heroChoice == 2) + { + Console.WriteLine("Оглушающий удар - противник пропускает ход"); + Console.WriteLine("Добавить? Да - Нет"); + } + else if (heroChoice == 3) + { + Console.WriteLine("Ледяные стрелы - противник получает 10 урона за ход (можно применить один раз)"); + Console.WriteLine("Добавить? Да - Нет"); + } + } + + public void PrintStartNumberPlayers() + { + Console.WriteLine("\nПриступить к выбору количества игроков? Да - Нет"); + } + + public void PrintNumberPlayers() + { + Console.WriteLine("Выберите число игроков:"); + } + + public void PrintTour(int numberTour) + { + Console.WriteLine($"Кон {numberTour}.\n"); + } + + public void PrintVersus(IPlayer firstPlayer, IPlayer secondPlayer) + { + Console.WriteLine($"({firstPlayer.ClassName}) {firstPlayer.Name} vs ({secondPlayer.ClassName}) {secondPlayer.Name}"); + } + + public void PrintAttack(IPlayer playerAttack, IPlayer playerDefend) + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} наносит урон {playerAttack.Strength} противнику ({playerDefend.ClassName}) {playerDefend.Name}"); + } + + public void PrintUltimate(IPlayer playerAttack, IPlayer playerDefend, int randomUlt) + { + if (playerAttack.ClassName == "Маг") + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) на противника ({playerDefend.ClassName}) {playerDefend.Name}"); + } + else if (playerAttack.ClassName == "Рыцарь") + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) и наносит урон {playerAttack.Strength} противнику ({playerDefend.ClassName}) {playerDefend.Name}"); + } + else if (playerAttack.ClassName == "Лучник") + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) и поджигает противника ({playerDefend.ClassName}) {playerDefend.Name}"); + } + else if (playerAttack.ClassName == "Огненный маг") + { + if (playerAttack.Abilities[randomUlt].AbilityName == "Заворожение") + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) на противника ({playerDefend.ClassName}) {playerDefend.Name}"); + } + else + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) и наносит урон {playerAttack.Strength} противнику ({playerDefend.ClassName}) {playerDefend.Name}"); + } + } + else if (playerAttack.ClassName == "Воин") + { + if (playerAttack.Abilities[randomUlt].AbilityName == "Удар возмездия") + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) и наносит урон {playerAttack.Strength} противнику ({playerDefend.ClassName}) {playerDefend.Name}"); + } + else + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) на противника ({playerDefend.ClassName}) {playerDefend.Name}"); + } + } + else if (playerAttack.ClassName == "Стрелок") + { + if (playerAttack.Abilities[randomUlt].AbilityName == "Огненные стрелы") + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) и поджигает противника ({playerDefend.ClassName}) {playerDefend.Name}"); + } + else + { + Console.WriteLine($"({playerAttack.ClassName}) {playerAttack.Name} использует ({playerAttack.Abilities[randomUlt].AbilityName}) на противника ({playerDefend.ClassName}) {playerDefend.Name}"); + } + } + } + + public void PrintEffect(IPlayer player) + { + foreach (var effect in player.MyEffects) + { + if (effect is Stun) + { + Console.WriteLine($"({player.ClassName}) {player.Name} пропускает ход!"); + } + + if (effect is LongDamage longDamage) + { + Console.WriteLine($"({player.ClassName}) {player.Name} получает урон {longDamage.Factor}"); + } + } + } + + public void PrintDefeat(IPlayer loser) + { + Console.WriteLine($"({loser.ClassName}) {loser.Name} погибает! \n\n"); + } + + public void PrintEnd(IPlayer winner) + { + Console.WriteLine($"({winner.ClassName}) {winner.Name} побеждает! \nThe END..."); + } + } +} diff --git a/CourseApp/Logger/ILogger.cs b/CourseApp/Logger/ILogger.cs new file mode 100644 index 0000000..7b7bf7e --- /dev/null +++ b/CourseApp/Logger/ILogger.cs @@ -0,0 +1,35 @@ +namespace CourseApp.Logger +{ + using CourseApp.Players; + + public interface ILogger + { + void PrintStart(); + + void PrintStartSelectHero(); + + void PrintSelectHero(); + + void PrintWrongNumber(); + + void PrintAddAbility(int heroChoice); + + void PrintStartNumberPlayers(); + + void PrintNumberPlayers(); + + void PrintTour(int numberTour); + + void PrintEnd(IPlayer winner); + + void PrintVersus(IPlayer firstPlayer, IPlayer secondPlayer); + + void PrintAttack(IPlayer playerAttack, IPlayer playerDefend); + + void PrintUltimate(IPlayer playerAttack, IPlayer playerDefend, int randomUlt); + + void PrintEffect(IPlayer player); + + void PrintDefeat(IPlayer loser); + } +} diff --git a/CourseApp/Main/Fight.cs b/CourseApp/Main/Fight.cs new file mode 100644 index 0000000..059db02 --- /dev/null +++ b/CourseApp/Main/Fight.cs @@ -0,0 +1,124 @@ +namespace CourseApp.Fight +{ + using System; + using System.Collections.Generic; + using CourseApp.Effects; + using CourseApp.Logger; + using CourseApp.Players; + + public class Fight + { + public Fight(IPlayer firstPlayer, IPlayer secondPlayer, ref List allPlayers, ILogger logger) + { + FirstPlayer = firstPlayer; + SecondPlayer = secondPlayer; + AllPlayers = allPlayers; + Logger = logger; + } + + private ILogger Logger { get; set; } + + private IPlayer FirstPlayer { get; set; } + + private IPlayer SecondPlayer { get; set; } + + private int Round { get; set; } = 1; + + private List AllPlayers { get; set; } + + public void Battle() + { + bool stopGame; + + Logger.PrintVersus(FirstPlayer, SecondPlayer); + + while (true) + { + stopGame = PlayerTurn(FirstPlayer, SecondPlayer, 1); + + if (stopGame) + { + break; + } + + stopGame = PlayerTurn(SecondPlayer, FirstPlayer, 2); + + if (stopGame) + { + break; + } + + Round++; + } + } + + private bool PlayerTurn(IPlayer playerGame, IPlayer playerWait, int numberPlayer) + { + Random rand = new Random(); + bool stopGame = false; + bool isStun = false; + + playerGame.DeleteEffect(playerGame, Round, numberPlayer); + playerGame.Effect(playerGame); + Logger.PrintEffect(playerGame); + + if (IsDefeat(playerGame, playerWait)) + { + stopGame = true; + return stopGame; + } + + foreach (var effect in playerGame.MyEffects) + { + if (effect is Stun) + { + isStun = true; + } + } + + if (!isStun) + { + if (rand.Next(0, 3) > 0) + { + playerGame.AttackEnemy(playerWait); + Logger.PrintAttack(playerGame, playerWait); + } + else + { + playerGame.EnterCurrentAbility(); + if (playerGame.CanUltimate()) + { + int randomUlt = playerGame.Ultimate(playerGame, playerWait, Round); + Logger.PrintUltimate(playerGame, playerWait, randomUlt); + } + else + { + playerGame.AttackEnemy(playerWait); + Logger.PrintAttack(playerGame, playerWait); + } + } + } + + if (IsDefeat(playerWait, playerGame)) + { + stopGame = true; + return stopGame; + } + + return stopGame; + } + + private bool IsDefeat(IPlayer loser, IPlayer winner) + { + if (loser.Health <= 0) + { + Logger.PrintDefeat(loser); + AllPlayers.Remove(loser); + winner.RestoreAfterBattle(); + return true; + } + + return false; + } + } +} diff --git a/CourseApp/Main/Game.cs b/CourseApp/Main/Game.cs new file mode 100644 index 0000000..f90160a --- /dev/null +++ b/CourseApp/Main/Game.cs @@ -0,0 +1,101 @@ +namespace CourseApp.Base +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text.Json; + using CourseApp.Fight; + using CourseApp.GeneratePlayers; + using CourseApp.Logger; + using CourseApp.PlayerNames; + using CourseApp.Players; + using CourseApp.SelectorGame; + + #nullable enable + + public class Game + { + public Game(ILogger gameLogger) + { + Logger = gameLogger; + NumberTour = 1; + + const string filepath = @"/home/kiosk/Develop/Tprogramming_2022/CourseApp/Main/Names.json"; + + var json = File.ReadAllText(filepath); + PlayerNames = JsonSerializer.Deserialize>(json); + } + + private ILogger Logger { get; set; } + + private int NumberTour { get; set; } + + private List? PlayerNames { get; set; } + + public void Run() + { + Logger.PrintStart(); + + Selector selector = new Selector(Logger); + + List newClasses = selector.SelectCustomClass(); + + int playerNumbers = selector.SelectNumbPlayers(); + + PlayersGenerator playersGenerator = new PlayersGenerator(playerNumbers, PlayerNames, newClasses); + + List players = new List(playersGenerator.GeneratePlayersArray()); + + while (true) + { + Logger.PrintTour(NumberTour); + NumberTour++; + + Draft(players); + Tour(players); + + if (EndGame(players)) + { + break; + } + } + } + + public void Draft(List players) + { + Random random = new Random(); + for (int i = players.Count - 1; i >= 1; i--) + { + int j = random.Next(i + 1); + var temp = players[j]; + players[j] = players[i]; + players[i] = temp; + } + } + + public void Tour(List players) + { + for (int i = 0; i < players.Count; i++) + { + if (i + 1 < players.Count) + { + Fight fight = new Fight(players[i], players[i + 1], ref players, Logger); + fight.Battle(); + } + } + } + + public bool EndGame(List players) + { + if (players.Count == 1) + { + Logger.PrintEnd(players[0]); + return true; + } + else + { + return false; + } + } + } +} diff --git a/CourseApp/Main/Names.cs b/CourseApp/Main/Names.cs new file mode 100644 index 0000000..b1afcb6 --- /dev/null +++ b/CourseApp/Main/Names.cs @@ -0,0 +1,7 @@ +namespace CourseApp.PlayerNames +{ + public class Names + { + public string PlayerName { get; set; } + } +} diff --git a/CourseApp/Main/Names.json b/CourseApp/Main/Names.json new file mode 100644 index 0000000..9abbce9 --- /dev/null +++ b/CourseApp/Main/Names.json @@ -0,0 +1,14 @@ +[ + {"PlayerName" : "Nikita"}, + {"PlayerName" : "Stanislav"}, + {"PlayerName" : "Oleg"}, + {"PlayerName" : "Danila"}, + {"PlayerName" : "Michael"}, + {"PlayerName" : "Max"}, + {"PlayerName" : "Ivan"}, + {"PlayerName" : "Nazar"}, + {"PlayerName" : "Kevin"}, + {"PlayerName" : "Vladislav"} +] + + diff --git a/CourseApp/Main/PlayersGenerator.cs b/CourseApp/Main/PlayersGenerator.cs new file mode 100644 index 0000000..15b1777 --- /dev/null +++ b/CourseApp/Main/PlayersGenerator.cs @@ -0,0 +1,100 @@ +namespace CourseApp.GeneratePlayers +{ + using System; + using System.Collections.Generic; + using CourseApp.PlayerNames; + using CourseApp.Players; + + public class PlayersGenerator + { + public PlayersGenerator(int playerCount, List names, List newClasses) + { + PlayersCount = playerCount; + PlayerNames = names; + NewClasses = newClasses; + } + + private int PlayersCount { get; set; } + + private List PlayerNames { get; set; } + + private List NewClasses { get; set; } + + public List GeneratePlayersArray() + { + var result = new List(); + var rand = new Random(); + for (int i = 0; i < PlayersCount; i++) + { + IPlayer player; + var playerName = PlayerNames[rand.Next(PlayerNames.Count)].PlayerName; + var playerStrength = rand.Next(25, 51); + var playerHealth = rand.Next(50, 101); + var playerVariant = rand.Next(0, 3); + switch (playerVariant) + { + case 0: + if (NewClasses[1] == true) + { + if (rand.Next(0, 2) > 0) + { + player = new Knight(playerName, playerStrength, playerHealth, "Рыцарь"); + } + else + { + player = new Knight(playerName, playerStrength, playerHealth, "Воин"); + } + } + else + { + player = new Knight(playerName, playerStrength, playerHealth, "Рыцарь"); + } + + break; + case 1: + if (NewClasses[0] == true) + { + if (rand.Next(0, 2) > 0) + { + player = new Mage(playerName, playerStrength, playerHealth, "Маг"); + } + else + { + player = new Mage(playerName, playerStrength, playerHealth, "Огненный маг"); + } + } + else + { + player = new Mage(playerName, playerStrength, playerHealth, "Маг"); + } + + break; + case 2: + if (NewClasses[2] == true) + { + if (rand.Next(0, 2) > 0) + { + player = new Archer(playerName, playerStrength, playerHealth, "Лучник"); + } + else + { + player = new Archer(playerName, playerStrength, playerHealth, "Стрелок"); + } + } + else + { + player = new Archer(playerName, playerStrength, playerHealth, "Лучник"); + } + + break; + default: + throw new Exception(); + } + + result.Add(player); + } + + return result; + } + } +} diff --git a/CourseApp/Main/Selector.cs b/CourseApp/Main/Selector.cs new file mode 100644 index 0000000..1a65483 --- /dev/null +++ b/CourseApp/Main/Selector.cs @@ -0,0 +1,105 @@ +namespace CourseApp.SelectorGame +{ + using System; + using System.Collections.Generic; + using CourseApp.Logger; + + #nullable enable + + public class Selector + { + public Selector(ILogger logger) + { + Logger = logger; + NewClasses.Add(false); + NewClasses.Add(false); + NewClasses.Add(false); + } + + private int ChoiceNewHero { get; set; } + + private ILogger Logger { get; set; } + + private List NewClasses { get; set; } = new List(); + + public List SelectCustomClass() + { + Logger.PrintStartSelectHero(); + string? confirm = "Нет"; + + while (true) + { + Logger.PrintSelectHero(); + + string? heroChoice = Console.ReadLine(); + + if (int.TryParse(heroChoice, out int i) && i < 4) + { + ChoiceNewHero = i; + + IsAddNewClass(confirm); + + Logger.PrintStartNumberPlayers(); + + string? answer = Console.ReadLine(); + if (!string.IsNullOrEmpty(answer)) + { + if (answer == "Да") + { + break; + } + } + } + else + { + Logger.PrintWrongNumber(); + } + } + + return NewClasses; + } + + public int SelectNumbPlayers() + { + int playersNumbers; + + while (true) + { + Logger.PrintNumberPlayers(); + + string? numberOfPlayers = Console.ReadLine(); + + if (int.TryParse(numberOfPlayers, out int i) && (i % 2 == 0)) + { + playersNumbers = i; + break; + } + else + { + Logger.PrintWrongNumber(); + } + } + + return playersNumbers; + } + + private void IsAddNewClass(string? confirm) + { + if (confirm != "Да") + { + Logger.PrintAddAbility(ChoiceNewHero); + confirm = Console.ReadLine(); + + if (confirm == "Да") + { + NewClasses[ChoiceNewHero - 1] = true; + confirm = "Нет"; + } + else + { + NewClasses[ChoiceNewHero - 1] = false; + } + } + } + } +} diff --git a/CourseApp/Program.cs b/CourseApp/Program.cs index d6d2c87..0c5e1a1 100644 --- a/CourseApp/Program.cs +++ b/CourseApp/Program.cs @@ -1,12 +1,13 @@ -namespace CourseApp +namespace CourseApp.Base { - using System; + using CourseApp.Logger; public class Program { public static void Main(string[] args) { - Console.WriteLine("Hello World"); + Game game = new Game(new GameLogger()); + game.Run(); } } -} +} \ No newline at end of file diff --git a/courseworkspace.code-workspace b/courseworkspace.code-workspace index 38f6cc3..5e4953c 100644 --- a/courseworkspace.code-workspace +++ b/courseworkspace.code-workspace @@ -1,15 +1,17 @@ { "folders": [ { + "name": "CourseApp", "path": "CourseApp" }, { - "path": "CourseApp.Tests" + "name": "Configs (Root)", + "path": "." }, { - "name": "Configs (Root)", - "path": "." - }, + "name": "CourseApp.Tests", + "path": "CourseApp.Tests" + } ], "settings": {}, "extensions": {