Files
nd-wfc/demos/sudoku/debug_failing_puzzles.cpp
2025-08-29 15:59:56 +09:00

166 lines
5.7 KiB
C++

#include "sudoku.h"
#include <nd-wfc/wfc.hpp>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <chrono>
#include <algorithm>
#include <iomanip>
// Helper function to load puzzles from a file (one puzzle per line)
std::vector<Sudoku> loadPuzzlesFromFile(const std::string& filename) {
std::vector<Sudoku> puzzles;
std::ifstream file(filename);
if (!file.is_open()) {
std::cerr << "Failed to open file: " << filename << std::endl;
return puzzles;
}
std::string line;
while (std::getline(file, line)) {
// Remove whitespace
line.erase(std::remove_if(line.begin(), line.end(),
[](char c) { return std::isspace(c); }), line.end());
if (line.empty()) continue;
Sudoku sudoku;
if (sudoku.loadFromString(line)) {
puzzles.push_back(std::move(sudoku));
}
}
return puzzles;
}
// Helper function to print a puzzle in a nice format
void printPuzzle(const Sudoku& sudoku, const std::string& title = "") {
if (!title.empty()) {
std::cout << title << std::endl;
std::cout << std::string(title.length(), '=') << std::endl;
}
for (int row = 0; row < 9; ++row) {
for (int col = 0; col < 9; ++col) {
uint8_t value = sudoku.get(row, col);
std::cout << (value == 0 ? '.' : static_cast<char>('0' + value));
if (col < 8) std::cout << " ";
if (col == 2 || col == 5) std::cout << "| ";
}
std::cout << std::endl;
if (row == 2 || row == 5) {
std::cout << "------+-------+------" << std::endl;
}
}
std::cout << std::endl;
}
// Helper function to count filled cells in a puzzle
int countFilledCells(const Sudoku& sudoku) {
int count = 0;
for (int i = 0; i < 81; ++i) {
if (sudoku.get(i / 9, i % 9) != 0) {
count++;
}
}
return count;
}
// Analyze a single failing puzzle in detail
void analyzeFailingPuzzle(const Sudoku& originalPuzzle, int puzzleIndex) {
std::cout << "\n" << std::string(60, '=') << std::endl;
std::cout << "ANALYZING FAILING PUZZLE #" << puzzleIndex << std::endl;
std::cout << std::string(60, '=') << std::endl;
// Show original puzzle
printPuzzle(originalPuzzle, "Original Puzzle");
// Show statistics
int filledCells = countFilledCells(originalPuzzle);
std::cout << "Statistics:" << std::endl;
std::cout << " Filled cells: " << filledCells << "/81 (" << std::fixed << std::setprecision(1)
<< (filledCells * 100.0 / 81) << "%)" << std::endl;
std::cout << " Empty cells: " << (81 - filledCells) << std::endl;
std::cout << " Is valid: " << (originalPuzzle.isValid() ? "Yes" : "No") << std::endl;
std::cout << " Is solved: " << (originalPuzzle.isSolved() ? "Yes" : "No") << std::endl;
std::cout << std::endl;
// Try different solving approaches
// Test 1: Try solving with different configurations
std::cout << "Testing different solving approaches:" << std::endl;
// Test with verbose output to see what happens
Sudoku testPuzzle = originalPuzzle;
std::cout << "\nTest 1: Solving with verbose output..." << std::endl;
auto start = std::chrono::high_resolution_clock::now();
SudokuSolver::Run(testPuzzle, true); // Enable verbose output
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
bool solved = testPuzzle.isSolved();
std::cout << "Result: " << (solved ? "SOLVED" : "FAILED") << std::endl;
std::cout << "Time taken: " << duration.count() << "ms" << std::endl;
if (solved) {
printPuzzle(testPuzzle, "Solved Puzzle");
}
// Test 2: Multiple attempts
if (!solved) {
std::cout << "\nTest 2: Multiple solving attempts..." << std::endl;
int attempts = 3;
for (int attempt = 1; attempt <= attempts; ++attempt) {
Sudoku attemptPuzzle = originalPuzzle;
std::cout << "Attempt " << attempt << ": ";
auto attemptStart = std::chrono::high_resolution_clock::now();
SudokuSolver::Run(attemptPuzzle, false); // No verbose output
auto attemptEnd = std::chrono::high_resolution_clock::now();
auto attemptDuration = std::chrono::duration_cast<std::chrono::milliseconds>(attemptEnd - attemptStart);
bool attemptSolved = attemptPuzzle.isSolved();
std::cout << (attemptSolved ? "SOLVED" : "FAILED")
<< " (" << attemptDuration.count() << "ms)" << std::endl;
if (attemptSolved) {
std::cout << "SUCCESS on attempt " << attempt << "!" << std::endl;
printPuzzle(attemptPuzzle, "Successfully Solved Puzzle");
break;
}
}
}
}
int main() {
const std::string failingPuzzlesFile = "/home/connor/repos/nd-wfc/demos/sudoku/data/Sudoku_failing.txt";
std::cout << "Loading failing puzzles from: " << failingPuzzlesFile << std::endl;
// Load failing puzzles
auto failingPuzzles = loadPuzzlesFromFile(failingPuzzlesFile);
if (failingPuzzles.empty()) {
std::cout << "No failing puzzles found!" << std::endl;
return 0;
}
std::cout << "Found " << failingPuzzles.size() << " failing puzzles" << std::endl;
// Analyze each failing puzzle
for (size_t i = 0; i < failingPuzzles.size(); ++i) {
analyzeFailingPuzzle(failingPuzzles[i], i + 1);
}
std::cout << "\n" << std::string(60, '=') << std::endl;
std::cout << "ANALYSIS COMPLETE" << std::endl;
std::cout << "Total failing puzzles analyzed: " << failingPuzzles.size() << std::endl;
std::cout << std::string(60, '=') << std::endl;
return 0;
}