diff --git a/Assets/Scripts/Services/BombService.cs b/Assets/Scripts/Services/BombService.cs index b72528e..c89a572 100644 --- a/Assets/Scripts/Services/BombService.cs +++ b/Assets/Scripts/Services/BombService.cs @@ -21,21 +21,6 @@ namespace Services 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, @@ -134,31 +119,16 @@ namespace Services } } - 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); - } - } - } - private static IEnumerable DiamondAreaInclusive(Vector2Int center, int radius) { - yield return center; - - for (int dist = 1; dist <= radius; dist++) + // Manhattan-distance filled diamond: + for (int distanceX = -radius; distanceX <= radius; distanceX++) { - foreach (Vector2Int pivot in DiamondRing(center, dist)) - yield return pivot; + int remaining = radius - Mathf.Abs(distanceX); + for (int distanceY = -remaining; distanceY <= remaining; distanceY++) + { + yield return new Vector2Int(center.x + distanceX, center.y + distanceY); + } } } } diff --git a/Assets/Scripts/Services/GameBoardService.cs b/Assets/Scripts/Services/GameBoardService.cs index 2372b06..6c22c54 100644 --- a/Assets/Scripts/Services/GameBoardService.cs +++ b/Assets/Scripts/Services/GameBoardService.cs @@ -306,6 +306,14 @@ namespace Services { Gem currentGem = this.gameBoard.GetGemAt(new Vector2Int(x,y)); if (currentGem == null) { int gemToUse = RandomUtils.RandomGemTypeAsInt(); + + int iterations = 0; + while (this.matchService.MatchesAt(new Vector2Int(x, y), (GemType)gemToUse) && iterations < 100) + { + gemToUse = RandomUtils.RandomGemTypeAsInt(); + iterations++; + } + SpawnGem(new Vector2Int(x, y), (GemType)gemToUse); } } diff --git a/Assets/Scripts/Services/MatchService.cs b/Assets/Scripts/Services/MatchService.cs index 50e33cb..d634f1f 100644 --- a/Assets/Scripts/Services/MatchService.cs +++ b/Assets/Scripts/Services/MatchService.cs @@ -34,19 +34,30 @@ namespace Services { 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; - - if (positionToCheck.x > 1) - { - if (gems[positionToCheck.x - 1, positionToCheck.y].Type == gemTypeToCheck && gems[positionToCheck.x - 2, positionToCheck.y].Type == gemTypeToCheck) + + // 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; } - if (positionToCheck.y > 1) - { - if (gems[positionToCheck.x, positionToCheck.y - 1].Type == gemTypeToCheck && gems[positionToCheck.x, positionToCheck.y - 2].Type == gemTypeToCheck) + // 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; } @@ -88,80 +99,12 @@ namespace Services { } } - if (this.currentMatches.Count > 0) - this.currentMatches = this.currentMatches.Distinct().ToList(); - - ExpandMatchesForLTShapes(); - if (this.currentMatches.Count > 0) this.currentMatches = this.currentMatches.Distinct().ToList(); DetectBombSpawnFromLastSwap(); } - - private void ExpandMatchesForLTShapes() { - if (this.currentMatches.Count == 0) - return; - List seeds = this.currentMatches.ToList(); - - foreach (Gem pivotGem in seeds) { - if (pivotGem == null) - continue; - - Vector2Int pivot = pivotGem.Position; - - int left = CountLine(pivot, Vector2Int.left); - int right = CountLine(pivot, Vector2Int.right); - int up = CountLine(pivot, Vector2Int.up); - int down = CountLine(pivot, Vector2Int.down); - - int horizontalLen = left + 1 + right; - int verticalLen = up + 1 + down; - - bool hasHorizontalMatch = horizontalLen >= 3; - bool hasVerticalMatch = verticalLen >= 3; - - // one more in the perpendicular direction = length = 2 - bool hasHorizontalArm = horizontalLen >= 2; - bool hasVerticalArm = verticalLen >= 2; - - // Main horizontal + vertical arm = include vertical run - if (hasHorizontalMatch && hasVerticalArm) { - AddRun(pivot, Vector2Int.up); - AddRun(pivot, Vector2Int.down); - this.currentMatches.Add(pivotGem); - } - - // Main vertical + horizontal arm = include horizontal run - if (hasVerticalMatch && hasHorizontalArm) { - AddRun(pivot, Vector2Int.left); - AddRun(pivot, Vector2Int.right); - this.currentMatches.Add(pivotGem); - } - } - } - - private void AddRun(Vector2Int start, Vector2Int direction) { - Gem startGem = this.gameBoard.GetGemAt(start); - if (startGem == null) - return; - - GemType color = startGem.MatchColor; - - Vector2Int position = start + direction; - while (position.x >= 0 && position.x < this.gameBoard.Width && - position.y >= 0 && position.y < this.gameBoard.Height) { - - Gem g = this.gameBoard.GetGemAt(position); - if (g == null || g.MatchColor != color) - break; - - this.currentMatches.Add(g); - position += direction; - } - } - private void DetectBombSpawnFromLastSwap() { Vector2Int from = this.lastSwapFrom; Vector2Int to = this.lastSwapTo; @@ -182,9 +125,8 @@ namespace Services { if (this.currentMatches.All(g => g.Position != pivot)) return; - // NEW RULE: - // If the match group that includes this pivot (including L/T expansions) has 4+ gems, spawn a bomb. - int groupSize = GetMatchedGroupSizeIncludingLT(pivot); + // If the matched group that includes this pivot has 4+ connected gems, spawn a bomb. + int groupSize = GetMatchedGroupSize(pivot); if (groupSize < 4) return; @@ -195,14 +137,13 @@ namespace Services { this.pendingBombSpawns.Add(new BombSpawnRequest(pivot, pivotGem.MatchColor)); } - private int GetMatchedGroupSizeIncludingLT(Vector2Int pivot) { + private int GetMatchedGroupSize(Vector2Int pivot) { Gem pivotGem = this.gameBoard.GetGemAt(pivot); if (pivotGem == null) return 0; GemType color = pivotGem.MatchColor; - // Only count gems that are actually in currentMatches (which already includes L/T expansions). HashSet matchedPositions = new HashSet( this.currentMatches .Where(g => g != null && g.MatchColor == color) @@ -243,90 +184,5 @@ namespace Services { return visited.Count; } - - private int CountLine(Vector2Int start, Vector2Int direction) { - Gem startGem = this.gameBoard.GetGemAt(start); - if (startGem == null) - return 0; - - GemType color = startGem.MatchColor; - - int count = 0; - Vector2Int position = start + direction; - - while (position.x >= 0 && position.x < this.gameBoard.Width && position.y >= 0 && position.y < this.gameBoard.Height) { - Gem g = this.gameBoard.GetGemAt(position); - if (g == null || g.MatchColor != color) - break; - - count++; - position += direction; - } - - return count; - } - - private void CheckForBombs() { - Gem[,] gems = this.gameBoard.GemsGrid; - int width = this.gameBoard.Width; - int height = this.gameBoard.Height; - - for (int i = 0; i < this.currentMatches.Count; i++) - { - Gem gem = this.currentMatches[i]; - int x = gem.Position.x; - int y = gem.Position.y; - - Vector2Int[] directions = - { - Vector2Int.left, - Vector2Int.right, - Vector2Int.down, - Vector2Int.up - }; - - foreach (Vector2Int direction in directions) - { - int newX = x + direction.x; - int newY = y + direction.y; - - if (newX < 0 || newX >= width || newY < 0 || newY >= height) - continue; - - Gem neighbor = gems[newX, newY]; - if (neighbor?.Type == GemType.Bomb) - MarkBombCross(new Vector2Int(newX, newY), 1); - } - } - } - - private void MarkBombCross(Vector2Int bombPosition, int radius) { - Gem[,] gems = this.gameBoard.GemsGrid; - int width = this.gameBoard.Width; - int height = this.gameBoard.Height; - - void Mark(Vector2Int p) { - if (p.x < 0 || p.x >= width || p.y < 0 || p.y >= height) - return; - Gem g = gems[p.x, p.y]; - if (g == null) - return; - - this.currentMatches.Add(g); - } - - Mark(bombPosition); - - for (int i = 1; i <= radius; i++) { - Mark(bombPosition + Vector2Int.left * i); - Mark(bombPosition + Vector2Int.right * i); - Mark(bombPosition + Vector2Int.up * i); - Mark(bombPosition + Vector2Int.down * i); - } - - this.currentMatches = this.currentMatches.Distinct().ToList(); - } } - - } \ No newline at end of file