// Assets/Scripts/Services/BombService.cs using System; using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using Enums; using Models; using Services.Interfaces; using UnityEngine; namespace Services { public class BombService : IBombService { public IReadOnlyList CollectTriggeredBombs(IReadOnlyList matchPositions) { if (matchPositions == null || matchPositions.Count == 0) return Array.Empty(); return matchPositions.Distinct().ToList(); } // This is the old implementation wherein any adjacent matches will detonate the bomb private List DetonateThroughAdjacentMatches(IReadOnlyList matchPositions) { HashSet candidates = new HashSet(); foreach (Vector2Int p in matchPositions) { candidates.Add(p + Vector2Int.left); candidates.Add(p + Vector2Int.right); candidates.Add(p + Vector2Int.up); candidates.Add(p + Vector2Int.down); } return candidates.ToList(); } public async UniTask DetonateChainAsync( IReadOnlyList initialBombs, Func inBounds, Func getGemAt, Func destroyAtAsync, int radius, float bombDelaySeconds, float bombSelfDelaySeconds) { if (initialBombs == null || initialBombs.Count == 0) return; Queue queue = new Queue(initialBombs); HashSet processed = new HashSet(); while (queue.Count > 0) { Vector2Int bombPos = queue.Dequeue(); if (processed.Contains(bombPos)) continue; if (!inBounds(bombPos)) continue; Gem bomb = getGemAt(bombPos); if (bomb is not { Type: GemType.Bomb }) continue; processed.Add(bombPos); int ringDelayMs = Mathf.RoundToInt(bombDelaySeconds * 1000f); for (int dist = 1; dist <= radius; dist++) { if (ringDelayMs > 0) await UniTask.Delay(ringDelayMs); foreach (Vector2Int n in DiamondRing(bombPos, dist)) { if (!inBounds(n)) continue; Gem g = getGemAt(n); if (g == null) continue; if (g.Type == GemType.Bomb) { if (!processed.Contains(n)) queue.Enqueue(n); continue; } await destroyAtAsync(n); } } int selfDelayMs = Mathf.Max(0, Mathf.RoundToInt(bombSelfDelaySeconds * 1000f)); if (selfDelayMs > 0) await UniTask.Delay(selfDelayMs); Gem stillBomb = getGemAt(bombPos); if (stillBomb is { Type: GemType.Bomb }) await destroyAtAsync(bombPos); } } private static IEnumerable DiamondRing(Vector2Int center, int distance) { for (int distanceX = -distance; distanceX <= distance; distanceX++) { int distanceY = distance - Mathf.Abs(distanceX); if (distanceY == 0) { yield return new Vector2Int(center.x + distanceX, center.y); } else { yield return new Vector2Int(center.x + distanceX, center.y + distanceY); yield return new Vector2Int(center.x + distanceX, center.y - distanceY); } } } } }