using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using Enums; using Models.Interfaces; using Services.Interfaces; using UnityEngine; namespace Services { public class MatchService : IMatchService { private readonly IGameBoard gameBoard; private readonly HashSet currentMatches = new HashSet(); public HashSet CurrentMatches => this.currentMatches; public MatchService(IGameBoard gameBoard) { this.gameBoard = gameBoard; } public bool MatchesAt(Vector2Int positionToCheck, GemType gemTypeToCheck) { Gem[,] gems = this.gameBoard.GemsGrid; // We don't prevent spawning bombs via this rule (and bombs shouldn't be treated as a normal color here). if (gemTypeToCheck == GemType.Bomb) return false; // Check horizontal: would placing gemTypeToCheck at positionToCheck create XXX with 2-left? if (positionToCheck.x > 1) { Gem left1 = gems[positionToCheck.x - 1, positionToCheck.y]; Gem left2 = gems[positionToCheck.x - 2, positionToCheck.y]; if (left1 != null && left2 != null && left1.MatchColor == gemTypeToCheck && left2.MatchColor == gemTypeToCheck) return true; } // Check vertical: would placing gemTypeToCheck at positionToCheck create XXX with 2-down? if (positionToCheck.y > 1) { Gem down1 = gems[positionToCheck.x, positionToCheck.y - 1]; Gem down2 = gems[positionToCheck.x, positionToCheck.y - 2]; if (down1 != null && down2 != null && down1.MatchColor == gemTypeToCheck && down2.MatchColor == gemTypeToCheck) return true; } return false; } public UniTask> GetMatchPositionsAsync(List protectedPositions) { HashSet matchPositions = new HashSet(); List matches = this.currentMatches.ToList(); for (int i = 0; i < matches.Count; i++) { Gem match = matches[i]; if (match == null) continue; Vector2Int pos = match.Position; if (protectedPositions != null && protectedPositions.Contains(pos)) continue; matchPositions.Add(pos); } return UniTask.FromResult(matchPositions); } public void FindAllMatches() { this.currentMatches.Clear(); Gem[,] grid = this.gameBoard.GemsGrid; int boardWidth = this.gameBoard.Width; int boardHeight = this.gameBoard.Height; // Horizontal runs for (int y = 0; y < boardHeight; y++) { int x = 0; while (x < boardWidth) { Gem start = grid[x, y]; if (start == null) { x++; continue; } GemType color = start.MatchColor; int runLen = 1; while (x + runLen < boardWidth) { Gem next = grid[x + runLen, y]; if (next == null || next.MatchColor != color) break; runLen++; } if (runLen >= 3) { for (int i = 0; i < runLen; i++) this.currentMatches.Add(grid[x + i, y]); } x += runLen; } } // Vertical runs for (int x = 0; x < boardWidth; x++) { int y = 0; while (y < boardHeight) { Gem start = grid[x, y]; if (start == null) { y++; continue; } GemType color = start.MatchColor; int runLen = 1; while (y + runLen < boardHeight) { Gem next = grid[x, y + runLen]; if (next == null || next.MatchColor != color) break; runLen++; } if (runLen >= 3) { for (int i = 0; i < runLen; i++) this.currentMatches.Add(grid[x, y + i]); } y += runLen; } } } } }