GameRoom.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using MafiaTelegramBot.Controllers;
  7. using MafiaTelegramBot.DataBase;
  8. using MafiaTelegramBot.Models;
  9. using MafiaTelegramBot.Resources;
  10. using MafiaTelegramBot.Extensions;
  11. using Telegram.Bot.Types.ReplyMarkups;
  12. namespace MafiaTelegramBot.Game
  13. {
  14. public class GameRoom
  15. {
  16. private bool _isRunning;
  17. public int MaxPlayers = 10;
  18. private int _minPlayers = Constants.PLAYER_LIMITS_MIN;
  19. public virtual bool IsPrivate { get; protected set; } = false;
  20. public bool IsExtended { get; init; }
  21. public bool TimerEnabled { get; set; } = true;
  22. public string RoomName { get; init; } = "NoNameRoom";
  23. public UserEntity Owner { get; init; } = new();
  24. private readonly Queue<UserEntity> _turnOrder = new();
  25. public readonly Dictionary<long, UserEntity> Players = new();
  26. public readonly Dictionary<Roles, int> Settings = new()
  27. {
  28. {Roles.Mafia, 0},
  29. {Roles.Cop, 0},
  30. {Roles.Villager, 0},
  31. {Roles.Doctor, 0},
  32. {Roles.Don, 0},
  33. {Roles.Hooker, 0},
  34. };
  35. public void Start()
  36. {
  37. new Task(async () =>
  38. {
  39. _isRunning = true;
  40. await FirstDay();
  41. await GameCycle();
  42. await EndOfGame();
  43. }).Start();
  44. }
  45. public async Task<ResultCode> Prepare()
  46. {
  47. var resultCode = CanStartGame();
  48. if (resultCode != ResultCode.CodeOk) return resultCode;
  49. await ReadSettings();
  50. await GenerateTurnOrder();
  51. await AssignRoles();
  52. return resultCode;
  53. }
  54. private async Task FirstDay()
  55. {
  56. await Task.Run(() => { });
  57. }
  58. private async Task GameCycle()
  59. {
  60. await Task.Run(() => { });
  61. }
  62. private async Task EndOfGame()
  63. {
  64. await Task.Run(async () =>
  65. {
  66. foreach (var (_, player) in Players)
  67. {
  68. player.SetRole(Roles.None);
  69. _isRunning = false;
  70. _turnOrder.Clear();
  71. Thread.Sleep(10000);//TODO just for tests
  72. if (!Players.ContainsKey(Owner.Id) || Players.Count == 0) new Task(async() =>
  73. await RoomController.DissolveRoom(IsPrivate ? RoomEncrypter.NameToCode(RoomName) : RoomName)).Start();
  74. else
  75. {
  76. await Bot.SendWithMarkdown2(Owner.ChatId, strings.thanks_for_game, Keyboards.OwnerGameMenu);
  77. await NotifyPlayersAbout(Owner.Id, strings.thanks_for_game, Keyboards.PlayerGameMenu);
  78. }
  79. }
  80. });
  81. }
  82. private async Task ReadSettings()
  83. {
  84. if (!IsExtended) await SetNormalRoles();
  85. }
  86. private ResultCode CanStartGame()
  87. {
  88. if (Players.Count < _minPlayers) return ResultCode.TooFewPlayers;
  89. if (Players.Count > MaxPlayers) return ResultCode.TooManyPlayers;
  90. return _isRunning ? ResultCode.GameAlreadyRunning : ResultCode.CodeOk;
  91. }
  92. private async Task SetNormalRoles()
  93. {
  94. await Task.Run(() =>
  95. {
  96. Settings[Roles.Villager] = Players.Count;
  97. Settings[Roles.Cop] = 1;
  98. if (Players.Count != 8) Settings[Roles.Doctor] = 1;
  99. else Settings[Roles.Doctor] = 0;
  100. if (Players.Count % 3 == 0)
  101. {
  102. Settings[Roles.Mafia] = Players.Count / 3;
  103. Settings[Roles.Don] = 0;
  104. }
  105. else
  106. {
  107. Settings[Roles.Mafia] = (Players.Count / 3) - 1;
  108. Settings[Roles.Don] = 1;
  109. }
  110. foreach (var (key, value) in Settings)
  111. if (key != Roles.Villager)
  112. Settings[Roles.Villager] -= value;
  113. foreach (var (key, value) in Settings)
  114. if (value < 1)
  115. Settings.Remove(key);
  116. });
  117. }
  118. public async Task<List<UserEntity>> GetPlayers()
  119. {
  120. return await Task.Run(() =>
  121. {
  122. var players = Players.Values.ToList();
  123. players.Remove(Owner);
  124. return players;
  125. });
  126. }
  127. private async Task AssignRoles()
  128. {
  129. await Task.Run(() =>
  130. {
  131. var random = new Random();
  132. for (var i = 0; i < _turnOrder.Count; ++i)
  133. {
  134. var user = _turnOrder.Dequeue();
  135. var roles = new List<Roles>();
  136. foreach (var (key, value) in Settings) roles.AddTimes(key, value);
  137. user.SetRole(roles.GetAndRemove(random.Next(roles.Count)));
  138. _turnOrder.Enqueue(user);
  139. }
  140. });
  141. }
  142. private async Task GenerateTurnOrder()
  143. {
  144. await Task.Run(() =>
  145. {
  146. var random = new Random();
  147. var playersCopy = Players.Values.ToList();
  148. while (playersCopy.Count != 0)
  149. {
  150. var player = playersCopy.GetAndRemove(random.Next(playersCopy.Count));
  151. _turnOrder.Enqueue(player);
  152. player.TurnOrder = _turnOrder.Count;
  153. }
  154. });
  155. }
  156. public bool IsFilled()
  157. {
  158. return Players.Count == MaxPlayers;
  159. }
  160. public async Task NotifyPlayersAbout(long ignoredUserId, string message, IReplyMarkup keyboard = null)
  161. {
  162. foreach (var player in Players.Values.Where(player => ignoredUserId != player.Id))
  163. {
  164. await Bot.SendWithMarkdown2(player.ChatId, message, keyboard);
  165. }
  166. }
  167. public async Task NotifyPlayersAboutGameStarted()
  168. {
  169. foreach (var player in Players.Values)
  170. {
  171. var message =
  172. $"{strings.your_role}: _*{player.GetRole()}*_\n" +
  173. $"{strings.your_turn_order}: _*{player.TurnOrder}*_\n"+
  174. $"{strings.bot_starting_game}";
  175. await Bot.SendWithMarkdown2(player.ChatId, message, Keyboards.InGamePlayerMenu);
  176. }
  177. }
  178. }
  179. }