From fffe1987b4a39fc1cd69289e427735b9bebbe7a0 Mon Sep 17 00:00:00 2001 From: Jesus Castro Date: Tue, 16 Dec 2025 21:44:49 +0800 Subject: [PATCH] Implement L and T Shapes --- Assets/Scripts/Services/GameBoardService.cs | 6 +- Assets/Scripts/Services/MatchService.cs | 127 +++++++++++++++++++- 2 files changed, 124 insertions(+), 9 deletions(-) diff --git a/Assets/Scripts/Services/GameBoardService.cs b/Assets/Scripts/Services/GameBoardService.cs index 345283d..9802938 100644 --- a/Assets/Scripts/Services/GameBoardService.cs +++ b/Assets/Scripts/Services/GameBoardService.cs @@ -183,10 +183,10 @@ namespace Services { private async UniTask DestroyMatchesAsync(List protectedPositions) { List matchPositions = new List(this.matchService.CurrentMatches.Count); for (int i = 0; i < this.matchService.CurrentMatches.Count; i++) { - var m = this.matchService.CurrentMatches[i]; - if (m == null) continue; + Gem match = this.matchService.CurrentMatches[i]; + if (match == null) continue; - Vector2Int pos = m.Position; + Vector2Int pos = match.Position; if (protectedPositions != null && protectedPositions.Contains(pos)) continue; diff --git a/Assets/Scripts/Services/MatchService.cs b/Assets/Scripts/Services/MatchService.cs index d7b4e00..50e33cb 100644 --- a/Assets/Scripts/Services/MatchService.cs +++ b/Assets/Scripts/Services/MatchService.cs @@ -88,12 +88,80 @@ 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; @@ -114,20 +182,67 @@ namespace Services { if (this.currentMatches.All(g => g.Position != pivot)) return; - int horizontal = CountLine(pivot, Vector2Int.left) + 1 + CountLine(pivot, Vector2Int.right); - int vertical = CountLine(pivot, Vector2Int.up) + 1 + CountLine(pivot, Vector2Int.down); - - int best = Mathf.Max(horizontal, vertical); - if (best < 4) + // 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 (groupSize < 4) return; - // Spawn a bomb on the creating slot with the same color group. // Prevent duplicates for the same cell. if (this.pendingBombSpawns.Any(b => b.Position == pivot)) return; this.pendingBombSpawns.Add(new BombSpawnRequest(pivot, pivotGem.MatchColor)); } + + private int GetMatchedGroupSizeIncludingLT(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) + .Select(g => g.Position) + ); + + if (!matchedPositions.Contains(pivot)) + return 0; + + Queue queue = new Queue(); + HashSet visited = new HashSet(); + + queue.Enqueue(pivot); + visited.Add(pivot); + + Vector2Int[] directions = { + Vector2Int.left, + Vector2Int.right, + Vector2Int.up, + Vector2Int.down + }; + + while (queue.Count > 0) { + Vector2Int currentPivot = queue.Dequeue(); + + for (int i = 0; i < directions.Length; i++) { + Vector2Int n = currentPivot + directions[i]; + if (visited.Contains(n)) + continue; + + if (!matchedPositions.Contains(n)) + continue; + + visited.Add(n); + queue.Enqueue(n); + } + } + + return visited.Count; + } private int CountLine(Vector2Int start, Vector2Int direction) { Gem startGem = this.gameBoard.GetGemAt(start);