diff --git a/logs/2025-09.md b/logs/2025-09.md index 7f7c42e..4f24173 100644 --- a/logs/2025-09.md +++ b/logs/2025-09.md @@ -5,7 +5,9 @@ ### Week 1 | 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 | |------|------|------|------|------|------|------| -| 09-01 | Maximum Average Pass Ratio | Medium | C# | 1hr | Done | 第一次用到Priority Queue | +| 09/01 | Maximum Average Pass Ratio | Medium | C# | 1hr | Done | 第一次用到Priority Queue | +| 09/02| Find The Number of Ways to Place People I | Medium | C# | 0.5hr | Done | 二維點位判斷 | +| 09/02| Find The Number of Ways to Place People I | Medium | go | 0.2hr | Done | go Prictice | ### Week 2 | 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 | @@ -25,13 +27,13 @@ ## 📈 本月統計 ### 完成情況 -- **總練習天數**: 1 天 -- **完成題數**: 1題 -- **語言分布**: C# 1(題), Go 0(題) -- **難度分布**: Easy 0(題), Medium 1(題), Hard 0(題) +- **總練習天數**: 2 天 +- **完成題數**: 2題 +- **語言分布**: C# 2(題), Go 1(題) +- **難度分布**: Easy 0(題), Medium 2(題), Hard 0(題) ### 時間投入 -- **總時間**: 1小時 +- **總時間**: 1.7小時 - **平均每題**: 分鐘 - **每日平均**: 分鐘 diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/README.md b/problems/3025-find-the-number-of-ways-to-place-people-i/README.md new file mode 100644 index 0000000..97f42de --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/README.md @@ -0,0 +1,69 @@ +# [3025] Find The Number Of Ways To Place People I + +## 題目資訊 +- **難度**: Medium +- **標籤**: Array, Math, Geometry, Sorting, Enumeration +- **題目連結**: [LeetCode](https://leetcode.com/problems/find-the-number-of-ways-to-place-people-i/) +- **練習日期**: 2025-09-02 + +## 題目描述 +You are given a 2D array `points` of size `n x 2` representing integer coordinates of some points on a 2D plane, where `points[i] = [xi, yi]`. + +Count the number of pairs of points `(A, B)`, where + - `A` is on **the upper** left side of `B`, and + - there are no other points in the rectangle (or line) they make (**including the border**). + +Return the count. + +## 解題思路 + +### 初步分析 +- 核心概念 + 幾何關係判斷 + 區域內點的檢測 +- 關鍵限制條件 + 1. A必須在B的左上方, A.x <= B.x, A.y >= B.y + 2. 矩形區域內(包含邊界)不能有其他點 +- 預期時間/空間複雜度? + +### 解法概述 +**解法**: + - 思路: + - 遍歷所有點對 (A, B) + - 檢查每個pair形成的矩形, 裡面跟邊界會不會包含其他點 + - 時間複雜度:O(N^3) + - 空間複雜度:O(1) + +## 測試案例 + +### 範例輸入輸出 +``` +Input: points = [[6,2],[4,4],[2,6]] +Output: 2 +Explanation: + - The left one is the pair (points[1], points[0]), where points[1] is on the upper left side of points[0] and the rectangle is empty. + - The left one is the pair (points[1], points[0]), where points[1] is on the upper left side of points[0] and the rectangle is empty. + - The right one is the pair (points[2], points[0]), where points[2] is on the upper left side of points[0], but points[1] is inside the rectangle so it's not a valid pair. +``` + +### 邊界情況 +- `2 <= n <= 50` +- `points[i].length == 2` +- `0 <= points[i][0], points[i][1] <= 50` +- All `points[i]` are distinct. + +## 學習筆記 + +### 今天學到什麼? +- 二維空間判斷點大小 + +### 遇到的困難 +- 無 + +### 改善方向 +- 無 + +### 相關題目 +- [#223](https://leetcode.com/problems/rectangle-area/) Rectangle Area + +--- +**總結**: 這題的核心概念是...,適合練習...技巧。 diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/csharp/Program.cs b/problems/3025-find-the-number-of-ways-to-place-people-i/csharp/Program.cs new file mode 100644 index 0000000..ff14dbc --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/csharp/Program.cs @@ -0,0 +1,86 @@ +// LeetCode 3025: Find The Number Of Ways To Place People I +// 難度: Medium +// 日期: 2025-09-02 + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +public class Solution +{ + public int NumberOfPairs(int[][] points) + { + // 遍歷所有點對 (A, B) + // 檢查每個pair形成的矩形, 裡面跟邊界會不會包含其他點 + + // points[0].Length == 2 + int n = points.Length; + int count = 0; + + for (var i = 0; i < n; i++) + { + for (var j = 0; j < n; j++) + { + if (i == j) continue; + + int[] pointA = points[i]; + int[] pointB = points[j]; + + // check if A.x <= B.x && A.y >= B.y + // if yes, check if any points in rectangle + if (pointA[0] <= pointB[0] && pointA[1] >= pointB[1]) + { + // difinition of border + bool hasOtherPoint = false; + int minX = pointA[0]; + int maxX = pointB[0]; + int minY = pointB[1]; + int maxY = pointA[1]; + + // check other point if its in border + for (var k = 0; k < n; k++) + { + if (k == i || k == j) continue; + + var pointC = points[k]; + if (minX <= pointC[0] && pointC[0] <= maxX + && minY <= pointC[1] && pointC[1] <= maxY) + { + hasOtherPoint = true; + break; + } + } + + if (!hasOtherPoint) count++; + } + } + } + return count; + } +} + +public class Program { + public static void Main() { + Solution solution = new Solution(); + + // 測試案例 + TestCase(solution); + } + + static void TestCase(Solution solution) { + // Input: + int[][] points = new int[][] { + new int[] {6, 2}, + new int[] {4, 4}, + new int[] {2, 6} + }; + // Expected: + Console.WriteLine($"Test Case: [[6,2],[4,4],[2,6]]"); + Console.WriteLine($"Expected: 2"); + + // Actual: + int result1 = solution.NumberOfPairs(points); + Console.WriteLine($"Result: {result1}"); + } +} diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/csharp/csharp.csproj b/problems/3025-find-the-number-of-ways-to-place-people-i/csharp/csharp.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/csharp/csharp.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/go/go.mod b/problems/3025-find-the-number-of-ways-to-place-people-i/go/go.mod new file mode 100644 index 0000000..3879058 --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/go/go.mod @@ -0,0 +1,3 @@ +module leetcode-3025 + +go 1.18 diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/go/main.go b/problems/3025-find-the-number-of-ways-to-place-people-i/go/main.go new file mode 100644 index 0000000..b48d086 --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/go/main.go @@ -0,0 +1,70 @@ +// LeetCode 3025: Find The Number Of Ways To Place People I +// 難度: Medium +// 日期: 2025-09-02 + +package main + +import "fmt" + +// TODO: 實作解法 +func numberOfPairs(points [][]int) int { + n := len(points) + count := 0; + + for i:= 0; i < n; i++{ + for j := 0; j < n; j++{ + if i == j { + continue + } + + pointA := points[i] + pointB := points[j] + + if pointA[0] <= pointB[0] && pointA[1] >= pointB[1] { + hasOtherPoint := false; + minX := pointA[0] + maxX := pointB[0] + minY := pointB[1] + maxY := pointA[1] + + for k := 0; k < n; k++{ + if i == k || j == k{ + continue + } + + pointC := points[k] + + if minX <= pointC[0] && pointC[0] <= maxX && minY <= pointC[1] && pointC[1] <= maxY{ + hasOtherPoint = true + break + } + } + + if !hasOtherPoint{ + count++ + } + } + } + } + return count; +} + +func main() { + testCase() +} + +// 測試案例模板 +func testCase() { + // Input: + points := [][]int{ + {6, 2}, + {4, 4}, + {2, 6}, + } + // Expected: + fmt.Printf("Test Case: [[6,2],[4,4],[2,6]]\n") + fmt.Printf("Expected: 2\n") + // Actual: + result := numberOfPairs(points) + fmt.Printf("Result: %d\n", result) +} diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/go/main_test.go b/problems/3025-find-the-number-of-ways-to-place-people-i/go/main_test.go new file mode 100644 index 0000000..dd276cf --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/go/main_test.go @@ -0,0 +1,239 @@ +// LeetCode 3025 Go 單元測試 +package main + +import ( + "math/rand" + "testing" + "fmt" +) + +func TestCase1_ExampleFromProblem(t *testing.T) { + // Arrange + points := [][]int{ + {6, 2}, + {4, 4}, + {2, 6}, + } + expected := 2 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestCase1 failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestCase2_TwoPoints(t *testing.T) { + // Arrange + points := [][]int{ + {1, 3}, + {2, 1}, + } + expected := 1 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestCase2 failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestCase3_NoValidPairs(t *testing.T) { + // Arrange - 沒有有效點對的情況 + points := [][]int{ + {1, 1}, + {2, 2}, + {3, 3}, + } + expected := 0 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestCase3 failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestCase4_SameXCoordinate(t *testing.T) { + // Arrange - x 座標相同的情況 + points := [][]int{ + {3, 5}, // A + {3, 2}, // B + {3, 1}, // C + } + // 詳細分析: + // (A, B): (3,5) -> (3,2) ✓ 矩形是線段,無其他點 + // (A, C): (3,5) -> (3,1) ✗ 點B在矩形內 + // (B, C): (3,2) -> (3,1) ✓ 矩形是線段,無其他點 + expected := 2 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestCase4 failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestCase5_SameYCoordinate(t *testing.T) { + // Arrange - y 座標相同的情況 + points := [][]int{ + {1, 4}, // A + {3, 4}, // B + {5, 4}, // C + } + // 詳細分析: + // (A, B): (1,4) -> (3,4) ✓ 矩形是線段,無其他點 + // (A, C): (1,4) -> (5,4) ✗ 點B在矩形內 + // (B, C): (3,4) -> (5,4) ✓ 矩形是線段,無其他點 + expected := 2 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestCase5 failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestCase6_PointsInsideRectangle(t *testing.T) { + // Arrange - 矩形內有其他點的情況 + points := [][]int{ + {0, 4}, // A + {4, 0}, // B + {2, 2}, // C + } + // 詳細分析: + // (A, B): (0,4) -> (4,0) ✗ 點C在矩形內 + // (A, C): (0,4) -> (2,2) ✓ 點B不在矩形內 + // (C, B): (2,2) -> (4,0) ✓ 點A不在矩形內 + expected := 2 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestCase6 failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestCase7_PointsOnBorder(t *testing.T) { + // Arrange - 點在矩形邊界上的情況 + points := [][]int{ + {0, 3}, // A + {3, 0}, // B + {0, 0}, // C + } + // 詳細分析: + // (A, B): (0,3) -> (3,0) ✗ 點C在矩形邊界上 + // (A, C): (0,3) -> (0,0) ✓ 矩形是線段,點B不在其中 + // (C, B): (0,0) -> (3,0) ✓ 矩形是線段,點A不在其中 + expected := 2 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestCase7 failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestEdgeCases_MinimumPoints(t *testing.T) { + // Arrange - 最少點數情況 (題目限制 n >= 2) + points := [][]int{ + {0, 1}, + {1, 0}, + } + expected := 1 // (0,1) 在 (1,0) 的左上方 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestEdgeCases_MinimumPoints failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestEdgeCases_MaxCoordinateValues(t *testing.T) { + // Arrange - 最大座標值情況 (題目限制 0 <= coordinates <= 50) + points := [][]int{ + {0, 50}, // A + {50, 0}, // B + {25, 25}, // C + } + expected := 2 // (A,C) 和 (C,B) 有效 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestEdgeCases_MaxCoordinateValues failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestEdgeCases_EmptyArray(t *testing.T) { + // Arrange - 空陣列情況 + points := [][]int{} + expected := 0 + + // Act + result := numberOfPairs(points) + + // Assert + if result != expected { + t.Errorf("TestEdgeCases_EmptyArray failed. Expected: %v, Got: %v", expected, result) + } +} + +func TestEdgeCases_MaxPoints_RandomPattern(t *testing.T) { + // Arrange - 50個不同的點,隨機模式 + points := make([][]int, 0, 50) + usedPoints := make(map[string]bool) + + // 使用固定種子確保測試可重現 + rand.Seed(42) + + for len(points) < 50 { + x := rand.Intn(51) // 0-50 + y := rand.Intn(51) // 0-50 + pointKey := fmt.Sprintf("%d,%d", x, y) + + if !usedPoints[pointKey] { + usedPoints[pointKey] = true + points = append(points, []int{x, y}) + } + } + + // Act + result := numberOfPairs(points) + + // Assert + if result < 0 { + t.Errorf("TestEdgeCases_MaxPoints_RandomPattern failed. Result should be non-negative, got: %v", result) + } + if result > 50*49 { + t.Errorf("TestEdgeCases_MaxPoints_RandomPattern failed. Result should not exceed 50*49, got: %v", result) + } + + // 額外驗證:確保所有點都是不同的 + distinctPoints := make(map[string]bool) + for _, point := range points { + key := fmt.Sprintf("%d,%d", point[0], point[1]) + distinctPoints[key] = true + } + if len(distinctPoints) != 50 { + t.Errorf("TestEdgeCases_MaxPoints_RandomPattern failed. Expected 50 distinct points, got: %v", len(distinctPoints)) + } +} diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/test/SolutionTests.cs b/problems/3025-find-the-number-of-ways-to-place-people-i/test/SolutionTests.cs new file mode 100644 index 0000000..0dbedc2 --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/test/SolutionTests.cs @@ -0,0 +1,244 @@ +// LeetCode 3025 單元測試 +// 使用 xUnit 框架 + +using Xunit; +using System; +using System.Collections.Generic; + +public class SolutionTests +{ + private readonly Solution _solution; + + public SolutionTests() + { + _solution = new Solution(); + } + + [Fact] + public void TestCase1_ExampleFromProblem() + { + // Arrange + int[][] points = new int[][] { + new int[] {6, 2}, + new int[] {4, 4}, + new int[] {2, 6} + }; + int expected = 2; + + // Act + var result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestCase2_TwoPoints() + { + // Arrange + int[][] points = new int[][] { + new int[] {1, 3}, + new int[] {2, 1} + }; + int expected = 1; + + // Act + var result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestCase3_NoValidPairs() + { + // Arrange - 沒有有效點對的情況 + int[][] points = new int[][] { + new int[] {1, 1}, + new int[] {2, 2}, + new int[] {3, 3} + }; + int expected = 0; + + // Act + var result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestCase4_SameXCoordinate() + { + // Arrange - x 座標相同的情況 + int[][] points = new int[][] { + new int[] {3, 5}, + new int[] {3, 2}, + new int[] {3, 1} + }; + int expected = 2; + + // Act + var result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestCase5_SameYCoordinate() + { + // Arrange - y 座標相同的情況 + int[][] points = new int[][] { + new int[] {1, 4}, + new int[] {3, 4}, + new int[] {5, 4} + }; + int expected = 2; + + // Act + var result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestCase6_PointsInsideRectangle() + { + // Arrange - 矩形內有其他點的情況 + int[][] points = new int[][] { + new int[] {0, 4}, // A + new int[] {4, 0}, // B + new int[] {2, 2} // C (在 A-B 矩形內) + }; + + int expected = 2; + + // Act + var result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestCase7_PointsOnBorder() + { + // Arrange - 點在矩形邊界上的情況 + int[][] points = new int[][] { + new int[] {0, 3}, // A + new int[] {3, 0}, // B + new int[] {0, 0} // C (在矩形邊界上) + }; + int expected = 2; // (A,C) 和 (C,B) 有效 + + // Act + var result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestEdgeCases_MinimumPoints() + { + // Arrange - 最少點數情況 (題目限制 n >= 2) + int[][] points = new int[][] { + new int[] {0, 1}, + new int[] {1, 0} + }; + int expected = 1; // (0,1) 在 (1,0) 的左上方 + + // Act + int result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestEdgeCases_IdenticalCoordinates() + { + // Arrange - 座標值相同的情況 + int[][] points = new int[][] { + new int[] {2, 2}, + new int[] {2, 2} // 題目保證所有點都不同,但測試邊界 + }; + + // 這個測試案例實際上違反了題目條件 (All points[i] are distinct) + // 但可以測試程式的健壯性 + int expected = 2; // 兩個相同點互相滿足左上方條件 + + // Act + int result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestEdgeCases_MaxCoordinateValues() + { + // Arrange - 最大座標值情況 (題目限制 0 <= coordinates <= 50) + int[][] points = new int[][] { + new int[] {0, 50}, + new int[] {50, 0}, + new int[] {25, 25} + }; + int expected = 2; // (A,C) 和 (C,B) 有效 + + // Act + int result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestEdgeCases_EmptyArray() + { + // Arrange - 空陣列情況 + int[][] points = new int[0][]; + int expected = 0; + + // Act + int result = _solution.NumberOfPairs(points); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void TestEdgeCases_MaxPoints_AllDistinct_RandomPattern() { + // Arrange - 50個不同的點,更複雜的模式 + var points = new List(); + + // 創建一個螺旋模式的50個不同點,確保都在 [0,50] 範圍內且互不相同 + var usedPoints = new HashSet(); + var random = new Random(42); // 固定種子確保測試可重現 + + while (points.Count < 50) { + int x = random.Next(0, 51); // 0-50 + int y = random.Next(0, 51); // 0-50 + string pointKey = $"{x},{y}"; + + if (!usedPoints.Contains(pointKey)) { + usedPoints.Add(pointKey); + points.Add(new int[] { x, y }); + } + } + + int[][] pointsArray = points.ToArray(); + + // 由於是隨機分佈,很難預測確切結果,但應該是一個合理的正數 + // 這個測試主要驗證程式在最大輸入時不會崩潰或超時 + + // Act + int result = _solution.NumberOfPairs(pointsArray); + + // Assert + Assert.True(result >= 0); // 至少結果應該是非負數 + Assert.True(result <= 50 * 49); // 最多不會超過所有可能的點對 + } +} diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/test/TestProject.csproj b/problems/3025-find-the-number-of-ways-to-place-people-i/test/TestProject.csproj new file mode 100644 index 0000000..2f44c14 --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/test/TestProject.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/test/edge_cases.md b/problems/3025-find-the-number-of-ways-to-place-people-i/test/edge_cases.md new file mode 100644 index 0000000..866e9a2 --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/test/edge_cases.md @@ -0,0 +1,13 @@ +# 邊界情況清單 + +## 需要測試的邊界情況 +- [x] 空輸入 (空陣列) - `TestEdgeCases_EmptyArray` +- [x] 最少元素 (n=2) - `TestEdgeCases_MinimumPoints` +- [x] 重複座標 (雖然違反題目條件) - `TestEdgeCases_IdenticalCoordinates` +- [x] 最大值/最小值 (座標範圍 [0,50]) - `TestEdgeCases_MaxCoordinateValues` +- [x] 最大資料量 (n=50) - `TestEdgeCases_MaxPoints_AllDistinct_RandomPattern` +- [x] 相同 x 座標 - `TestCase4_SameXCoordinate` +- [x] 相同 y 座標 - `TestCase5_SameYCoordinate` +- [x] 矩形內含其他點 - `TestCase6_PointsInsideRectangle` +- [x] 點在矩形邊界上 - `TestCase7_PointsOnBorder` +- [x] 無有效點對情況 - `TestCase3_NoValidPairs` diff --git a/problems/3025-find-the-number-of-ways-to-place-people-i/test/run_tests.sh b/problems/3025-find-the-number-of-ways-to-place-people-i/test/run_tests.sh new file mode 100755 index 0000000..59227c5 --- /dev/null +++ b/problems/3025-find-the-number-of-ways-to-place-people-i/test/run_tests.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +echo "🧪 執行 LeetCode 題目測試" +echo "==========================" + +# 執行 C# 測試 +echo "📋 C# 測試結果:" +cd ../csharp +if dotnet build > /dev/null 2>&1; then + cd ../test + if dotnet test --logger "console;verbosity=minimal" 2>/dev/null; then + echo "✅ C# 測試通過" + else + echo "❌ C# 測試失敗" + fi +else + echo "❌ C# 編譯失敗" +fi + +echo "" + +# 執行 Go 測試 +echo "📋 Go 測試結果:" +cd ../go +if go build > /dev/null 2>&1; then + # cd ../test + if go test -v > /dev/null 2>&1; then + echo "✅ Go 測試通過" + else + echo "❌ Go 測試失敗" + echo "詳細輸出:" + go test -v + fi +else + echo "❌ Go 編譯失敗" +fi + +echo "" +echo "📊 測試完成!"