185 lines
6.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
/// <summary>
/// Проверяет, привела ли последняя фишка (установленная командой lastPlayer в клетку (row, col)) к победе.
/// </summary>
/// <param name="lastPlayer">Команда, которая только что сделала ход.</param>
/// <param name="row">Строка (индекс по вертикали).</param>
/// <param name="col">Столбец (индекс по горизонтали).</param>
/// <returns>Результат проверки (окончание игры, ничья, множество победных клеток).</returns>
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;
}
/// <summary>
/// Проверяет линию, заданную направлением (rowStep, colStep), проходящую через клетку (row, col).
/// Если найдена непрерывная последовательность из фишек lastPlayer длиной >= TargetLineLength,
/// все клетки этой последовательности добавляются в winningCells.
/// </summary>
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));
}
}
}
/// <summary>
/// Проверяет, заполнено ли всё поле (ничья).
/// </summary>
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;
}
}