From 1ee4d49f99e7925b9ac19aadc944007bd4320389 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Fri, 12 Jul 2013 13:45:53 +0000 Subject: Removes sidebar buttons, adds current filename to the window title, adds a Move -> Guess option to the menu bar, adds messageboxes to the Step, Guess and Validate actions. --- src/mainwindow.cc | 54 +++++++++++++++-- src/mainwindow.h | 12 ++++ src/solverwindow.cc | 165 +++++++++++++++++++++++++++------------------------- src/solverwindow.h | 32 +++++++++- src/sudokuwidget.cc | 36 ++++++++++++ src/sudokuwidget.h | 2 + 6 files changed, 216 insertions(+), 85 deletions(-) diff --git a/src/mainwindow.cc b/src/mainwindow.cc index b929aaa..4f252d3 100644 --- a/src/mainwindow.cc +++ b/src/mainwindow.cc @@ -27,17 +27,17 @@ void MainWindow::initActions() action_load = new QAction(tr("&Load..."), this); action_load->setShortcuts(QKeySequence::Open); action_load->setStatusTip(tr("Load a previously saved game")); - connect(action_load, SIGNAL(triggered()), mainwindow_solverwindow, SLOT(load())); + connect(action_load, SIGNAL(triggered()), this, SLOT(doLoad())); // Game -> Save action_save = new QAction(tr("&Save"), this); action_load->setStatusTip(tr("Save the current game")); - //TODO + connect(action_save, SIGNAL(triggered()), this, SLOT(doSave())); // Game -> Save As action_saveas = new QAction(tr("Save &As..."), this); action_load->setStatusTip(tr("Save the current game to a new file")); - connect(action_saveas, SIGNAL(triggered()), mainwindow_solverwindow, SLOT(saveas())); + connect(action_saveas, SIGNAL(triggered()), this, SLOT(doSaveAs())); // Game -> Revert action_revert = new QAction(tr("&Revert"), this); @@ -60,6 +60,11 @@ void MainWindow::initActions() action_step->setStatusTip(tr("Solve a single cell")); connect(action_step, SIGNAL(triggered()), mainwindow_solverwindow, SLOT(step())); + // Move -> Step + action_guess = new QAction(tr("Guess"), this); + action_guess->setStatusTip(tr("Solve a single cell with guessing")); + connect(action_guess, SIGNAL(triggered()), mainwindow_solverwindow, SLOT(guess())); + // Move -> Solve action_solve = new QAction(tr("Solve rules"), this); action_solve->setStatusTip(tr("Solve sudoku rules")); @@ -69,6 +74,11 @@ void MainWindow::initActions() action_search = new QAction(tr("Find solution"), this); action_search->setStatusTip(tr("Find a solution")); connect(action_search, SIGNAL(triggered()), mainwindow_solverwindow, SLOT(search())); + + // Move -> Validate + action_validate = new QAction(tr("Validate"), this); + action_validate ->setStatusTip(tr("Validate the sudoku")); + connect(action_validate, SIGNAL(triggered()), this, SLOT(doValidate())); } void MainWindow::initMenus() @@ -77,7 +87,7 @@ void MainWindow::initMenus() mainwindow_gamemenu->addAction(action_new); mainwindow_gamemenu->addAction(action_load); mainwindow_gamemenu->addSeparator(); - //mainwindow_gamemenu->addAction(action_save); + mainwindow_gamemenu->addAction(action_save); mainwindow_gamemenu->addAction(action_saveas); mainwindow_gamemenu->addAction(action_revert); mainwindow_gamemenu->addSeparator(); @@ -86,7 +96,43 @@ void MainWindow::initMenus() mainwindow_movemenu = menuBar()->addMenu(tr("&Move")); //mainwindow_movemenu->addAction(action_hint); mainwindow_movemenu->addAction(action_step); + mainwindow_movemenu->addAction(action_guess); + mainwindow_movemenu->addSeparator(); mainwindow_movemenu->addAction(action_solve); mainwindow_movemenu->addAction(action_search); + mainwindow_movemenu->addSeparator(); + mainwindow_movemenu->addAction(action_validate); +} + +void MainWindow::updateTitle() +{ + if (mainwindow_solverwindow->filename().isEmpty()) { + setWindowTitle("Sudoku"); + } else { + setWindowTitle(mainwindow_solverwindow->filename() + " - Sudoku"); + } +} + +void MainWindow::doSave() +{ + mainwindow_solverwindow->save(); + updateTitle(); } +void MainWindow::doSaveAs() +{ + mainwindow_solverwindow->saveas(); + updateTitle(); +} + +void MainWindow::doLoad() +{ + mainwindow_solverwindow->load(); + updateTitle(); +} + +void MainWindow::doValidate() +{ + mainwindow_solverwindow->validate(); +} + \ No newline at end of file diff --git a/src/mainwindow.h b/src/mainwindow.h index 2467f25..13283fe 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -22,6 +22,8 @@ private: void initMenus(); + void updateTitle(); + SolverWindow *mainwindow_solverwindow; QMenu *mainwindow_gamemenu; QMenu *mainwindow_movemenu; @@ -37,8 +39,18 @@ private: // Move menu actions QAction *action_hint; QAction *action_step; + QAction *action_guess; QAction *action_solve; QAction *action_search; + QAction *action_validate; + +private slots: + + void doSave(); + void doSaveAs(); + void doLoad(); + + void doValidate(); }; diff --git a/src/solverwindow.cc b/src/solverwindow.cc index 9947d5d..bad0791 100644 --- a/src/solverwindow.cc +++ b/src/solverwindow.cc @@ -14,6 +14,7 @@ * FIXME * On windows, this results in a rather awkward directory. * The homepath should probably be a setting. + * This should move to mainwindow * */ const QString HOMEDIR(QDir::homePath() + "/.sudoku"); @@ -21,63 +22,7 @@ const QString HOMEDIR(QDir::homePath() + "/.sudoku"); SolverWindow::SolverWindow() { QHBoxLayout *windowlayout = new QHBoxLayout(); - - - // sidebar - QVBoxLayout *sidebarlayout = new QVBoxLayout(); - - // add stretch - sidebarlayout->addStretch(1); - - // add load button - QPushButton *loadbutton = new QPushButton(tr("Load")); - sidebarlayout->addWidget(loadbutton); - connect(loadbutton, SIGNAL(clicked()), this, SLOT(load())); - - // add save button - QPushButton *savebutton = new QPushButton(tr("Save")); - sidebarlayout->addWidget(savebutton); - connect(savebutton, SIGNAL(clicked()), this, SLOT(saveas())); - - // add revert button - QPushButton *revertbutton = new QPushButton(tr("Revert")); - sidebarlayout->addWidget(revertbutton); - connect(revertbutton, SIGNAL(clicked()), this, SLOT(revert())); - // add validate button - QPushButton *validatebutton = new QPushButton(tr("Validate")); - sidebarlayout->addWidget(validatebutton); - connect(validatebutton, SIGNAL(clicked()), this, SLOT(validate())); - - // add a step button - QPushButton *stepbutton = new QPushButton(tr("Step")); - sidebarlayout->addWidget(stepbutton); - connect(stepbutton, SIGNAL(clicked()), this, SLOT(step())); - - // add stretch - sidebarlayout->addStretch(2); - - // add a solve button - QPushButton *solvebutton = new QPushButton(tr("Solve")); - sidebarlayout->addWidget(solvebutton); - connect(solvebutton, SIGNAL(clicked()), this, SLOT(solve())); - - // add a search button - QPushButton *searchbutton = new QPushButton(tr("Search")); - sidebarlayout->addWidget(searchbutton); - connect(searchbutton, SIGNAL(clicked()), this, SLOT(search())); - - // add clear button - QPushButton *clearbutton = new QPushButton(tr("Clear")); - sidebarlayout->addWidget(clearbutton); - connect(clearbutton, SIGNAL(clicked()), this, SLOT(clear())); - - // add stretch - sidebarlayout->addStretch(1); - - // add sidebar layout - windowlayout->addLayout(sidebarlayout); - // sudoku widget solverwindow_sudokuwidget = new SudokuWidget(); windowlayout->addWidget(solverwindow_sudokuwidget, 1); @@ -86,20 +31,17 @@ SolverWindow::SolverWindow() setLayout(windowlayout); // create home directory + // FIXME this should move to mainwindow QDir directory; if (!directory.exists(HOMEDIR)) { directory.mkdir(HOMEDIR); } } -void SolverWindow::load() +void SolverWindow::loadFromFile(const QString & filename) { - QString filename = QFileDialog::getOpenFileName(this, tr("Open..."), HOMEDIR, "Sudoku (*.sudoku)"); - if (filename.isEmpty()) { - return; - } - QFile file(filename); + if (!file.open(QFile::ReadOnly | QFile::Text)) { QMessageBox::warning(this, tr("Open file"), tr("Could not open file %1:\n%2.") @@ -125,22 +67,14 @@ void SolverWindow::load() file.close(); + solverwindow_filename = filename; + QApplication::restoreOverrideCursor(); } -void SolverWindow::revert() -{ - // FIXME this should actually re-load the savegame - solverwindow_sudokuwidget->set_values(solverwindow_revertstate); -} -void SolverWindow::saveas() +void SolverWindow::saveToFile(const QString & filename) { - QString filename = QFileDialog::getSaveFileName(this, tr("Save as..."), HOMEDIR, "Sudoku (*.sudoku)"); - if (filename.isEmpty()) { - return; - } - QFile file(filename); if (!file.open(QFile::WriteOnly | QFile::Text)) { QMessageBox::warning(this, tr("Save file"), @@ -149,7 +83,7 @@ void SolverWindow::saveas() .arg(file.errorString())); return; } - + QApplication::setOverrideCursor(Qt::WaitCursor); QTextStream textstream(&file); @@ -176,8 +110,48 @@ void SolverWindow::saveas() file.close(); + solverwindow_filename = filename; + QApplication::restoreOverrideCursor(); +} + +void SolverWindow::load() +{ + QString filename = QFileDialog::getOpenFileName(this, tr("Open..."), HOMEDIR, "Sudoku (*.sudoku)"); + + if (!filename.isEmpty()) { + loadFromFile(filename); + } + + return; +} + +void SolverWindow::revert() +{ + if (!solverwindow_filename.isEmpty()) { + loadFromFile(solverwindow_filename); + } +} + +void SolverWindow::save() +{ + if (solverwindow_filename.isEmpty()) { + saveas(); + } else { + saveToFile(solverwindow_filename); + } + return; +} + +void SolverWindow::saveas() +{ + QString filename = QFileDialog::getSaveFileName(this, tr("Save as..."), HOMEDIR, "Sudoku (*.sudoku)"); + if (!filename.isEmpty()) { + solverwindow_filename = filename; + saveToFile(solverwindow_filename); + } + return; } @@ -195,7 +169,37 @@ void SolverWindow::step() Sudoku solution(sudoku); int solved = solution.solve_rules(); if (solved == 0) { - qDebug() << "no solveable cells left!"; + QMessageBox::warning(this, tr("Step"), tr("No cells to solve found")); + return; + } + + // compare sudoku and solution values + int index_start = (int) random() % 81; + int index_current = index_start; + do { + int column = index_current % 9; + int row = (index_current - column) / 9; + if ((sudoku.cell(row,column).value() == 0) && (solution.cell(row,column).value() != 0)) { + sudoku.cell(row,column).set_value(solution.cell(row, column).value()); + solverwindow_sudokuwidget->set_values(sudoku); + return; + } + + index_current = (index_current + 1) % 81; + + } while (index_current != index_start); + +} + +void SolverWindow::guess() +{ + Sudoku sudoku; + solverwindow_sudokuwidget->get_values(sudoku); + + Sudoku solution(sudoku); + int solved = solution.solve_search(); + if (solved == 0) { + QMessageBox::warning(this, tr("Guess"), tr("No cells to solve found")); return; } @@ -219,6 +223,7 @@ void SolverWindow::step() void SolverWindow::solve() { + // TODO messagebox, detect invalid and solved states Sudoku sudoku; solverwindow_sudokuwidget->get_values(sudoku); int solved = sudoku.solve_rules(); @@ -229,6 +234,7 @@ void SolverWindow::solve() void SolverWindow::search() { + // TODO messagebox, detect invalid and solved states Sudoku sudoku; solverwindow_sudokuwidget->get_values(sudoku); int iterations = sudoku.solve_search(); @@ -244,7 +250,7 @@ void SolverWindow::step_constraints() solverwindow_sudokuwidget->get_values(sudoku); int solved = sudoku.solve_constraints(); solverwindow_sudokuwidget->set_values(sudoku); - qDebug() << solved << " cells solved"; + // qDebug() << solved << " cells solved"; } void SolverWindow::step_coverage() @@ -253,7 +259,7 @@ void SolverWindow::step_coverage() solverwindow_sudokuwidget->get_values(sudoku); int solved = sudoku.solve_coverage(); solverwindow_sudokuwidget->set_values(sudoku); - qDebug() << solved << " cells solved"; + // qDebug() << solved << " cells solved"; } void SolverWindow::validate() @@ -261,11 +267,10 @@ void SolverWindow::validate() Sudoku sudoku; solverwindow_sudokuwidget->get_values(sudoku); if (sudoku.validate()) { - qDebug() << "sudoku is valid"; + QMessageBox::information(this, tr("Validate"), tr("Sudoku is valid.")); } else { - qDebug() << "sudoku is not valid"; + QMessageBox::warning(this, tr("Validate"), tr("Sudoku is not valid!")); } solverwindow_sudokuwidget->set_values(sudoku); - qDebug() << "sudoku validated"; } diff --git a/src/solverwindow.h b/src/solverwindow.h index 17cb55c..4520c9e 100644 --- a/src/solverwindow.h +++ b/src/solverwindow.h @@ -14,23 +14,53 @@ class SolverWindow : public QWidget public: SolverWindow(); + + inline const QString & filename() + { + return solverwindow_filename; + } public slots: void load(); + void save(); void saveas(); void revert(); + + /** + * @brief try to find a solution by using the rules only + * */ void solve(); + + /** + * @brief try to find a solution by guessing where required + * */ void search(); + + /** + * @brief try to solve a single cell by using the rules only + * */ void step(); + void step_constraints(); - void step_coverage(); + void step_coverage(); + + /** + * @brief try to solve a single cell by guessing where required + * */ + void guess(); + void clear(); + void validate(); private: + void saveToFile(const QString & filename); + void loadFromFile(const QString & filename); + SudokuWidget *solverwindow_sudokuwidget; Sudoku solverwindow_revertstate; + QString solverwindow_filename; }; #endif // __INCLUDED_SUDOKUSOLVER_SOLVERWINDOW__ \ No newline at end of file diff --git a/src/sudokuwidget.cc b/src/sudokuwidget.cc index 23052ef..75fc3be 100644 --- a/src/sudokuwidget.cc +++ b/src/sudokuwidget.cc @@ -13,6 +13,42 @@ SudokuWidget::SudokuWidget() sudokuwidget_value[row][column] = new QLineEdit(this); sudokuwidget_value[row][column]->setFrame(false); sudokuwidget_value[row][column]->setAlignment(Qt::AlignCenter); + + connect(sudokuwidget_value[row][column], SIGNAL(textEdited(const QString &)), this, SLOT(verify(const QString &))); + } + } +} + +void SudokuWidget::verify(const QString & text) +{ + Sudoku values; + for (int row = 0; row < 9; row++) { + for (int column = 0; column < 9 ; column++) { + bool ok; + QString str(sudokuwidget_value[row][column]->text()); + int i = str.toInt(&ok); + if (ok && (i > 0) && (i <= 9)) { + values.cell(row, column).set_value(i); + } else { + values.cell(row, column).set_value(0); + } + } + } + + values.validate(); + + for (int row = 0; row < 9; row++) { + for (int column = 0; column < 9 ; column++) { + QPalette child_palette(palette()); + int i = values.cell(row, column).value(); + if ( (i > 0) && (i <= 9) ) { + // set background color depending on the validity of the cell value + if (!values.cell(row, column).valid()) { + // FIXME colors should be configurable + child_palette.setColor(QPalette::Base, QColor(255, 0, 0)); + } + } + sudokuwidget_value[row][column]->setPalette(child_palette); } } } diff --git a/src/sudokuwidget.h b/src/sudokuwidget.h index ce1cffd..e4140a0 100644 --- a/src/sudokuwidget.h +++ b/src/sudokuwidget.h @@ -45,6 +45,8 @@ protected: private: QLineEdit * sudokuwidget_value[9][9]; +private slots: + void verify(const QString & text); }; #endif // __INCLUDED_SUDOKUSOLVER_SUDOKUWIDGET__ \ No newline at end of file -- cgit v1.2.3