Skip to content
Snippets Groups Projects
Select Git revision
  • b7af9f935c0ec6eaf943d41882b3adac3d3a10cc
  • main default protected
  • backtracking
  • vis
  • pure_wfc
  • plain_sudoku
6 results

window.cpp

Blame
  • user avatar
    Silas Dohm authored
    b7af9f93
    History
    window.cpp 5.54 KiB
    #include "window.h"
    #include <QApplication>
    #include <QDebug>
    #include <QPushButton>
    #include <QSlider>
    #include <QGridLayout>
    #include <QHBoxLayout>
    #include <QVBoxLayout>
    #include <QSpacerItem>
    #include <QTimer>
    
    Window::Window(QWidget *parent)
        : QWidget{parent}
    {
        solveButton = new QPushButton("solve", this);
        connect(solveButton, SIGNAL(clicked()), this, SLOT(solveButtonClicked()));
        clearButton = new QPushButton("Clear", this);
        connect(clearButton, SIGNAL(clicked()), this, SLOT(clearButtonClicked()));
    
        slider = new QSlider(this);
        slider->setRange(0, 1000);
        slider->setOrientation(Qt::Horizontal);
        slider->setValue(delayTime);
        connect(slider, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)));
    
        horizontalLayout = new QHBoxLayout(this);
        verticalLayout = new QVBoxLayout();
        layout = new QGridLayout();
    
        spacer[0] = new QSpacerItem(4, 4, QSizePolicy::Minimum, QSizePolicy::Fixed);
        spacer[1] = new QSpacerItem(4, 4, QSizePolicy::Minimum, QSizePolicy::Fixed);
        spacer[2] = new QSpacerItem(8, 8, QSizePolicy::Minimum, QSizePolicy::Expanding);
        verticalLayout->addItem(spacer[2]);
    
        verticalLayout->addWidget(solveButton);
        verticalLayout->addWidget(slider);
        verticalLayout->addWidget(clearButton);
        horizontalLayout->addLayout(layout, 5);
        horizontalLayout->addLayout(verticalLayout, 1);
    
        layout->addItem(spacer[0], 3, 3);
        layout->addItem(spacer[1], 7, 7);
        layout->setSpacing(0);
    
        for (int x = 0; x < 9; x++)
        {
            for (int y = 0; y < 9; y++)
            {
                grid[x + y * 9].setParent(this);
                layout->addWidget(&grid[x + y * 9], y + y / 3, x + x / 3);
                // connecting signals & slots
                for (int d = 0; d < 9; d++) // rows and columns
                {
                    connect(&grid[x + y * 9], SIGNAL(update(int)), &grid[x + d * 9], SLOT(removeOption(int)));
                    connect(&grid[x + y * 9], SIGNAL(undo(int)), &grid[x + d * 9], SLOT(addOption(int)));
                    if (&grid[x + y * 9] != &grid[d + y * 9])
                    {
                        connect(&grid[x + y * 9], SIGNAL(update(int)), &grid[d + y * 9], SLOT(removeOption(int)));
                        connect(&grid[x + y * 9], SIGNAL(undo(int)), &grid[d + y * 9], SLOT(addOption(int)));
                    }
                }
                int a = x / 3 * 3;
                int b = y / 3 * 3;
                for (int x1 = a; x1 < a + 3; x1++) // square
                {
                    for (int y1 = b; y1 < b + 3; y1++)
                    {
                        if (x1 == x || y1 == y)
                            continue;
                        connect(&grid[x + y * 9], SIGNAL(update(int)), &grid[x1 + y1 * 9], SLOT(removeOption(int)));
    
                        connect(&grid[x + y * 9], SIGNAL(undo(int)), &grid[x1 + y1 * 9], SLOT(addOption(int)));
                    }
                }
            }
        }
    }
    
    void Window::solveButtonClicked()
    {
        std::list<History> hist;
        bool backtracking = false;
        srand(time(NULL)); // random seed
        while (1)
        {
            repaint(); // draw cells again
            delay(delayTime);
            if (backtracking)
            {
                hist.back().cell->collapsedCellClicked();
                std::vector<int> validNrs;
                for (int i = 0; i < 9; i++)
                    if (!hist.back().blocked[i])
                        validNrs.push_back(i);
                if (validNrs.size() == 0)
                {
                    hist.pop_back();
                    continue;
                }
                backtracking = false;
                int rndNr = rand() % validNrs.size(); // choose a random number;
                repaint();                            // draw cells again
                delay(delayTime);
                hist.back().cell->collapse(validNrs[rndNr]); // collapse cell with chosen number;
                hist.back().blocked[validNrs[rndNr]]++;
            }
            else
            {
                std::vector<Cell *> b; // vector of cells with least entropy
                int minEtropy = 10;
                for (auto &cell : grid)
                {
                    if (cell.collapsed)
                        continue;
                    else if (cell.possibleStates < minEtropy)
                    {
                        minEtropy = cell.possibleStates;
                        b.clear();
                        b.push_back(&cell);
                    }
                    else if (cell.possibleStates == minEtropy)
                    {
                        b.push_back(&cell);
                    }
                }
                if (b.size() == 0) // if b is empty -> solved
                    return;
    
                else if (minEtropy == 0)
                {
                    // qInfo("backtracking");
                    backtracking = true;
                    continue;
                }
    
                int rndCell = rand() % b.size(); // choose a random cell
                std::vector<int> validNrs;
                for (int i = 0; i < 9; i++)
                {
                    if (!b[rndCell]->blocked[i])
                        validNrs.push_back(i);
                }
                int rndNr = rand() % validNrs.size(); // choose a random number;
                hist.push_back(History(b[rndCell], b[rndCell]->blocked, validNrs[rndNr]));
                b[rndCell]->collapse(validNrs[rndNr]); // collapse that random cell with chosen number;
            }
        }
    }
    inline void Window::delay(int millisecondsWait)
    {
        QEventLoop loop;
        QTimer t;
        t.connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
        t.start(millisecondsWait);
        loop.exec();
    }
    void Window::clearButtonClicked()
    {
        for (auto &x : grid)
        {
            if (x.collapsed)
                x.collapsedCellClicked();
        }
        return;
    }
    void Window::setValue(int s)
    {
        delayTime = s;
        return;
    }