using System.Collections.Generic;
public enum Team
{
None,
Player1,
Player2
}
public static class FieldChecker
{
public static Chip[,] FieldArray => Board.Instance.Grid;
public static int Height => Board.Instance.Rows;
public static int Width => Board.Instance.Columns;
public static int TargetLineLength = 4;
public static CheckResult lastResult;
///
/// Проверяет, привела ли последняя фишка (установленная командой lastPlayer в клетку (row, col)) к победе.
///
/// Команда, которая только что сделала ход.
/// Строка (индекс по вертикали).
/// Столбец (индекс по горизонтали).
/// Результат проверки (окончание игры, ничья, множество победных клеток).
public static CheckResult Check(Team lastPlayer, int row, int col)
{
var winningCells = new HashSet<(int row, int col)>();
// Проверяем четыре направления, проходящие через (row, col)
CheckLine(row, col, 0, 1, lastPlayer, winningCells); // горизонталь
CheckLine(row, col, 1, 0, lastPlayer, winningCells); // вертикаль
CheckLine(row, col, 1, 1, lastPlayer, winningCells); // главная диагональ
CheckLine(row, col, 1, -1, lastPlayer, winningCells); // побочная диагональ
bool hasWin = winningCells.Count > 0;
if (hasWin)
{
lastResult = new CheckResult(end: true, isDraw: false, winningCells);
return lastResult;
}
if (CheckDraw())
{
lastResult = new CheckResult(end: true, isDraw: true, winningCells);
return lastResult;
}
lastResult = new CheckResult(end: false, isDraw: false, winningCells);
return lastResult;
}
///
/// Проверяет линию, заданную направлением (rowStep, colStep), проходящую через клетку (row, col).
/// Если найдена непрерывная последовательность из фишек lastPlayer длиной >= TargetLineLength,
/// все клетки этой последовательности добавляются в winningCells.
///
private static void CheckLine(int row, int col, int rowStep, int colStep, Team team, HashSet<(int, int)> winningCells)
{
// Движение назад (против направления)
int r = row, c = col;
int backCount = 0;
while (true)
{
int prevR = r - rowStep;
int prevC = c - colStep;
if (prevR < 0 || prevR >= Height || prevC < 0 || prevC >= Width)
break;
var chip = FieldArray[prevC, prevR]; // массив индексируется [x=col, y=row]
if (chip == null || chip.team != team)
break;
backCount++;
r = prevR;
c = prevC;
}
int startR = r, startC = c;
// Движение вперёд (по направлению)
r = row;
c = col;
int forwardCount = 0;
while (true)
{
int nextR = r + rowStep;
int nextC = c + colStep;
if (nextR < 0 || nextR >= Height || nextC < 0 || nextC >= Width)
break;
var chip = FieldArray[nextC, nextR];
if (chip == null || chip.team != team)
break;
forwardCount++;
r = nextR;
c = nextC;
}
int endR = r, endC = c;
int totalLength = backCount + 1 + forwardCount; // +1 за саму клетку
if (totalLength >= TargetLineLength)
{
// Добавляем все клетки от (startR, startC) до (endR, endC) с шагом (rowStep, colStep)
for (int i = 0; i < totalLength; i++)
{
int curR = startR + i * rowStep;
int curC = startC + i * colStep;
winningCells.Add((curR, curC));
}
}
}
///
/// Проверяет, заполнено ли всё поле (ничья).
///
public static bool CheckDraw()
{
for (int col = 0; col < Width; col++)
{
if (Board.Instance.GetLowestEmptyRow(col) != -1)
return false;
}
return true;
}
public static bool IsWinningMove(Team[,] board, int row, int col, Team player)
{
int height = board.GetLength(0);
int width = board.GetLength(1);
// Проверяем четыре направления
return CheckLine(board, row, col, 0, 1, player, height, width) ||
CheckLine(board, row, col, 1, 0, player, height, width) ||
CheckLine(board, row, col, 1, 1, player, height, width) ||
CheckLine(board, row, col, 1, -1, player, height, width);
}
// Вспомогательный метод для проверки одной линии
private static bool CheckLine(Team[,] board, int row, int col, int dr, int dc, Team player, int height, int width)
{
int count = 1;
// вперёд
int r = row + dr, c = col + dc;
while (r >= 0 && r < height && c >= 0 && c < width && board[r, c] == player)
{
count++;
r += dr;
c += dc;
}
// назад
r = row - dr; c = col - dc;
while (r >= 0 && r < height && c >= 0 && c < width && board[r, c] == player)
{
count++;
r -= dr;
c -= dc;
}
return count >= 4;
}
// Метод для проверки, есть ли у оппонента немедленная победа в один ход
public static bool HasImmediateWin(Team[,] board, Team player)
{
int height = board.GetLength(0);
int width = board.GetLength(1);
for (int col = 0; col < width; col++)
{
int row = GetLowestEmptyRow(board, col);
if (row == -1) continue;
board[row, col] = player;
bool win = IsWinningMove(board, row, col, player);
board[row, col] = Team.None;
if (win) return true;
}
return false;
}
private static int GetLowestEmptyRow(Team[,] board, int col)
{
int height = board.GetLength(0);
for (int r = height - 1; r >= 0; r--)
if (board[r, col] == Team.None)
return r;
return -1;
}
}