├── .gitignore ├── CMakeLists.txt ├── COPYING ├── CREDITS ├── ChangeLog ├── INSTALL ├── README ├── cmake ├── AddVersionCompileDefinition.cmake ├── BundleResources.cmake └── TranslateMetainfo.cmake ├── doc ├── Doxyfile └── simsu.6 ├── icons ├── hicolor │ ├── 1024x1024 │ │ └── apps │ │ │ └── simsu.png │ ├── 128x128 │ │ └── apps │ │ │ └── simsu.png │ ├── 16x16 │ │ └── apps │ │ │ └── simsu.png │ ├── 22x22 │ │ └── apps │ │ │ └── simsu.png │ ├── 24x24 │ │ └── apps │ │ │ └── simsu.png │ ├── 256x256 │ │ └── apps │ │ │ └── simsu.png │ ├── 32x32 │ │ └── apps │ │ │ └── simsu.png │ ├── 48x48 │ │ └── apps │ │ │ └── simsu.png │ ├── 512x512 │ │ └── apps │ │ │ └── simsu.png │ ├── 64x64 │ │ └── apps │ │ │ └── simsu.png │ └── scalable │ │ └── apps │ │ └── simsu.svg ├── highlight.png ├── highlight@2x.png ├── icon.qrc ├── images.qrc ├── pen.png ├── pen@2x.png ├── pencil.png ├── pencil@2x.png ├── po │ ├── LINGUAS │ ├── bg.po │ ├── cs.po │ ├── de.po │ ├── description.pot │ ├── el.po │ ├── es.po │ ├── fr.po │ ├── he.po │ ├── it.po │ ├── lt.po │ ├── ms.po │ ├── nl.po │ ├── pl.po │ ├── pt.po │ ├── ro.po │ ├── ru.po │ ├── te.po │ ├── zh.po │ └── zh_TW.po ├── simsu.appdata.xml.in ├── simsu.desktop.in ├── simsu.icns └── simsu.ico ├── mac ├── Info.plist.in └── background.tiff ├── mac_deploy.sh ├── src ├── board.cpp ├── board.h ├── cell.cpp ├── cell.h ├── frame.cpp ├── frame.h ├── locale_dialog.cpp ├── locale_dialog.h ├── main.cpp ├── move.cpp ├── move.h ├── new_game_page.cpp ├── new_game_page.h ├── pattern.h ├── puzzle.cpp ├── puzzle.h ├── solver_dlx.cpp ├── solver_dlx.h ├── solver_logic.cpp ├── solver_logic.h ├── square.cpp ├── square.h ├── window.cpp └── window.h ├── symmetry ├── anti_diagonal.png ├── anti_diagonal@2x.png ├── diagonal.png ├── diagonal@2x.png ├── diagonal_anti_diagonal.png ├── diagonal_anti_diagonal@2x.png ├── dihedral.png ├── dihedral@2x.png ├── horizontal.png ├── horizontal@2x.png ├── horizontal_vertical.png ├── horizontal_vertical@2x.png ├── none.png ├── none@2x.png ├── random.png ├── random@2x.png ├── rotational_180.png ├── rotational_180@2x.png ├── rotational_full.png ├── rotational_full@2x.png ├── symmetry.qrc ├── vertical.png └── vertical@2x.png ├── translations ├── simsu_bg.ts ├── simsu_ca.ts ├── simsu_cs.ts ├── simsu_de.ts ├── simsu_el.ts ├── simsu_en.ts ├── simsu_es.ts ├── simsu_es_CL.ts ├── simsu_fr.ts ├── simsu_he.ts ├── simsu_hu.ts ├── simsu_it.ts ├── simsu_lt.ts ├── simsu_ms.ts ├── simsu_nl.ts ├── simsu_pl.ts ├── simsu_pt.ts ├── simsu_ro.ts ├── simsu_ru.ts ├── simsu_te.ts ├── simsu_tr.ts ├── simsu_uk.ts ├── simsu_zh.ts └── simsu_zh_TW.ts ├── windows ├── installer.nsi └── removeprevious.nsh └── windows_deploy.bat /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | build 3 | simsu 4 | *.qm 5 | *~ 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021-2025 Graeme Gott 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | cmake_minimum_required(VERSION 3.16) 6 | 7 | # Configure project 8 | project(simsu VERSION 1.4.6 LANGUAGES CXX) 9 | 10 | set(project_copyright "2009-2025 Graeme Gott") 11 | 12 | set(CMAKE_CXX_STANDARD 17) 13 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 14 | 15 | set(CMAKE_AUTOMOC ON) 16 | set(CMAKE_AUTORCC ON) 17 | 18 | find_package(Qt6 REQUIRED COMPONENTS Concurrent Core Gui LinguistTools PrintSupport Widgets) 19 | include(GNUInstallDirs) 20 | 21 | add_compile_definitions( 22 | QT_NO_KEYWORDS 23 | $<$:QT_STRICT_ITERATORS> 24 | $<$:QT_NO_NARROWING_CONVERSIONS_IN_CONNECT> 25 | $<$:QT_DISABLE_DEPRECATED_BEFORE=0x060900> 26 | ) 27 | 28 | # Version number 29 | include(cmake/AddVersionCompileDefinition.cmake) 30 | add_version_compile_definition(src/main.cpp VERSIONSTR) 31 | 32 | # Create program 33 | qt_add_executable(simsu 34 | # Headers 35 | src/board.h 36 | src/cell.h 37 | src/frame.h 38 | src/locale_dialog.h 39 | src/move.h 40 | src/new_game_page.h 41 | src/pattern.h 42 | src/puzzle.h 43 | src/solver_dlx.h 44 | src/solver_logic.h 45 | src/square.h 46 | src/window.h 47 | # Sources 48 | src/board.cpp 49 | src/cell.cpp 50 | src/frame.cpp 51 | src/locale_dialog.cpp 52 | src/move.cpp 53 | src/main.cpp 54 | src/new_game_page.cpp 55 | src/puzzle.cpp 56 | src/solver_dlx.cpp 57 | src/solver_logic.cpp 58 | src/square.cpp 59 | src/window.cpp 60 | # Resources 61 | icons/images.qrc 62 | symmetry/symmetry.qrc 63 | ${translations_QM} 64 | ) 65 | 66 | target_link_libraries(simsu PRIVATE 67 | Qt6::Concurrent 68 | Qt6::Core 69 | Qt6::Gui 70 | Qt6::PrintSupport 71 | Qt6::Widgets 72 | ) 73 | 74 | # Create translations 75 | file(GLOB translations_SRCS translations/*.ts) 76 | qt_add_translations(simsu 77 | TS_FILES ${translations_SRCS} 78 | QM_FILES_OUTPUT_VARIABLE translations_QM 79 | LUPDATE_OPTIONS -no-obsolete -locations none 80 | ) 81 | 82 | # Optimize build 83 | option(ENABLE_LINK_TIME_OPTIMIZATION "Enable link time optimization" OFF) 84 | if(ENABLE_LINK_TIME_OPTIMIZATION) 85 | include(CheckIPOSupported) 86 | check_ipo_supported(RESULT result) 87 | if(result) 88 | set_target_properties(simsu PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) 89 | endif() 90 | endif() 91 | 92 | option(ENABLE_STRIP "Enable automatic stripping of builds" OFF) 93 | if(ENABLE_STRIP) 94 | add_custom_command(TARGET simsu 95 | POST_BUILD 96 | COMMAND ${CMAKE_STRIP} $ 97 | ) 98 | endif() 99 | 100 | # Install 101 | if(APPLE) 102 | set(datadir "../Resources") 103 | 104 | set_target_properties(simsu PROPERTIES 105 | OUTPUT_NAME Simsu 106 | MACOSX_BUNDLE TRUE 107 | MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/mac/Info.plist.in 108 | ) 109 | 110 | include(cmake/BundleResources.cmake) 111 | bundle_data(simsu ${CMAKE_SOURCE_DIR}/icons/simsu.icns Resources) 112 | bundle_translations(simsu "${translations_QM}") 113 | elseif(WIN32) 114 | set(datadir ".") 115 | 116 | # Use Qt6 macro until CMake provides something 117 | # https://bugreports.qt.io/browse/QTBUG-87618 118 | set_target_properties(simsu PROPERTIES 119 | OUTPUT_NAME Simsu 120 | WIN32_EXECUTABLE TRUE 121 | QT_TARGET_VERSION "${PROJECT_VERSION}" 122 | QT_TARGET_COMPANY_NAME "Graeme Gott" 123 | QT_TARGET_DESCRIPTION "Sudoku game" 124 | QT_TARGET_COPYRIGHT "\\xA9 ${project_copyright}" 125 | QT_TARGET_PRODUCT_NAME "Simsu" 126 | QT_TARGET_RC_ICONS ${CMAKE_SOURCE_DIR}/icons/simsu.ico 127 | ) 128 | _qt_internal_generate_win32_rc_file(simsu) 129 | else() 130 | file(RELATIVE_PATH datadir ${CMAKE_INSTALL_FULL_BINDIR} ${CMAKE_INSTALL_FULL_DATADIR}/simsu) 131 | 132 | target_sources(simsu PRIVATE icons/icon.qrc) 133 | 134 | install(TARGETS simsu RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 135 | install(FILES ${translations_QM} DESTINATION ${CMAKE_INSTALL_DATADIR}/simsu/translations) 136 | install(FILES doc/simsu.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6 COMPONENT doc) 137 | install(DIRECTORY icons/hicolor DESTINATION ${CMAKE_INSTALL_DATADIR}/icons) 138 | 139 | include(cmake/TranslateMetainfo.cmake) 140 | process_and_install_metainfo(PO_DIR ${CMAKE_SOURCE_DIR}/icons/po) 141 | endif() 142 | 143 | set_property(SOURCE src/main.cpp APPEND PROPERTY COMPILE_DEFINITIONS SIMSU_DATADIR="${datadir}") 144 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Developers 2 | ---------- 3 | * Graeme Gott 4 | 5 | 6 | Translations 7 | ------------ 8 | Bulgarian: 9 | * Emilia 10 | 11 | Czech: 12 | * Pavel Fric 13 | 14 | French: 15 | * Guillaume Gay 16 | 17 | German: 18 | * leonidus 19 | 20 | Greek: 21 | * Γιάννης Ανθυμίδης 22 | 23 | Hungarian: 24 | * Tóth Attila 25 | 26 | Lithuanian: 27 | * Moo 28 | 29 | Malay: 30 | * abuyop 31 | 32 | Polish: 33 | * Michał Trzebiatowski 34 | 35 | Romanian: 36 | * Jaff (Oprea Nicolae) 37 | 38 | Russian: 39 | * Alexander Vorobyev 40 | 41 | Spanish: 42 | * Edgar Carballo 43 | 44 | Turkish: 45 | * Yusuf Kayan 46 | 47 | 48 | Libraries 49 | --------- 50 | * Qt, http://www.qt.io/ 51 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 1.4.6 2 | ----- 3 | * FIXED: Compile error due to missing header 4 | * Translation updates: French 5 | 6 | 1.4.5 7 | ----- 8 | * Improved code for building translations. 9 | 10 | 1.4.4 11 | ----- 12 | * Improved deployment. 13 | * FIXED: Very wide window when played for first time. 14 | * Translation updates: Portuguese. 15 | 16 | 1.4.3 17 | ----- 18 | * Replaced deprecated code. 19 | * Translation updates: Portuguese. 20 | 21 | 1.4.2 22 | ----- 23 | * Added portable mode. 24 | * Improved Linux deployment. 25 | * Replaced deprecated code. 26 | 27 | 1.4.1 28 | ----- 29 | * Switched to Qt 6. 30 | * Translation updates: Dutch, Telugu. 31 | 32 | 1.4.0 33 | ----- 34 | * Added difficulty ratings. 35 | * Added getting hints. 36 | * Added optional automatic pencil marks. 37 | * Added playing puzzles entered by player. 38 | * Added printing puzzles. 39 | * Added restarting puzzles. 40 | * Added support for Qt 6. 41 | * Improved new game interface. 42 | * Improved window spacing. 43 | * Refactored code. 44 | * Removed XPM icon. 45 | * Translation updates: Bulgarian, Lithuanian, Romanian, Russian, Telugu. 46 | 47 | 1.3.9 48 | ----- 49 | * FIXED: Did not load locales with underscores. 50 | * Improved Windows deployment. 51 | * Replaced deprecated code. 52 | 53 | 1.3.8 54 | ----- 55 | * FIXED: Window icon didn't work in Wayland. 56 | * Improved loading locales. 57 | * Improved Windows deployment. 58 | * Replaced deprecated code. 59 | 60 | 1.3.7 61 | ----- 62 | * FIXED: Automatic high DPI support. 63 | 64 | 1.3.6 65 | ----- 66 | * Replaced deprecated code. 67 | * Extra warnings only shown in debug build. 68 | * Improved Linux deployment. 69 | * Improved macOS deployment. 70 | * Improved Windows deployment. 71 | * Translation updates: Chinese, Chinese (Taiwan), Italian, Portuguese. 72 | 73 | 1.3.5 74 | ----- 75 | * FIXED: Could not compile with Qt 5.10. 76 | 77 | 1.3.4 78 | ----- 79 | * FIXED: Did not always install translations in Linux. 80 | * Translation updates: Chinese (Taiwan). 81 | 82 | 1.3.3 83 | ----- 84 | * Generate binary translations at build time. 85 | * FIXED: Was not properly loading Qt translations. 86 | * FIXED: Compiler warned about signed interger overflow. 87 | * Translation updates: Dutch, Lithuanian. 88 | 89 | 1.3.2 90 | ----- 91 | * FIXED: Switching keys was slow. 92 | * FIXED: Moving focus betweens cells was slow. 93 | * FIXED: Success message was not high DPI. 94 | * Translation updates: Bulgarian, Catalan, German, Greek, Polish, 95 | Portuguese, Spanish. 96 | 97 | 1.3.1 98 | ----- 99 | * FIXED: Application layout did not respect RTL languages. 100 | * FIXED: All new games used the same seed in Windows. 101 | * Translation updates: Lithuanian. 102 | 103 | 1.3.0 104 | ----- 105 | * Added support for high DPI displays. 106 | * Switched to C++11 random classes. 107 | * Removed support for Qt 4. 108 | * Translation updates: Bulgarian, Czech, German, Greek, French, Lithuanian, 109 | Malay, Polish, Romanian, Spanish (Chile), Turkish. 110 | 111 | 1.2.3 112 | ----- 113 | * Added support for Qt 5. 114 | * Translation updates: Hungarian, Romanian. 115 | 116 | 1.2.2 117 | ----- 118 | * Highlights text when all cells are found 119 | * Highlights column and row of current cell 120 | * New program icon 121 | * Translation updates: Catalan, French, Greek, Russian, Spanish, 122 | Spanish (Chile), Ukranian. 123 | 124 | 1.2.1 125 | ----- 126 | * Translation updates: Czech. 127 | 128 | 1.2.0 129 | ----- 130 | * Added multiple types of symmetry. 131 | * Added an easier solving algorithm. 132 | * Added a widescreen layout. 133 | 134 | 1.1.0 135 | ----- 136 | * Added support for undo and redo. 137 | * Added support for highlighting current number. 138 | * Added number entry buttons. 139 | * Added selectable givens. 140 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | Open a terminal and browse into the extracted folder. 5 | 6 | Linux: 7 | 1. `cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/usr' to create a location 8 | for the build and then configure the program. There are more options 9 | you can pass to CMake, see below for details. 10 | 11 | 2. `cmake --build build' to compile the program. 12 | 13 | 3. `cmake --install build' to install the program. This has to be done 14 | with root privileges if installing to system directories, but the 15 | rest of the build should be done with regular user privileges. 16 | 17 | For packaging you can optionally install the program into a temporary 18 | directory by setting the DESTDIR environment variable. For example, 19 | `DESTDIR="alternate/directory" cmake --install build' will prepend 20 | 'alternate/directory' before all installation names. 21 | 22 | macOS: 23 | 1. `cmake -B build -S .' to create a location for the build and then 24 | configure the program. There are more options you can pass to CMake, 25 | see below for details. 26 | 27 | 2. `cmake --build build' to compile the program. 28 | 29 | 3. Run `mac_deploy.sh' from inside the build directory to create a disk 30 | image of the program. 31 | 32 | Windows: 33 | 1. `cmake -B ..\build -S .' to create a location for the build and then 34 | configure the program. There are more options you can pass to CMake, 35 | see below for details. 36 | 37 | 2. `cmake --build ..\build' to compile the program. 38 | 39 | 3. Run `windows_deploy.bat' from inside the build directory to create an 40 | installer of the program. Note that you must have the NSIS executable 41 | from nsis.sourceforge.io and the 7z executable from 7-zip.org in your 42 | %PATH% for this to work. 43 | 44 | 45 | Release Builds 46 | ============== 47 | 48 | CMake does not specify any compiler optimizations by default; this is 49 | useful if you want to inherit CFLAGS and CXXFLAGS from the environment. 50 | You may want to add "-DCMAKE_BUILD_TYPE=Release" during configuration 51 | to get an optimized build. 52 | 53 | 54 | Debug Builds 55 | ============ 56 | 57 | You should create different directories for each type of build: 58 | 59 | 1. `cmake -B debug -S . -DCMAKE_BUILD_TYPE=Debug' to configure the sources. 60 | 61 | 2. `cmake --build debug' to compile the program. 62 | 63 | 64 | More CMake Options 65 | ================== 66 | 67 | -DCMAKE_BUILD_TYPE= 68 | Choose the type of build. Possible values are: 69 | 'None' 'Debug' 'Release' 'RelWithDebInfo' 'MinSizeRel' 70 | 71 | -DENABLE_LINK_TIME_OPTIMIZATION=[OFF] 72 | Reduce size by optimizing entire program at link time. 73 | 74 | -DENABLE_STRIP=[OFF] 75 | Reduce size by removing symbols. 76 | 77 | 78 | Linux CMake Options 79 | =================== 80 | 81 | -DCMAKE_INSTALL_PREFIX= 82 | Choose the base location where the program is installed 83 | (defaults to /usr/local). 84 | 85 | -DCMAKE_INSTALL_BINDIR= 86 | Choose where binaries are installed 87 | (defaults to $CMAKE_INSTALL_PREFIX/bin). 88 | 89 | -DCMAKE_INSTALL_DATADIR= 90 | Choose where the data files are installed 91 | (defaults to $CMAKE_INSTALL_PREFIX/share). 92 | 93 | -DCMAKE_INSTALL_MANDIR= 94 | Choose where manual pages are installed 95 | (defaults to $CMAKE_INSTALL_DATADIR/man). 96 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | 4 | Simsu is a basic Sudoku game. You can switch between filling in notes 5 | (pencil mode), or filling in answers (pen mode). To make it easier to 6 | see where to place numbers, you can highlight all instances of a number. 7 | You can also check your answers for correctness while playing. The game 8 | stores your current notes and answers, so that you can pick up where you 9 | left off the next time you play. 10 | -------------------------------------------------------------------------------- /cmake/AddVersionCompileDefinition.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Graeme Gott 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | function(add_version_compile_definition versionstr_file versionstr_def) 6 | find_package(Git QUIET) 7 | if(Git_FOUND) 8 | # Find git repository 9 | execute_process( 10 | COMMAND ${GIT_EXECUTABLE} rev-parse --absolute-git-dir 11 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 12 | RESULT_VARIABLE git_dir_result 13 | OUTPUT_VARIABLE git_dir 14 | ERROR_QUIET 15 | OUTPUT_STRIP_TRAILING_WHITESPACE 16 | ) 17 | 18 | if (git_dir_result EQUAL 0) 19 | # Find version number from git 20 | execute_process( 21 | COMMAND ${GIT_EXECUTABLE} describe --tags --match "v*" 22 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 23 | OUTPUT_VARIABLE versionstr 24 | ERROR_QUIET 25 | OUTPUT_STRIP_TRAILING_WHITESPACE 26 | ) 27 | string(REGEX REPLACE "^v" "" versionstr "${versionstr}") 28 | 29 | # Rerun CMake when git repository changes 30 | if (EXISTS ${git_dir}/logs/HEAD) 31 | set_property( 32 | DIRECTORY 33 | APPEND 34 | PROPERTY CMAKE_CONFIGURE_DEPENDS ${git_dir}/logs/HEAD 35 | ) 36 | endif() 37 | endif() 38 | endif() 39 | 40 | # Fall back to project's VERSION 41 | if ("${versionstr}" STREQUAL "") 42 | set(versionstr ${PROJECT_VERSION}) 43 | endif() 44 | 45 | # Pass version as compile definition to file 46 | set_property( 47 | SOURCE ${versionstr_file} 48 | APPEND 49 | PROPERTY COMPILE_DEFINITIONS ${versionstr_def}="${versionstr}" 50 | ) 51 | endfunction() 52 | -------------------------------------------------------------------------------- /cmake/BundleResources.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Graeme Gott 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | # Add files to a macOS bundle. 6 | function(bundle_data target source destination) 7 | if(IS_DIRECTORY ${source}) 8 | # Recursively find files under source 9 | file(GLOB_RECURSE files RELATIVE ${source} ${source}/*) 10 | set(parent ${source}) 11 | else() 12 | # Handle single file 13 | get_filename_component(files ${source} NAME) 14 | get_filename_component(parent ${source} DIRECTORY) 15 | endif() 16 | 17 | # Set each file to be located under destination 18 | foreach(resource ${files}) 19 | get_filename_component(path ${resource} DIRECTORY) 20 | set_property( 21 | SOURCE ${parent}/${resource} 22 | PROPERTY 23 | MACOSX_PACKAGE_LOCATION ${destination}/${path} 24 | ) 25 | endforeach() 26 | 27 | # Make target depend on resources 28 | list(TRANSFORM files PREPEND "${parent}/") 29 | target_sources(${target} PRIVATE ${files}) 30 | endfunction() 31 | 32 | # Add translations to a macOS bundle. 33 | function(bundle_translations target translations) 34 | foreach(file ${translations}) 35 | # Set each translation to be located under Resources 36 | set_property( 37 | SOURCE ${file} 38 | PROPERTY 39 | MACOSX_PACKAGE_LOCATION Resources/translations 40 | ) 41 | 42 | # Inform macOS about translation for native dialogs 43 | get_filename_component(resource ${file} NAME) 44 | string(REGEX REPLACE "[^_]*_([^\\.]*)\\..*" "\\1.lproj" lang ${resource}) 45 | add_custom_command( 46 | TARGET ${target} 47 | POST_BUILD 48 | COMMAND ${CMAKE_COMMAND} 49 | ARGS -E make_directory $/Resources/${lang} 50 | ) 51 | endforeach() 52 | endfunction() 53 | -------------------------------------------------------------------------------- /cmake/TranslateMetainfo.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Graeme Gott 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | function(process_and_install_metainfo) 6 | cmake_parse_arguments(PARSE_ARGV 0 arg "" "PO_DIR" "MIMETYPES") 7 | 8 | find_package(Gettext 0.19.8 REQUIRED) 9 | 10 | # Generate LINGUAS file 11 | file(GLOB po_files ${arg_PO_DIR}/*.po) 12 | foreach(po_file ${po_files}) 13 | get_filename_component(lang ${po_file} NAME_WE) 14 | list(APPEND linguas ${lang}) 15 | endforeach() 16 | add_custom_command( 17 | OUTPUT ${arg_PO_DIR}/LINGUAS 18 | COMMAND ${CMAKE_COMMAND} -E echo "${linguas}" > ${arg_PO_DIR}/LINGUAS 19 | COMMAND_EXPAND_LISTS 20 | COMMENT "Generating LINGUAS" 21 | ) 22 | 23 | # Generate desktop file 24 | set(desktop_file "${PROJECT_NAME}.desktop") 25 | add_custom_command( 26 | OUTPUT ${desktop_file} 27 | COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} 28 | --desktop 29 | --template=${arg_PO_DIR}/../${desktop_file}.in 30 | -d ${arg_PO_DIR} 31 | -o ${desktop_file} 32 | DEPENDS ${arg_PO_DIR}/../${desktop_file}.in ${po_files} ${arg_PO_DIR}/LINGUAS 33 | ) 34 | install( 35 | FILES ${CMAKE_CURRENT_BINARY_DIR}/${desktop_file} 36 | DESTINATION ${CMAKE_INSTALL_DATADIR}/applications 37 | ) 38 | list(APPEND metainfo_files ${desktop_file}) 39 | 40 | # Generate AppData file 41 | set(appdata_file "${PROJECT_NAME}.appdata.xml") 42 | add_custom_command( 43 | OUTPUT ${appdata_file} 44 | COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} 45 | --xml 46 | --template=${arg_PO_DIR}/../${appdata_file}.in 47 | -d ${arg_PO_DIR} 48 | -o ${appdata_file} 49 | DEPENDS ${arg_PO_DIR}/../${appdata_file}.in ${po_files} ${arg_PO_DIR}/LINGUAS 50 | ) 51 | install( 52 | FILES ${CMAKE_CURRENT_BINARY_DIR}/${appdata_file} 53 | DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo 54 | ) 55 | list(APPEND metainfo_files ${appdata_file}) 56 | 57 | # Generate mimetype files 58 | foreach(mimetype_file ${arg_MIMETYPES}) 59 | add_custom_command( 60 | OUTPUT ${mimetype_file} 61 | COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} 62 | --xml 63 | --template=${arg_PO_DIR}/../${mimetype_file}.in 64 | -d ${arg_PO_DIR} 65 | -o ${mimetype_file} 66 | DEPENDS ${arg_PO_DIR}/../${mimetype_file}.in ${po_files} ${arg_PO_DIR}/LINGUAS 67 | ) 68 | install( 69 | FILES ${CMAKE_CURRENT_BINARY_DIR}/${mimetype_file} 70 | DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages 71 | ) 72 | list(APPEND metainfo_files ${mimetype_file}) 73 | endforeach() 74 | 75 | # Generate description template 76 | find_program(XGETTEXT_EXECUTABLE xgettext) 77 | if(XGETTEXT_EXECUTABLE) 78 | add_custom_target(update_description_template 79 | COMMAND ${XGETTEXT_EXECUTABLE} 80 | --output=description.pot 81 | --from-code=UTF-8 82 | --package-name='${PROJECT_NAME}' 83 | --copyright-holder='Graeme Gott' 84 | ../*.in 85 | WORKING_DIRECTORY ${arg_PO_DIR} 86 | COMMENT "Generating description.pot" 87 | ) 88 | endif() 89 | 90 | # Translate metainfo files 91 | add_custom_target(metainfo ALL DEPENDS ${metainfo_files}) 92 | endfunction() 93 | -------------------------------------------------------------------------------- /doc/simsu.6: -------------------------------------------------------------------------------- 1 | .TH SIMSU 6 "May 2025" "Simsu 1.4.6" "Games Manual" 2 | 3 | .SH "NAME" 4 | simsu \- basic sudoku game 5 | 6 | .SH "SYNOPSIS" 7 | .B simsu 8 | [options] 9 | 10 | .SH "DESCRIPTION" 11 | Simsu is a basic Sudoku game. You can switch between filling in notes 12 | (pencil mode), or filling in answers (pen mode). To make it easier to 13 | see where to place numbers, you can highlight all instances of a number. 14 | You can also check your answers for correctness while playing. The game 15 | stores your current notes and answers, so that you can pick up where you 16 | left off the next time you play. 17 | 18 | .SH "OPTIONS" 19 | .TP 20 | .BR \-h ", " \-\-help 21 | Displays help on commandline options. 22 | .TP 23 | .B \-\-help-all 24 | Displays help including Qt specific options. 25 | .TP 26 | .BR \-v ", " \-\-version 27 | Displays version information. 28 | 29 | .SH "SEE ALSO" 30 | .BR qt6options (7) 31 | 32 | .SH "REPORTING BUGS" 33 | Report bugs to . 34 | 35 | .SH "COPYRIGHT" 36 | Copyright \(co 2009-2025 Graeme Gott 37 | .PP 38 | Free use of this software is granted under the terms of the GNU General 39 | Public License version 3 (GPLv3). There is NO WARRANTY, to the extent 40 | permitted by law. 41 | 42 | .SH "AUTHOR" 43 | Graeme Gott . 44 | -------------------------------------------------------------------------------- /icons/hicolor/1024x1024/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/1024x1024/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/128x128/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/128x128/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/16x16/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/16x16/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/22x22/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/22x22/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/24x24/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/24x24/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/256x256/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/256x256/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/32x32/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/32x32/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/48x48/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/48x48/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/512x512/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/512x512/apps/simsu.png -------------------------------------------------------------------------------- /icons/hicolor/64x64/apps/simsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/hicolor/64x64/apps/simsu.png -------------------------------------------------------------------------------- /icons/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/highlight.png -------------------------------------------------------------------------------- /icons/highlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/highlight@2x.png -------------------------------------------------------------------------------- /icons/icon.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | hicolor/256x256/apps/simsu.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /icons/images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | highlight.png 4 | pen.png 5 | pencil.png 6 | 7 | highlight@2x.png 8 | pen@2x.png 9 | pencil@2x.png 10 | 11 | 12 | -------------------------------------------------------------------------------- /icons/pen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/pen.png -------------------------------------------------------------------------------- /icons/pen@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/pen@2x.png -------------------------------------------------------------------------------- /icons/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/pencil.png -------------------------------------------------------------------------------- /icons/pencil@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/pencil@2x.png -------------------------------------------------------------------------------- /icons/po/LINGUAS: -------------------------------------------------------------------------------- 1 | bg cs de el es fr he it lt ms nl pl pt ro ru te zh zh_TW 2 | -------------------------------------------------------------------------------- /icons/po/bg.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Любомир Василев, 2015 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-23 20:29+0000\n" 13 | "Last-Translator: Любомир Василев\n" 14 | "Language-Team: Bulgarian (http://www.transifex.com/gottcode/simsu/language/bg/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: bg\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Попълнете числата, за да решите загадките" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Симсу е простичка игра от тип Судоку. Можете да превключвате между това да попълвате бележки (режим „молив“) или отговори (режим „писалка“) За да е по-лесно да видите къде трябва да поставите цифрите, можете да осветите всички срещания на дадена цифра. Също така можете да проверите дали отговорите Ви са верни докато играете. Играта запазва текущите Ви бележки и отговори, така че да можете да продължите от там, където сте прекъснали, следващия път, когато играете." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Симсу" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Игра от тип Судоку" 42 | -------------------------------------------------------------------------------- /icons/po/cs.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # fri, 2014 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-23 20:29+0000\n" 13 | "Last-Translator: fri\n" 14 | "Language-Team: Czech (http://www.transifex.com/gottcode/simsu/language/cs/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: cs\n" 19 | "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Vyplňte čísla a vyřešte hádanku" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "" 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Hra Sudoku" 42 | -------------------------------------------------------------------------------- /icons/po/de.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # M T , 2015 7 | # Wasilis Mandratzis-Walz, 2015 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: Simsu\n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 13 | "PO-Revision-Date: 2017-09-21 13:55+0000\n" 14 | "Last-Translator: M T \n" 15 | "Language-Team: German (http://www.transifex.com/gottcode/simsu/language/de/)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Language: de\n" 20 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 21 | 22 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 23 | msgid "Fill in numbers to solve puzzles" 24 | msgstr "Geben Sie Zahlen ein, um das Rätsel zu lösen" 25 | 26 | #: ../simsu.appdata.xml.in.h:2 27 | msgid "" 28 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 29 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 30 | "where to place numbers, you can highlight all instances of a number. You can" 31 | " also check your answers for correctness while playing. The game stores your" 32 | " current notes and answers, so that you can pick up where you left off the " 33 | "next time you play." 34 | msgstr "Simsu ist ein grundlegendes Sudoku-Spiel. Sie können zwischen dem Ausfüllen von Anmerkungen (Bleistift-Modus) oder Ausfüllen von Antworten (Stiftmodus) wechseln. Um einfacher zu sehen, wo Zahlen gesetzt werden können, können Sie alle Vorkommen einer Zahl markieren. Sie können auch Ihre Antworten auf Richtigkeit während des Spielens überprüfen. Das Spiel speichert Ihre aktuellen Notizen und Antworten, so dass können Sie sie beim nächsten Start des Spiels aufrufen können." 35 | 36 | #: ../simsu.desktop.in.h:1 37 | msgid "Simsu" 38 | msgstr "Simsu" 39 | 40 | #: ../simsu.desktop.in.h:2 41 | msgid "Sudoku Game" 42 | msgstr "Sudoku Spiel" 43 | -------------------------------------------------------------------------------- /icons/po/description.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the Simsu package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 20:55+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: ../simsu.appdata.xml.in:6 ../simsu.desktop.in:3 21 | msgid "Simsu" 22 | msgstr "" 23 | 24 | #: ../simsu.appdata.xml.in:7 ../simsu.desktop.in:5 25 | msgid "Fill in numbers to solve puzzles" 26 | msgstr "" 27 | 28 | #: ../simsu.appdata.xml.in:10 29 | msgid "" 30 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 31 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 32 | "where to place numbers, you can highlight all instances of a number. You can " 33 | "also check your answers for correctness while playing. The game stores your " 34 | "current notes and answers, so that you can pick up where you left off the " 35 | "next time you play." 36 | msgstr "" 37 | 38 | #: ../simsu.desktop.in:4 39 | msgid "Sudoku Game" 40 | msgstr "" 41 | -------------------------------------------------------------------------------- /icons/po/el.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Γιάννης Ανθυμίδης, 2014 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-21 13:55+0000\n" 13 | "Last-Translator: Γιάννης Ανθυμίδης\n" 14 | "Language-Team: Greek (http://www.transifex.com/gottcode/simsu/language/el/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: el\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Συμπληρώστε τους αριθμούς για να λύσετε τους γρίφους" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Το Simsu είναι βασικό πρόγραμμα για το παιχνίδι Σουντόκου. Μπορείτε να αλλάξετε μεταξύ λειτουργίες σημείωσης (με το μολύβι) και συμπλήρωσης (με το στυλό). Για να βλέπετε πιο εύκολα που μπορείτε να βάλετε αριθμούς, μπορείτε να επισημάνετε όλες τις παρουσίες ενός αριθμού. Μπορείτε επίσης να ελέγξτε τη λύση σας για ορθότητα όσο παίζετε με τον υπολογιστή. Το παιχνίδι αποθηκεύει τις σημειώσεις σας και αριθμούς, ώστε να μπορείτε να συνεχίσετε από εκεί που αφήσατε το παιχνίδι την επόμενη φορά που παίζεται Σουντόκου." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Παιχνίδι Σουντόκου" 42 | -------------------------------------------------------------------------------- /icons/po/es.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Edgar Carballo , 2015 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-21 13:55+0000\n" 13 | "Last-Translator: Edgar Carballo \n" 14 | "Language-Team: Spanish (http://www.transifex.com/gottcode/simsu/language/es/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: es\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Escriba números para resolver rompecabezas" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu es un juego de Sudoku básico. Puedes intercambiar entre escribir notas (modo lápiz), o escribir las respuestas (modo pluma). Para hacer que ver dónde poner los números sea más fácil, puedes marcar todas las instancias de un número. También puedes verificar si tus respuestas son correctas mientras juegas. El juego almacena tus notas y respuestas actuales, para que después puedas continuar donde te quedaste." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Juego de Sudoku" 42 | -------------------------------------------------------------------------------- /icons/po/fr.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Guillaume Gay , 2014 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2018-11-05 20:18+0000\n" 13 | "Last-Translator: Guillaume Gay \n" 14 | "Language-Team: French (http://www.transifex.com/gottcode/simsu/language/fr/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: fr\n" 19 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Résolution de puzzles numériques" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu est un simple jeu de Sodoku. Vous pouvez basculer du remplissage en mode notes (mode crayon), au remplissage en mode réponses définitives (mode stylo). Pour faciliter le placement des numéros, vous avez la possibilité de mettre en surbrillance toutes les occurrences d'un certain nombre. Vous pouvez également vérifier l'exactitude de vos réponses tout en jouant. Le jeu enregistre vos notes et vos réponses en cours en cours, de sorte que vous puissiez reprendre là où vous vous étiez arrêté la prochaine fois." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Jeu de Sodoku" 42 | -------------------------------------------------------------------------------- /icons/po/he.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: Simsu\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 11 | "PO-Revision-Date: 2018-05-28 18:34+0000\n" 12 | "Last-Translator: Graeme Gott \n" 13 | "Language-Team: Hebrew (http://www.transifex.com/gottcode/simsu/language/he/)\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Language: he\n" 18 | "Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n" 19 | 20 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 21 | msgid "Fill in numbers to solve puzzles" 22 | msgstr "" 23 | 24 | #: ../simsu.appdata.xml.in.h:2 25 | msgid "" 26 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 27 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 28 | "where to place numbers, you can highlight all instances of a number. You can" 29 | " also check your answers for correctness while playing. The game stores your" 30 | " current notes and answers, so that you can pick up where you left off the " 31 | "next time you play." 32 | msgstr "" 33 | 34 | #: ../simsu.desktop.in.h:1 35 | msgid "Simsu" 36 | msgstr "" 37 | 38 | #: ../simsu.desktop.in.h:2 39 | msgid "Sudoku Game" 40 | msgstr "משחק סודוקו" 41 | -------------------------------------------------------------------------------- /icons/po/it.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Antonio Spadaro , 2018 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2018-01-18 14:12+0000\n" 13 | "Last-Translator: Antonio Spadaro \n" 14 | "Language-Team: Italian (Italy) (http://www.transifex.com/gottcode/simsu/language/it_IT/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: it\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "" 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Sudoku" 42 | -------------------------------------------------------------------------------- /icons/po/lt.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Moo, 2014,2016 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-21 13:55+0000\n" 13 | "Last-Translator: Moo\n" 14 | "Language-Team: Lithuanian (http://www.transifex.com/gottcode/simsu/language/lt/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: lt\n" 19 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Irašykite skaičius, kad išspręstumėte dėlionę" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu yra paprastas Sudoku žaidimas. Galite perjungti tarp užrašų pildymo (pieštuko veiksenos) arba atsakymų pildymo (tušinuko veiksenos). Kad būtų lengviau matoma, kur įrašyti skaičius, galite paryškinti tam tikro skaičiaus visus egzempliorius. Taip pat žaisdami, galite tikrinti ar jūsų įrašyti atsakymai yra teisingi. Žaidimas saugo jūsų dabartinius užrašus ir atsakymus, taigi kitą kartą galėsite tęsti žaidimą nuo tos vietos, kur užbaigėte anksčiau." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Sudoku žaidimas" 42 | -------------------------------------------------------------------------------- /icons/po/ms.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # abuyop , 2014 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-21 13:55+0000\n" 13 | "Last-Translator: abuyop \n" 14 | "Language-Team: Malay (Malaysia) (http://www.transifex.com/gottcode/simsu/language/ms_MY/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: ms\n" 19 | "Plural-Forms: nplurals=1; plural=0;\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Isikan nombor untuk menyelesaikan teka-teki" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu merupakan permainan Sudoku asas. Anda boleh tukar diantara mengisi dalam bentuk nota (mod pensel), atau mengisi jawapan (mod pen). Untuk memudahkan dimana nombor diletakkan, anda boleh sorotkan semua kejadian nombor tersebut. Anda juga boleh memeriksa jawapan sama ada betul atau sebaliknya ketika bermain. Permainan akan menyimpan nota semasa dan jawapan sekali, supaya anda dapat mula kembali pada tempat yang sama dilain masa." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Permainan Sudoku" 42 | -------------------------------------------------------------------------------- /icons/po/nl.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # RobertBorst , 2016 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2014-11-14 17:11+0000\n" 13 | "Last-Translator: RobertBorst , 2016\n" 14 | "Language-Team: Dutch (http://www.transifex.com/gottcode/simsu/language/nl/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: nl\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Vul nummers in om de puzzel op te lossen" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu is een standaard Sudoku spel. Je kunt omschakelen tussen notitie maken (potlood mode) of het werkelijk invullen van de antwoorden (pen mode). Om het gemakkelijker te maken waar je nummers kunt plaatsen, kun je de nummers op laten lichten. Je kunt ook je antwoorden laten controleren tijdens het spelen. Het spel bewaart je notities en antwoorden zodat je kunt doorgaan waar je gebleven was." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Sudoku spel" 42 | -------------------------------------------------------------------------------- /icons/po/pl.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # M T , 2015 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-21 13:55+0000\n" 13 | "Last-Translator: M T \n" 14 | "Language-Team: Polish (http://www.transifex.com/gottcode/simsu/language/pl/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: pl\n" 19 | "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Uzupełnij liczby aby rozwiązać puzzle" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu jest podstawową grą Sudoku. Możesz przełączać pomiędzy wypełnianiem notatek (tryb ołówek), lub wypełnianiem odpowiedzi (tryb pióra). Aby łatwiej rozpoznać, gdzie można umieścić liczby, możesz zaznaczyć wszystkie wystąpienia liczby. Możesz również sprawdzać rozwiązanie podczas gry. Gra zapisuje twoje obecne notatki i odpowiedzi, aby zostały odtworzone przy następnym uruchomieniu gry." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Gra Sudoku" 42 | -------------------------------------------------------------------------------- /icons/po/pt.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # João Frade <100nome.portugal@gmail.com>, 2015 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-23 20:44+0000\n" 13 | "Last-Translator: João Frade <100nome.portugal@gmail.com>\n" 14 | "Language-Team: Portuguese (http://www.transifex.com/gottcode/simsu/language/pt/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: pt\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Preenche com números para resolveres quebra-cabeças" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu é um simples jogo de Sudoku. Podes escolher entre preencher com notas (modo de lápis) ou com respostas (modo de caneta). Para facilitar uma nova colocação, podes realçar todas as instâncias de um número. Podes também fazer a verificação durante o jogo. A aplicação guarda as tuas notas e respostas atuais, de modo a que possas retomar o jogo anterior." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Jogo de Sudoku" 42 | -------------------------------------------------------------------------------- /icons/po/ro.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Oprea Nicolae , 2015 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2017-09-23 20:29+0000\n" 13 | "Last-Translator: Oprea Nicolae \n" 14 | "Language-Team: Romanian (http://www.transifex.com/gottcode/simsu/language/ro/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: ro\n" 19 | "Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Completaţi cu numere pentru a rezolva puzzle-uri" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu este un joc de bază Sudoku. Puteți comuta între completarea notelor (modul creion), sau completarea răspunsurilor (modul stilou). Pentru a vedea mai uşor unde să plaseze numere, puteţi evidenția toate instanţele unui număr. Puteţi verifica, de asemenea, răspunsurile dumneavoastră pentru corectitudine în timpul jocului. Jocul stochează notele curente și răspunsurile, astfel încît să puteți contunua de unde aţi rămas data viitoare cînd jucaţi." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Joc Sudooku" 42 | -------------------------------------------------------------------------------- /icons/po/ru.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Evgeny Gureev, 2021 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2021-01-12 15:52+0000\n" 13 | "Last-Translator: Evgeny Gureev\n" 14 | "Language-Team: Russian (http://www.transifex.com/gottcode/simsu/language/ru/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: ru\n" 19 | "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "Заполните цифры для решения головоломки" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu - это классическая игра Судоку. Вы можете переключаться между заполнением заметок (режим карандаш) или ответов (режим ручка). Для облегчения размещения чисел можно подсветить все экземпляры числа. Вы также можете проверить свои ответы на правильность во время игры. Игра хранит ваши текущие заметки и ответы, так что вы можете продолжить с того места, где остановились, когда будете играть в следующий раз." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "Игра Судоку" 42 | -------------------------------------------------------------------------------- /icons/po/te.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Jagadeeshvarma, 2021 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2021-05-14 05:10+0000\n" 13 | "Last-Translator: Jagadeeshvarma\n" 14 | "Language-Team: Telugu (http://www.transifex.com/gottcode/simsu/language/te/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: te\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "పజిల్స్ పరిష్కరించడానికి సంఖ్యలను పూరించండి" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "సిమ్సు ఒక ప్రాథమిక సుడోకు ఆట. మీరు గమనికలను నింపడం (పెన్సిల్ మోడ్) లేదా సమాధానాలను నింపడం (పెన్ మోడ్) మధ్య మారవచ్చు. సంఖ్యలను ఎక్కడ ఉంచాలో చూడటం సులభతరం చేయడానికి, మీరు సంఖ్య యొక్క అన్ని సందర్భాలను హైలైట్ చేయవచ్చు. మీరు ఆడుతున్నప్పుడు సరైనదానికి మీ సమాధానాలను కూడా తనిఖీ చేయవచ్చు. ఆట మీ ప్రస్తుత గమనికలు మరియు సమాధానాలను నిల్వ చేస్తుంది, తద్వారా మీరు తదుపరిసారి ఆడుతున్నప్పుడు మీరు ఎక్కడినుండి వెళ్లిపోయారో అక్కడనుండి కొనసాగించవ్చు." 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "సిస్ము" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "సుడోకు ఆట" 42 | -------------------------------------------------------------------------------- /icons/po/zh.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # 高垚鑫, 2018 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Simsu\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 12 | "PO-Revision-Date: 2018-03-25 12:39+0000\n" 13 | "Last-Translator: 高垚鑫\n" 14 | "Language-Team: Chinese (http://www.transifex.com/gottcode/simsu/language/zh/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: zh\n" 19 | "Plural-Forms: nplurals=1; plural=0;\n" 20 | 21 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 22 | msgid "Fill in numbers to solve puzzles" 23 | msgstr "填入数字,解答难题" 24 | 25 | #: ../simsu.appdata.xml.in.h:2 26 | msgid "" 27 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 28 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 29 | "where to place numbers, you can highlight all instances of a number. You can" 30 | " also check your answers for correctness while playing. The game stores your" 31 | " current notes and answers, so that you can pick up where you left off the " 32 | "next time you play." 33 | msgstr "Simsu 是一款简单的数独游戏。你可以打草稿(铅笔模式)或填答案(钢笔模式)。为了更容易看出在哪里填数字,你可以高亮同一数字的所有出现。你可以在游戏进行的任何时候检查你所填的答案正确与否。游戏会记忆当前的草稿和答案,您下次游戏时可以直接继续。" 34 | 35 | #: ../simsu.desktop.in.h:1 36 | msgid "Simsu" 37 | msgstr "Simsu" 38 | 39 | #: ../simsu.desktop.in.h:2 40 | msgid "Sudoku Game" 41 | msgstr "数独游戏" 42 | -------------------------------------------------------------------------------- /icons/po/zh_TW.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Graeme Gott 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # st.michael c, 2017 7 | # st.michael c, 2017 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: Simsu\n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2014-11-14 17:10+0000\n" 13 | "PO-Revision-Date: 2017-09-23 23:49+0000\n" 14 | "Last-Translator: st.michael c\n" 15 | "Language-Team: Chinese (Taiwan) (http://www.transifex.com/gottcode/simsu/language/zh_TW/)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Language: zh_TW\n" 20 | "Plural-Forms: nplurals=1; plural=0;\n" 21 | 22 | #: ../simsu.appdata.xml.in.h:1 ../simsu.desktop.in.h:3 23 | msgid "Fill in numbers to solve puzzles" 24 | msgstr "填入數字,解答數謎。" 25 | 26 | #: ../simsu.appdata.xml.in.h:2 27 | msgid "" 28 | "Simsu is a basic Sudoku game. You can switch between filling in notes " 29 | "(pencil mode), or filling in answers (pen mode). To make it easier to see " 30 | "where to place numbers, you can highlight all instances of a number. You can" 31 | " also check your answers for correctness while playing. The game stores your" 32 | " current notes and answers, so that you can pick up where you left off the " 33 | "next time you play." 34 | msgstr "Simsu是一個基本的數獨遊戲。你可以在劃記(鉛筆模式)和作答(原子筆模式)之間切換。你可以把所有子表格的同一個號碼都塗上色,方便釐清下一個數字要放在哪裡。在玩遊戲時,你可以同時檢查答案的正確性。這遊戲會儲存你目前的劃記和答案,所以下次你可以重拾你前次未完成的殘局。" 35 | 36 | #: ../simsu.desktop.in.h:1 37 | msgid "Simsu" 38 | msgstr "Simsu" 39 | 40 | #: ../simsu.desktop.in.h:2 41 | msgid "Sudoku Game" 42 | msgstr "數獨遊戲" 43 | -------------------------------------------------------------------------------- /icons/simsu.appdata.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | simsu.desktop 4 | CC0-1.0 5 | GPL-3.0+ 6 | 7 | Simsu 8 | Fill in numbers to solve puzzles 9 | 10 |

Simsu is a basic Sudoku game. You can switch between filling in notes (pencil mode), or filling in answers (pen mode). To make it easier to see where to place numbers, you can highlight all instances of a number. You can also check your answers for correctness while playing. The game stores your current notes and answers, so that you can pick up where you left off the next time you play.

11 |
12 | 13 | 14 | 15 | https://gottcode.org/simsu/screenshots/appdata.png 16 | 17 | 18 | 19 | https://gottcode.org/simsu/ 20 | https://gottcode.org/simsu/bugs/ 21 | https://gottcode.org/tip/ 22 | https://www.transifex.com/gottcode/simsu/ 23 | 24 | 25 | Graeme Gott 26 | 27 | graeme@gottcode.org 28 | 29 | simsu 30 | 31 | 32 | simsu 33 | 34 | simsu.desktop 35 | 36 | 37 | HiDpiIcon 38 | ModernToolkit 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
    47 |
  • FIXED: Compile error due to missing header
  • 48 |
  • Translation updates: French
  • 49 |
50 |
51 |
52 | 53 | 54 |
    55 |
  • Improved code for building translations
  • 56 |
57 |
58 |
59 | 60 | 61 |
    62 |
  • Improved deployment
  • 63 |
  • FIXED: Very wide window when played for first time
  • 64 |
  • Translation updates: Portuguese
  • 65 |
66 |
67 |
68 | 69 | 70 |
    71 |
  • Replaced deprecated code
  • 72 |
  • Translation updates: Portuguese
  • 73 |
74 |
75 |
76 | 77 | 78 |
    79 |
  • Added portable mode
  • 80 |
  • Improved Linux deployment
  • 81 |
  • Replaced deprecated code
  • 82 |
83 |
84 |
85 | 86 | 87 |
    88 |
  • Switched to Qt 6
  • 89 |
  • Translation updates: Dutch, Telugu
  • 90 |
91 |
92 |
93 | 94 | 95 |
    96 |
  • Added difficulty ratings
  • 97 |
  • Added getting hints
  • 98 |
  • Added optional automatic pencil marks
  • 99 |
  • Added playing puzzles entered by player
  • 100 |
  • Added printing puzzles
  • 101 |
  • Added restarting puzzles
  • 102 |
  • Added support for Qt 6
  • 103 |
  • Improved new game interface
  • 104 |
  • Improved window spacing
  • 105 |
  • Refactored code
  • 106 |
  • Removed XPM icon
  • 107 |
  • Translation updates: Bulgarian, Lithuanian, Romanian, Russian, Telugu
  • 108 |
109 |
110 |
111 | 112 | 113 |
    114 |
  • FIXED: Did not load locales with underscores
  • 115 |
  • Improved Windows deployment
  • 116 |
  • Replaced deprecated code
  • 117 |
118 |
119 |
120 | 121 | 122 |
    123 |
  • FIXED: Window icon didn't work in Wayland
  • 124 |
  • Improved loading locales
  • 125 |
  • Improved Windows deployment
  • 126 |
  • Replaced deprecated code
  • 127 |
128 |
129 |
130 | 131 | 132 |
    133 |
  • FIXED: Automatic high DPI support
  • 134 |
135 |
136 |
137 | 138 | 139 |
    140 |
  • Replaced deprecated code
  • 141 |
  • Extra warnings only shown in debug build
  • 142 |
  • Improved Linux deployment
  • 143 |
  • Improved macOS deployment
  • 144 |
  • Improved Windows deployment
  • 145 |
  • Translation updates: Chinese, Chinese (Taiwan), Italian, Portuguese
  • 146 |
147 |
148 |
149 |
150 |
151 | -------------------------------------------------------------------------------- /icons/simsu.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Simsu 3 | GenericName=Sudoku Game 4 | Comment=Fill in numbers to solve puzzles 5 | TryExec=simsu 6 | Exec=simsu 7 | Icon=simsu 8 | Terminal=false 9 | Type=Application 10 | Categories=Qt;Game;LogicGame; 11 | Keywords=game;logic; 12 | -------------------------------------------------------------------------------- /icons/simsu.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/simsu.icns -------------------------------------------------------------------------------- /icons/simsu.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/icons/simsu.ico -------------------------------------------------------------------------------- /mac/Info.plist.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleInfoDictionaryVersion 6 | 6.0 7 | CFBundlePackageType 8 | APPL 9 | CFBundleDevelopmentRegion 10 | en 11 | 12 | CFBundleName 13 | Simsu 14 | CFBundleIdentifier 15 | org.gottcode.Simsu 16 | CFBundleIconFile 17 | simsu.icns 18 | CFBundleExecutable 19 | ${MACOSX_BUNDLE_EXECUTABLE_NAME} 20 | 21 | CFBundleVersion 22 | ${PROJECT_VERSION} 23 | CFBundleShortVersionString 24 | ${PROJECT_VERSION} 25 | 26 | NSHumanReadableCopyright 27 | © ${project_copyright} 28 | 29 | LSMinimumSystemVersion 30 | ${CMAKE_OSX_DEPLOYMENT_TARGET} 31 | 32 | NSPrincipalClass 33 | NSApplication 34 | NSSupportsAutomaticGraphicsSwitching 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /mac/background.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/mac/background.tiff -------------------------------------------------------------------------------- /mac_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APP='Simsu' 4 | BUNDLE="$APP.app" 5 | VERSION='1.4.6' 6 | 7 | # Locate deployment script 8 | BIN_DIR=$(pwd) 9 | cd $(dirname "${BASH_SOURCE[0]}") 10 | 11 | # Remove any previous disk folder or DMG 12 | echo -n 'Preparing... ' 13 | rm -f "${APP}_$VERSION.dmg" 14 | if [ -e "/Volumes/$APP" ]; then 15 | hdiutil detach -quiet "/Volumes/$APP" 16 | fi 17 | rm -Rf "$APP" 18 | echo 'Done' 19 | 20 | # Create disk folder 21 | echo -n 'Copying application bundle... ' 22 | mkdir "$APP" 23 | cp -Rf "${BIN_DIR}/${BUNDLE}" "$APP/" 24 | strip "$APP/$BUNDLE/Contents/MacOS/$APP" 25 | cp COPYING "$APP/License.txt" 26 | echo 'Done' 27 | 28 | # Create ReadMe 29 | echo -n 'Creating ReadMe... ' 30 | cp README "$APP/Read Me.txt" 31 | echo >> "$APP/Read Me.txt" 32 | echo >> "$APP/Read Me.txt" 33 | echo 'CREDITS' >> "$APP/Read Me.txt" 34 | echo '=======' >> "$APP/Read Me.txt" 35 | echo >> "$APP/Read Me.txt" 36 | cat CREDITS >> "$APP/Read Me.txt" 37 | echo >> "$APP/Read Me.txt" 38 | echo >> "$APP/Read Me.txt" 39 | echo 'NEWS' >> "$APP/Read Me.txt" 40 | echo '====' >> "$APP/Read Me.txt" 41 | echo >> "$APP/Read Me.txt" 42 | cat ChangeLog >> "$APP/Read Me.txt" 43 | echo 'Done' 44 | 45 | # Copy Qt translations 46 | echo -n 'Copying Qt translations... ' 47 | TRANSLATIONS="$APP/$BUNDLE/Contents/Resources/translations" 48 | cp $QTDIR/translations/qt_* "$TRANSLATIONS" 49 | cp $QTDIR/translations/qtbase_* "$TRANSLATIONS" 50 | rm -f $TRANSLATIONS/qt_help_* 51 | echo 'Done' 52 | 53 | # Copy frameworks and plugins 54 | echo -n 'Copying frameworks and plugins... ' 55 | macdeployqt "$APP/$BUNDLE" 56 | rm -Rf "$APP/$BUNDLE/Contents/Frameworks/QtSvg.framework" 57 | rm -Rf "$APP/$BUNDLE/Contents/PlugIns/iconengines" 58 | rm -Rf "$APP/$BUNDLE/Contents/PlugIns/imageformats" 59 | echo 'Done' 60 | 61 | # Copy background 62 | echo -n 'Copying background... ' 63 | mkdir "$APP/.background" 64 | cp mac/background.tiff "$APP/.background/background.tiff" 65 | echo 'Done' 66 | 67 | # Create disk image 68 | echo -n 'Creating disk image... ' 69 | hdiutil create -quiet -srcfolder "$APP" -volname "$APP" -fs HFS+ -format UDRW 'temp.dmg' 70 | echo 'Done' 71 | 72 | echo -n 'Configuring disk image... ' 73 | hdiutil attach -quiet -readwrite -noverify -noautoopen 'temp.dmg' 74 | echo ' 75 | tell application "Finder" 76 | tell disk "'$APP'" 77 | open 78 | 79 | tell container window 80 | set the bounds to {400, 100, 949, 458} 81 | set current view to icon view 82 | set toolbar visible to false 83 | set statusbar visible to true 84 | set the bounds to {400, 100, 800, 460} 85 | end tell 86 | 87 | set viewOptions to the icon view options of container window 88 | tell viewOptions 89 | set arrangement to not arranged 90 | set icon size to 80 91 | set label position to bottom 92 | set shows icon preview to true 93 | set shows item info to false 94 | end tell 95 | set background picture of viewOptions to file ".background:background.tiff" 96 | 97 | make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} 98 | set position of item "'$BUNDLE'" of container window to {90, 90} 99 | set position of item "Applications" of container window to {310, 90} 100 | set position of item "Read Me.txt" of container window to {140, 215} 101 | set position of item "License.txt" of container window to {260, 215} 102 | close 103 | open 104 | 105 | update without registering applications 106 | delay 5 107 | end tell 108 | end tell 109 | ' | osascript 110 | chmod -Rf go-w "/Volumes/$APP" >& /dev/null 111 | sync 112 | hdiutil detach -quiet "/Volumes/$APP" 113 | echo 'Done' 114 | 115 | echo -n 'Compressing disk image... ' 116 | hdiutil convert -quiet 'temp.dmg' -format UDBZ -o "${APP}_${VERSION}.dmg" 117 | rm -f temp.dmg 118 | echo 'Done' 119 | 120 | # Clean up disk folder 121 | echo -n 'Cleaning up... ' 122 | rm -Rf "$APP" 123 | echo 'Done' 124 | -------------------------------------------------------------------------------- /src/board.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2021 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_BOARD_H 8 | #define SIMSU_BOARD_H 9 | 10 | class Cell; 11 | class Puzzle; 12 | class SolverLogic; 13 | 14 | #include "frame.h" 15 | class QLabel; 16 | class QPagedPaintDevice; 17 | class QSettings; 18 | class QUndoStack; 19 | 20 | /** 21 | * The game board. 22 | * 23 | * This class controls all of the game objects as well as the move history. 24 | */ 25 | class Board : public Frame 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | enum AutoNotes { 31 | ManualNotes, /**< Player sets notes */ 32 | AutoClearNotes, /**< Clears invalid player set notes */ 33 | AutoFillNotes /**< Fills in notes for player */ 34 | }; 35 | 36 | /** 37 | * Initializes board and starts a new game. If there is a saved game, it 38 | * loads that instead of starting a new game. 39 | */ 40 | explicit Board(QWidget* parent = nullptr); 41 | 42 | /** 43 | * Cleans up board and removes current game if it is finished so that a new 44 | * game will start on next program launch. 45 | */ 46 | ~Board(); 47 | 48 | /** 49 | * Clears out current game and starts a new game. 50 | * 51 | * @param symmetry specify mirroring of givens; if @c -1 use previous symmetry, defaults to Pattern::Rotational180 52 | * @param difficulty specify how hard to make puzzle; if @c -1 use previous algorithm, defaults to Puzzle::VeryEasy 53 | */ 54 | void newPuzzle(int symmetry, int difficulty); 55 | 56 | /** 57 | * Clears out current game and starts a new game. 58 | * 59 | * @param givens the values already set on the board 60 | * @return @c true if the puzzle could be loaded 61 | */ 62 | bool newPuzzle(const std::array& givens); 63 | 64 | /** 65 | * Clears out current game and loads a game. 66 | * 67 | * @return @c true if the puzzle could be loaded 68 | */ 69 | bool loadPuzzle(); 70 | 71 | /** 72 | * Saves current game. 73 | */ 74 | void savePuzzle(); 75 | 76 | /** Resets the board to its original state. */ 77 | void restartPuzzle(); 78 | 79 | /** Returns currently selected number. */ 80 | int activeKey() const 81 | { 82 | return m_active_key; 83 | } 84 | 85 | /** Returns the automatic note filling mode. */ 86 | AutoNotes autoNotes() const 87 | { 88 | return m_auto_notes; 89 | } 90 | 91 | /** Returns @c true if auto switching modes is enabled; @c false otherwise */ 92 | bool autoSwitch() const 93 | { 94 | return m_auto_switch; 95 | } 96 | 97 | /** Returns @c true if highlighting is enabled; @c false otherwise */ 98 | bool highlightActive() const 99 | { 100 | return m_highlight_active; 101 | } 102 | 103 | /** 104 | * Return the amount of times @p key appears on the board. 105 | * 106 | * @param key the number to check 107 | * @return the amount of instances of a @p key 108 | */ 109 | int keyCount(int key) const 110 | { 111 | return m_key_count[key - 1]; 112 | } 113 | 114 | /** Returns @c true if in notes mode, @c false if in answers mode. */ 115 | bool notesMode() const 116 | { 117 | return m_notes_mode; 118 | } 119 | 120 | /** 121 | * Returns @c true if cell can contain @p value. 122 | * 123 | * @param column cell column 124 | * @param row cell row 125 | * @param value value to check 126 | */ 127 | bool hasPossible(int column, int row, int value) const; 128 | 129 | /** Returns @c true if game is over, @c false otherwise */ 130 | bool isFinished() const 131 | { 132 | return m_finished; 133 | } 134 | 135 | /** Returns @c true if the game is loaded and playable. */ 136 | bool isLoaded() const 137 | { 138 | return m_loaded; 139 | } 140 | 141 | /** 142 | * Prints the current board layout if it is loaded. 143 | * 144 | * @param printer device to print to 145 | */ 146 | void print(QPagedPaintDevice* printer) const; 147 | 148 | /** 149 | * Checks if the board has been completed successfully. If it has, it informs 150 | * the player by showing the success message. 151 | */ 152 | void checkFinished(); 153 | 154 | /** 155 | * Move the focus highlight. 156 | * 157 | * @param column starting cell column 158 | * @param row starting cell row 159 | * @param deltax distance to move horizontally 160 | * @param deltay distance to move vertically 161 | */ 162 | void moveFocus(int column, int row, int deltax, int deltay); 163 | 164 | /** 165 | * Reduce amount of times @c key appears on the board. 166 | * 167 | * @param key the number which instances will be reduced 168 | */ 169 | void decreaseKeyCount(int key); 170 | 171 | /** 172 | * Increase amount of times @c key appears on the board. 173 | * 174 | * @param key the number which instances will be increased 175 | */ 176 | void increaseKeyCount(int key); 177 | 178 | /** Solves the current board state to find available possibles. */ 179 | void updatePossibles(); 180 | 181 | /** 182 | * Fetch a cell instance. 183 | * 184 | * @param column cell column 185 | * @param row cell row 186 | * @return pointer to Cell instance; owned by Board 187 | */ 188 | Cell* cell(int column, int row) const 189 | { 190 | column = qBound(0, column, 8); 191 | row = qBound(0, row, 8); 192 | return m_cells[column][row]; 193 | } 194 | 195 | /** 196 | * Fetch neighbors of a cell. 197 | * 198 | * @param column cell column 199 | * @param row cell row 200 | * @return list of pointers to Cell instances 201 | */ 202 | QList cellNeighbors(int column, int row) const; 203 | 204 | /** Returns move history. */ 205 | QUndoStack* moves() 206 | { 207 | return m_moves; 208 | } 209 | 210 | public Q_SLOTS: 211 | /** 212 | * Finds an empty cell and fills it with a value from the solution. If there 213 | * are errors on the board, it corrects them first. 214 | */ 215 | void hint(); 216 | 217 | /** 218 | * If @p show is @c true, it highlights any cells that the player has filled 219 | * incorrectly. Otherwise, it clears the highlight of incorrect cells. 220 | */ 221 | void showWrong(bool show); 222 | 223 | /** 224 | * Set which key is currently being used. 225 | * 226 | * @param key the current key 227 | */ 228 | void setActiveKey(int key); 229 | 230 | /** 231 | * Set which cell is currently active. 232 | * 233 | * @param cell the current cell 234 | */ 235 | void setActiveCell(Cell* cell); 236 | 237 | /** 238 | * Sets if it should automatically fill notes. 239 | * 240 | * @param mode what fill mode the board should use 241 | */ 242 | void setAutoNotes(int auto_notes); 243 | 244 | /** 245 | * Sets if it should automatically switch between answers and notes mode. 246 | * 247 | * @param auto_switch if @c true enables auto-switching 248 | */ 249 | void setAutoSwitch(bool auto_switch); 250 | 251 | /** 252 | * Sets if all instances of current key should be highlighted. 253 | * 254 | * @param highlight if @c true it will highlight all instances. 255 | */ 256 | void setHighlightActive(bool highlight); 257 | 258 | /** 259 | * Sets if notes mode is enabled. 260 | * 261 | * @param mode if @c true notes mode is enabled; otherwise answers mode is enabled 262 | */ 263 | void setMode(int mode); 264 | 265 | Q_SIGNALS: 266 | /** 267 | * This signal is emitted when the current key is changed. 268 | * 269 | * @param key current key 270 | */ 271 | void activeKeyChanged(int key); 272 | 273 | /** 274 | * This signal is emitted when the player has finished the game. 275 | */ 276 | void gameFinished(); 277 | 278 | /** 279 | * This signal is emitted when the game has finished loading. 280 | */ 281 | void gameStarted(); 282 | 283 | /** 284 | * This signal is emitted when notes mode is enabled or disabled. 285 | * 286 | * @param mode @c true if notes mode is enabled 287 | */ 288 | void notesModeChanged(bool mode); 289 | 290 | /** 291 | * This signal is emitted when the count of an active key has changed. 292 | */ 293 | void keysChanged(); 294 | 295 | private: 296 | /** 297 | * Loads board after puzzle finishes generating. 298 | * 299 | * @param symmetry specify mirroring of givens 300 | * @param difficulty specify how hard to make puzzle 301 | */ 302 | void puzzleGenerated(int symmetry, int difficulty); 303 | 304 | /** Clear previous game. */ 305 | void reset(); 306 | 307 | private: 308 | Cell* m_cells[9][9]; /**< game data */ 309 | int m_key_count[9]; /**< how many instances of each key are on the board */ 310 | Puzzle* m_puzzle; /**< the algorithm used to generate the board */ 311 | SolverLogic* m_notes; /**< the solver used to find the allowed possibles */ 312 | int m_active_key; /**< the current key */ 313 | Cell* m_active_cell; /**< the current cell */ 314 | Cell* m_hint_cell; /**< the last used cell for a hint */ 315 | bool m_auto_switch; /**< auto-switching is enabled */ 316 | bool m_highlight_active; /**< tracks if all instances of the current key should be highlighted */ 317 | bool m_notes_mode; /**< tracks if in notes mode */ 318 | bool m_finished; /**< tracks if game is finished */ 319 | bool m_loaded; /**< tracks if game has been loaded */ 320 | AutoNotes m_auto_notes; /**< tracks what fill mode should be used */ 321 | QLabel* m_message; /**< used to show messages to the player */ 322 | QUndoStack* m_moves; /**< history of player actions */ 323 | }; 324 | 325 | #endif // SIMSU_BOARD_H 326 | -------------------------------------------------------------------------------- /src/cell.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2021 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_CELL_H 8 | #define SIMSU_CELL_H 9 | 10 | #include "frame.h" 11 | class Board; 12 | class Puzzle; 13 | 14 | /** 15 | * %Cell on the game board. 16 | * 17 | * This class represents a single number cell on the board. It tracks what 18 | * answers or notes the player has set in a list of Cell::State instances. 19 | * It also tracks if the current state is an incorrect answer, as well as 20 | * which other cells it may be in conflict with. 21 | */ 22 | class Cell : public Frame 23 | { 24 | public: 25 | /** 26 | * Constrcts a cell. 27 | * 28 | * @param column cell column 29 | * @param row cell row 30 | * @param board the game board 31 | * @param parent the parent widget 32 | */ 33 | Cell(int column, int row, Board* board, QWidget* parent = nullptr); 34 | 35 | /** @return column of cell. */ 36 | int column() const; 37 | 38 | /** @return row of cell. */ 39 | int row() const; 40 | 41 | /** Returns @c true if cell is correct value; @c false otherwise. */ 42 | bool isCorrect() const; 43 | 44 | /** Returns the current value of the cell. */ 45 | int value() const 46 | { 47 | return m_states[m_current_state].value; 48 | } 49 | 50 | /** 51 | * Sets the puzzle used to determine if cell is a given, and what value it 52 | * should have. 53 | * 54 | * @param puzzle the puzzle instance 55 | */ 56 | void setPuzzle(Puzzle* puzzle); 57 | 58 | /** 59 | * Set which state to use for values. 60 | * 61 | * @param state the state to use for values. 62 | */ 63 | void setState(int state); 64 | 65 | /** Sets if it should show player if the value they set is wrong. */ 66 | void showWrong(bool show); 67 | 68 | protected: 69 | /** Override parent function to add partial highlight to cells in column and row. */ 70 | void focusInEvent(QFocusEvent* event) override; 71 | 72 | /** Override parent function to remove partial highlight from cells in column and row. */ 73 | void focusOutEvent(QFocusEvent* event) override; 74 | 75 | /** Override parent function to handle moving focus or inputting a guess. */ 76 | void keyPressEvent(QKeyEvent* event) override; 77 | 78 | /** Override parent function to make sure cell has focus highlight. */ 79 | void enterEvent(QEnterEvent* event) override; 80 | 81 | /** Override parent function to handle inputting a guess. */ 82 | void mousePressEvent(QMouseEvent* event) override; 83 | 84 | /** Override parent function to draw cell value and highlight. */ 85 | void paintEvent(QPaintEvent* event) override; 86 | 87 | /** Override parent function to set font size used in paintEvent(). */ 88 | void resizeEvent(QResizeEvent* event) override; 89 | 90 | private: 91 | /** 92 | * %Cell state class. 93 | * 94 | * This class is used to track what answer and guesses a player has inputted. 95 | */ 96 | struct State 97 | { 98 | int value; /**< answer set by player */ 99 | bool notes[9]; /**< notes set by player */ 100 | bool autonotes[9]; /** autonotes unchanged by player */ 101 | }; 102 | QList m_states; /**< list of all changes player has made */ 103 | int m_current_state; /**< which state is current */ 104 | 105 | private: 106 | /** 107 | * Determine if cell has the same answer as another cell. 108 | * 109 | * @param cell the cell to check for conflicts 110 | */ 111 | void checkConflict(Cell* cell); 112 | 113 | /** 114 | * Store answer or notes. 115 | * 116 | * Inserts a new state containing answer or notes. It first removes all 117 | * states after the current state to make undo/redo work properly. 118 | */ 119 | void updateValue(); 120 | 121 | /** 122 | * Determine font to use for in paintEvent(). 123 | * 124 | * Checks if current state has notes or answer and choose a font size 125 | * that is appropriate for notes or answers. 126 | */ 127 | void updateFont(); 128 | 129 | private: 130 | int m_column; /**< column on board */ 131 | int m_row; /**< row on board */ 132 | QList m_conflicts; /**< cells the current state conflicts with */ 133 | bool m_wrong; /**< track if value of current state is wrong */ 134 | bool m_given; /**< @c true if a given on the board and therefore not editable */ 135 | Board* m_board; /**< the game board */ 136 | Puzzle* m_puzzle; /**< the algorithm used to generate the board */ 137 | }; 138 | 139 | #endif // SIMSU_CELL_H 140 | -------------------------------------------------------------------------------- /src/frame.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2016 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include "frame.h" 8 | 9 | #include 10 | 11 | //----------------------------------------------------------------------------- 12 | 13 | Frame::Frame(QWidget* parent) 14 | : QWidget(parent) 15 | , m_highlight(false) 16 | , m_highlight_border(false) 17 | , m_highlight_partial(false) 18 | , m_highlight_mid(false) 19 | { 20 | } 21 | 22 | //----------------------------------------------------------------------------- 23 | 24 | void Frame::paintEvent(QPaintEvent* event) 25 | { 26 | QWidget::paintEvent(event); 27 | 28 | QPainter painter(this); 29 | painter.setRenderHint(QPainter::Antialiasing, true); 30 | 31 | QColor background = palette().highlight().color(); 32 | 33 | painter.setPen(QPen((m_highlight || m_highlight_mid) ? background : palette().dark().color(), 0)); 34 | painter.setBrush(palette().color(backgroundRole())); 35 | painter.drawRoundedRect(QRectF(0.5, 0.5, width() - 1, height() - 1), 3, 3); 36 | 37 | if (m_highlight) { 38 | background.setAlphaF(0.5); 39 | painter.setBrush(background); 40 | painter.drawRoundedRect(QRectF(0.5, 0.5, width() - 1, height() - 1), 3, 3); 41 | } else if (m_highlight_mid) { 42 | background.setAlphaF(0.3); 43 | painter.setBrush(background); 44 | painter.drawRoundedRect(QRectF(0.5, 0.5, width() - 1, height() - 1), 3, 3); 45 | } else if (m_highlight_partial) { 46 | background.setAlphaF(0.1); 47 | painter.setBrush(background); 48 | painter.drawRoundedRect(QRectF(0.5, 0.5, width() - 1, height() - 1), 3, 3); 49 | } 50 | 51 | if (m_highlight_border) { 52 | painter.setPen(QPen(palette().color(QPalette::Highlight), 2)); 53 | painter.setBrush(Qt::NoBrush); 54 | painter.drawRoundedRect(QRectF(1.5, 1.5, width() - 3, height() - 3), 3, 3); 55 | } 56 | } 57 | 58 | //----------------------------------------------------------------------------- 59 | -------------------------------------------------------------------------------- /src/frame.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2016 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_FRAME_H 8 | #define SIMSU_FRAME_H 9 | 10 | #include 11 | 12 | /** 13 | * Graphical frame widget. 14 | * 15 | * This class is a custom frame to give the cells and game board edges. 16 | */ 17 | class Frame : public QWidget 18 | { 19 | public: 20 | /** Constructs a frame. */ 21 | explicit Frame(QWidget* parent = nullptr); 22 | 23 | protected: 24 | /** Override parent function to draw border and custom background color. */ 25 | void paintEvent(QPaintEvent* event) override; 26 | 27 | /** Sets whether or not background should be drawn in full highlight. */ 28 | void setHighlight(bool highlight) 29 | { 30 | m_highlight = highlight; 31 | } 32 | 33 | /** Sets whether or not border should be drawn in highlight. */ 34 | void setHighlightBorder(bool highlight) 35 | { 36 | m_highlight_border = highlight; 37 | } 38 | 39 | /** Sets whether or not background should be drawn in partial highlight. */ 40 | void setHighlightPartial(bool highlight) 41 | { 42 | m_highlight_partial = highlight; 43 | } 44 | 45 | /** Sets whether or not background should be drawn in partial highlight. */ 46 | void setHighlightMid(bool mid) 47 | { 48 | m_highlight_mid = mid; 49 | } 50 | 51 | private: 52 | bool m_highlight; /**< tracks if background should be drawn highlighted */ 53 | bool m_highlight_border; /**< tracks if border should be drawn highlighted */ 54 | bool m_highlight_partial; /**< tracks if background should be drawn only partially highlighted */ 55 | bool m_highlight_mid; /**< tracks if background should be drawn mid highlighted */ 56 | }; 57 | 58 | #endif // SIMSU_FRAME_H 59 | -------------------------------------------------------------------------------- /src/locale_dialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2010-2020 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include "locale_dialog.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | //----------------------------------------------------------------------------- 26 | 27 | QString LocaleDialog::m_current; 28 | QString LocaleDialog::m_path; 29 | QString LocaleDialog::m_appname; 30 | 31 | //----------------------------------------------------------------------------- 32 | 33 | LocaleDialog::LocaleDialog(QWidget* parent) 34 | : QDialog(parent, Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) 35 | { 36 | QString title = parent ? parent->window()->windowTitle() : QString(); 37 | setWindowTitle(!title.isEmpty() ? title : QCoreApplication::applicationName()); 38 | 39 | QLabel* text = new QLabel(tr("Select application language:"), this); 40 | 41 | m_translations = new QComboBox(this); 42 | m_translations->addItem(tr("")); 43 | const QStringList translations = findTranslations(); 44 | for (QString translation : translations) { 45 | if (translation.startsWith("qt")) { 46 | continue; 47 | } 48 | translation.remove(m_appname); 49 | m_translations->addItem(languageName(translation), translation); 50 | } 51 | int index = std::max(0, m_translations->findData(m_current)); 52 | m_translations->setCurrentIndex(index); 53 | 54 | QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); 55 | connect(buttons, &QDialogButtonBox::accepted, this, &LocaleDialog::accept); 56 | connect(buttons, &QDialogButtonBox::rejected, this, &LocaleDialog::reject); 57 | 58 | QVBoxLayout* layout = new QVBoxLayout(this); 59 | layout->setSizeConstraint(QLayout::SetFixedSize); 60 | layout->addWidget(text); 61 | layout->addWidget(m_translations); 62 | layout->addWidget(buttons); 63 | } 64 | 65 | //----------------------------------------------------------------------------- 66 | 67 | void LocaleDialog::loadTranslator(const QString& name, const QString& datadir) 68 | { 69 | m_appname = name; 70 | 71 | // Find translator path 72 | m_path = datadir + "/translations/"; 73 | 74 | // Find current locale 75 | m_current = QSettings().value("Locale/Language").toString(); 76 | if (!m_current.isEmpty()) { 77 | QLocale::setDefault(QLocale(m_current)); 78 | } 79 | const QString locale = QLocale().name(); 80 | 81 | // Load translators 82 | static QTranslator translator; 83 | if (translator.load(m_appname + locale, m_path)) { 84 | QCoreApplication::installTranslator(&translator); 85 | 86 | const QString path = QLibraryInfo::path(QLibraryInfo::TranslationsPath); 87 | 88 | static QTranslator qtbase_translator; 89 | if (qtbase_translator.load("qtbase_" + locale, m_path) || qtbase_translator.load("qtbase_" + locale, path)) { 90 | QCoreApplication::installTranslator(&qtbase_translator); 91 | } 92 | 93 | static QTranslator qt_translator; 94 | if (qt_translator.load("qt_" + locale, m_path) || qt_translator.load("qt_" + locale, path)) { 95 | QCoreApplication::installTranslator(&qt_translator); 96 | } 97 | } 98 | } 99 | 100 | //----------------------------------------------------------------------------- 101 | 102 | QString LocaleDialog::languageName(const QString& language) 103 | { 104 | QString name; 105 | const QLocale locale(language); 106 | if (language.contains('_')) { 107 | if (locale.name() == language) { 108 | name = locale.nativeLanguageName() + " (" + locale.nativeTerritoryName() + ")"; 109 | } else { 110 | name = locale.nativeLanguageName() + " (" + language + ")"; 111 | } 112 | } else { 113 | name = locale.nativeLanguageName(); 114 | } 115 | if (name.isEmpty() || name == "C") { 116 | if (language == "eo") { 117 | name = "Esperanto"; 118 | } else { 119 | name = language; 120 | } 121 | } 122 | if (locale.textDirection() == Qt::RightToLeft) { 123 | name.prepend(QChar(0x202b)); 124 | } 125 | return name; 126 | } 127 | 128 | //----------------------------------------------------------------------------- 129 | 130 | QStringList LocaleDialog::findTranslations() 131 | { 132 | QStringList result = QDir(m_path, "*.qm").entryList(QDir::Files); 133 | result.replaceInStrings(".qm", ""); 134 | return result; 135 | } 136 | 137 | //----------------------------------------------------------------------------- 138 | 139 | void LocaleDialog::accept() 140 | { 141 | int current = m_translations->findData(m_current); 142 | if (current == m_translations->currentIndex()) { 143 | return reject(); 144 | } 145 | QDialog::accept(); 146 | 147 | m_current = m_translations->itemData(m_translations->currentIndex()).toString(); 148 | QSettings().setValue("Locale/Language", m_current); 149 | QMessageBox::information(this, tr("Note"), tr("Please restart this application for the change in language to take effect."), QMessageBox::Ok); 150 | } 151 | 152 | //----------------------------------------------------------------------------- 153 | -------------------------------------------------------------------------------- /src/locale_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2010-2013 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_LOCALE_DIALOG_H 8 | #define SIMSU_LOCALE_DIALOG_H 9 | 10 | #include 11 | class QComboBox; 12 | 13 | /** 14 | * Dialog to set application language. 15 | * 16 | * This class handles setting the application language when the application is 17 | * launched, as well as allowing the user to choose a different language for 18 | * future launches. 19 | */ 20 | class LocaleDialog : public QDialog 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | /** 26 | * Construct a dialog to choose application language. 27 | * 28 | * @param parent the parent widget of the dialog 29 | */ 30 | explicit LocaleDialog(QWidget* parent = nullptr); 31 | 32 | /** 33 | * Load the stored language into the application; defaults to system language. 34 | * 35 | * @param appname application name to prepend to translation filenames 36 | * @param datadir location to search for translations 37 | */ 38 | static void loadTranslator(const QString& appname, const QString& datadir); 39 | 40 | /** 41 | * Fetch native language name for QLocale name. 42 | * 43 | * @param language QLocale name to look up 44 | * @return translated language name 45 | */ 46 | static QString languageName(const QString& language); 47 | 48 | public Q_SLOTS: 49 | /** Override parent function to store application language. */ 50 | void accept() override; 51 | 52 | private: 53 | /** 54 | * Fetch list of application translations. 55 | * 56 | * @return list of QLocale names 57 | */ 58 | static QStringList findTranslations(); 59 | 60 | private: 61 | QComboBox* m_translations; /**< list of found translations */ 62 | 63 | static QString m_current; /**< stored application language */ 64 | static QString m_path; /**< location of translations; found in loadTranslator() */ 65 | static QString m_appname; /**< application name passed to loadTranslator() */ 66 | }; 67 | 68 | #endif // SIMSU_LOCALE_DIALOG_H 69 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2022 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include "locale_dialog.h" 8 | #include "window.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /** 17 | * Program entry point. 18 | * 19 | * @param argc amount of command line arguments 20 | * @param argv command line arguments 21 | * @return @c 0 on successful exit 22 | */ 23 | int main(int argc, char** argv) 24 | { 25 | QApplication app(argc, argv); 26 | app.setApplicationName("Simsu"); 27 | app.setApplicationVersion(VERSIONSTR); 28 | app.setApplicationDisplayName(Window::tr("Simsu")); 29 | app.setOrganizationDomain("gottcode.org"); 30 | app.setOrganizationName("GottCode"); 31 | #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) 32 | app.setWindowIcon(QIcon::fromTheme("simsu", QIcon(":/simsu.png"))); 33 | app.setDesktopFileName("simsu"); 34 | #endif 35 | 36 | // Find application data 37 | const QString appdir = app.applicationDirPath(); 38 | const QString datadir = QDir::cleanPath(appdir + "/" + SIMSU_DATADIR); 39 | 40 | // Handle portability 41 | #ifdef Q_OS_MAC 42 | const QFileInfo portable(appdir + "/../../../Data"); 43 | #else 44 | const QFileInfo portable(appdir + "/Data"); 45 | #endif 46 | if (portable.exists() && portable.isWritable()) { 47 | QSettings::setDefaultFormat(QSettings::IniFormat); 48 | QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, portable.absoluteFilePath() + "/Settings"); 49 | } 50 | 51 | // Load application language 52 | LocaleDialog::loadTranslator("simsu_", datadir); 53 | 54 | // Handle commandline 55 | QCommandLineParser parser; 56 | parser.setApplicationDescription(Window::tr("A basic Sudoku game")); 57 | parser.addHelpOption(); 58 | parser.addVersionOption(); 59 | parser.process(app); 60 | 61 | // Create main window 62 | Window window; 63 | window.show(); 64 | 65 | return app.exec(); 66 | } 67 | -------------------------------------------------------------------------------- /src/move.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2013 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include "move.h" 8 | 9 | #include "cell.h" 10 | 11 | //----------------------------------------------------------------------------- 12 | 13 | Move::Move(Cell* cell, int id, int column, int row, bool note, int value) 14 | : m_cell(cell) 15 | , m_id(id) 16 | { 17 | setText(QString("%1%2%3%4").arg(column).arg(row).arg(note ? "n" : "v").arg(value)); 18 | } 19 | 20 | //----------------------------------------------------------------------------- 21 | 22 | void Move::redo() 23 | { 24 | m_cell->setState(m_id + 1); 25 | } 26 | 27 | //----------------------------------------------------------------------------- 28 | 29 | void Move::undo() 30 | { 31 | m_cell->setState(m_id); 32 | } 33 | 34 | //----------------------------------------------------------------------------- 35 | -------------------------------------------------------------------------------- /src/move.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2013 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_MOVE_H 8 | #define SIMSU_MOVE_H 9 | 10 | class Cell; 11 | 12 | #include 13 | 14 | /** 15 | * Player move. 16 | * 17 | * This class represents an action by the player. It only stores the ID of the 18 | * current state of a cell so that it can tell the cell to switch states. 19 | */ 20 | class Move : public QUndoCommand 21 | { 22 | public: 23 | /** 24 | * Constructs a move. 25 | * 26 | * @param cell the cell to modify 27 | * @param id the current state of the cell 28 | * @param column the column of the cell 29 | * @param row the row of the cell 30 | * @param note the note, if any, that was set in this move 31 | * @param value the value, if any, that was set in this move 32 | */ 33 | Move(Cell* cell, int id, int column, int row, bool note, int value); 34 | 35 | /** Switch cell to the answer or notes of this move. */ 36 | void redo() override; 37 | 38 | /** Switch cell to the answer or notes from before this move. */ 39 | void undo() override; 40 | 41 | private: 42 | Cell* m_cell; /**< cell to modify */ 43 | int m_id; /**< state of cell to start from */ 44 | }; 45 | 46 | #endif // SIMSU_MOVE_H 47 | -------------------------------------------------------------------------------- /src/new_game_page.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2021 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include "new_game_page.h" 8 | 9 | #include "pattern.h" 10 | #include "puzzle.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | //----------------------------------------------------------------------------- 28 | 29 | namespace 30 | { 31 | 32 | class LineEdit : public QLineEdit 33 | { 34 | public: 35 | explicit LineEdit(QWidget* parent = nullptr) 36 | : QLineEdit(parent) 37 | { 38 | setMaxLength(1); 39 | setAlignment(Qt::AlignCenter); 40 | setMinimumWidth(1); 41 | } 42 | 43 | protected: 44 | void focusInEvent(QFocusEvent* e) override 45 | { 46 | QLineEdit::focusInEvent(e); 47 | QTimer::singleShot(0, this, &QLineEdit::selectAll); 48 | } 49 | }; 50 | 51 | } 52 | 53 | //----------------------------------------------------------------------------- 54 | 55 | NewGamePage::NewGamePage(QWidget* parent) 56 | : QWidget(parent) 57 | , m_current_difficulty(0) 58 | { 59 | m_contents = new QStackedWidget(this); 60 | 61 | QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); 62 | connect(buttons, &QDialogButtonBox::accepted, this, &NewGamePage::playGame); 63 | connect(buttons, &QDialogButtonBox::rejected, this, &NewGamePage::cancel); 64 | 65 | m_play_button = buttons->button(QDialogButtonBox::Ok); 66 | m_play_button->setText(tr("Play Game")); 67 | m_play_button->hide(); 68 | 69 | m_create_button = new QPushButton(tr("Create Your Own"), this); 70 | m_create_button->setCheckable(true); 71 | connect(m_create_button, &QPushButton::toggled, this, &NewGamePage::showCustom); 72 | 73 | QGridLayout* layout = new QGridLayout(this); 74 | layout->setRowStretch(0, 1); 75 | layout->setRowMinimumHeight(1, 12); 76 | layout->addWidget(m_contents, 0, 0, 1, 2); 77 | layout->addWidget(m_create_button, 2, 0); 78 | layout->addWidget(buttons, 2, 1); 79 | 80 | 81 | // Create widgets for generated puzzles 82 | QWidget* generated = new QWidget(this); 83 | m_contents->addWidget(generated); 84 | 85 | // Create symmetry list 86 | m_symmetry = new QListWidget(generated); 87 | m_symmetry->setIconSize(QSize(60, 60)); 88 | m_symmetry->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 89 | m_symmetry->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); 90 | for (int i = Pattern::Rotational180; i <= Pattern::None; ++i) { 91 | new QListWidgetItem(QIcon(Pattern::icon(i)).pixmap(60, 60), Pattern::name(i), m_symmetry); 92 | } 93 | 94 | // Create difficulty buttons for starting a new game 95 | for (int i = Puzzle::VeryEasy; i <= Puzzle::Hard; ++i) { 96 | QPushButton* button = new QPushButton(Puzzle::difficultyString(i), generated); 97 | button->setAutoDefault(true); 98 | m_difficulty.append(button); 99 | connect(button, &QPushButton::clicked, this, [this, i]() { 100 | Q_EMIT generatePuzzle(m_symmetry->currentRow(), i); 101 | }); 102 | } 103 | 104 | // Lay out generated widgets 105 | QVBoxLayout* generated_layout = new QVBoxLayout(generated); 106 | generated_layout->setContentsMargins(0,0,0,0); 107 | generated_layout->setSpacing(2); 108 | generated_layout->addWidget(m_symmetry); 109 | generated_layout->addSpacing(12); 110 | for (QPushButton* button : std::as_const(m_difficulty)) { 111 | generated_layout->addWidget(button); 112 | } 113 | 114 | 115 | // Create widgets for custom puzzles 116 | QWidget* custom = new QWidget(this); 117 | m_contents->addWidget(custom); 118 | 119 | // Create line edits 120 | QIntValidator* validator = new QIntValidator(1, 9, this); 121 | for (int i = 0; i < 81; ++i) { 122 | QLineEdit* edit = new LineEdit(custom); 123 | edit->setValidator(validator); 124 | connect(edit, &QLineEdit::textChanged, this, &NewGamePage::showConflicts); 125 | m_custom.append(edit); 126 | } 127 | 128 | // Lay out custom widgets 129 | QGridLayout* custom_layout = new QGridLayout(custom); 130 | custom_layout->setContentsMargins(0,0,0,0); 131 | custom_layout->setColumnStretch(0, 100); 132 | custom_layout->setColumnStretch(12, 100); 133 | custom_layout->setColumnMinimumWidth(4, 6); 134 | custom_layout->setColumnMinimumWidth(8, 6); 135 | custom_layout->setRowStretch(0, 1); 136 | custom_layout->setRowStretch(12, 1); 137 | custom_layout->setRowMinimumHeight(4, 6); 138 | custom_layout->setRowMinimumHeight(8, 6); 139 | custom_layout->setSpacing(1); 140 | for (int r = 0; r < 9; ++r) { 141 | const int y = r * 9; 142 | const int y_offset = (y / 27) + 1; 143 | for (int c = 0; c < 9; ++c) { 144 | const int x_offset = (c / 3) + 1; 145 | QLineEdit* edit = m_custom[c + y]; 146 | custom_layout->addWidget(edit, r + y_offset, c + x_offset); 147 | } 148 | } 149 | } 150 | 151 | //----------------------------------------------------------------------------- 152 | 153 | void NewGamePage::reset() 154 | { 155 | m_create_button->setChecked(false); 156 | 157 | // Reset widgets for custom puzzle 158 | m_contents->setCurrentIndex(1); 159 | 160 | for (QLineEdit* edit : std::as_const(m_custom)) { 161 | edit->clear(); 162 | } 163 | 164 | m_custom[0]->setFocus(); 165 | 166 | // Reset widgets for generated puzzle 167 | m_contents->setCurrentIndex(0); 168 | 169 | QSettings settings; 170 | 171 | const int symmetry = qBound(int(Pattern::Rotational180), settings.value("Symmetry", Pattern::Rotational180).toInt(), int(Pattern::None)); 172 | QListWidgetItem* item = m_symmetry->item(symmetry); 173 | m_symmetry->setCurrentItem(item); 174 | m_symmetry->scrollToItem(item, QAbstractItemView::PositionAtCenter); 175 | 176 | m_current_difficulty = qBound(int(Puzzle::VeryEasy), settings.value("Difficulty", Puzzle::VeryEasy).toInt(), int(Puzzle::Hard)) - Puzzle::VeryEasy; 177 | m_difficulty[m_current_difficulty]->setFocus(); 178 | } 179 | 180 | //----------------------------------------------------------------------------- 181 | 182 | void NewGamePage::keyPressEvent(QKeyEvent* event) 183 | { 184 | if ((m_contents->currentIndex() == 1) && (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) { 185 | m_play_button->click(); 186 | } else { 187 | QWidget::keyPressEvent(event); 188 | } 189 | } 190 | 191 | //----------------------------------------------------------------------------- 192 | 193 | void NewGamePage::playGame() 194 | { 195 | // Fetch givens entered by player 196 | std::array givens; 197 | for (int i = 0; i < 81; ++i) { 198 | givens[i] = m_custom[i]->text().toInt(); 199 | } 200 | 201 | // Start game 202 | Q_EMIT loadPuzzle(givens); 203 | } 204 | 205 | //----------------------------------------------------------------------------- 206 | 207 | void NewGamePage::showConflicts() 208 | { 209 | // Reset cells 210 | QPalette p = palette(); 211 | for (QLineEdit* edit : std::as_const(m_custom)) { 212 | edit->setPalette(p); 213 | } 214 | 215 | p.setColor(QPalette::Text, Qt::white); 216 | p.setColor(QPalette::Base, Qt::red); 217 | std::array found; 218 | 219 | // Find conflicts in rows 220 | for (int r = 0; r < 81; r += 9) { 221 | found.fill(nullptr); 222 | for (int c = 0; c < 9; ++c) { 223 | QLineEdit* edit = m_custom[c + r]; 224 | int value = edit->text().toInt(); 225 | if (!value) { 226 | continue; 227 | } 228 | --value; 229 | 230 | if (found[value]) { 231 | found[value]->setPalette(p); 232 | edit->setPalette(p); 233 | } else { 234 | found[value] = edit; 235 | } 236 | } 237 | } 238 | 239 | // Find conflicts in columns 240 | for (int c = 0; c < 9; ++c) { 241 | found.fill(nullptr); 242 | for (int r = 0; r < 81; r += 9) { 243 | QLineEdit* edit = m_custom[c + r]; 244 | int value = edit->text().toInt(); 245 | if (!value) { 246 | continue; 247 | } 248 | --value; 249 | 250 | if (found[value]) { 251 | found[value]->setPalette(p); 252 | edit->setPalette(p); 253 | } else { 254 | found[value] = edit; 255 | } 256 | } 257 | } 258 | 259 | // Find conflicts in boxes 260 | for (int box_r = 0; box_r < 9; box_r += 3) { 261 | for (int box_c = 0; box_c < 9; box_c += 3) { 262 | found.fill(nullptr); 263 | for (int r = 0; r < 3; ++r) { 264 | const int y = (r + box_r) * 9; 265 | for (int c = 0; c < 3; ++c) { 266 | QLineEdit* edit = m_custom[c + box_c + y]; 267 | int value = edit->text().toInt(); 268 | if (!value) { 269 | continue; 270 | } 271 | --value; 272 | 273 | if (found[value]) { 274 | found[value]->setPalette(p); 275 | edit->setPalette(p); 276 | } else { 277 | found[value] = edit; 278 | } 279 | } 280 | } 281 | } 282 | } 283 | } 284 | 285 | //----------------------------------------------------------------------------- 286 | 287 | void NewGamePage::showCustom(bool show) 288 | { 289 | if (show) { 290 | m_contents->setCurrentIndex(1); 291 | m_play_button->show(); 292 | m_custom[0]->setFocus(); 293 | } else { 294 | m_contents->setCurrentIndex(0); 295 | m_play_button->hide(); 296 | m_difficulty[m_current_difficulty]->setFocus(); 297 | } 298 | } 299 | 300 | //----------------------------------------------------------------------------- 301 | -------------------------------------------------------------------------------- /src/new_game_page.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2021 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_NEW_GAME_PAGE_H 8 | #define SIMSU_NEW_GAME_PAGE_H 9 | 10 | #include 11 | class QLineEdit; 12 | class QListWidget; 13 | class QPushButton; 14 | class QStackedWidget; 15 | 16 | /** 17 | * @brief The NewGamePage class allows the player to choose the settings for a new game. 18 | */ 19 | class NewGamePage : public QWidget 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | /** 25 | * Constructs the page. 26 | */ 27 | explicit NewGamePage(QWidget* parent = nullptr); 28 | 29 | /** 30 | * Resets values and shows settings for computer generated games. 31 | */ 32 | void reset(); 33 | 34 | Q_SIGNALS: 35 | /** 36 | * This signal is emitted when the player cancels starting a new game. 37 | */ 38 | void cancel(); 39 | 40 | /** 41 | * This signal is emitted when the player starts a new game. 42 | * 43 | * @param symmetry specify mirroring of givens 44 | * @param difficulty specify how hard to make puzzle 45 | */ 46 | void generatePuzzle(int symmetry, int difficulty); 47 | 48 | /** 49 | * This signal is emitted when the player starts a custom game. 50 | * 51 | * @param givens the values chosen by the player to build the board 52 | */ 53 | void loadPuzzle(const std::array& givens); 54 | 55 | protected: 56 | /** 57 | * Override parent function to start new game when enter is pressed. 58 | */ 59 | void keyPressEvent(QKeyEvent* event) override; 60 | 61 | private Q_SLOTS: 62 | /** 63 | * Handles starting a player-entered game. 64 | */ 65 | void playGame(); 66 | 67 | /** 68 | * Shows if player has entered givens that conflict with each other. 69 | */ 70 | void showConflicts(); 71 | 72 | /** 73 | * Switches what settings are visible to the player. 74 | * 75 | * @param show if @c true, show the widgets for building a custom game 76 | */ 77 | void showCustom(bool show); 78 | 79 | private: 80 | QStackedWidget* m_contents; /**< contains widgets for computer games and player entered games */ 81 | QPushButton* m_create_button; /**< button to show settings for a custom game */ 82 | QPushButton* m_play_button; /**< button to start a custom game */ 83 | 84 | QListWidget* m_symmetry; /**< list of board symmetries */ 85 | QList m_difficulty; /**< buttons to choose difficulty and start game */ 86 | int m_current_difficulty; /**< the difficulty most recently chosen by the player */ 87 | 88 | QList m_custom; /**< buttons to set the givens of a new game */ 89 | }; 90 | 91 | #endif // SIMSU_NEW_GAME_PAGE_H 92 | -------------------------------------------------------------------------------- /src/pattern.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2017 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_PATTERN_H 8 | #define SIMSU_PATTERN_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | * %Pattern of givens. 17 | * 18 | * This class controls the placement of the givens to make them symmetrical. 19 | */ 20 | class Pattern 21 | { 22 | Q_DECLARE_TR_FUNCTIONS(Pattern); 23 | 24 | public: 25 | /** Specify how givens are mirrored when placed. */ 26 | enum Symmetry { 27 | Rotational180, /**< Givens are rotated 180° */ 28 | RotationalFull, /**< Givens are rotated 90° four times */ 29 | Horizontal, /**< Givens are reflected across horizontal axis */ 30 | Vertical, /**< Givens are reflected across vertical axis */ 31 | HorizontalVertical, /**< Givens are reflected across both horizontal and vertical axes */ 32 | Diagonal, /**< Givens are reflected across top-left to bottom-right axis */ 33 | AntiDiagonal, /**< Givens are reflected across top-right to bottom-left axis */ 34 | DiagonalAntiDiagonal, /**< Givens are reflected across both diagonal axes */ 35 | FullDihedral, /**< Givens are reflected across both horizontal and vertical axes and rotated 90° four times */ 36 | Random, /**< Choose a symmetry at random */ 37 | None /**< No symmetry at all */ 38 | }; 39 | 40 | /** Clean up pattern */ 41 | virtual ~Pattern() 42 | { 43 | } 44 | 45 | /** Returns amount of cells that are mirrored for each step. */ 46 | virtual int count() const = 0; 47 | 48 | /** 49 | * Returns the mirrored positions for a cell. 50 | * 51 | * @param cell the cell to mirror. 52 | */ 53 | virtual QList pattern(const int c, const int r) const = 0; 54 | 55 | /** 56 | * Returns the human readable name for a pattern. 57 | * 58 | * @param symmetry fetch the name of the specified pattern 59 | */ 60 | static QString name(int symmetry) 61 | { 62 | static QHash names; 63 | if (names.isEmpty()) { 64 | names[Rotational180] = tr("180° Rotational"); 65 | names[RotationalFull] = tr("Full Rotational"); 66 | names[Horizontal] = tr("Horizontal"); 67 | names[Vertical] = tr("Vertical"); 68 | names[HorizontalVertical] = tr("Horizontal & Vertical"); 69 | names[Diagonal] = tr("Diagonal"); 70 | names[AntiDiagonal] = tr("Anti-Diagonal"); 71 | names[DiagonalAntiDiagonal] = tr("Diagonal & Anti-Diagonal"); 72 | names[FullDihedral] = tr("Full Dihedral"); 73 | names[Random] = tr("Random"); 74 | names[None] = tr("None"); 75 | } 76 | return names.value(symmetry); 77 | } 78 | 79 | /** 80 | * Returns the preview image for a pattern. 81 | * 82 | * @param symmetry fetch the preview image for the specified pattern 83 | */ 84 | static QString icon(int symmetry) 85 | { 86 | static QHash icons; 87 | if (icons.isEmpty()) { 88 | icons[Rotational180] = ":/rotational_180.png"; 89 | icons[RotationalFull] = ":/rotational_full.png"; 90 | icons[Horizontal] = ":/horizontal.png"; 91 | icons[Vertical] = ":/vertical.png"; 92 | icons[HorizontalVertical] = ":/horizontal_vertical.png"; 93 | icons[Diagonal] = ":/diagonal.png"; 94 | icons[AntiDiagonal] = ":/anti_diagonal.png"; 95 | icons[DiagonalAntiDiagonal] = ":/diagonal_anti_diagonal.png"; 96 | icons[FullDihedral] = ":/dihedral.png"; 97 | icons[Random] = ":/random.png"; 98 | icons[None] = ":/none.png"; 99 | } 100 | return icons.value(symmetry); 101 | } 102 | 103 | protected: 104 | /** 105 | * Returns the array index of a point. 106 | * 107 | * @param c the column 108 | * @param r the row 109 | */ 110 | int point(const int c, const int r) const 111 | { 112 | return c + (r * 9); 113 | } 114 | }; 115 | 116 | /** 117 | * %Pattern where givens are reflected across both horizontal and vertical 118 | * axes and rotated 90° four times. 119 | */ 120 | class PatternFullDihedral : public Pattern 121 | { 122 | public: 123 | int count() const override 124 | { 125 | return 8; 126 | } 127 | 128 | QList pattern(const int c, const int r) const override 129 | { 130 | return { 131 | point(c, r), 132 | point(c, 8 - r), 133 | point(8 - r, c), 134 | point(r, c), 135 | point(8 - c, 8 - r), 136 | point(8 - c, r), 137 | point(r, 8 - c), 138 | point(8 - r, 8 - c) 139 | }; 140 | } 141 | }; 142 | 143 | /** %Pattern where givens are rotated 180°. */ 144 | class PatternRotational180 : public Pattern 145 | { 146 | public: 147 | int count() const override 148 | { 149 | return 2; 150 | } 151 | 152 | QList pattern(const int c, const int r) const override 153 | { 154 | return { 155 | point(c, r), 156 | point(8 - c, 8 - r) 157 | }; 158 | } 159 | }; 160 | 161 | /** %Pattern where givens are rotated 90° four times. */ 162 | class PatternRotationalFull : public Pattern 163 | { 164 | public: 165 | int count() const override 166 | { 167 | return 4; 168 | } 169 | 170 | QList pattern(const int c, const int r) const override 171 | { 172 | return { 173 | point(c, r), 174 | point(8 - r, c), 175 | point(8 - c, 8 - r), 176 | point(r, 8 - c) 177 | }; 178 | } 179 | }; 180 | 181 | /** %Pattern where givens are reflected across horizontal axis. */ 182 | class PatternHorizontal : public Pattern 183 | { 184 | public: 185 | int count() const override 186 | { 187 | return 2; 188 | } 189 | 190 | QList pattern(const int c, const int r) const override 191 | { 192 | return { 193 | point(c, r), 194 | point(8 - c, r) 195 | }; 196 | } 197 | }; 198 | 199 | /** %Pattern where givens are reflected across vertical axis. */ 200 | class PatternVertical : public Pattern 201 | { 202 | public: 203 | int count() const override 204 | { 205 | return 2; 206 | } 207 | 208 | QList pattern(const int c, const int r) const override 209 | { 210 | return { 211 | point(c, r), 212 | point(c, 8 - r) 213 | }; 214 | } 215 | }; 216 | 217 | /** %Pattern where givens are reflected across both horizontal and vertical axes. */ 218 | class PatternHorizontalVertical : public Pattern 219 | { 220 | public: 221 | int count() const override 222 | { 223 | return 4; 224 | } 225 | 226 | QList pattern(const int c, const int r) const override 227 | { 228 | return { 229 | point(c, r), 230 | point(8 - c, r), 231 | point(c, 8 - r), 232 | point(8 - c, 8 - r) 233 | }; 234 | } 235 | }; 236 | 237 | /** %Pattern where givens are reflected across top-left to bottom-right axis. */ 238 | class PatternDiagonal : public Pattern 239 | { 240 | public: 241 | int count() const override 242 | { 243 | return 2; 244 | } 245 | 246 | QList pattern(const int c, const int r) const override 247 | { 248 | return { 249 | point(c, r), 250 | point(r, c) 251 | }; 252 | } 253 | }; 254 | 255 | /** %Pattern where givens are reflected across top-right to bottom-left axis. */ 256 | class PatternAntiDiagonal : public Pattern 257 | { 258 | public: 259 | int count() const override 260 | { 261 | return 2; 262 | } 263 | 264 | QList pattern(const int c, const int r) const override 265 | { 266 | return { 267 | point(c, r), 268 | point(8 - r, 8 - c) 269 | }; 270 | } 271 | }; 272 | 273 | /** %Pattern where givens are reflected across both diagonal axes. */ 274 | class PatternDiagonalAntiDiagonal : public Pattern 275 | { 276 | public: 277 | int count() const override 278 | { 279 | return 4; 280 | } 281 | 282 | QList pattern(const int c, const int r) const override 283 | { 284 | return { 285 | point(c, r), 286 | point(r, c), 287 | point(8 - r, 8 - c), 288 | point(8 - c, 8 - r) 289 | }; 290 | } 291 | }; 292 | 293 | /** %Pattern with no symmetry at all. */ 294 | class PatternNone : public Pattern 295 | { 296 | public: 297 | int count() const override 298 | { 299 | return 1; 300 | } 301 | 302 | QList pattern(const int c, const int r) const override 303 | { 304 | return { 305 | point(c, r) 306 | }; 307 | } 308 | }; 309 | 310 | #endif // SIMSU_PATTERN_H 311 | -------------------------------------------------------------------------------- /src/puzzle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2016 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include "puzzle.h" 8 | 9 | #include "pattern.h" 10 | #include "solver_dlx.h" 11 | #include "solver_logic.h" 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | //----------------------------------------------------------------------------- 19 | 20 | Puzzle::Puzzle(QObject* parent) 21 | : QObject(parent) 22 | , m_random(QRandomGenerator::securelySeeded()) 23 | , m_pattern(nullptr) 24 | , m_difficulty(VeryEasy) 25 | , m_generated(INT_MAX) 26 | , m_canceled(false) 27 | { 28 | } 29 | 30 | //----------------------------------------------------------------------------- 31 | 32 | Puzzle::~Puzzle() 33 | { 34 | cancel(); 35 | delete m_pattern; 36 | } 37 | 38 | //----------------------------------------------------------------------------- 39 | 40 | void Puzzle::cancel() 41 | { 42 | blockSignals(true); 43 | m_canceled.store(true, std::memory_order_relaxed); 44 | m_future.waitForFinished(); 45 | m_canceled.store(false, std::memory_order_relaxed); 46 | blockSignals(false); 47 | } 48 | 49 | //----------------------------------------------------------------------------- 50 | 51 | void Puzzle::generate(int symmetry, int difficulty) 52 | { 53 | cancel(); 54 | 55 | delete m_pattern; 56 | switch (symmetry) { 57 | case Pattern::FullDihedral: 58 | m_pattern = new PatternFullDihedral; 59 | break; 60 | case Pattern::Rotational180: 61 | m_pattern = new PatternRotational180; 62 | break; 63 | case Pattern::RotationalFull: 64 | m_pattern = new PatternRotationalFull; 65 | break; 66 | case Pattern::Horizontal: 67 | m_pattern = new PatternHorizontal; 68 | break; 69 | case Pattern::Vertical: 70 | m_pattern = new PatternVertical; 71 | break; 72 | case Pattern::HorizontalVertical: 73 | m_pattern = new PatternHorizontalVertical; 74 | break; 75 | case Pattern::Diagonal: 76 | m_pattern = new PatternDiagonal; 77 | break; 78 | case Pattern::AntiDiagonal: 79 | m_pattern = new PatternAntiDiagonal; 80 | break; 81 | case Pattern::DiagonalAntiDiagonal: 82 | m_pattern = new PatternDiagonalAntiDiagonal; 83 | break; 84 | case Pattern::None: 85 | default: 86 | m_pattern = new PatternNone; 87 | break; 88 | } 89 | 90 | m_difficulty = qBound(VeryEasy, Difficulty(difficulty), Hard); 91 | 92 | m_future = QtConcurrent::run([this, symmetry]() { 93 | int givens = 0; 94 | do { 95 | m_generated = INT_MAX; 96 | createSolution(); 97 | if (!createGivens()) { 98 | return; 99 | } 100 | 101 | givens = 81; 102 | for (int i = 0; i < 81; ++i) { 103 | givens -= !m_givens[i]; 104 | } 105 | } while ((givens > 30) || (m_generated != m_difficulty)); 106 | 107 | Q_EMIT generated(symmetry, m_difficulty); 108 | }); 109 | } 110 | 111 | //----------------------------------------------------------------------------- 112 | 113 | bool Puzzle::load(const std::array& givens) 114 | { 115 | cancel(); 116 | 117 | SolverDLX solver; 118 | if (solver.solvePuzzle(givens)) { 119 | m_givens = givens; 120 | m_solution = solver.solution(); 121 | return true; 122 | } else { 123 | return false; 124 | } 125 | } 126 | 127 | //----------------------------------------------------------------------------- 128 | 129 | void Puzzle::createSolution() 130 | { 131 | // Create list of initial values 132 | static const QList initial{1,2,3,4,5,6,7,8,9}; 133 | std::array, 81> cells; 134 | cells.fill(initial); 135 | 136 | // Reset solution grid 137 | m_solution.fill(0); 138 | 139 | // Fill solution grid 140 | for (int i = 0; i < 81; ++i) { 141 | const unsigned int r = i / 9; 142 | const unsigned int c = i % 9; 143 | const unsigned int box_row = (r / 3) * 3; 144 | const unsigned int box_col = (c / 3) * 3; 145 | 146 | // Reset cell in case of backtrack 147 | m_solution[i] = 0; 148 | 149 | QList& cell = cells[i]; 150 | std::shuffle(cell.begin(), cell.end(), m_random); 151 | 152 | Q_FOREVER { 153 | // Backtrack if there are no possiblities 154 | if (cell.isEmpty()) { 155 | cell = initial; 156 | i -= 2; 157 | break; 158 | } 159 | 160 | // Fetch value 161 | int value = cell.takeLast(); 162 | 163 | // Check for conflicts 164 | bool conflicts = false; 165 | for (unsigned int j = 0; j < 9; ++j) { 166 | conflicts |= (m_solution[j + (r * 9)] == value); 167 | conflicts |= (m_solution[c + (j * 9)] == value); 168 | } 169 | for (unsigned int row = box_row; row < box_row + 3; ++row) { 170 | for (unsigned int col = box_col; col < box_col + 3; ++col) { 171 | conflicts |= (m_solution[col + (row * 9)] == value); 172 | } 173 | } 174 | if (!conflicts) { 175 | m_solution[i] = value; 176 | break; 177 | } 178 | } 179 | } 180 | } 181 | 182 | //----------------------------------------------------------------------------- 183 | 184 | bool Puzzle::createGivens() 185 | { 186 | // Initialize givens 187 | m_givens = m_solution; 188 | 189 | // Initialize cells 190 | std::array cells; 191 | for (int i = 0; i < 81; ++i) { 192 | cells[i] = i; 193 | } 194 | std::shuffle(cells.begin(), cells.end(), m_random); 195 | 196 | // Remove as many givens as possible 197 | for (const int cell : cells) { 198 | const QList positions = m_pattern->pattern(cell % 9, cell / 9); 199 | 200 | bool valid = true; 201 | for (const int pos : positions) { 202 | valid &= bool(m_givens[pos]); 203 | } 204 | if (!valid) { 205 | continue; 206 | } 207 | 208 | for (const int pos : positions) { 209 | m_givens[pos] = 0; 210 | } 211 | if (!isUnique()) { 212 | for (const int pos : positions) { 213 | m_givens[pos] = m_solution[pos]; 214 | } 215 | } 216 | 217 | if (m_canceled.load(std::memory_order_relaxed)) { 218 | return false; 219 | } 220 | } 221 | return true; 222 | } 223 | 224 | //----------------------------------------------------------------------------- 225 | 226 | bool Puzzle::isUnique() 227 | { 228 | if (m_difficulty >= Hard) { 229 | static SolverDLX solver; 230 | if (!solver.solvePuzzle(m_givens)) { 231 | return false; 232 | } 233 | } 234 | 235 | static SolverLogic solver; 236 | const int generated = solver.solvePuzzle(m_givens, m_difficulty); 237 | if (generated > m_difficulty) { 238 | return false; 239 | } 240 | 241 | m_generated = generated; 242 | 243 | return true; 244 | } 245 | 246 | //----------------------------------------------------------------------------- 247 | -------------------------------------------------------------------------------- /src/puzzle.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2016 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_PUZZLE_H 8 | #define SIMSU_PUZZLE_H 9 | 10 | class Pattern; 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | /** 21 | * Layout generator. 22 | * 23 | * This class will build a layout of givens based upon the settings chosen. 24 | */ 25 | class Puzzle : public QObject 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | enum Difficulty { 31 | VeryEasy = 1, 32 | Easy, 33 | Medium, 34 | Hard, 35 | Unsolved 36 | }; 37 | 38 | /** Constructs a puzzle. */ 39 | explicit Puzzle(QObject* parent = nullptr); 40 | 41 | /** Clean up puzzle. */ 42 | ~Puzzle(); 43 | 44 | /** Abort currently running generation. */ 45 | void cancel(); 46 | 47 | /** 48 | * Creates a new layout. 49 | * 50 | * @param symmetry the pattern to use when laying out givens 51 | * @param difficulty specify how hard to make puzzle 52 | */ 53 | void generate(int symmetry, int difficulty); 54 | 55 | /** 56 | * Loads a layout. 57 | * 58 | * @param givens list of givens to use 59 | * @return @c true if the puzzle could be loaded 60 | */ 61 | bool load(const std::array& givens); 62 | 63 | /** 64 | * Returns the given at the requested position. 65 | * 66 | * @param x the column of the given 67 | * @param y the row of the given 68 | */ 69 | int given(int x, int y) const 70 | { 71 | Q_ASSERT(x >= 0); 72 | Q_ASSERT(x < 9 ); 73 | Q_ASSERT(y >= 0); 74 | Q_ASSERT(y < 9); 75 | return m_givens[x + (y * 9)]; 76 | } 77 | 78 | /** 79 | * Returns the value at the requested position. 80 | * 81 | * @param x the column of the cell 82 | * @param y the row of the cell 83 | */ 84 | int value(int x, int y) const 85 | { 86 | Q_ASSERT(x >= 0); 87 | Q_ASSERT(x < 9 ); 88 | Q_ASSERT(y >= 0); 89 | Q_ASSERT(y < 9); 90 | return m_solution[x + (y * 9)]; 91 | } 92 | 93 | /** 94 | * Returns the human readable name for a difficulty level. 95 | * 96 | * @param difficulty fetch the name of the specified difficulty level 97 | */ 98 | static QString difficultyString(int difficulty) 99 | { 100 | static const QStringList names = QStringList() 101 | << tr("Simple") 102 | << tr("Easy") 103 | << tr("Medium") 104 | << tr("Hard"); 105 | return names.at(qBound(1, difficulty, names.size()) - 1); 106 | } 107 | 108 | Q_SIGNALS: 109 | /** 110 | * Emitted when puzzle has finished generating. 111 | * 112 | * @param symmetry specify mirroring of givens 113 | * @param difficulty specify how hard to make puzzle 114 | */ 115 | void generated(int symmetry, int difficulty); 116 | 117 | private: 118 | /** Fills the board with unique values. */ 119 | void createSolution(); 120 | 121 | /** Finds a set of givens to show the player. */ 122 | bool createGivens(); 123 | 124 | /** Check if the givens on the board have a unique solution. */ 125 | bool isUnique(); 126 | 127 | private: 128 | std::array m_solution; /**< board solution */ 129 | std::array m_givens; /**< board givens */ 130 | 131 | QRandomGenerator m_random; /**< random number generator */ 132 | 133 | Pattern* m_pattern; /**< the pattern used to lay out the givens */ 134 | Difficulty m_difficulty; /**< requested difficulty setting */ 135 | int m_generated; /**< actual difficulty of board */ 136 | 137 | QFuture m_future; /**< results of puzzle generation */ 138 | std::atomic m_canceled; /**< if the generation has been aborted by player */ 139 | }; 140 | 141 | #endif // SIMSU_PUZZLE_H 142 | -------------------------------------------------------------------------------- /src/solver_dlx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2008-2016 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include "solver_dlx.h" 8 | 9 | #include "puzzle.h" 10 | 11 | //----------------------------------------------------------------------------- 12 | 13 | SolverDLX::SolverDLX() 14 | : m_max_columns(324) 15 | , m_max_rows(729) 16 | , m_max_nodes(2916) 17 | , m_columns(m_max_columns) 18 | , m_output(m_max_columns) 19 | , m_solutions(0) 20 | , m_tries(0) 21 | { 22 | init(); 23 | } 24 | 25 | //----------------------------------------------------------------------------- 26 | 27 | SolverDLX::~SolverDLX() 28 | { 29 | delete m_header; 30 | } 31 | 32 | //----------------------------------------------------------------------------- 33 | 34 | bool SolverDLX::solvePuzzle(const std::array& givens) 35 | { 36 | // Reset matrix 37 | if (m_tries) { 38 | m_columns.clear(); 39 | m_output.clear(); 40 | m_rows.clear(); 41 | m_nodes.clear(); 42 | m_solution.fill(nullptr); 43 | delete m_header; 44 | 45 | m_columns.resize(m_max_columns); 46 | m_output.resize(m_max_columns); 47 | init(); 48 | } 49 | 50 | // Build matrix 51 | for (int r = 0; r < 9; ++r) { 52 | for (int c = 0; c < 9; ++c) { 53 | const int g = givens[c + (r * 9)]; 54 | if (!g) { 55 | for (int i = 0; i < 9; ++i) { 56 | addRow((c << 8) | (r << 4) | (i + 1)); 57 | addNode(r * 9 + c); 58 | addNode(r * 9 + i + 81); 59 | addNode(c * 9 + i + 162); 60 | addNode((3 * (r / 3) + (c / 3)) * 9 + i + 243); 61 | } 62 | } else { 63 | addRow((c << 8) | (r << 4) | g); 64 | addNode(r * 9 + c); 65 | addNode(r * 9 + (g - 1) + 81); 66 | addNode(c * 9 + (g - 1) + 162); 67 | addNode((3 * (r / 3) + (c / 3)) * 9 + (g - 1) + 243); 68 | } 69 | } 70 | } 71 | 72 | // Solve matrix 73 | m_solutions = 0; 74 | 75 | m_tries = 0; 76 | 77 | solve(0); 78 | return m_solutions == 1; 79 | } 80 | 81 | //----------------------------------------------------------------------------- 82 | 83 | std::array SolverDLX::solution() const 84 | { 85 | std::array result; 86 | 87 | // Return null solution array if invalid 88 | if (m_solution.front() == nullptr) { 89 | result.fill(0); 90 | return result; 91 | } 92 | 93 | // Copy values to solution array 94 | for (int i = 0; i < 81; ++i) { 95 | const int id = m_solution[i]->row->id; 96 | const int c = (id >> 8) & 0xF; 97 | const int r = (id >> 4) & 0xF; 98 | const int v = id & 0xF; 99 | result[c + (r * 9)] = v; 100 | } 101 | return result; 102 | } 103 | 104 | //----------------------------------------------------------------------------- 105 | 106 | void SolverDLX::addRow(unsigned int id) 107 | { 108 | m_rows.append(HeaderNode()); 109 | HeaderNode* row = &m_rows.back(); 110 | row->id = id; 111 | row->left = row->right = row->up = row->down = row->column = row; 112 | } 113 | 114 | //----------------------------------------------------------------------------- 115 | 116 | void SolverDLX::addNode(unsigned int c) 117 | { 118 | HeaderNode* column = &m_columns[c]; 119 | HeaderNode* row = &m_rows.back(); 120 | 121 | m_nodes.append(Node()); 122 | Node* node = &m_nodes.back(); 123 | 124 | node->left = row->left; 125 | node->right = row; 126 | row->left->right = node; 127 | row->left = node; 128 | 129 | node->up = column->up; 130 | node->down = column; 131 | column->up->down = node; 132 | column->up = node; 133 | 134 | node->column = column; 135 | node->row = row; 136 | 137 | column->size++; 138 | } 139 | 140 | //----------------------------------------------------------------------------- 141 | 142 | void SolverDLX::init() 143 | { 144 | m_solutions = 0; 145 | m_tries = 0; 146 | 147 | m_header = new HeaderNode; 148 | m_header->column = m_header; 149 | 150 | Node* node = m_header; 151 | HeaderNode* column = nullptr; 152 | for (unsigned int i = 0; i < m_max_columns; ++i) { 153 | column = &m_columns[i]; 154 | column->id = i; 155 | column->up = column->down = column->column = column; 156 | column->left = node; 157 | node->right = column; 158 | node = column; 159 | } 160 | node->right = m_header; 161 | 162 | m_rows.reserve(m_max_rows); 163 | m_nodes.reserve(m_max_nodes); 164 | } 165 | 166 | //----------------------------------------------------------------------------- 167 | 168 | void SolverDLX::solve(unsigned int k) 169 | { 170 | // If matrix is empty a solution has been found. 171 | if (m_header->right == m_header) { 172 | ++m_solutions; 173 | std::copy(m_output.cbegin(), m_output.cbegin() + 81, m_solution.begin()); 174 | return; 175 | } 176 | 177 | if ((m_solutions >= 2) || (++m_tries >= m_max_columns)) { 178 | return; 179 | } 180 | 181 | // Choose column with lowest amount of 1s. 182 | HeaderNode* column = nullptr; 183 | unsigned int s = 0xFFFFFFFF; 184 | for(HeaderNode* i = m_header->right->column; i != m_header; i = i->right->column) { 185 | if (i->size < s) { 186 | column = i; 187 | s = i->size; 188 | } 189 | } 190 | cover(column); 191 | 192 | unsigned int next_k = k + 1; 193 | 194 | for(Node* row = column->down; row != column; row = row->down) { 195 | m_output[k] = row; 196 | 197 | for(Node* j = row->right; j != row; j = j->right) { 198 | cover(j->column); 199 | } 200 | 201 | solve(next_k); 202 | 203 | row = m_output[k]; 204 | column = row->column; 205 | 206 | for(Node* j = row->left; j != row; j = j->left) { 207 | uncover(j->column); 208 | } 209 | } 210 | 211 | uncover(column); 212 | } 213 | 214 | //----------------------------------------------------------------------------- 215 | 216 | void SolverDLX::cover(HeaderNode* node) 217 | { 218 | node->right->left = node->left; 219 | node->left->right = node->right; 220 | 221 | for (Node* i = node->down; i != node; i = i->down) { 222 | for (Node* j = i->right; j != i; j = j->right) { 223 | j->down->up = j->up; 224 | j->up->down = j->down; 225 | j->column->size--; 226 | } 227 | } 228 | } 229 | 230 | //----------------------------------------------------------------------------- 231 | 232 | void SolverDLX::uncover(HeaderNode* node) 233 | { 234 | for (Node* i = node->up; i != node; i = i->up) { 235 | for (Node* j = i->left; j != i; j = j->left) { 236 | j->column->size++; 237 | j->down->up = j; 238 | j->up->down = j; 239 | } 240 | } 241 | 242 | node->right->left = node; 243 | node->left->right = node; 244 | } 245 | 246 | //----------------------------------------------------------------------------- 247 | -------------------------------------------------------------------------------- /src/solver_dlx.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2008-2016 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_SOLVER_DLX_H 8 | #define SIMSU_SOLVER_DLX_H 9 | 10 | #include 11 | 12 | #include 13 | 14 | /** 15 | * Puzzle solver that uses Dancing Links implementation of Algorithm X. 16 | * 17 | * Algorithm X is a recursive backtracking algorithm that finds all solutions 18 | * to the exact cover problem. It works on a matrix consisting of 0s an 1s. 19 | * The purpose is to find a combination of rows such that the digit 1 appears 20 | * in each column only once. 21 | * 22 | * To convert an exact cover problem into a sparse matrix solvable by 23 | * Algorithm X you represent each constraint by a column. Each possible value 24 | * is then placed into a row with 1s in the columns for the constraints it 25 | * matches. 26 | */ 27 | class SolverDLX 28 | { 29 | struct HeaderNode; 30 | 31 | /** %Node in matrix. */ 32 | struct Node 33 | { 34 | /** Constructs a node with the value of 1. */ 35 | explicit Node() 36 | : left(nullptr) 37 | , right(nullptr) 38 | , up(nullptr) 39 | , down(nullptr) 40 | , column(nullptr) 41 | , row(nullptr) 42 | { 43 | } 44 | 45 | Node* left; /**< node to the left with value of 1 */ 46 | Node* right; /**< node to the right with value of 1 */ 47 | Node* up; /**< node above with value of 1 */ 48 | Node* down; /**< node below with value of 1 */ 49 | HeaderNode* column; /**< column containing this node */ 50 | HeaderNode* row; /**< row containing this node */ 51 | }; 52 | 53 | /** Head node of column or row in matrix. */ 54 | struct HeaderNode : public Node 55 | { 56 | /** Constructs an empty column. */ 57 | explicit HeaderNode() 58 | : size(0) 59 | , id(0) 60 | { 61 | } 62 | 63 | unsigned int size; /**< how many nodes with value of 1 are in column */ 64 | unsigned int id; /**< unique identifier */ 65 | }; 66 | 67 | public: 68 | /** Construct a solver. */ 69 | explicit SolverDLX(); 70 | 71 | /** Clean up solver. */ 72 | ~SolverDLX(); 73 | 74 | /** 75 | * Find if puzzle has a solution. 76 | * 77 | * @param givens the values already set on the board 78 | * @return was a solution found 79 | */ 80 | bool solvePuzzle(const std::array& givens); 81 | 82 | /** 83 | * Retrieve solution. 84 | * 85 | * @return last solution found as 2D array 86 | */ 87 | std::array solution() const; 88 | 89 | private: 90 | /** Set to initial values. */ 91 | void init(); 92 | 93 | /** Add row to matrix. */ 94 | void addRow(unsigned int id); 95 | 96 | /** 97 | * Add node to matrix. 98 | * 99 | * @param column which column in current row to mark as filled 100 | */ 101 | void addNode(unsigned int column); 102 | 103 | /** 104 | * Run Algorithm X at depth @p k. 105 | * 106 | * This is a recursive function that hides rows and columns and checks to 107 | * see if a solution has been found. 108 | */ 109 | void solve(unsigned int k); 110 | 111 | /** 112 | * Remove column or row from matrix. 113 | * 114 | * @param node head node of column or row to remove 115 | */ 116 | void cover(HeaderNode* node); 117 | 118 | /** 119 | * Add column or row back to matrix. 120 | * 121 | * @param node head node of column or row to add 122 | */ 123 | void uncover(HeaderNode* node); 124 | 125 | private: 126 | const unsigned int m_max_columns; /**< amount of constraints */ 127 | const unsigned int m_max_rows; /**< amount of choices */ 128 | const unsigned int m_max_nodes; /**< amount of nodes */ 129 | 130 | HeaderNode* m_header; /**< root element */ 131 | QList m_columns; /**< constraints */ 132 | QList m_rows; /**< rows */ 133 | QList m_nodes; /**< row values */ 134 | QList m_output; /**< rows where columns do not conflict */ 135 | std::array m_solution; /**< nodes of most recent solution */ 136 | 137 | unsigned int m_solutions; /**< how many solutions have been found so far */ 138 | unsigned int m_tries; /**< how many attempts have been made so far */ 139 | }; 140 | 141 | #endif // SIMSU_SOLVER_DLX_H 142 | -------------------------------------------------------------------------------- /src/solver_logic.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2016-2021 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_SOLVER_LOGIC_H 8 | #define SIMSU_SOLVER_LOGIC_H 9 | 10 | #include 11 | 12 | /** 13 | * Puzzle solver that uses logic methods to imitate human solving. 14 | */ 15 | class SolverLogic 16 | { 17 | /** 18 | * Cell on the game board. 19 | */ 20 | class CellValue 21 | { 22 | public: 23 | /** 24 | * Constructs a cell. 25 | */ 26 | explicit CellValue() 27 | : m_value(0) 28 | , m_possible_count(9) 29 | , m_possible{true,true,true,true,true,true,true,true,true} 30 | { 31 | } 32 | 33 | /** 34 | * @return how many possible values can go in cell 35 | */ 36 | int countPossibles() const 37 | { 38 | return m_possible_count; 39 | } 40 | 41 | /** 42 | * @return @c true if @p possible can be placed in cell 43 | */ 44 | bool hasPossible(const int possible) const 45 | { 46 | return m_possible[possible - 1]; 47 | } 48 | 49 | /** 50 | * @return the only value that can be placed in cell 51 | */ 52 | int possibleSingle() const; 53 | 54 | /** 55 | * @return the values of the cell if it can only have two values 56 | */ 57 | int possiblePair() const; 58 | 59 | /** 60 | * Removes the possibility to set a specific value in the cell. 61 | * @param possible the value to remove 62 | * @return if the value was allowed before 63 | */ 64 | bool removePossible(const int possible) 65 | { 66 | const bool has = m_possible[possible - 1]; 67 | m_possible_count -= has; 68 | m_possible[possible - 1] = false; 69 | return has; 70 | } 71 | 72 | /** 73 | * Removes the possibility to set specific values in the cell. 74 | * @param possible the values to remove 75 | * @return if the values were allowed before 76 | */ 77 | bool removePossibles(const int possible); 78 | 79 | /** 80 | * Sets the cell to nothing values and allows all possibles. 81 | */ 82 | void reset() 83 | { 84 | m_value = 0; 85 | m_possible_count = 9; 86 | m_possible = {true,true,true,true,true,true,true,true,true}; 87 | } 88 | 89 | /** 90 | * Sets the cell to a specific @p value and removes the possibles. 91 | */ 92 | void setValue(const int value) 93 | { 94 | m_value = value; 95 | m_possible_count = 0; 96 | m_possible = {false,false,false,false,false,false,false,false,false}; 97 | } 98 | 99 | /** 100 | * @return the value set in the cell 101 | */ 102 | int value() const 103 | { 104 | return m_value; 105 | } 106 | 107 | private: 108 | int m_value; /**< value contained by cell */ 109 | int m_possible_count; /**< total amount of values that can go in the cell */ 110 | std::array m_possible; /**< values that can go in the cell */ 111 | }; 112 | 113 | /** 114 | * Pair of cells with the same possible values. 115 | */ 116 | struct HiddenPair 117 | { 118 | /** 119 | * Constructs a hidden pair. 120 | */ 121 | HiddenPair() 122 | : count(0) 123 | , cell1(0) 124 | , cell2(0) 125 | { 126 | } 127 | 128 | int count; /**< how many cells have been found */ 129 | int cell1; /**< first cell with the possible values */ 130 | int cell2; /**< second cell with the possible values */ 131 | }; 132 | 133 | public: 134 | typedef std::array Box; 135 | 136 | /** 137 | * Constructs a solver. 138 | */ 139 | explicit SolverLogic(); 140 | 141 | /** 142 | * Checks if a cell can contain a value. 143 | * 144 | * @param column the column of the cell 145 | * @param row the row of the cell 146 | * @param value the value to check 147 | * @return @c true if the cell can contain the value 148 | */ 149 | bool hasPossible(int column, int row, int value) const 150 | { 151 | return m_cells[column + (row * 9)].hasPossible(value); 152 | } 153 | 154 | /** 155 | * Prepares the board for solving by filling in the givens. This removes 156 | * the possible values from the row, columns, and boxes of the givens. 157 | * 158 | * @param givens the values already set on the board 159 | */ 160 | void loadPuzzle(const std::array& givens); 161 | 162 | /** 163 | * Find if puzzle has a solution. 164 | * 165 | * @param givens the values already set on the board 166 | * @param max_difficulty the maximum difficulty of checks when solving 167 | * @return difficulty of solution found, or Puzzle::Unsolved if none found 168 | */ 169 | int solvePuzzle(const std::array& givens, int max_difficulty); 170 | 171 | private: 172 | /** 173 | * Fetch the box containing a cell. 174 | * 175 | * @param c column of the cell 176 | * @param r row of the cell 177 | * @return const reference to the box 178 | */ 179 | const Box& cellBox(int c, int r) const 180 | { 181 | return m_boxes[(c / 3) + ((r / 3) * 3)]; 182 | } 183 | 184 | /** 185 | * Sets all cells containing a single possible to that value. 186 | * 187 | * @return @c true if successful 188 | */ 189 | bool removeSingles(); 190 | 191 | /** 192 | * Sets the value of the only cell in a row with a possible value. 193 | * 194 | * @return @c true if successful 195 | */ 196 | bool removeRowHiddenSingle(); 197 | 198 | /** 199 | * Sets the value of the only cell in a column with a possible value. 200 | * 201 | * @return @c true if successful 202 | */ 203 | bool removeColumnHiddenSingle(); 204 | 205 | /** 206 | * Sets the value of the only cell in a box with a possible value. 207 | * 208 | * @return @c true if successful 209 | */ 210 | bool removeBoxHiddenSingle(); 211 | 212 | /** 213 | * Removes possibles from other cells in a row if there are only two 214 | * cells in a box that can contain a possible value and they are both 215 | * in the same row. 216 | * 217 | * @return @c true if successful 218 | */ 219 | bool removeRowPointingPair(); 220 | 221 | /** 222 | * Removes possibles from other cells in a column if there are only two 223 | * cells in a box that can contain a possible value and they are both 224 | * in the same column. 225 | * 226 | * @return @c true if successful 227 | */ 228 | bool removeColumnPointingPair(); 229 | 230 | /** 231 | * Removes possibles from other cells in a box if they must appear in a 232 | * row because they are the only spots in that row which can contain that 233 | * possible value. 234 | * 235 | * @return @c true if successful 236 | */ 237 | bool removeRowBoxIntersection(); 238 | 239 | /** 240 | * Removes possibles from other cells in a box if they must appear in a 241 | * column because they are the only spots in that column which can contain 242 | * that possible value. 243 | * 244 | * @return @c true if successful 245 | */ 246 | bool removeColumnBoxIntersection(); 247 | 248 | /** 249 | * Removes possibles from other cells in a column, row, or box if there 250 | * are two cells that have the same two values as the only possibility. 251 | * 252 | * @return @c true if successful 253 | */ 254 | bool removeNakedPair(); 255 | 256 | /** 257 | * Removes possibles from other cells in a row if there are only two 258 | * cells that can contain the possible values. 259 | * 260 | * @return @c true if successful 261 | */ 262 | bool removeRowHiddenPair(); 263 | 264 | /** 265 | * Removes possibles from other cells in a column if there are only two 266 | * cells that can contain the possible values. 267 | * 268 | * @return @c true if successful 269 | */ 270 | bool removeColumnHiddenPair(); 271 | 272 | /** 273 | * Removes possibles from other cells in a box if there are only two 274 | * cells that can contain the possible values. 275 | * 276 | * @return @c true if successful 277 | */ 278 | bool removeBoxHiddenPair(); 279 | 280 | /** 281 | * Sets the value of a cell. 282 | * 283 | * @param c column of the cell 284 | * @param r row of the cell 285 | * @param value the value to put in a cell 286 | */ 287 | void setValue(const int c, const int r, const int value); 288 | 289 | private: 290 | int m_remaining; /**< how many cells are unset */ 291 | std::array m_cells; /**< the cells of the board */ 292 | static const std::array m_boxes; /**< the boxes of the board */ 293 | }; 294 | 295 | #endif // SIMSU_SOLVER_LOGIC_H 296 | -------------------------------------------------------------------------------- /src/square.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2014 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include "square.h" 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | //----------------------------------------------------------------------------- 15 | 16 | Square::Square(QWidget* parent) 17 | : QWidget(parent) 18 | , m_child(nullptr) 19 | { 20 | setMinimumSize(345, 345); 21 | } 22 | 23 | //----------------------------------------------------------------------------- 24 | 25 | void Square::setChild(QWidget* child) 26 | { 27 | m_child = child; 28 | m_child->setParent(this); 29 | resize(size()); 30 | } 31 | 32 | //----------------------------------------------------------------------------- 33 | 34 | void Square::resizeEvent(QResizeEvent* event) 35 | { 36 | QWidget::resizeEvent(event); 37 | if (m_child) { 38 | QRect region = contentsRect(); 39 | int size = std::min(region.width(), region.height()); 40 | QRect rect = QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, QSize(size, size), region); 41 | m_child->setGeometry(rect); 42 | } 43 | } 44 | 45 | //----------------------------------------------------------------------------- 46 | -------------------------------------------------------------------------------- /src/square.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2013 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_SQUARE_H 8 | #define SIMSU_SQUARE_H 9 | 10 | #include 11 | 12 | /** Widget that squares a child widget. */ 13 | class Square : public QWidget 14 | { 15 | public: 16 | /** 17 | * Constructs a square widget. 18 | * 19 | * @param parent the parent widget 20 | */ 21 | explicit Square(QWidget* parent = nullptr); 22 | 23 | /** 24 | * Set the widget to be squared. 25 | * 26 | * @param child widget to be squared 27 | */ 28 | void setChild(QWidget* child); 29 | 30 | protected: 31 | /** Override parent function to handle setting child position and size. */ 32 | void resizeEvent(QResizeEvent* event) override; 33 | 34 | private: 35 | QWidget* m_child; /**< widget to be squared */ 36 | }; 37 | 38 | #endif // SIMSU_SQUARE_H 39 | -------------------------------------------------------------------------------- /src/window.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2021 Graeme Gott 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef SIMSU_WINDOW_H 8 | #define SIMSU_WINDOW_H 9 | 10 | class Board; 11 | class NewGamePage; 12 | 13 | #include 14 | class QActionGroup; 15 | class QBoxLayout; 16 | class QButtonGroup; 17 | class QLabel; 18 | class QStackedWidget; 19 | class QToolButton; 20 | 21 | /** 22 | * Main window of the game. 23 | * 24 | * This class is the main window of the game. It handles the menubar and 25 | * placement of the interface buttons. 26 | */ 27 | class Window : public QMainWindow 28 | { 29 | Q_OBJECT 30 | 31 | public: 32 | /** 33 | * Constructs the main window. 34 | */ 35 | explicit Window(); 36 | 37 | protected: 38 | /** Override parent function to save window geometry. */ 39 | void closeEvent(QCloseEvent* event) override; 40 | 41 | /** Override parent function to handle scrolling through current keys. */ 42 | void wheelEvent(QWheelEvent* event) override; 43 | 44 | private Q_SLOTS: 45 | /** 46 | * Start a new game. 47 | * 48 | * Shows a dialog of options that the player can adjust. 49 | */ 50 | void newGame(); 51 | 52 | /** Handle player not starting a new game. */ 53 | void newGameCanceled(); 54 | 55 | /** Restart the current game. */ 56 | void restartGame(); 57 | 58 | /** Prints the current board. */ 59 | void print(); 60 | 61 | /** Show the current game details. */ 62 | void showDetails(); 63 | 64 | /** Show a dialog that explains how to interact with the game. */ 65 | void showControls(); 66 | 67 | /** Show the program details. */ 68 | void about(); 69 | 70 | /** Disable interface when game is over. */ 71 | void gameFinished(); 72 | 73 | /** Enable interface when game is ready to play. */ 74 | void gameStarted(); 75 | 76 | /** 77 | * Set which key button is depressed. 78 | * 79 | * @param key the current key 80 | */ 81 | void activeKeyChanged(int key); 82 | 83 | /** Flatten buttons for values that are fully on the board. */ 84 | void flattenUsedKeys(); 85 | 86 | /** 87 | * Set if notes or answer button should be depressed. 88 | * 89 | * @param mode if @c true notes button is active; otherwise answer button 90 | */ 91 | void notesModeChanged(bool mode); 92 | 93 | /** 94 | * Sets how the board handles auto filling notes. 95 | * 96 | * @param action what notes fill mode to use 97 | */ 98 | void autoNotesChanged(QAction* action); 99 | 100 | /** Switch between entering answers and notes. */ 101 | void toggleMode(); 102 | 103 | /** 104 | * Switch window layouts. 105 | * 106 | * @param checked if @c true buttons are on left and right; otherwise on bottom 107 | */ 108 | void toggleWidescreen(bool checked); 109 | 110 | /** Allows the player to change the application language. */ 111 | void setLocaleClicked(); 112 | 113 | private: 114 | QStackedWidget* m_contents; /**< the layers of display widgets */ 115 | NewGamePage* m_new_game; /**< options to start a new game */ 116 | QLabel* m_load_message; /**< shows player a wait screen */ 117 | 118 | Board* m_board; /**< game board */ 119 | 120 | QButtonGroup* m_key_buttons; /**< button group to choose which number is active */ 121 | QButtonGroup* m_mode_buttons; /**< button group to choose if in notes or answer mode */ 122 | QActionGroup* m_auto_notes_actions; /**< action group to choose mode for auto filling notes */ 123 | QAction* m_new_action; /**< action for starting a game */ 124 | QAction* m_restart_action; /** action for restarting the current game */ 125 | QAction* m_print_action; /**< action for printing current board */ 126 | QAction* m_details_action; /**< action for showing game details */ 127 | QAction* m_undo_action; /**< action for undoing */ 128 | QAction* m_redo_action; /**< action for redoing */ 129 | QAction* m_check_action; /**< action for checking if cells are valid */ 130 | QAction* m_hint_action; /**< action for getting a hint */ 131 | 132 | QBoxLayout* m_keys_layout; /**< QLayout for key buttons */ 133 | QBoxLayout* m_mode_layout; /**< QLayout for mode buttons */ 134 | QBoxLayout* m_layout; /**< QLayout for widgets */ 135 | QList m_sidebar_buttons; /**< interface buttons */ 136 | }; 137 | 138 | #endif // SIMSU_WINDOW_H 139 | -------------------------------------------------------------------------------- /symmetry/anti_diagonal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/anti_diagonal.png -------------------------------------------------------------------------------- /symmetry/anti_diagonal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/anti_diagonal@2x.png -------------------------------------------------------------------------------- /symmetry/diagonal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/diagonal.png -------------------------------------------------------------------------------- /symmetry/diagonal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/diagonal@2x.png -------------------------------------------------------------------------------- /symmetry/diagonal_anti_diagonal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/diagonal_anti_diagonal.png -------------------------------------------------------------------------------- /symmetry/diagonal_anti_diagonal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/diagonal_anti_diagonal@2x.png -------------------------------------------------------------------------------- /symmetry/dihedral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/dihedral.png -------------------------------------------------------------------------------- /symmetry/dihedral@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/dihedral@2x.png -------------------------------------------------------------------------------- /symmetry/horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/horizontal.png -------------------------------------------------------------------------------- /symmetry/horizontal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/horizontal@2x.png -------------------------------------------------------------------------------- /symmetry/horizontal_vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/horizontal_vertical.png -------------------------------------------------------------------------------- /symmetry/horizontal_vertical@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/horizontal_vertical@2x.png -------------------------------------------------------------------------------- /symmetry/none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/none.png -------------------------------------------------------------------------------- /symmetry/none@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/none@2x.png -------------------------------------------------------------------------------- /symmetry/random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/random.png -------------------------------------------------------------------------------- /symmetry/random@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/random@2x.png -------------------------------------------------------------------------------- /symmetry/rotational_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/rotational_180.png -------------------------------------------------------------------------------- /symmetry/rotational_180@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/rotational_180@2x.png -------------------------------------------------------------------------------- /symmetry/rotational_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/rotational_full.png -------------------------------------------------------------------------------- /symmetry/rotational_full@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/rotational_full@2x.png -------------------------------------------------------------------------------- /symmetry/symmetry.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | anti_diagonal.png 4 | diagonal_anti_diagonal.png 5 | diagonal.png 6 | dihedral.png 7 | horizontal.png 8 | horizontal_vertical.png 9 | none.png 10 | random.png 11 | rotational_180.png 12 | rotational_full.png 13 | vertical.png 14 | 15 | anti_diagonal@2x.png 16 | diagonal_anti_diagonal@2x.png 17 | diagonal@2x.png 18 | dihedral@2x.png 19 | horizontal@2x.png 20 | horizontal_vertical@2x.png 21 | none@2x.png 22 | random@2x.png 23 | rotational_180@2x.png 24 | rotational_full@2x.png 25 | vertical@2x.png 26 | 27 | 28 | -------------------------------------------------------------------------------- /symmetry/vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/vertical.png -------------------------------------------------------------------------------- /symmetry/vertical@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gottcode/simsu/aa44267cb43ee166cedbe8c5d4048e43553c2356/symmetry/vertical@2x.png -------------------------------------------------------------------------------- /translations/simsu_es_CL.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Board 6 | 7 | Success 8 | Éxito 9 | 10 | 11 | 12 | LocaleDialog 13 | 14 | Select application language: 15 | Seleccionar lenguaje: 16 | 17 | 18 | <System Language> 19 | 20 | 21 | 22 | Note 23 | Nota 24 | 25 | 26 | Please restart this application for the change in language to take effect. 27 | Por favor, reinicie esta aplicación para efectuar los cambios de lenguaje. 28 | 29 | 30 | 31 | NewGamePage 32 | 33 | Play Game 34 | 35 | 36 | 37 | Create Your Own 38 | 39 | 40 | 41 | 42 | Pattern 43 | 44 | 180° Rotational 45 | 180° de rotación 46 | 47 | 48 | Full Rotational 49 | Rotación Completa 50 | 51 | 52 | Horizontal 53 | Horizontal 54 | 55 | 56 | Vertical 57 | Vertical 58 | 59 | 60 | Horizontal & Vertical 61 | Horizontal & Vertical 62 | 63 | 64 | Diagonal 65 | Diagonal 66 | 67 | 68 | Anti-Diagonal 69 | Anti-Diagonal 70 | 71 | 72 | Diagonal & Anti-Diagonal 73 | Diagonal & Anti-Diagonal 74 | 75 | 76 | Full Dihedral 77 | Diedro completo 78 | 79 | 80 | Random 81 | Al azar 82 | 83 | 84 | None 85 | Ninguno 86 | 87 | 88 | 89 | Puzzle 90 | 91 | Simple 92 | 93 | 94 | 95 | Easy 96 | 97 | 98 | 99 | Medium 100 | 101 | 102 | 103 | Hard 104 | 105 | 106 | 107 | 108 | Window 109 | 110 | Simsu 111 | Simsu 112 | 113 | 114 | Pen 115 | Pluma 116 | 117 | 118 | Pencil 119 | Lápiz 120 | 121 | 122 | Highlight 123 | Resaltado 124 | 125 | 126 | H 127 | H 128 | 129 | 130 | S 131 | S 132 | 133 | 134 | &Game 135 | &Juego 136 | 137 | 138 | &New 139 | &Nuevo 140 | 141 | 142 | &Details 143 | &Detalles 144 | 145 | 146 | &Quit 147 | &Salir 148 | 149 | 150 | &Move 151 | &Mover 152 | 153 | 154 | &Undo 155 | &Deshacer 156 | 157 | 158 | &Redo 159 | &Rehacer 160 | 161 | 162 | &Check 163 | &Comprobar 164 | 165 | 166 | C 167 | C 168 | 169 | 170 | &Settings 171 | &Configuración 172 | 173 | 174 | &Auto Switch Modes 175 | &Modos de cambio automático 176 | 177 | 178 | &Widescreen Layout 179 | &Pantalla ancha 180 | 181 | 182 | Application &Language... 183 | Aplicación &Lenguaje ... 184 | 185 | 186 | &Help 187 | &Ayuda 188 | 189 | 190 | &Controls 191 | &Controles 192 | 193 | 194 | &About 195 | &Acerca de 196 | 197 | 198 | About &Qt 199 | Acerca de &Qt 200 | 201 | 202 | Symmetry: 203 | Simetría: 204 | 205 | 206 | Details 207 | Detalles 208 | 209 | 210 | Controls 211 | Controles 212 | 213 | 214 | <p><big><b>Mouse Controls:</b></big><br><b>Left click:</b> Toggle number in pen mode<br><b>Right click:</b> Toggle number in pencil mode<br><b>Scrollwheel:</b> Change current number</p><p><big><b>Keyboard Controls:</b></big><br><b>Arrow keys:</b> Move selection<br><b>Number keys:</b> Toggle value or note<br><b>S:</b> Switch between pen and pencil modes<br><b>H:</b> Highlight all instances of current number</p> 215 | 216 | 217 | 218 | About Simsu 219 | Acerca de Simsu 220 | 221 | 222 | A basic Sudoku game 223 | Un juego de Sudoku básico 224 | 225 | 226 | Copyright &copy; 2009-%1 Graeme Gott 227 | Copyright &copy; 2009-%1 Graeme Gott 228 | 229 | 230 | Released under the <a href=%1>GPL 3</a> license 231 | 232 | 233 | 234 | Sorry 235 | 236 | 237 | 238 | You have not created a valid puzzle. Please try again. 239 | 240 | 241 | 242 | Please wait 243 | 244 | 245 | 246 | Generating puzzle... 247 | 248 | 249 | 250 | &Restart 251 | 252 | 253 | 254 | &Print... 255 | 256 | 257 | 258 | &Hint 259 | 260 | 261 | 262 | F2 263 | 264 | 265 | 266 | &Manual Notes 267 | 268 | 269 | 270 | Auto &Clear Notes 271 | 272 | 273 | 274 | Auto &Fill Notes 275 | 276 | 277 | 278 | Restart Game 279 | 280 | 281 | 282 | Reset the board to its original state? 283 | 284 | 285 | 286 | Print Board 287 | 288 | 289 | 290 | Difficulty: 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /translations/simsu_he.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Board 6 | 7 | Success 8 | הצלחה 9 | 10 | 11 | 12 | LocaleDialog 13 | 14 | Select application language: 15 | בחירת שפת יישום: 16 | 17 | 18 | <System Language> 19 | <שפת מערכת> 20 | 21 | 22 | Note 23 | הערה 24 | 25 | 26 | Please restart this application for the change in language to take effect. 27 | אנא אתחל את יישום זה כדי ששינויים בשפה יכנסו לתוקף. 28 | 29 | 30 | 31 | NewGamePage 32 | 33 | Play Game 34 | 35 | 36 | 37 | Create Your Own 38 | 39 | 40 | 41 | 42 | Pattern 43 | 44 | 180° Rotational 45 | 46 | 47 | 48 | Full Rotational 49 | 50 | 51 | 52 | Horizontal 53 | אופקי 54 | 55 | 56 | Vertical 57 | אנכי 58 | 59 | 60 | Horizontal & Vertical 61 | אופקית ואנכית 62 | 63 | 64 | Diagonal 65 | אלכסוני 66 | 67 | 68 | Anti-Diagonal 69 | אנטי-אלכסוני 70 | 71 | 72 | Diagonal & Anti-Diagonal 73 | אלכסוני וגם אנטי-אלכסוני 74 | 75 | 76 | Full Dihedral 77 | דו-מישורי מלא 78 | 79 | 80 | Random 81 | אקראי 82 | 83 | 84 | None 85 | ללא 86 | 87 | 88 | 89 | Puzzle 90 | 91 | Simple 92 | 93 | 94 | 95 | Easy 96 | 97 | 98 | 99 | Medium 100 | 101 | 102 | 103 | Hard 104 | 105 | 106 | 107 | 108 | Window 109 | 110 | Simsu 111 | Simsu 112 | 113 | 114 | Pen 115 | עט 116 | 117 | 118 | Pencil 119 | עפרון 120 | 121 | 122 | Highlight 123 | הדגשה 124 | 125 | 126 | H 127 | H 128 | 129 | 130 | S 131 | S 132 | 133 | 134 | &Game 135 | &משחק 136 | 137 | 138 | &New 139 | &חדש 140 | 141 | 142 | &Details 143 | &פרטים 144 | 145 | 146 | &Quit 147 | י&ציאה 148 | 149 | 150 | &Move 151 | &תור 152 | 153 | 154 | &Undo 155 | &בטל 156 | 157 | 158 | &Redo 159 | בצ&ע שוב 160 | 161 | 162 | &Check 163 | &בדיקה 164 | 165 | 166 | C 167 | C 168 | 169 | 170 | &Settings 171 | &הגדרות 172 | 173 | 174 | &Auto Switch Modes 175 | 176 | 177 | 178 | &Widescreen Layout 179 | 180 | 181 | 182 | Application &Language... 183 | &שפת יישום... 184 | 185 | 186 | &Help 187 | &עזרה 188 | 189 | 190 | &Controls 191 | &בקרים 192 | 193 | 194 | &About 195 | &אודות 196 | 197 | 198 | About &Qt 199 | אודות &QT 200 | 201 | 202 | Symmetry: 203 | סימטרייה: 204 | 205 | 206 | Details 207 | פרטים 208 | 209 | 210 | Controls 211 | בקרים 212 | 213 | 214 | <p><big><b>Mouse Controls:</b></big><br><b>Left click:</b> Toggle number in pen mode<br><b>Right click:</b> Toggle number in pencil mode<br><b>Scrollwheel:</b> Change current number</p><p><big><b>Keyboard Controls:</b></big><br><b>Arrow keys:</b> Move selection<br><b>Number keys:</b> Toggle value or note<br><b>S:</b> Switch between pen and pencil modes<br><b>H:</b> Highlight all instances of current number</p> 215 | 216 | 217 | 218 | About Simsu 219 | אודות Simsu 220 | 221 | 222 | A basic Sudoku game 223 | משחק סודוקו בסיסי 224 | 225 | 226 | Copyright &copy; 2009-%1 Graeme Gott 227 | 228 | 229 | 230 | Released under the <a href=%1>GPL 3</a> license 231 | משוחרר תחת הרשיון <a href=%1>GPL 3</a> 232 | 233 | 234 | Sorry 235 | 236 | 237 | 238 | You have not created a valid puzzle. Please try again. 239 | 240 | 241 | 242 | Please wait 243 | 244 | 245 | 246 | Generating puzzle... 247 | 248 | 249 | 250 | &Restart 251 | 252 | 253 | 254 | &Print... 255 | 256 | 257 | 258 | &Hint 259 | 260 | 261 | 262 | F2 263 | 264 | 265 | 266 | &Manual Notes 267 | 268 | 269 | 270 | Auto &Clear Notes 271 | 272 | 273 | 274 | Auto &Fill Notes 275 | 276 | 277 | 278 | Restart Game 279 | 280 | 281 | 282 | Reset the board to its original state? 283 | 284 | 285 | 286 | Print Board 287 | 288 | 289 | 290 | Difficulty: 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /translations/simsu_it.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Board 6 | 7 | Success 8 | 9 | 10 | 11 | 12 | LocaleDialog 13 | 14 | Select application language: 15 | Seleziona la lingua dell'applicazione: 16 | 17 | 18 | <System Language> 19 | <System Language> 20 | 21 | 22 | Note 23 | Note 24 | 25 | 26 | Please restart this application for the change in language to take effect. 27 | Riavvia l'applicazione per rendere effettivo il cambiamento della lingua. 28 | 29 | 30 | 31 | NewGamePage 32 | 33 | Play Game 34 | 35 | 36 | 37 | Create Your Own 38 | 39 | 40 | 41 | 42 | Pattern 43 | 44 | 180° Rotational 45 | Rotazione di 180° 46 | 47 | 48 | Full Rotational 49 | Rotazione completa 50 | 51 | 52 | Horizontal 53 | Orizzonale 54 | 55 | 56 | Vertical 57 | Verticale 58 | 59 | 60 | Horizontal & Vertical 61 | Orizzontale & Verticale 62 | 63 | 64 | Diagonal 65 | Diagonale 66 | 67 | 68 | Anti-Diagonal 69 | 70 | 71 | 72 | Diagonal & Anti-Diagonal 73 | 74 | 75 | 76 | Full Dihedral 77 | 78 | 79 | 80 | Random 81 | Casuale 82 | 83 | 84 | None 85 | 86 | 87 | 88 | 89 | Puzzle 90 | 91 | Simple 92 | 93 | 94 | 95 | Easy 96 | 97 | 98 | 99 | Medium 100 | 101 | 102 | 103 | Hard 104 | 105 | 106 | 107 | 108 | Window 109 | 110 | Simsu 111 | Simsu 112 | 113 | 114 | Pen 115 | Penna 116 | 117 | 118 | Pencil 119 | Matita 120 | 121 | 122 | Highlight 123 | Evidenzia 124 | 125 | 126 | H 127 | H 128 | 129 | 130 | S 131 | S 132 | 133 | 134 | &Game 135 | 136 | 137 | 138 | &New 139 | &Nuovo 140 | 141 | 142 | &Details 143 | &Dettagli 144 | 145 | 146 | &Quit 147 | &Esci 148 | 149 | 150 | &Move 151 | 152 | 153 | 154 | &Undo 155 | &Annulla 156 | 157 | 158 | &Redo 159 | 160 | 161 | 162 | &Check 163 | &Controlla 164 | 165 | 166 | C 167 | C 168 | 169 | 170 | &Settings 171 | &Impostazioni 172 | 173 | 174 | &Auto Switch Modes 175 | 176 | 177 | 178 | &Widescreen Layout 179 | 180 | 181 | 182 | Application &Language... 183 | &Lingua 184 | 185 | 186 | &Help 187 | &Aiuto 188 | 189 | 190 | &Controls 191 | 192 | 193 | 194 | &About 195 | 196 | 197 | 198 | About &Qt 199 | 200 | 201 | 202 | Symmetry: 203 | 204 | 205 | 206 | Details 207 | Dettagli 208 | 209 | 210 | Controls 211 | 212 | 213 | 214 | <p><big><b>Mouse Controls:</b></big><br><b>Left click:</b> Toggle number in pen mode<br><b>Right click:</b> Toggle number in pencil mode<br><b>Scrollwheel:</b> Change current number</p><p><big><b>Keyboard Controls:</b></big><br><b>Arrow keys:</b> Move selection<br><b>Number keys:</b> Toggle value or note<br><b>S:</b> Switch between pen and pencil modes<br><b>H:</b> Highlight all instances of current number</p> 215 | 216 | 217 | 218 | About Simsu 219 | 220 | 221 | 222 | A basic Sudoku game 223 | Un semplice Sudoku 224 | 225 | 226 | Copyright &copy; 2009-%1 Graeme Gott 227 | Copyright &copy; 1009-%1 Graeme Gott 228 | 229 | 230 | Released under the <a href=%1>GPL 3</a> license 231 | Rilasciato sotto la licenza <a href=%1>GPL 3</a> 232 | 233 | 234 | Sorry 235 | 236 | 237 | 238 | You have not created a valid puzzle. Please try again. 239 | 240 | 241 | 242 | Please wait 243 | 244 | 245 | 246 | Generating puzzle... 247 | 248 | 249 | 250 | &Restart 251 | 252 | 253 | 254 | &Print... 255 | 256 | 257 | 258 | &Hint 259 | 260 | 261 | 262 | F2 263 | 264 | 265 | 266 | &Manual Notes 267 | 268 | 269 | 270 | Auto &Clear Notes 271 | 272 | 273 | 274 | Auto &Fill Notes 275 | 276 | 277 | 278 | Restart Game 279 | 280 | 281 | 282 | Reset the board to its original state? 283 | 284 | 285 | 286 | Print Board 287 | 288 | 289 | 290 | Difficulty: 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /translations/simsu_zh.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Board 6 | 7 | Success 8 | 恭喜,你成功了! 9 | 10 | 11 | 12 | LocaleDialog 13 | 14 | Select application language: 15 | 选择本游戏的语言: 16 | 17 | 18 | <System Language> 19 | <系统语言> 20 | 21 | 22 | Note 23 | 提示 24 | 25 | 26 | Please restart this application for the change in language to take effect. 27 | 请重启本程序使语言设置生效。 28 | 29 | 30 | 31 | NewGamePage 32 | 33 | Play Game 34 | 35 | 36 | 37 | Create Your Own 38 | 39 | 40 | 41 | 42 | Pattern 43 | 44 | 180° Rotational 45 | 180° 旋转对称 46 | 47 | 48 | Full Rotational 49 | 完全旋转对称 50 | 51 | 52 | Horizontal 53 | 水平 54 | 55 | 56 | Vertical 57 | 垂直 58 | 59 | 60 | Horizontal & Vertical 61 | 水平 & 垂直 62 | 63 | 64 | Diagonal 65 | 对角线 66 | 67 | 68 | Anti-Diagonal 69 | 宫对角线 70 | 71 | 72 | Diagonal & Anti-Diagonal 73 | 对角线 & 宫对角线 74 | 75 | 76 | Full Dihedral 77 | 全二面角 78 | 79 | 80 | Random 81 | 随机 82 | 83 | 84 | None 85 | 86 | 87 | 88 | 89 | Puzzle 90 | 91 | Simple 92 | 93 | 94 | 95 | Easy 96 | 97 | 98 | 99 | Medium 100 | 101 | 102 | 103 | Hard 104 | 105 | 106 | 107 | 108 | Window 109 | 110 | Simsu 111 | Simsu 112 | 113 | 114 | Pen 115 | 钢笔 116 | 117 | 118 | Pencil 119 | 铅笔 120 | 121 | 122 | Highlight 123 | 高亮 124 | 125 | 126 | H 127 | H 128 | 129 | 130 | S 131 | S 132 | 133 | 134 | &Game 135 | &游戏 136 | 137 | 138 | &New 139 | &新游戏 140 | 141 | 142 | &Details 143 | &本局游戏详情 144 | 145 | 146 | &Quit 147 | &退出程序 148 | 149 | 150 | &Move 151 | &移动 152 | 153 | 154 | &Undo 155 | &撤销 156 | 157 | 158 | &Redo 159 | &重做 160 | 161 | 162 | &Check 163 | &检查 164 | 165 | 166 | C 167 | C 168 | 169 | 170 | &Settings 171 | &设置 172 | 173 | 174 | &Auto Switch Modes 175 | &自动适应模式 176 | 177 | 178 | &Widescreen Layout 179 | &宽屏布局 180 | 181 | 182 | Application &Language... 183 | 程序 &语言... 184 | 185 | 186 | &Help 187 | &帮助 188 | 189 | 190 | &Controls 191 | &控制 192 | 193 | 194 | &About 195 | &关于 196 | 197 | 198 | About &Qt 199 | 关于 &Qt 200 | 201 | 202 | Symmetry: 203 | 对称: 204 | 205 | 206 | Details 207 | 详情 208 | 209 | 210 | Controls 211 | 控制 212 | 213 | 214 | <p><big><b>Mouse Controls:</b></big><br><b>Left click:</b> Toggle number in pen mode<br><b>Right click:</b> Toggle number in pencil mode<br><b>Scrollwheel:</b> Change current number</p><p><big><b>Keyboard Controls:</b></big><br><b>Arrow keys:</b> Move selection<br><b>Number keys:</b> Toggle value or note<br><b>S:</b> Switch between pen and pencil modes<br><b>H:</b> Highlight all instances of current number</p> 215 | <p><big><b>鼠标控制:</b></big><br><b>左击:</b> 切换至钢笔模式<br><b>右击:</b> 切换至铅笔模式<br><b>滚轮:</b> 改变当前数字</p><p><big><b>键盘控制:</b></big><br><b>方向键:</b> 改变位置<br><b>数字键:</b> 改变值或草稿<br><b>S:</b> 转换钢笔、铅笔模式<br><b>H:</b> 高亮当前数字的所有出现</p> 216 | 217 | 218 | About Simsu 219 | 关于 Simsu 220 | 221 | 222 | A basic Sudoku game 223 | 一款简单的数独游戏 224 | 225 | 226 | Copyright &copy; 2009-%1 Graeme Gott 227 | 版权所有 &copy; 2009-%1 Graeme Gott 228 | 229 | 230 | Released under the <a href=%1>GPL 3</a> license 231 | 基于 <a href=%1>GPL 3</a> 协议发布 232 | 233 | 234 | Sorry 235 | 236 | 237 | 238 | You have not created a valid puzzle. Please try again. 239 | 240 | 241 | 242 | Please wait 243 | 244 | 245 | 246 | Generating puzzle... 247 | 248 | 249 | 250 | &Restart 251 | 252 | 253 | 254 | &Print... 255 | 256 | 257 | 258 | &Hint 259 | 260 | 261 | 262 | F2 263 | 264 | 265 | 266 | &Manual Notes 267 | 268 | 269 | 270 | Auto &Clear Notes 271 | 272 | 273 | 274 | Auto &Fill Notes 275 | 276 | 277 | 278 | Restart Game 279 | 280 | 281 | 282 | Reset the board to its original state? 283 | 284 | 285 | 286 | Print Board 287 | 288 | 289 | 290 | Difficulty: 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /windows/installer.nsi: -------------------------------------------------------------------------------- 1 | ;-------------------------------- 2 | ;Definitions 3 | 4 | !define APPNAME "Simsu" 5 | !define VERSIONMAJOR 1 6 | !define VERSIONMINOR 4 7 | !define VERSIONPATCH 6 8 | !define APPVERSION "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONPATCH}" 9 | !define ABOUTURL "https://gottcode.org/simsu/" 10 | 11 | ;-------------------------------- 12 | ;Includes 13 | 14 | !include "MUI2.nsh" 15 | !include "FileFunc.nsh" 16 | !include "TextFunc.nsh" 17 | 18 | ;-------------------------------- 19 | ;General 20 | 21 | ;Use highest compression 22 | SetCompressor /SOLID /FINAL lzma 23 | 24 | ;Name and file 25 | Name "${APPNAME}" 26 | OutFile "${APPNAME}_${APPVERSION}.exe" 27 | 28 | ;Default installation folder 29 | InstallDir "$PROGRAMFILES64\${APPNAME}" 30 | InstallDirRegKey HKLM "Software\${APPNAME}" "" 31 | 32 | ;Request application privileges for Windows Vista 33 | RequestExecutionLevel admin 34 | 35 | ;-------------------------------- 36 | ;Variables 37 | 38 | Var StartMenuFolder 39 | 40 | ;-------------------------------- 41 | ;Interface Settings 42 | 43 | !define MUI_ICON "..\icons\simsu.ico" 44 | !define MUI_UNICON "..\icons\simsu.ico" 45 | !define MUI_ABORTWARNING 46 | !define MUI_LANGDLL_ALLLANGUAGES 47 | 48 | ;-------------------------------- 49 | ;Language Selection Dialog Settings 50 | 51 | ;Remember the installer language 52 | !define MUI_LANGDLL_REGISTRY_ROOT "HKLM" 53 | !define MUI_LANGDLL_REGISTRY_KEY "Software\${APPNAME}" 54 | !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" 55 | 56 | ;-------------------------------- 57 | ;Start Menu Folder Page Settings 58 | 59 | !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" 60 | !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${APPNAME}" 61 | !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" 62 | 63 | ;-------------------------------- 64 | ;Finish Page Settings 65 | 66 | !define MUI_FINISHPAGE_RUN "$INSTDIR\${APPNAME}.exe" 67 | !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\ReadMe.txt" 68 | 69 | ;-------------------------------- 70 | ;Pages 71 | 72 | !insertmacro MUI_PAGE_WELCOME 73 | !insertmacro MUI_PAGE_LICENSE "..\COPYING" 74 | !insertmacro MUI_PAGE_DIRECTORY 75 | !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder 76 | !insertmacro MUI_PAGE_INSTFILES 77 | !insertmacro MUI_PAGE_FINISH 78 | 79 | !insertmacro MUI_UNPAGE_CONFIRM 80 | !insertmacro MUI_UNPAGE_INSTFILES 81 | 82 | ;-------------------------------- 83 | ;Languages 84 | 85 | !insertmacro MUI_LANGUAGE "English" ;first language is the default language 86 | !insertmacro MUI_LANGUAGE "French" 87 | !insertmacro MUI_LANGUAGE "German" 88 | !insertmacro MUI_LANGUAGE "Spanish" 89 | !insertmacro MUI_LANGUAGE "SpanishInternational" 90 | !insertmacro MUI_LANGUAGE "SimpChinese" 91 | !insertmacro MUI_LANGUAGE "TradChinese" 92 | !insertmacro MUI_LANGUAGE "Japanese" 93 | !insertmacro MUI_LANGUAGE "Korean" 94 | !insertmacro MUI_LANGUAGE "Italian" 95 | !insertmacro MUI_LANGUAGE "Dutch" 96 | !insertmacro MUI_LANGUAGE "Danish" 97 | !insertmacro MUI_LANGUAGE "Swedish" 98 | !insertmacro MUI_LANGUAGE "Norwegian" 99 | !insertmacro MUI_LANGUAGE "NorwegianNynorsk" 100 | !insertmacro MUI_LANGUAGE "Finnish" 101 | !insertmacro MUI_LANGUAGE "Greek" 102 | !insertmacro MUI_LANGUAGE "Russian" 103 | !insertmacro MUI_LANGUAGE "Portuguese" 104 | !insertmacro MUI_LANGUAGE "PortugueseBR" 105 | !insertmacro MUI_LANGUAGE "Polish" 106 | !insertmacro MUI_LANGUAGE "Ukrainian" 107 | !insertmacro MUI_LANGUAGE "Czech" 108 | !insertmacro MUI_LANGUAGE "Slovak" 109 | !insertmacro MUI_LANGUAGE "Croatian" 110 | !insertmacro MUI_LANGUAGE "Bulgarian" 111 | !insertmacro MUI_LANGUAGE "Hungarian" 112 | !insertmacro MUI_LANGUAGE "Thai" 113 | !insertmacro MUI_LANGUAGE "Romanian" 114 | !insertmacro MUI_LANGUAGE "Latvian" 115 | !insertmacro MUI_LANGUAGE "Macedonian" 116 | !insertmacro MUI_LANGUAGE "Estonian" 117 | !insertmacro MUI_LANGUAGE "Turkish" 118 | !insertmacro MUI_LANGUAGE "Lithuanian" 119 | !insertmacro MUI_LANGUAGE "Slovenian" 120 | !insertmacro MUI_LANGUAGE "Serbian" 121 | !insertmacro MUI_LANGUAGE "SerbianLatin" 122 | !insertmacro MUI_LANGUAGE "Arabic" 123 | !insertmacro MUI_LANGUAGE "Farsi" 124 | !insertmacro MUI_LANGUAGE "Hebrew" 125 | !insertmacro MUI_LANGUAGE "Indonesian" 126 | !insertmacro MUI_LANGUAGE "Mongolian" 127 | !insertmacro MUI_LANGUAGE "Luxembourgish" 128 | !insertmacro MUI_LANGUAGE "Albanian" 129 | !insertmacro MUI_LANGUAGE "Breton" 130 | !insertmacro MUI_LANGUAGE "Belarusian" 131 | !insertmacro MUI_LANGUAGE "Icelandic" 132 | !insertmacro MUI_LANGUAGE "Malay" 133 | !insertmacro MUI_LANGUAGE "Bosnian" 134 | !insertmacro MUI_LANGUAGE "Kurdish" 135 | !insertmacro MUI_LANGUAGE "Irish" 136 | !insertmacro MUI_LANGUAGE "Uzbek" 137 | !insertmacro MUI_LANGUAGE "Galician" 138 | !insertmacro MUI_LANGUAGE "Afrikaans" 139 | !insertmacro MUI_LANGUAGE "Catalan" 140 | !insertmacro MUI_LANGUAGE "Esperanto" 141 | !insertmacro MUI_LANGUAGE "Asturian" 142 | 143 | ;-------------------------------- 144 | ;Reserve Files 145 | 146 | !insertmacro MUI_RESERVEFILE_LANGDLL 147 | 148 | ;-------------------------------- 149 | ;Installer Functions 150 | 151 | Function .onInit 152 | 153 | !insertmacro MUI_LANGDLL_DISPLAY 154 | 155 | FunctionEnd 156 | 157 | ;-------------------------------- 158 | ;Installer Section 159 | 160 | Section "install" 161 | 162 | ;Remove previous installs 163 | !include removeprevious.nsh 164 | 165 | ;Copy files 166 | SetOutPath "$INSTDIR" 167 | File /r "..\${APPNAME}\*" 168 | 169 | ;Registry information for add/remove programs 170 | WriteRegStr HKLM "Software\${APPNAME}" "" "$INSTDIR" 171 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" 172 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "Publisher" "Graeme Gott" 173 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" 174 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" 175 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "InstallLocation" "$\"$INSTDIR$\"" 176 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayIcon" "$\"$INSTDIR\${APPNAME}.exe$\"" 177 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\"" 178 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayVersion" "${APPVERSION}" 179 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMajor" ${VERSIONMAJOR} 180 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMinor" ${VERSIONMINOR} 181 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoModify" 1 182 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoRepair" 1 183 | ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 184 | IntFmt $0 "0x%08X" $0 185 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "EstimatedSize" "$0" 186 | 187 | ;Create uninstaller 188 | WriteUninstaller "$INSTDIR\Uninstall.exe" 189 | 190 | ;Create shortcut 191 | SetShellVarContext all 192 | !insertmacro MUI_STARTMENU_WRITE_BEGIN Application 193 | CreateDirectory "$SMPROGRAMS\$StartMenuFolder" 194 | CreateShortCut "$SMPROGRAMS\$StartMenuFolder\${APPNAME}.lnk" "$INSTDIR\${APPNAME}.exe" 195 | !insertmacro MUI_STARTMENU_WRITE_END 196 | SetShellVarContext current 197 | 198 | SectionEnd 199 | 200 | ;-------------------------------- 201 | ;Uninstaller Functions 202 | 203 | Function un.onInit 204 | 205 | !insertmacro MUI_UNGETLANGUAGE 206 | 207 | FunctionEnd 208 | 209 | ;-------------------------------- 210 | ;Uninstaller Section 211 | 212 | Section "Uninstall" 213 | 214 | ; Remove from registry 215 | DeleteRegKey HKLM "Software\${APPNAME}" 216 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" 217 | 218 | ;Remove files 219 | !include files.nsh 220 | Delete "$INSTDIR\Uninstall.exe" 221 | 222 | ;Remove directories 223 | !include dirs.nsh 224 | RMDir "$INSTDIR" 225 | 226 | ;Remove shortcut 227 | SetShellVarContext all 228 | !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder 229 | Delete "$SMPROGRAMS\$StartMenuFolder\${APPNAME}.lnk" 230 | RMDir "$SMPROGRAMS\$StartMenuFolder" 231 | SetShellVarContext current 232 | 233 | SectionEnd 234 | -------------------------------------------------------------------------------- /windows/removeprevious.nsh: -------------------------------------------------------------------------------- 1 | Delete "$INSTDIR\COPYING.txt" 2 | Delete "$INSTDIR\CREDITS.txt" 3 | Delete "$INSTDIR\libgcc_s_dw2-1.dll" 4 | Delete "$INSTDIR\mingwm10.dll" 5 | Delete "$INSTDIR\Qt5Core.dll" 6 | Delete "$INSTDIR\Qt5Gui.dll" 7 | Delete "$INSTDIR\Qt5Widgets.dll" 8 | Delete "$INSTDIR\QtCore4.dll" 9 | Delete "$INSTDIR\QtGui4.dll" 10 | Delete "$INSTDIR\styles\qwindowsvistastyle.dll" 11 | Delete "$INSTDIR\translations\qtbase_bg.qm" 12 | Delete "$INSTDIR\translations\qtbase_ca.qm" 13 | Delete "$INSTDIR\translations\qtbase_cs.qm" 14 | Delete "$INSTDIR\translations\qtbase_da.qm" 15 | Delete "$INSTDIR\translations\qtbase_de.qm" 16 | Delete "$INSTDIR\translations\qtbase_en.qm" 17 | Delete "$INSTDIR\translations\qtbase_es.qm" 18 | Delete "$INSTDIR\translations\qtbase_fi.qm" 19 | Delete "$INSTDIR\translations\qtbase_fr.qm" 20 | Delete "$INSTDIR\translations\qtbase_gd.qm" 21 | Delete "$INSTDIR\translations\qtbase_he.qm" 22 | Delete "$INSTDIR\translations\qtbase_hu.qm" 23 | Delete "$INSTDIR\translations\qtbase_it.qm" 24 | Delete "$INSTDIR\translations\qtbase_ja.qm" 25 | Delete "$INSTDIR\translations\qtbase_ko.qm" 26 | Delete "$INSTDIR\translations\qtbase_lv.qm" 27 | Delete "$INSTDIR\translations\qtbase_pl.qm" 28 | Delete "$INSTDIR\translations\qtbase_ru.qm" 29 | Delete "$INSTDIR\translations\qtbase_sk.qm" 30 | Delete "$INSTDIR\translations\qtbase_uk.qm" 31 | Delete "$INSTDIR\translations\qt_gl.qm" 32 | Delete "$INSTDIR\translations\qt_help_cs.qm" 33 | Delete "$INSTDIR\translations\qt_help_da.qm" 34 | Delete "$INSTDIR\translations\qt_help_de.qm" 35 | Delete "$INSTDIR\translations\qt_help_en.qm" 36 | Delete "$INSTDIR\translations\qt_help_fr.qm" 37 | Delete "$INSTDIR\translations\qt_help_gl.qm" 38 | Delete "$INSTDIR\translations\qt_help_hu.qm" 39 | Delete "$INSTDIR\translations\qt_help_it.qm" 40 | Delete "$INSTDIR\translations\qt_help_ja.qm" 41 | Delete "$INSTDIR\translations\qt_help_ko.qm" 42 | Delete "$INSTDIR\translations\qt_help_pl.qm" 43 | Delete "$INSTDIR\translations\qt_help_ru.qm" 44 | Delete "$INSTDIR\translations\qt_help_sk.qm" 45 | Delete "$INSTDIR\translations\qt_help_sl.qm" 46 | Delete "$INSTDIR\translations\qt_help_uk.qm" 47 | Delete "$INSTDIR\translations\qt_help_zh_CN.qm" 48 | Delete "$INSTDIR\translations\qt_help_zh_TW.qm" 49 | Delete "$INSTDIR\translations\qt_lt.qm" 50 | Delete "$INSTDIR\translations\qt_pt.qm" 51 | Delete "$INSTDIR\translations\qt_sl.qm" 52 | Delete "$INSTDIR\translations\qt_sv.qm" 53 | -------------------------------------------------------------------------------- /windows_deploy.bat: -------------------------------------------------------------------------------- 1 | @ECHO ON>..\simsu\windows\dirs.nsh 2 | @ECHO ON>..\simsu\windows\files.nsh 3 | @ECHO OFF 4 | 5 | SET SRCDIR=..\simsu 6 | SET APP=Simsu 7 | SET VERSION=1.4.6 8 | 9 | ECHO Copying executable 10 | MKDIR %SRCDIR%\%APP% 11 | COPY %APP%.exe %SRCDIR%\%APP%\%APP%.exe >nul 12 | 13 | ECHO Copying translations 14 | SET TRANSLATIONS=%SRCDIR%\%APP%\translations 15 | MKDIR %TRANSLATIONS% 16 | COPY *.qm %TRANSLATIONS% >nul 17 | 18 | CD %SRCDIR% 19 | 20 | ECHO Copying Qt 21 | windeployqt.exe --verbose 0 --release --compiler-runtime^ 22 | --no-opengl-sw --no-system-dxc-compiler --no-system-d3d-compiler^ 23 | --no-svg^ 24 | --skip-plugin-types imageformats^ 25 | %APP%\%APP%.exe 26 | 27 | ECHO Creating ReadMe 28 | TYPE README >> %APP%\ReadMe.txt 29 | ECHO. >> %APP%\ReadMe.txt 30 | ECHO. >> %APP%\ReadMe.txt 31 | ECHO CREDITS >> %APP%\ReadMe.txt 32 | ECHO ======= >> %APP%\ReadMe.txt 33 | ECHO. >> %APP%\ReadMe.txt 34 | TYPE CREDITS >> %APP%\ReadMe.txt 35 | ECHO. >> %APP%\ReadMe.txt 36 | ECHO. >> %APP%\ReadMe.txt 37 | ECHO NEWS >> %APP%\ReadMe.txt 38 | ECHO ==== >> %APP%\ReadMe.txt 39 | ECHO. >> %APP%\ReadMe.txt 40 | TYPE ChangeLog >> %APP%\ReadMe.txt 41 | 42 | ECHO Creating installer 43 | CD %APP% 44 | SETLOCAL EnableDelayedExpansion 45 | SET "parentfolder=%__CD__%" 46 | FOR /R . %%F IN (*) DO ( 47 | SET "var=%%F" 48 | ECHO Delete "$INSTDIR\!var:%parentfolder%=!" >> ..\windows\files.nsh 49 | ) 50 | FOR /R /D %%F IN (*) DO ( 51 | TYPE ..\windows\dirs.nsh > temp.txt 52 | SET "var=%%F" 53 | ECHO RMDir "$INSTDIR\!var:%parentfolder%=!" > ..\windows\dirs.nsh 54 | TYPE temp.txt >> ..\windows\dirs.nsh 55 | ) 56 | DEL temp.txt 57 | ENDLOCAL 58 | CD .. 59 | makensis.exe /V0 windows\installer.nsi 60 | 61 | ECHO Making portable 62 | MKDIR %APP%\Data 63 | COPY COPYING %APP%\COPYING.txt >nul 64 | 65 | ECHO Creating compressed file 66 | CD %APP% 67 | 7z a -mx=9 %APP%_%VERSION%.zip * >nul 68 | CD .. 69 | MOVE %APP%\%APP%_%VERSION%.zip . >nul 70 | 71 | ECHO Cleaning up 72 | RMDIR /S /Q %APP% 73 | DEL windows\dirs.nsh 74 | DEL windows\files.nsh 75 | --------------------------------------------------------------------------------