package generator import ( "fmt" "time" ) // BenchmarkResult contains statistics from puzzle generation benchmarking. type BenchmarkResult struct { Difficulty Difficulty TotalAttempts int SuccessfulPuzzles int FailedPuzzles int AverageTime time.Duration MinTime time.Duration MaxTime time.Duration AverageRating float64 Ratings []int } // BenchmarkGeneration tests puzzle generation performance for a given difficulty. func BenchmarkGeneration(d Difficulty, attempts int) BenchmarkResult { result := BenchmarkResult{ Difficulty: d, TotalAttempts: attempts, MinTime: time.Hour, // Start with a large value Ratings: make([]int, 0, attempts), } var totalDuration time.Duration for i := 0; i < attempts; i++ { seed := fmt.Sprintf("benchmark-%d-%d", time.Now().UnixNano(), i) start := time.Now() puzzle, err := Generate(d, seed) elapsed := time.Since(start) if err != nil { result.FailedPuzzles++ continue } result.SuccessfulPuzzles++ totalDuration += elapsed if elapsed < result.MinTime { result.MinTime = elapsed } if elapsed > result.MaxTime { result.MaxTime = elapsed } rating := RatePuzzle(puzzle) result.Ratings = append(result.Ratings, rating) } if result.SuccessfulPuzzles > 0 { result.AverageTime = totalDuration / time.Duration(result.SuccessfulPuzzles) var totalRating int for _, r := range result.Ratings { totalRating += r } result.AverageRating = float64(totalRating) / float64(len(result.Ratings)) } return result } // String returns a formatted string representation of the benchmark result. func (br BenchmarkResult) String() string { successRate := float64(br.SuccessfulPuzzles) / float64(br.TotalAttempts) * 100 return fmt.Sprintf(`Benchmark Results for %s: Total Attempts: %d Successful: %d (%.1f%%) Failed: %d Average Time: %v Min Time: %v Max Time: %v Average Rating: %.1f/100 `, br.Difficulty.String(), br.TotalAttempts, br.SuccessfulPuzzles, successRate, br.FailedPuzzles, br.AverageTime, br.MinTime, br.MaxTime, br.AverageRating, ) } // CompareGenerationMethods compares standard vs symmetric generation. func CompareGenerationMethods(d Difficulty, attempts int) (standard, symmetric BenchmarkResult) { // Benchmark standard generation standard = BenchmarkGeneration(d, attempts) // Benchmark symmetric generation symmetric = BenchmarkResult{ Difficulty: d, TotalAttempts: attempts, MinTime: time.Hour, Ratings: make([]int, 0, attempts), } var totalDuration time.Duration for i := 0; i < attempts; i++ { seed := fmt.Sprintf("symmetric-benchmark-%d-%d", time.Now().UnixNano(), i) start := time.Now() puzzle, err := GenerateWithSymmetry(d, seed, SymmetryRotational180) elapsed := time.Since(start) if err != nil { symmetric.FailedPuzzles++ continue } symmetric.SuccessfulPuzzles++ totalDuration += elapsed if elapsed < symmetric.MinTime { symmetric.MinTime = elapsed } if elapsed > symmetric.MaxTime { symmetric.MaxTime = elapsed } rating := RatePuzzle(puzzle) symmetric.Ratings = append(symmetric.Ratings, rating) } if symmetric.SuccessfulPuzzles > 0 { symmetric.AverageTime = totalDuration / time.Duration(symmetric.SuccessfulPuzzles) var totalRating int for _, r := range symmetric.Ratings { totalRating += r } symmetric.AverageRating = float64(totalRating) / float64(len(symmetric.Ratings)) } return standard, symmetric } // PuzzleStatistics provides detailed statistics about a generated puzzle. type PuzzleStatistics struct { Grid Grid Analysis PuzzleAnalysis Rating int EstimatedSolveTime time.Duration ComplexityScore float64 } // GetPuzzleStatistics performs comprehensive analysis on a puzzle. func GetPuzzleStatistics(g Grid) PuzzleStatistics { analysis := g.Analyze() rating := RatePuzzle(g) // Estimate solve time based on difficulty (rough approximation) var estimatedTime time.Duration switch analysis.EstimatedDifficulty { case Easy: estimatedTime = 3 * time.Minute case Normal: estimatedTime = 8 * time.Minute case Hard: estimatedTime = 15 * time.Minute case Expert: estimatedTime = 25 * time.Minute case Lunatic: estimatedTime = 45 * time.Minute } // Calculate complexity score (0-1) complexityScore := float64(rating) / 100.0 return PuzzleStatistics{ Grid: g, Analysis: analysis, Rating: rating, EstimatedSolveTime: estimatedTime, ComplexityScore: complexityScore, } } // String returns a formatted string of puzzle statistics. func (ps PuzzleStatistics) String() string { return fmt.Sprintf(`Puzzle Statistics: Difficulty: %s Rating: %d/100 Filled Cells: %d Empty Cells: %d Min Candidates: %d Max Candidates: %d Avg Candidates: %.2f Unique Solution: %v Symmetry: %s Techniques: %v Complexity Score: %.2f Est. Solve Time: %v `, ps.Analysis.EstimatedDifficulty.String(), ps.Rating, ps.Analysis.FilledCells, ps.Analysis.EmptyCells, ps.Analysis.MinCandidates, ps.Analysis.MaxCandidates, ps.Analysis.AvgCandidates, ps.Analysis.HasUniqueSolution, ps.Analysis.SymmetryType.String(), ps.Analysis.SolvingTechniques, ps.ComplexityScore, ps.EstimatedSolveTime, ) }