GameBoard.cs 3.7 KB

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