diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e85deb023e3223c52d5d5425ef9a368bfcd01f43 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.5) + +project(sodoku_solver VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED) + +set(PROJECT_SOURCES + main.cpp + window.h + window.cpp + cell.h + cell.cpp +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(sodoku_solver + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET sodoku_solver APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(sodoku_solver SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(sodoku_solver + ${PROJECT_SOURCES} + ) + endif() +endif() + +target_link_libraries(sodoku_solver PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) + +set_target_properties(sodoku_solver PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(sodoku_solver) +endif() diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..40c0c8415b2ef77e4d25c59111cc5acd985e46ed --- /dev/null +++ b/Makefile @@ -0,0 +1,276 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.22 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/sls/Documents/dev/soduoku_solver + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/sls/Documents/dev/soduoku_solver + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/sls/Documents/dev/soduoku_solver/CMakeFiles /home/sls/Documents/dev/soduoku_solver//CMakeFiles/progress.marks + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /home/sls/Documents/dev/soduoku_solver/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named sodoku_solver + +# Build rule for target. +sodoku_solver: cmake_check_build_system + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 sodoku_solver +.PHONY : sodoku_solver + +# fast build rule for target. +sodoku_solver/fast: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/build +.PHONY : sodoku_solver/fast + +#============================================================================= +# Target rules for targets named sodoku_solver_autogen + +# Build rule for target. +sodoku_solver_autogen: cmake_check_build_system + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 sodoku_solver_autogen +.PHONY : sodoku_solver_autogen + +# fast build rule for target. +sodoku_solver_autogen/fast: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver_autogen.dir/build.make CMakeFiles/sodoku_solver_autogen.dir/build +.PHONY : sodoku_solver_autogen/fast + +cell.o: cell.cpp.o +.PHONY : cell.o + +# target to build an object file +cell.cpp.o: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/cell.cpp.o +.PHONY : cell.cpp.o + +cell.i: cell.cpp.i +.PHONY : cell.i + +# target to preprocess a source file +cell.cpp.i: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/cell.cpp.i +.PHONY : cell.cpp.i + +cell.s: cell.cpp.s +.PHONY : cell.s + +# target to generate assembly for a file +cell.cpp.s: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/cell.cpp.s +.PHONY : cell.cpp.s + +main.o: main.cpp.o +.PHONY : main.o + +# target to build an object file +main.cpp.o: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/main.cpp.o +.PHONY : main.cpp.o + +main.i: main.cpp.i +.PHONY : main.i + +# target to preprocess a source file +main.cpp.i: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/main.cpp.i +.PHONY : main.cpp.i + +main.s: main.cpp.s +.PHONY : main.s + +# target to generate assembly for a file +main.cpp.s: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/main.cpp.s +.PHONY : main.cpp.s + +sodoku_solver_autogen/mocs_compilation.o: sodoku_solver_autogen/mocs_compilation.cpp.o +.PHONY : sodoku_solver_autogen/mocs_compilation.o + +# target to build an object file +sodoku_solver_autogen/mocs_compilation.cpp.o: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/sodoku_solver_autogen/mocs_compilation.cpp.o +.PHONY : sodoku_solver_autogen/mocs_compilation.cpp.o + +sodoku_solver_autogen/mocs_compilation.i: sodoku_solver_autogen/mocs_compilation.cpp.i +.PHONY : sodoku_solver_autogen/mocs_compilation.i + +# target to preprocess a source file +sodoku_solver_autogen/mocs_compilation.cpp.i: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/sodoku_solver_autogen/mocs_compilation.cpp.i +.PHONY : sodoku_solver_autogen/mocs_compilation.cpp.i + +sodoku_solver_autogen/mocs_compilation.s: sodoku_solver_autogen/mocs_compilation.cpp.s +.PHONY : sodoku_solver_autogen/mocs_compilation.s + +# target to generate assembly for a file +sodoku_solver_autogen/mocs_compilation.cpp.s: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/sodoku_solver_autogen/mocs_compilation.cpp.s +.PHONY : sodoku_solver_autogen/mocs_compilation.cpp.s + +window.o: window.cpp.o +.PHONY : window.o + +# target to build an object file +window.cpp.o: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/window.cpp.o +.PHONY : window.cpp.o + +window.i: window.cpp.i +.PHONY : window.i + +# target to preprocess a source file +window.cpp.i: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/window.cpp.i +.PHONY : window.cpp.i + +window.s: window.cpp.s +.PHONY : window.s + +# target to generate assembly for a file +window.cpp.s: + $(MAKE) $(MAKESILENT) -f CMakeFiles/sodoku_solver.dir/build.make CMakeFiles/sodoku_solver.dir/window.cpp.s +.PHONY : window.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... rebuild_cache" + @echo "... sodoku_solver_autogen" + @echo "... sodoku_solver" + @echo "... cell.o" + @echo "... cell.i" + @echo "... cell.s" + @echo "... main.o" + @echo "... main.i" + @echo "... main.s" + @echo "... sodoku_solver_autogen/mocs_compilation.o" + @echo "... sodoku_solver_autogen/mocs_compilation.i" + @echo "... sodoku_solver_autogen/mocs_compilation.s" + @echo "... window.o" + @echo "... window.i" + @echo "... window.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/cell.cpp b/cell.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d448ede2b5c9460d3c3ac82e4300706552108acb --- /dev/null +++ b/cell.cpp @@ -0,0 +1,77 @@ +#include "cell.h" +#include <QPushButton> +#include <QDebug> +#include <QSignalMapper> + +Cell::Cell(QWidget *parent) : QWidget(parent) +{ + // Set size of the window + // Create and position the button + setAutoFillBackground(true); + setStyleSheet("background-color:gray;"); + setFixedSize(100, 100); + float w = width() / 3.0; + float h = height() / 3.0; + QSignalMapper *mapper = new QSignalMapper(this); + connect(mapper, SIGNAL(mapped(int)), this, SLOT(collapse(int))); + for (char i = 0; i < 9; i++) + { + m_states[i] = new QPushButton(QString::number(i + 1), this); + m_states[i]->setGeometry(i % 3 * w, i / 3 * h, w, h); + m_states[i]->setStyleSheet("border:none"); + connect(m_states[i], SIGNAL(clicked()), mapper, SLOT(map())); + mapper->setMapping(m_states[i], i); + m_blocked[i] = 0; + } + m_number = new QPushButton(this); + m_number->setFixedSize(100, 100); + m_number->setStyleSheet("font-size:44px"); + m_number->hide(); + + connect(m_number,SIGNAL(clicked()),this,SLOT(un())); +} + +Cell::Cell(const Cell &old_obj){ + possibleStates = old_obj.possibleStates; + collapsed = old_obj.collapsed; + index = old_obj.index; + + m_number = new QPushButton(old_obj.m_number); + //m_states = old_obj.m_states; + qInfo("aaa"); +} +void Cell::collapse(int x) +{ + collapsed = true; + m_number->show(); + m_number->setText(QString::number(x + 1)); + emit(update(x)); +} +void Cell::removeOption(int x) +{ + // states[x]->hide(); + if (m_states[x]->isEnabled()) + { + m_states[x]->setDisabled(true); + possibleStates--; + index.erase(std::find(index.begin(), index.end(), x)); + } + m_blocked[x] ++; +} + +void Cell::addOption(int x) +{ + m_blocked[x] --; + //if (!m_states[x]->isEnabled()) + if (m_blocked[x]<1) + { + m_states[x]->setDisabled(false); + possibleStates++; + index.push_back(x); + } +} +void Cell::un(void){ + collapsed = false; + m_number->hide(); + emit(undo(m_number->text().toInt()-1)); +} \ No newline at end of file diff --git a/cell.h b/cell.h new file mode 100644 index 0000000000000000000000000000000000000000..3ca68e39781f4b8974d24627722a3b3a6c528bf2 --- /dev/null +++ b/cell.h @@ -0,0 +1,32 @@ +#ifndef CELL_H +#define CELL_H + +#include <QWidget> + +class QPushButton; +class Cell : public QWidget +{ + Q_OBJECT +public: + explicit Cell(QWidget *parent = 0); + Cell (const Cell &old_obj); + int possibleStates=9; + bool collapsed = false; + std::vector<int> index={0,1,2,3,4,5,6,7,8}; + +private: + QPushButton *m_states[9]; + QPushButton *m_number; + std::array<int,9> m_blocked; + +signals: + void update(int x); + void undo(int x); +public slots: + void addOption(int x); + void removeOption(int x); + void collapse(int x); + void un(void); +}; + +#endif // CELL_H \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..139dd85bf16db9c3f40c617c3829c001d6be5017 --- /dev/null +++ b/main.cpp @@ -0,0 +1,10 @@ +#include "window.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Window w; + w.show(); + return a.exec(); +} diff --git a/window.cpp b/window.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8d0b2270e322f4ba99dcc8212bbb167e8e94381 --- /dev/null +++ b/window.cpp @@ -0,0 +1,126 @@ +#include "window.h" +#include <QApplication> +#include <QStandardPaths> +#include <QDebug> +#include <QThread> +#include <QProgressBar> +#include <QSlider> + +Window::Window(QWidget *parent) + : QWidget{parent} +{ + setFixedWidth(1600); + m_button = new QPushButton("solve", this); + connect(m_button, SIGNAL(clicked()), this, SLOT(solveButtonClicked())); + m_button->setGeometry(1200, height() - 30, width() - 1200, 30); + m_slider = new QSlider(this); + m_slider->setRange(0,1000); + m_slider->setOrientation(Qt::Horizontal); + m_slider->setValue(m_delay); + m_slider->setGeometry(1200, height() - 60, width() - 1200, 30); + connect(m_slider,SIGNAL(valueChanged(int)),this,SLOT(setValue(int))); + + int dx = 0; + int dy = 0; + for (int x = 0; x < 9; x++) + { + for (int y = 0; y < 9; y++) + { + if (x == 3) + dx = 4; + if (x == 6) + dx = 8; + if (y < 3) + dy = 0; + if (y >= 3) + dy = 4; + if (y >= 6) + dy = 8; + m_cell[x+y*9].setParent(this); + m_cell[x+y*9].setGeometry(x * 100 + dx, y * 100 + dy, 100, 100); + /* code */ + } + } + // init signals + for (int x = 0; x < 9; x++) + { + for (int y = 0; y < 9; y++) + { + for (int d = 0; d < 9; d++) //rows and columns + { + connect(&m_cell[x+y*9], SIGNAL(update(int)), &m_cell[x+d*9], SLOT(removeOption(int))); + connect(&m_cell[x+y*9], SIGNAL(update(int)), &m_cell[d+y*9], SLOT(removeOption(int))); + + connect(&m_cell[x+y*9], SIGNAL(undo(int)), &m_cell[x+d*9], SLOT(addOption(int))); + connect(&m_cell[x+y*9], SIGNAL(undo(int)), &m_cell[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++) + { + connect(&m_cell[x+y*9], SIGNAL(update(int)), &m_cell[x1+y1*9], SLOT(removeOption(int))); + + connect(&m_cell[x+y*9], SIGNAL(undo(int)), &m_cell[x1+y1*9], SLOT(addOption(int))); + } + } + } + } +} + +void Window::solveButtonClicked() +{ + // std::array<Cell,81> start = m_cell; + std::list<Cell*> hist; + srand(time(NULL)); + while (1) + { + std::vector<Cell *> b; //vector of cells with least entropy + int minEtropy = 10; + for (int x = 0; x < 9; x++) //loop through all cells and fill list b --> this could be optimzed + { + for (int y = 0; y < 9; y++) + { + if (m_cell[x+y*9].collapsed) + continue; + else if (m_cell[x+y*9].possibleStates < minEtropy) + { + minEtropy = m_cell[x+y*9].possibleStates; + b.clear(); + b.push_back(&m_cell[x+y*9]); + } + else if (m_cell[x+y*9].possibleStates == minEtropy) + { + b.push_back(&m_cell[x+y*9]); + } + } + } + if (b.size() == 0) //if b is empty -> solved + { + qInfo("Solved!!"); + return; + } + else if(minEtropy ==0){ + while (hist.size()>0) + { + hist.back()->un(); + hist.pop_back(); + } + return; + //solveButtonClicked(); + } + int choiceCell = rand() % b.size(); //choose a random cell + int choiceNr = rand() % b[choiceCell]->index.size(); //choose a random number; + b[choiceCell]->collapse(b[choiceCell]->index[choiceNr]); //collapse that random cell with chosen number; + hist.push_back(b[choiceCell]); + repaint(); //draw cells again + QThread::msleep(m_delay); + } + // qInfo("%d---:)"); +} + +void Window::setValue(int s){ + m_delay = s; + return; +} \ No newline at end of file diff --git a/window.h b/window.h new file mode 100644 index 0000000000000000000000000000000000000000..3127c7e2675b3575f488d648501efce57c402e64 --- /dev/null +++ b/window.h @@ -0,0 +1,29 @@ +#ifndef WINDOW_H +#define WINDOW_H + +#include <QWidget> +#include <QPushButton> +#include <QProgressBar> +#include <QSlider> +#include "cell.h" +class Window : public QWidget +{ + Q_OBJECT +public: + explicit Window(QWidget *parent = nullptr); +private: + QPushButton *m_buttonQuit; + QPushButton *m_button; + QPushButton *grid[9][9]; + QProgressBar *m_progressBar; + QSlider *m_slider; + std::array<Cell,81> m_cell; + int m_delay =300; +signals: + void counterReached(); +private slots: + void setValue(int s); + void solveButtonClicked(); +}; + +#endif // WINDOW_H