GameBoard.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. using System.Text;
  2. using MinMaxAB;
  3. namespace FourInARow;
  4. public class GameBoard : ICloneable
  5. {
  6. public Player[,] cells;
  7. public readonly GameDimensions dimensions;
  8. protected int lastPlayedRow;
  9. protected int lastPlayedColumn;
  10. public GameBoard(GameDimensions dim)
  11. {
  12. cells = Extensions.Fill(dim.Columns, dim.Rows, Player.None);
  13. dimensions = dim;
  14. }
  15. private bool cacheInvalidated = false;
  16. private Player winnerCache = Player.None;
  17. public bool PlaceCoin(Player player, int column)
  18. {
  19. int row = 0;
  20. while (row < dimensions.Rows && cells[column, row] == Player.None)
  21. {
  22. row++;
  23. }
  24. if (row == 0)
  25. return false;
  26. cells[column, row - 1] = player;
  27. cacheInvalidated = true;
  28. lastPlayedRow = row;
  29. lastPlayedColumn = column;
  30. return true;
  31. }
  32. public bool RemoveFromTop(int column)
  33. {
  34. int row = 0;
  35. while (row < dimensions.Rows && cells[column, row] == Player.None)
  36. {
  37. row++;
  38. }
  39. if (row == dimensions.Rows)
  40. return false;
  41. cells[column, row] = Player.None;
  42. cacheInvalidated = true;
  43. return true;
  44. }
  45. public static Player Opposite(Player player) => player switch
  46. {
  47. Player.Player => Player.Computer,
  48. Player.Computer => Player.Player,
  49. _ => Player.None
  50. };
  51. public Player? GetWinner()
  52. {
  53. if (!cacheInvalidated) return winnerCache;
  54. cacheInvalidated = false;
  55. for (int i = 0; i < dimensions.Columns; i++)
  56. {
  57. for (int j = 0; j < dimensions.Rows; j++)
  58. {
  59. if (cells[i, j] == Player.None)
  60. continue;
  61. bool h = i + 3 < dimensions.Columns;
  62. bool v = j + 3 < dimensions.Rows;
  63. if (!h && !v)
  64. continue;
  65. bool d = h && v;
  66. bool bd = v && i - 3 >= 0;
  67. for (int k = 1; k < 4; k++)
  68. {
  69. h = h && cells[i, j] == cells[i + k, j];
  70. v = v && cells[i, j] == cells[i, j + k];
  71. d = d && cells[i, j] == cells[i + k, j + k];
  72. bd = bd && cells[i, j] == cells[i - k, j + k];
  73. if (!h && !v && !d && !bd)
  74. break;
  75. }
  76. if (h || v || d || bd)
  77. {
  78. winnerCache = cells[i, j];
  79. return cells[i, j];
  80. }
  81. }
  82. }
  83. winnerCache = Player.None;
  84. return Player.None;
  85. }
  86. public bool HasEmptyColumns()
  87. {
  88. for (int x = 0; x < dimensions.Columns; x++)
  89. {
  90. if (cells[x, 0] == Player.None) return true;
  91. }
  92. return false;
  93. }
  94. protected char PlayerChar(Player player) => player switch
  95. {
  96. Player.Player => 'O',
  97. Player.Computer => 'X',
  98. _ => ' ',
  99. };
  100. public override string ToString()
  101. {
  102. string sep = $"\n{new('-', dimensions.Columns * 4)}";
  103. var builder = new StringBuilder(sep);
  104. builder.Append("\n| ");
  105. for (int column = 0; column < dimensions.Columns; column++)
  106. {
  107. builder.Append(column + 1).Append(" | ");
  108. }
  109. builder.AppendLine(sep);
  110. for (int row = 0; row < dimensions.Rows; row++)
  111. {
  112. builder.Append("| ");
  113. for (int column = 0; column < dimensions.Columns; column++) builder.Append(PlayerChar(cells[column, row])).Append(" | ");
  114. builder.AppendLine(sep);
  115. }
  116. return builder.ToString();
  117. }
  118. public object Clone()
  119. {
  120. var newBoard = new GameBoard(dimensions)
  121. {
  122. cells = (cells.Clone() as Player[,])!
  123. };
  124. return newBoard;
  125. }
  126. }