Создан пул для фишек

This commit is contained in:
Сергей Бондарь 2026-08-03 11:20:01 +03:00
parent fbb3bca0a9
commit 473fb279bf
23 changed files with 186 additions and 105 deletions

View File

@ -11,7 +11,7 @@ public class ChipPointer : MonoBehaviour
public void SetPosition(Vector2 position) => transform.position = position;
public void SetColorByPlayer(CellState player) => spriteRenderer.color = player == CellState.Player1 ? player1Color : player2Color;
public void SetColorByPlayer(Team player) => spriteRenderer.color = player == Team.Player1 ? player1Color : player2Color;
public void SinAlphaAnimation()
{

View File

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class ChipPool : MonoBehaviour
{
private Chip _prefab;
private Queue<Chip> _availableChips;
private bool _isInit;
public static ChipPool Instance { get; private set; }
public void Init(Chip prefab, int amount)
{
if (_isInit)
return;
_prefab = prefab;
_availableChips = new Queue<Chip>(amount);
for (int i = 0; i < amount; i++)
Create();
Instance = this;
_isInit = true;
}
public Chip Get()
{
if (_isInit == false)
throw new InvalidOperationException("Пул фишек не инициализирован");
if (_availableChips.Count == 0)
Create();
Chip chip = _availableChips.Dequeue();
chip.gameObject.SetActive(true);
return chip;
}
public Chip GetConfigured(Sprite sprite, Team team)
{
if (_isInit == false)
throw new InvalidOperationException("Пул фишек не инициализирован");
Chip chip = Get();
chip.Configure(sprite, team);
return chip;
}
public void Release(Chip chip)
{
if (_isInit == false)
throw new InvalidOperationException("Пул фишек не инициализирован");
chip.gameObject.SetActive(false);
_availableChips.Enqueue(chip);
}
private Chip Create()
{
Chip chip = Instantiate(_prefab);
chip.gameObject.SetActive(false);
_availableChips.Enqueue(chip);
return chip;
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6f304a4db5b21a3438c74970b41a0db7

View File

@ -63,7 +63,7 @@ public class ChipFallingState : IState
private void AnnouncePlayerTurn()
{
if (GameManager.instance.currentPlayer == CellState.Player1)
if (GameManager.instance.currentPlayer == Team.Player1)
{
CharacterEventBus.Instance.OnPlayerTurn?.Invoke();
}

View File

@ -88,7 +88,7 @@ public class ShowWinnerState : IState
winningChips = new List<SpriteRenderer>();
CollectChipsList(result);
if (gm.currentPlayer == CellState.Player1)//Последный держал фишку игрок
if (gm.currentPlayer == Team.Player1)//Последный держал фишку игрок
{
if (gm.vsBotScore == 5)//5 побед над ботом
@ -164,13 +164,13 @@ public class ShowWinnerState : IState
//Вопрос к логике тут.
//bool bossUpgraded = GameManager.instance.BossUpgraded;
bool bossFirst = SettingsManager.GetString(SettingKey.DIFFICULTY_MODE) != "Прохождение";
CellState firstRoundPlayer = bossFirst ? CellState.Player2 : CellState.Player1;
Team firstRoundPlayer = bossFirst ? Team.Player2 : Team.Player1;
gm.PrepareRound(firstRoundPlayer);
return;
}
else
{
CellState nextPlayer = GameManager.instance.currentPlayer == CellState.Player1 ? CellState.Player2 : CellState.Player2;
Team nextPlayer = GameManager.instance.currentPlayer == Team.Player1 ? Team.Player2 : Team.Player2;
gm.PrepareRound(nextPlayer);
}
}
@ -209,7 +209,7 @@ public class ShowWinnerState : IState
AvatarEventBus.Instance.OnNewRoundStarted?.Invoke(gm.currentPlayer);
Board.Instance.MakeClearField();
CellState nextPlayer = gm.currentPlayer == CellState.Player1 ? CellState.Player2 : CellState.Player1;
Team nextPlayer = gm.currentPlayer == Team.Player1 ? Team.Player2 : Team.Player1;
gm.PrepareRound(nextPlayer);
break;
case EndOption.Menu://чистим поле и переходим в меню с параметром чтобы панельки съехались обратно

View File

@ -121,7 +121,7 @@ public static class StateRouter
}
private static IState PlayerWinPvpHandler(CellState winner)
private static IState PlayerWinPvpHandler(Team winner)
{
gm.IncreaseScore(winner);

View File

@ -26,7 +26,7 @@ public class GameManager : MonoBehaviour
[Header("Menu")]
public GameMode gameMode;
[HideInInspector] public CellState currentPlayer = CellState.Player2;
[HideInInspector] public Team currentPlayer = Team.Player2;
@ -131,28 +131,28 @@ public class GameManager : MonoBehaviour
{
GameObject chipToSpawn;
if (gameMode == GameMode.pvp)
chipToSpawn = currentPlayer == CellState.Player1 ? player1Chip : player2Chip;
chipToSpawn = currentPlayer == Team.Player1 ? player1Chip : player2Chip;
else
chipToSpawn = currentPlayer == CellState.Player1 ? player1Chip : botChip;
chipToSpawn = currentPlayer == Team.Player1 ? player1Chip : botChip;
currentChip = Instantiate(chipPrefab, new Vector2(0, 20), Quaternion.identity);
currentChip.Team = currentPlayer;
if (currentPlayer == CellState.Player2)
currentChip.team = currentPlayer;
if (currentPlayer == Team.Player2)
currentChip.GetComponentInChildren<SpriteRenderer>().sprite = CharactersController.CurrentCharacter.chipImage;
}
public void SwitchPlayer()
{
currentPlayer = currentPlayer == CellState.Player1 ? CellState.Player2 : CellState.Player1;
currentPlayer = currentPlayer == Team.Player1 ? Team.Player2 : Team.Player1;
}
public void SetMode(GameMode mode) => gameMode = mode;
public void IncreaseScore(CellState player)
public void IncreaseScore(Team player)
{
if (player == CellState.Player1)
if (player == Team.Player1)
player1score += 1;
else
player2score += 1;
@ -194,14 +194,14 @@ public class GameManager : MonoBehaviour
}
}
public void PrepareRound(CellState firstPlayer)
public void PrepareRound(Team firstPlayer)
{
currentPlayer = firstPlayer;
timerManager.SetupTimers(gameMode);
if (gameMode == GameMode.pve)
{
timerManager.SetActiveTimer(CellState.Player1);
timerManager.SetActiveTimer(Team.Player1);
int difficultyIndex = DifficultyManager.Instance.currentOpponent;
CharactersController.SwitchToCharacter(difficultyIndex);
}
@ -223,7 +223,7 @@ public class GameManager : MonoBehaviour
LightUtility.Player(currentPlayer);
}
if (currentPlayer == CellState.Player1)
if (currentPlayer == Team.Player1)
{
stateMachine.ChangeState(new PositioningState());
}

View File

@ -25,7 +25,7 @@ public class COMinput : InputSource
//Свойство для определения текущего игрока
//Должно возвращать 1 или 2
//Используется для получения состояния кнопок с пометкой ...CurrentPlayer
private int currentPlayer => gm.currentPlayer == CellState.Player1 ? 1 : 2;//ПЕРЕОПРЕДЕЛИТЕ ОПРЕДЕЛЕНИЕ ТЕКУЩЕГО ИГРОКА ПОД СВОЮ СИСТЕМУ.
private int currentPlayer => gm.currentPlayer == Team.Player1 ? 1 : 2;//ПЕРЕОПРЕДЕЛИТЕ ОПРЕДЕЛЕНИЕ ТЕКУЩЕГО ИГРОКА ПОД СВОЮ СИСТЕМУ.
private GameManager gm;//я получаю кто сейчас ходит через этого менеджера. Если у вас другое, допишите.

View File

@ -13,7 +13,7 @@
/// </remarks>
public class KeyboardInput : InputSource
{
private int currentPlayer => gm.currentPlayer == CellState.Player1 ? 1 : 2;//ПЕРЕОПРЕДЕЛИТЕ ОПРЕДЕЛЕНИЕ ТЕКУЩЕГО ИГРОКА ПОД СВОЮ СИСТЕМУ.
private int currentPlayer => gm.currentPlayer == Team.Player1 ? 1 : 2;//ПЕРЕОПРЕДЕЛИТЕ ОПРЕДЕЛЕНИЕ ТЕКУЩЕГО ИГРОКА ПОД СВОЮ СИСТЕМУ.
private GameManager gm;//я получаю кто сейчас ходит через этого менеджера. Если у вас другое, допишите.

View File

@ -22,9 +22,9 @@ public static class LightUtility
SendLightCommandToCom(LightMode.Lose);
}
public static void Player(CellState currentPlayer)
public static void Player(Team currentPlayer)
{
if (currentPlayer == CellState.Player1)
if (currentPlayer == Team.Player1)
SendLightCommandToCom(LightMode.Orange);
else
SendLightCommandToCom(LightMode.Blue);

View File

@ -163,7 +163,7 @@ public class SoundManager : MonoBehaviour
audioSource.clip = clipToPlay;
//audioSource.pitch = 1 + Random.Range(0, 2) * 0.6f;
audioSource.pitch = GameManager.instance.currentPlayer == CellState.Player1 ? 1 : 1.3f;
audioSource.pitch = GameManager.instance.currentPlayer == Team.Player1 ? 1 : 1.3f;
audioSource.volume = effectsVolume;
@ -186,7 +186,7 @@ public class SoundManager : MonoBehaviour
audioSource.clip = clipToPlay;
audioSource.volume = effectsVolume;
audioSource.pitch = GameManager.instance.currentPlayer == CellState.Player1 ? 0.8f : 0.85f;
audioSource.pitch = GameManager.instance.currentPlayer == Team.Player1 ? 0.8f : 0.85f;
effect.SetActive(true);
audioSource.Play();

View File

@ -81,16 +81,16 @@ public class Board : MonoBehaviour
return -1;
}
public CellState[,] GridToTeam()
public Team[,] GridToTeam()
{
CellState[,] res = new CellState[Columns, Rows];
Team[,] res = new Team[Columns, Rows];
for (int col = 0; col < Columns; col++)
{
for (int row = 0; row < Rows; row++)
{
var chip = Grid[col, row];
if (chip == null) res[col, row] = CellState.Empty;
else res[col, row] = chip.Team;
if (chip == null) res[col, row] = Team.None;
else res[col, row] = chip.team;
}
}
return res;

View File

@ -2,13 +2,21 @@
public class Chip : MonoBehaviour
{
public CellState Team;
public Team team;
[SerializeField] float acceleration = 200f;
[SerializeField] float maxFallingRotationSpeed = 500;
[SerializeField] private SpriteRenderer spriteRenderer;
private float chipVelocity = 0;
private float rotationSpeed = 0;
public void Configure(Sprite sprite, Team team)
{
spriteRenderer.sprite = sprite;
this.team = team;
}
public virtual void RemoveFromField()
{
Destroy(gameObject);
@ -17,8 +25,10 @@ public class Chip : MonoBehaviour
public bool MoveToLinear(Vector2 target, float speed)
{
transform.position = Vector2.MoveTowards(transform.position, target, speed * Time.deltaTime);
if ((Vector2)transform.position == target)
return true;
return false;
}
@ -32,10 +42,11 @@ public class Chip : MonoBehaviour
acceleration = 0;
return true;
}
return false;
}
public void SetRandomRotationSpeed() => rotationSpeed = Random.Range(-maxFallingRotationSpeed, maxFallingRotationSpeed);
public void Rotate() => transform.Rotate(Vector3.forward * rotationSpeed * Time.deltaTime);
}

View File

@ -27,7 +27,7 @@ public static class EndOfTurnHandler
if (gm.gameMode == GameMode.pvp)
{
//p2 не успел
if (gm.currentPlayer == CellState.Player2)
if (gm.currentPlayer == Team.Player2)
{
gm.player1score += 1;
//gm.Player1Scale.SetMedalsCount(gm.player1score);
@ -65,7 +65,7 @@ public static class EndOfTurnHandler
}
public static TurnEndingResult Evaluate(CheckResult result, GameMode gameMode, CellState lastPlayer)
public static TurnEndingResult Evaluate(CheckResult result, GameMode gameMode, Team lastPlayer)
{
if (!result.End) return TurnEndingResult.GameContinues;
if (result.Draw) return TurnEndingResult.Draw;
@ -73,7 +73,7 @@ public static class EndOfTurnHandler
if (gameMode == GameMode.pve)
{
return lastPlayer == CellState.Player1 ? TurnEndingResult.PlayerWinPve : TurnEndingResult.BotWin;
return lastPlayer == Team.Player1 ? TurnEndingResult.PlayerWinPve : TurnEndingResult.BotWin;
}
else //pvp
{

View File

@ -1,19 +1,19 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
public enum CellState
public enum Team
{
Empty, Player1, Player2
None,
Player1,
Player2
}
public static class FieldChecker
{
static GameManager gm => GameManager.instance;
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 Check(CellState lastPlayer)
public static CheckResult Check(Team lastPlayer)
{
HashSet<(int row, int col)> WinningIndexes = new();
@ -51,7 +51,7 @@ public static class FieldChecker
}
private static (bool hasWin, HashSet<(int row, int col)> winningIndexes) checkAllRows(CellState targetTeam)
private static (bool hasWin, HashSet<(int row, int col)> winningIndexes) checkAllRows(Team targetTeam)
{
var winningCells = new HashSet<(int row, int col)>();
@ -63,7 +63,7 @@ public static class FieldChecker
{
// Проверяем, не вышли ли за границы массива
var chip = FieldArray[col, row];
bool isMatch = col < Width && chip != null && chip.Team == targetTeam;
bool isMatch = col < Width && chip != null && chip.team == targetTeam;
if (isMatch && start == -1)
start = col;
@ -83,7 +83,7 @@ public static class FieldChecker
return (winningCells.Count > 0, winningCells);
}
private static (bool hasWin, HashSet<(int row, int col)> winningIndexes) checkAllColumns(CellState targetTeam)
private static (bool hasWin, HashSet<(int row, int col)> winningIndexes) checkAllColumns(Team targetTeam)
{
var winningCells = new HashSet<(int row, int col)>();
@ -94,7 +94,7 @@ public static class FieldChecker
for (int row = 0; row <= Height; row++)
{
var chip = FieldArray[col, row];
bool isMatch = row < Height && chip != null && chip.Team == targetTeam;
bool isMatch = row < Height && chip != null && chip.team == targetTeam;
if (isMatch && start == -1)
start = row;
@ -115,7 +115,7 @@ public static class FieldChecker
return (winningCells.Count > 0, winningCells);
}
private static (bool hasWin, HashSet<(int row, int col)> winningIndexes) checkAllDiagonals(CellState targetCellState)
private static (bool hasWin, HashSet<(int row, int col)> winningIndexes) checkAllDiagonals(Team targetCellState)
{
var winningCells = new HashSet<(int row, int col)>();
@ -143,7 +143,7 @@ public static class FieldChecker
}
private static void CheckDiagonalStartingAt(int startRow, int startCol, int rowStep, int colStep,
CellState targetCellState, HashSet<(int, int)> winningCells)
Team targetCellState, HashSet<(int, int)> winningCells)
{
int rows = Height;
int cols = Width;
@ -157,7 +157,7 @@ public static class FieldChecker
currentCol >= 0 && currentCol < cols)
{
var chip = FieldArray[currentCol, currentRow];
bool isMatch = chip != null && chip.Team == targetCellState;
bool isMatch = chip != null && chip.team == targetCellState;
if (isMatch)
{

View File

@ -23,7 +23,7 @@ public class Avatar : MonoBehaviour
private GameObject currentMessageBox;
private bool nowTyping = false;
private CellState team;
private Team team;
#region REPLICAS_LISTS
[Header("Появление")]
@ -80,7 +80,7 @@ public class Avatar : MonoBehaviour
public void Initialize(CellState team)
public void Initialize(Team team)
{
this.team = team;
SettingsManager.OnSettingsChanged += pullSettings;

View File

@ -7,12 +7,12 @@ public class AvatarEventBus : MonoBehaviour
//Список событий переделать
public UnityEvent OnAvatarsAppeared; //когда уже выехали на экран
public UnityEvent<CellState> OnTurnStart; //Начало хода конкретного игрока
public UnityEvent<CellState> OnTurnEnd; //Конец хода конкретного игрока (перед падением фишки)
public UnityEvent<CellState> OnEndRound; //Конец раунда (передаем победителя)
public UnityEvent<Team> OnTurnStart; //Начало хода конкретного игрока
public UnityEvent<Team> OnTurnEnd; //Конец хода конкретного игрока (перед падением фишки)
public UnityEvent<Team> OnEndRound; //Конец раунда (передаем победителя)
public UnityEvent OnDraw; //Ничья
public UnityEvent<CellState> OnNewRoundStarted; //Новый раунд (передаем кто прошлый победитель)
public UnityEvent<CellState> OnEndGame; //Конец игры (победителя передаем)
public UnityEvent<Team> OnNewRoundStarted; //Новый раунд (передаем кто прошлый победитель)
public UnityEvent<Team> OnEndGame; //Конец игры (победителя передаем)
public void Initialize() => Instance = this;
}

View File

@ -13,12 +13,12 @@ public class DualAvatarController : MonoBehaviour
const CellState PLAYER1 = CellState.Player1;
const CellState PLAYER2 = CellState.Player2;
const Team PLAYER1 = Team.Player1;
const Team PLAYER2 = Team.Player2;
[SerializeField] private List<GameObject> characterPrefabs;
Dictionary<CellState, Avatar> avatars = new();
Dictionary<Team, Avatar> avatars = new();
[SerializeField] Transform AvatarsParent;
private AvatarEventBus bus;
@ -73,7 +73,7 @@ public class DualAvatarController : MonoBehaviour
StartCoroutine(MoveLocal(avatars[PLAYER2], GetHiddenPosition(PLAYER2), CharacterMovementSpeed, OnComplete: () => { }));
}
Avatar CreateAvatar(GameObject prefab, Transform parent, CellState team)
Avatar CreateAvatar(GameObject prefab, Transform parent, Team team)
{
GameObject go = Instantiate(prefab, parent);
@ -86,9 +86,9 @@ public class DualAvatarController : MonoBehaviour
return avatar;
}
Vector2 GetHiddenPosition(CellState team)
Vector2 GetHiddenPosition(Team team)
=> team == PLAYER1 ? baseHiddenLocalPosition : new Vector2(-baseHiddenLocalPosition.x, baseHiddenLocalPosition.y);
Vector2 GetShownPosition(CellState team)
Vector2 GetShownPosition(Team team)
=> team == PLAYER1 ? baseShownLocalPosition : new Vector2(-baseShownLocalPosition.x, baseShownLocalPosition.y);
@ -129,21 +129,21 @@ public class DualAvatarController : MonoBehaviour
{
avatars[PLAYER1].Animator.SetTrigger(APPEAR_TRIGGER);
}
private void TurnStart(CellState player) { }
private void TurnEnd(CellState player)
private void TurnStart(Team player) { }
private void TurnEnd(Team player)
{
avatars[player].Animator.SetTrigger(CHIPSPAWN_TRIGGER);
}
private void EndRound(CellState winner)
private void EndRound(Team winner)
{
//Обозначние для ничьей
if (winner == CellState.Empty)
if (winner == Team.None)
{
Draw();
return;
}
CellState loser = winner == CellState.Player1 ? CellState.Player2 : CellState.Player1;
Team loser = winner == Team.Player1 ? Team.Player2 : Team.Player1;
avatars[winner].Animator.SetTrigger(WIN_TRIGGER);
avatars[loser].Animator.SetTrigger(LOSE_TRIGGER);
}
@ -151,11 +151,11 @@ public class DualAvatarController : MonoBehaviour
{
Debug.Log("DRAW");
}
private void NewRound(CellState lastRoundWinner)
private void NewRound(Team lastRoundWinner)
{
//Debug.Log("NEW ROUND LAST WINNER " + lastRoundWinner);
}
private void EndGame(CellState gameWinner)
private void EndGame(Team gameWinner)
{
//Debug.Log("ENDGAME");
}

View File

@ -8,7 +8,7 @@ public class PvpPointer : MonoBehaviour
[SerializeField] List<Sprite> sprites;//0 - первый, 1 - второй игрок.
[SerializeField] Vector3 offset;
public void SetColor(CellState player) => _renderer.sprite = player == CellState.Player1 ? sprites[0] : sprites[1];
public void SetColor(Team player) => _renderer.sprite = player == Team.Player1 ? sprites[0] : sprites[1];
public void SetVisibility(bool visible) => _renderer.enabled = visible;
public void MoveTo(Vector3 targetPosition) => _renderer.transform.position = targetPosition + offset;

View File

@ -16,8 +16,8 @@ public class Solver
private static System.Random rand = new System.Random();
// текущие фигуры бота и оппонента — задаём при вызове FindBestMove
private static CellState BotPiece;
private static CellState HumanPiece;
private static Team BotPiece;
private static Team HumanPiece;
private static int DEPTH = 8;
private static int WIN_SCORE = 1_000_000;
@ -58,14 +58,14 @@ public class Solver
}
// -------- Публичный API --------
public static int FindBestMove(CellState[,] board, CellState currentPlayer)
public static int FindBestMove(Team[,] board, Team currentPlayer)
{
ROWS = board.GetLength(0);
COLS = board.GetLength(1);
// сохраняем, за кого сейчас считаем
BotPiece = currentPlayer;
HumanPiece = (currentPlayer == CellState.Player1) ? CellState.Player2 : CellState.Player1;
HumanPiece = (currentPlayer == Team.Player1) ? Team.Player2 : Team.Player1;
var root = EvaluateRootMoves(board, DEPTH);
@ -105,7 +105,7 @@ public class Solver
}
// -------- Корневые ходы --------
private static List<(int col, int score)> EvaluateRootMoves(CellState[,] board, int depth)
private static List<(int col, int score)> EvaluateRootMoves(Team[,] board, int depth)
{
var result = new List<(int col, int score)>();
var valid = GetValidLocations(board);
@ -123,20 +123,20 @@ public class Solver
// если сразу победа — отлично
if (WinningMoveAt(board, row, col, BotPiece))
{
board[row, col] = CellState.Empty;
board[row, col] = Team.None;
result.Add((col, WIN_SCORE * depth));
continue;
}
int score = Minimax(board, depth - 1, int.MinValue, int.MaxValue, false, row, col, BotPiece).score;
board[row, col] = CellState.Empty;
board[row, col] = Team.None;
result.Add((col, score));
}
return result;
}
private static bool LeadsToImmediateLoss(CellState[,] board, int botCol)
private static bool LeadsToImmediateLoss(Team[,] board, int botCol)
{
int row = GetNextOpenRow(board, botCol);
if (row < 0) return false;
@ -148,7 +148,7 @@ public class Solver
// соперник просто не получит ход
if (WinningMoveAt(board, row, botCol, BotPiece))
{
board[row, botCol] = CellState.Empty;
board[row, botCol] = Team.None;
return false;
}
@ -156,7 +156,7 @@ public class Solver
bool res = HasImmediateWin(board, HumanPiece);
// откат
board[row, botCol] = CellState.Empty;
board[row, botCol] = Team.None;
return res;
}
@ -187,8 +187,8 @@ public class Solver
// maximizingPlayer == true → ход бота (BOT)
// maximizingPlayer == false → ход человека (HUMAN)
private static (int column, int score) Minimax(
CellState[,] board, int depth, int alpha, int beta,
bool maximizingPlayer, int lastRow, int lastCol, CellState lastPlayer)
Team[,] board, int depth, int alpha, int beta,
bool maximizingPlayer, int lastRow, int lastCol, Team lastPlayer)
{
if (lastRow >= 0 && WinningMoveAt(board, lastRow, lastCol, lastPlayer))
{
@ -213,7 +213,7 @@ public class Solver
board[r, col] = BotPiece;
var child = Minimax(board, depth - 1, alpha, beta, false, r, col, BotPiece);
board[r, col] = CellState.Empty;
board[r, col] = Team.None;
if (child.score > best) { best = child.score; bestCol = col; }
alpha = Math.Max(alpha, best);
@ -234,7 +234,7 @@ public class Solver
board[r, col] = HumanPiece;
var child = Minimax(board, depth - 1, alpha, beta, true, r, col, HumanPiece);
board[r, col] = CellState.Empty;
board[r, col] = Team.None;
if (child.score < best) { best = child.score; bestCol = col; }
beta = Math.Min(beta, best);
@ -245,10 +245,10 @@ public class Solver
}
// -------- Эвристика --------
private static int EvaluatePosition(CellState[,] board, CellState perspective /* всегда BOTpiece */)
private static int EvaluatePosition(Team[,] board, Team perspective /* всегда BOTpiece */)
{
int score = 0;
var opp = (perspective == CellState.Player1) ? CellState.Player2 : CellState.Player1;
var opp = (perspective == Team.Player1) ? Team.Player2 : Team.Player1;
// 1) Центр (весим 3-4-5-7-5-4-3), не масштабируем на DEPTH
for (int r = 0; r < ROWS; r++)
@ -273,12 +273,12 @@ public class Solver
// Счёт «окон» длины 4, где pieceCount==length и остальные пусты, причём
// хотя бы одна из пустых клеток «играбельна» (подперта снизу или нижняя граница).
private static int CountPotentialLinesPlayable(CellState[,] b, CellState piece, int length)
private static int CountPotentialLinesPlayable(Team[,] b, Team piece, int length)
{
int total = 0;
bool In(int r, int c) => r >= 0 && r < ROWS && c >= 0 && c < COLS;
bool PlayableEmpty(int r, int c) => r == ROWS - 1 || b[r + 1, c] != CellState.Empty;
bool PlayableEmpty(int r, int c) => r == ROWS - 1 || b[r + 1, c] != Team.None;
int ScanDir(int dr, int dc)
{
@ -300,7 +300,7 @@ public class Solver
int rr = r0 + dr * k, cc = c0 + dc * k;
var v = b[rr, cc];
if (v == piece) p++;
else if (v == CellState.Empty)
else if (v == Team.None)
{
e++;
if (PlayableEmpty(rr, cc)) hasPlayableEmpty = true;
@ -327,23 +327,23 @@ public class Solver
}
// -------- Хелперы по ходам/победам --------
private static List<int> GetValidLocations(CellState[,] board)
private static List<int> GetValidLocations(Team[,] board)
{
var res = new List<int>(COLS);
for (int c = 0; c < COLS; c++)
if (board[0, c] == CellState.Empty)
if (board[0, c] == Team.None)
res.Add(c);
return res;
}
private static int GetNextOpenRow(CellState[,] board, int col)
private static int GetNextOpenRow(Team[,] board, int col)
{
for (int r = ROWS - 1; r >= 0; r--)
if (board[r, col] == CellState.Empty) return r;
if (board[r, col] == Team.None) return r;
return -1;
}
private static bool HasImmediateWin(CellState[,] board, CellState player)
private static bool HasImmediateWin(Team[,] board, Team player)
{
var valid = GetValidLocations(board);
foreach (int c in valid)
@ -352,13 +352,13 @@ public class Solver
if (r < 0) continue;
board[r, c] = player;
bool win = WinningMoveAt(board, r, c, player);
board[r, c] = CellState.Empty;
board[r, c] = Team.None;
if (win) return true;
}
return false;
}
private static bool WinningMoveAt(CellState[,] b, int r, int c, CellState p)
private static bool WinningMoveAt(Team[,] b, int r, int c, Team p)
{
bool In(int rr, int cc) => rr >= 0 && rr < ROWS && cc >= 0 && cc < COLS;

View File

@ -82,7 +82,7 @@ public static class SolverV2
/// <summary>
/// Главный метод: верни индекс колонки 0..6, куда бросать фишку.
/// </summary>
public static int FindBestMove(CellState[,] board, CellState currentPlayer)
public static int FindBestMove(Team[,] board, Team currentPlayer)
{
if (board == null) throw new ArgumentNullException(nameof(board));
if (board.GetLength(0) != HEIGHT || board.GetLength(1) != WIDTH)
@ -95,14 +95,14 @@ public static class SolverV2
for (int c = 0; c < WIDTH; c++)
{
var cs = board[r, c];
if (cs == CellState.Empty) continue;
if (cs == Team.None) continue;
// В битбордах row=0 снизу. В массиве чаще row=0 сверху => инвертируем
int br = (HEIGHT - 1) - r; // bottom=0
ulong bit = 1UL << (c * H1 + br);
if (cs == CellState.Player1) p1 |= bit;
else if (cs == CellState.Player2) p2 |= bit;
if (cs == Team.Player1) p1 |= bit;
else if (cs == Team.Player2) p2 |= bit;
}
}
@ -114,7 +114,7 @@ public static class SolverV2
}
// Камень текущего игрока
ulong currentBits = (currentPlayer == CellState.Player1) ? p1 : p2;
ulong currentBits = (currentPlayer == Team.Player1) ? p1 : p2;
var pos = new Position(currentBits, mask);

View File

@ -34,9 +34,9 @@ public class TimerManager : MonoBehaviour
player2Timer.StopTimer();
}
public void SetActiveTimer(CellState currentPlayer)
public void SetActiveTimer(Team currentPlayer)
{
(currentPlayer == CellState.Player1 ? player1Timer : player2Timer).StartTimer();
(currentPlayer == CellState.Player1 ? player2Timer : player1Timer).StopTimer();
(currentPlayer == Team.Player1 ? player1Timer : player2Timer).StartTimer();
(currentPlayer == Team.Player1 ? player2Timer : player1Timer).StopTimer();
}
}

View File

@ -5,7 +5,7 @@ public class WinPanel : MonoBehaviour
{
public GameObject win1, win2, winBot;
public AudioSource sound;
public void ShowWin(CellState winner)
public void ShowWin(Team winner)
{
win1.SetActive(false);
win2.SetActive(false);
@ -13,11 +13,11 @@ public class WinPanel : MonoBehaviour
switch (winner)
{
case CellState.Player1:
case Team.Player1:
win1.SetActive(true); break;
case CellState.Player2:
case Team.Player2:
win2.SetActive(true); break;
case CellState.Empty:
case Team.None:
winBot.SetActive(true); break;
}