summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING340
-rw-r--r--Doxyfile1218
-rw-r--r--HISTORY6
-rw-r--r--Makefile96
-rw-r--r--README81
-rw-r--r--backtrack.cpp140
-rw-r--r--backtrack.h159
-rw-r--r--bitmap.cpp151
-rw-r--r--bitmap.h53
-rw-r--r--generator.cpp128
-rw-r--r--generator.h77
-rw-r--r--i18n.cpp247
-rw-r--r--i18n.h23
-rw-r--r--menu.cpp244
-rw-r--r--menu.h66
-rw-r--r--puzzle.cpp260
-rw-r--r--puzzle.h163
-rw-r--r--setup.cpp80
-rw-r--r--setup.h60
-rw-r--r--solver.cpp95
-rw-r--r--solver.h104
-rw-r--r--sudoku.cpp114
-rw-r--r--sudoku.h24
-rw-r--r--tools/Makefile41
-rw-r--r--tools/sudoku_generator.cpp378
25 files changed, 4348 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..42a1785
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1218 @@
+# Doxyfile 1.4.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "VDR plugin 'Sudoku'"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = $(VERSION)
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the progam writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT =
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS = */tools/* */.svn/* */CVS/*
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = srcdoc
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = VDRVERSNUM=$(VDRVERSNUM)
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..dcf04ae
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,6 @@
+VDR Plugin 'sudoku' Revision History
+------------------------------------
+
+2005-10-28: Version 0.1.0
+
+- Initial revision.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..36917d3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,96 @@
+#
+# Sudoku: A plugin for the Video Disk Recorder
+#
+# See the README file for copyright information and how to reach the author.
+#
+# $Id: Makefile 11 2005-10-28 01:00:01Z tom $
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = sudoku
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char\* VERSION *=' $(PLUGIN).cpp | \
+ awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX ?= g++
+CXXFLAGS ?= -fPIC -O2 -Wall -Woverloaded-virtual
+
+### The directory environment:
+
+DVBDIR = ../../../../DVB
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | \
+ awk '{ print $$3 }' | sed -e 's/"//g')
+VDRVERSNUM = $(shell grep 'define VDRVERSNUM ' $(VDRDIR)/config.h | \
+ awk '{ print $$3 }')
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o setup.o i18n.o bitmap.o menu.o \
+ puzzle.o generator.o solver.o backtrack.o
+
+### Implicit rules:
+
+%.o: %.cpp
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.cpp) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: libvdr-$(PLUGIN).so
+ @cd tools && $(MAKE)
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+ @cp $@ $(LIBDIR)/$@.$(VDRVERSION)
+
+dist: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(PACKAGE).tgz -C $(TMPDIR) \
+ --exclude debian --exclude CVS --exclude .svn $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(PACKAGE).tgz
+
+srcdoc: Doxyfile $(OBJS:%.o=%.cpp) $(OBJS:%.o=%.h)
+ VERSION=$(VERSION) VDRVERSNUM=$(VDRVERSNUM) /usr/bin/doxygen
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.so* *.tgz core* *~
+ @-rm -rf srcdoc
+ @cd tools && $(MAKE) clean
diff --git a/README b/README
new file mode 100644
index 0000000..570f69c
--- /dev/null
+++ b/README
@@ -0,0 +1,81 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Thomas Günther <tom@toms-cafe.de>
+
+Project's homepage: http://toms-cafe.de/vdr/sudoku
+
+Latest version available at: http://toms-cafe.de/vdr/sudoku
+
+See the file COPYING for license information.
+
+
+Description:
+------------
+
+'Sudoku' is a VDR plugin to generate and solve Number Place puzzles, so called
+Sudokus.
+
+A Sudoku puzzle consists of 9 x 9 cells subdivided into 9 regions with 3 x 3
+cells. The rules are simple. There have to be the numbers from 1 to 9 in every
+row, column and region. In the beginning some numbers are given. These cells are
+painted with cyan background color. The aim of the puzzle is to find the missing
+numbers. There is only one solution of a Sudoku puzzle.
+
+The Sudoku puzzles are generated on-the-fly. The number of givens can be set in
+the plugin's setup page down to a minimum of 26 givens. The generation of
+puzzles with less than 26 givens takes too long. By default the cells with
+givens are symmetrically ordered. But this can be disabled in the setup.
+
+To solve difficult Sudoku puzzles some hints can be used. Incorrect cells are
+red and cells with ambiguous numbers are magenta. These hints can be disabled in
+the setup. With the green key a cell can be marked. A marked cell has green
+background color. With the yellow key the cursor is moved to the next free cell
+with minimal possible numbers. The red key set the next possible number for the
+current cell.
+
+Each time the plugin is started from the main menu the same puzzle is shown. A
+new puzzle is only generated on VDR startup or if it has been requested by
+pressing the blue key. This key has two functions. If no numbers are set a new
+puzzle is generated. Otherwise all numbers are reset so that only the givens are
+shown.
+
+
+Setup:
+------
+
+- Givens count Givens count of the generated puzzles (26-81).
+ Default is 36.
+- Symmetric givens Cells with givens are symmetrically ordered (yes/no).
+ Default is yes.
+- Mark errors Incorrect cells are marked with red color (yes/no).
+ Default is yes.
+- Mark ambiguous numbers Cells with ambiguous numbers are marked with magenta
+ color (yes/no).
+ Default is yes.
+- Transparency (%) Set the transparency of the menu (0-100).
+ Default is 50.
+
+
+Keys:
+-----
+
+- Left/Right/Up/Down Move the cursor in the puzzle.
+- 1-9 Set the number in the current cell.
+- 0 Remove the number from the current cell.
+- Green Mark/unmark the current cell.
+- Yellow Move the cursor to the next free cell with minimal
+ possible numbers.
+- Red Set the next possible number for the current cell -
+ reset the number if greater numbers are not possible.
+- Blue Reset the puzzle (if some numbers set).
+ Start a new puzzle (if no numbers set).
+- Back Quit the plugin.
+
+
+Cell colors:
+------------
+
+- Cyan Givens
+- Green Marked cells
+- Red Incorrect cells
+- Magenta Ambiguous numbers
diff --git a/backtrack.cpp b/backtrack.cpp
new file mode 100644
index 0000000..963724a
--- /dev/null
+++ b/backtrack.cpp
@@ -0,0 +1,140 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: backtrack.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#include "backtrack.h"
+
+using namespace BackTrack;
+
+
+//--- class BackTrack::Algorithm -----------------------------------------------
+
+/** Constructor
+ *
+ * Constructs an backtracking algorithm to solve a problem. The problem is
+ * implemented in 'solution' which represents a path through the decision
+ * tree from the root to one leaf.
+ */
+Algorithm::Algorithm (Solution& solution, unsigned int max_iter) :
+ solution(solution), max_iter(max_iter)
+{
+ first = true;
+ valid = false;
+ level = -1;
+ iter = 0;
+}
+
+/** Find the next valid solution to the problem.
+ *
+ * Repeated calls will find all solutions to a problem if multiple solutions
+ * exist.
+ */
+void Algorithm::find_next_solution()
+{
+ valid = find_solution();
+}
+
+/** Is the current solution a valid solution? */
+bool Algorithm::solution_is_valid()
+{
+ return valid;
+}
+
+/** Reset the decision tree, i.e. the next call to 'find_solution' finds
+ * the first valid solution.
+ */
+void Algorithm::reset()
+{
+ while (level >= 0)
+ {
+ solution.reset_at(level);
+ --level;
+ }
+ first = true;
+}
+
+/** Create the next leaf on the end of the solution. */
+void Algorithm::create_left_leaf()
+{
+ ++level;
+ solution.set_first_at(level);
+}
+
+/** Backtrack through the decision tree until a node was found that hasn't
+ * been visited, return true if an unvisited node was found.
+ */
+bool Algorithm::visit_new_node()
+{
+ // If the current node is the rightmost child we must backtrack
+ // one level because there are no more children at this level.
+ // So we back up until we find a non-rightmost child, then
+ // generate the child to the right. If we back up to the top
+ // without finding an unvisted child, then all nodes have been
+ // generated.
+ while (level >= 0 && solution.is_last_at(level))
+ {
+ solution.reset_at(level);
+ --level;
+ }
+ if (level < 0)
+ return false;
+ solution.set_next_at(level);
+ return true;
+}
+
+/** Find the next valid sibling of the last leaf, return true if a valid
+ * sibling was found.
+ */
+bool Algorithm::find_valid_sibling()
+{
+ // If the current node is not valid pass through all siblings until either
+ // a valid sibling is found or the last sibling is reached.
+ for (;;)
+ {
+ ++iter;
+ if (max_iter != 0 && iter > max_iter)
+ return false;
+ if (solution.is_valid_at(level))
+ return true;
+ if (solution.is_last_at(level))
+ return false;
+ solution.set_next_at(level);
+ }
+}
+
+/** Find the next valid solution to the problem, return true if a solution
+ * was found.
+ */
+bool Algorithm::find_solution()
+{
+ // If first time, need to create a root.
+ if (first)
+ {
+ first = false;
+ level = -1;
+ if (solution.is_last_level(level))
+ return solution.is_valid_at(level);
+ create_left_leaf();
+ }
+ // Otherwise visit new node since solution contains the last solution.
+ else if (!visit_new_node())
+ return false;
+
+ for (;;)
+ {
+ if (find_valid_sibling())
+ {
+ if (solution.is_last_level(level))
+ return true;
+ create_left_leaf();
+ }
+ else if (max_iter != 0 && iter > max_iter)
+ return false;
+ else if (!visit_new_node())
+ return false; // The tree has been exhausted, so no solution exists.
+ }
+}
diff --git a/backtrack.h b/backtrack.h
new file mode 100644
index 0000000..263e1dc
--- /dev/null
+++ b/backtrack.h
@@ -0,0 +1,159 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: backtrack.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_BACKTRACK_H
+#define VDR_SUDOKU_BACKTRACK_H
+
+#include "sudoku.h"
+
+
+/** Generic backtracking algorithm
+ *
+ * Inspired by an article by Roger Labbe "Solving Combinatorial Problems with
+ * STL and Backtracking" in C/C++-Users Journal, February 2000, pp. 56-64.
+ *
+ * The solution to a combinatorial problem can be described as a sequence of
+ * decisions. The backtracking algorithm traverses the decision tree
+ * depth-first. Each solution of the problem is a path through the tree from the
+ * root to one leaf. The algorithm traverses the tree by changing the elements
+ * of the solution. An element passes through all siblings on a certain level,
+ * i.e. through all possible decisions. Each step is checked if it makes the
+ * solution invalid, in which case the traversal of the whole branch is
+ * cancelled. Otherwise the algorithm either goes one level deeper or if this is
+ * the last level it has found one valid solution. After the last sibling on a
+ * level has been processed the algorithm goes back one level. Finally all valid
+ * solutions have been found if it comes back to the root node.
+ *
+ * This implementation of the backtracking algorithm consists of two classes.
+ * The Algorithm class contains the generic backtracking algorithm itself. The
+ * Solution class is the virtual base class for all specific solution classes.
+ * To solve a certain problem the specific solution class has to inherit from
+ * Solution implementing all virtual methods.
+ *
+ * Example:
+ *
+ * \code
+ * class ColorStatesList : public Solution
+ * {
+ * int clist[NUMBER_STATES];
+ * void set_first_at(unsigned int level) { clist[level] = 0; }
+ * void set_next_at(unsigned int level) { ++clist[level]; }
+ * void reset_at(unsigned int level) {}
+ * bool is_last_at(unsigned int level) { return clist[level] >= LAST_COLOR; }
+ * bool is_valid_at(int level) { return check_all_neighbors_until(level); }
+ * bool is_last_level(int level) [ return level >= NUMBER_STATES-1; }
+ * ...
+ * };
+ *
+ * void find_all_solutions()
+ * {
+ * ColorStatesList color_states_list(...);
+ * Algorithm algorithm(color_states_list);
+ * algorithm.find_next_solution();
+ * while (algorithm.solution_is_valid())
+ * {
+ * // Do something with the solution.
+ * ...
+ * algorithm.find_next_solution();
+ * }
+ * }
+ * \endcode
+ */
+namespace BackTrack
+{
+
+ //--- virtual base class BackTrack::Solution ---------------------------------
+
+ /** Virtual base class of solutions for the backtracking algorithm */
+ class Solution
+ {
+ public:
+
+ /** Destructor */
+ virtual ~Solution() {};
+
+ /** Set the element to the first sibling. */
+ virtual void set_first_at(unsigned int level) = 0;
+
+ /** Set the element to the next sibling. */
+ virtual void set_next_at(unsigned int level) = 0;
+
+ /** Reset the element. */
+ virtual void reset_at(unsigned int level) = 0;
+
+ /** Check if the element is set to the last sibling. */
+ virtual bool is_last_at(unsigned int level) const = 0;
+
+ /** Check if the element is valid (following elements ignored). */
+ virtual bool is_valid_at(int level) const = 0;
+
+ /** Check if the level is the last possible level. */
+ virtual bool is_last_level(int level) const = 0;
+ };
+
+
+ //--- class BackTrack::Algorithm ---------------------------------------------
+
+ /** Implementation of a generic backtracking algorithm */
+ class Algorithm
+ {
+ Solution& solution;
+ bool first;
+ bool valid;
+ int level;
+ unsigned int max_iter, iter;
+
+ public:
+
+ /** Constructor
+ *
+ * Constructs an backtracking algorithm to solve a problem. The problem is
+ * implemented in 'solution' which represents a path through the decision
+ * tree from the root to one leaf.
+ */
+ Algorithm(Solution& solution, unsigned int max_iter = 0);
+
+ /** Find the next valid solution to the problem.
+ *
+ * Repeated calls will find all solutions to a problem if multiple solutions
+ * exist. Return true if a solution was found.
+ */
+ void find_next_solution();
+
+ /** Is the current solution a valid solution? */
+ bool solution_is_valid();
+
+ /** Reset the decision tree, i.e. the next call to 'find_solution' finds
+ * the first valid solution.
+ */
+ virtual void reset();
+
+ private:
+
+ /** Create the next leaf on the end of the solution. */
+ void create_left_leaf();
+
+ /** Backtrack through the decision tree until a node was found that hasn't
+ * been visited, return true if an unvisited node was found.
+ */
+ bool visit_new_node();
+
+ /** Find the next valid sibling of the last leaf, return true if a valid
+ * sibling was found.
+ */
+ bool find_valid_sibling();
+
+ /** Find the next valid solution to the problem, return true if a solution
+ * was found.
+ */
+ bool find_solution();
+ };
+
+} // namespace BackTrack
+
+#endif // VDR_SUDOKU_BACKTRACK_H
diff --git a/bitmap.cpp b/bitmap.cpp
new file mode 100644
index 0000000..f41ca73
--- /dev/null
+++ b/bitmap.cpp
@@ -0,0 +1,151 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: bitmap.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#include "bitmap.h"
+#include <vdr/config.h>
+#include <vdr/osdbase.h>
+#include <vdr/osd.h>
+#include <ctype.h>
+
+// Compatibility to older vdr versions
+#if VDRVERSNUM < 10307
+ #define tColor eDvbColor
+ #define DrawRectangle Fill
+#endif
+
+using namespace SudokuPlugin;
+
+
+//--- class SudokuPlugin::Bitmap -----------------------------------------------
+
+/** Constructor */
+Bitmap::Bitmap(int width, int height) :
+ cBitmap(width, height, 4)
+{
+}
+
+/** Constructor for a bitmap with frame */
+Bitmap::Bitmap(int width, int height, tColor frameColor,
+ tColor backgroundColor) :
+ cBitmap(width, height, 4)
+{
+ DrawRectangle(0, 0, width - 1, height - 1, backgroundColor);
+ frame(0, 0, width - 1, height - 1, frameColor);
+}
+
+/** Write a text into the bitmap. */
+void Bitmap::text(const char* text, bool centered)
+{
+ DrawRectangle(0, 0, Width() - 1, Height() - 1, clrWhite);
+ frame(0, 0, Width() - 1, Height() - 1, clrRed);
+
+#if VDRVERSNUM < 10307
+ SetFont(fontOsd);
+ int lineCount;
+ char* wrapper = textWrapper(text, &lineCount);
+ int y = max((Height() - lineCount * cOsd::LineHeight()) / 2, 0);
+ char* line = wrapper;
+ while (*line)
+ {
+ char* newline = strchr(line, '\n');
+ if (newline)
+ *newline = 0;
+ int x = 0;
+ if (centered)
+ x = max((Width() - Width(line)) / 2, 0);
+ Text(x, y, line, clrBlack, clrWhite);
+ if (newline)
+ *newline = '\n';
+ if (!newline)
+ break;
+ line = newline + 1;
+ y += cOsd::LineHeight();
+ }
+ free(wrapper);
+#else
+ const cFont* font = cFont::GetFont(fontOsd);
+ cTextWrapper wrapper(text, font, Width());
+ int y = max((Height() - wrapper.Lines() * font->Height()) / 2, 0);
+ for (int l = 0; l < wrapper.Lines(); ++l, y += font->Height())
+ {
+ int x = 0;
+ if (centered)
+ x = max((Width() - font->Width(wrapper.GetLine(l))) / 2, 0);
+ DrawText(x, y, wrapper.GetLine(l), clrBlack, clrWhite, font);
+ }
+#endif
+}
+
+/** Draw a frame into the bitmap. */
+void Bitmap::frame(int x1, int y1, int x2, int y2, tColor frameColor)
+{
+ DrawRectangle(x1, y1, x2, y1 + 1, frameColor);
+ DrawRectangle(x1, y1, x1 + 1, y2, frameColor);
+ DrawRectangle(x1, y2 - 1, x2, y2, frameColor);
+ DrawRectangle(x2 - 1, y1, x2, y2, frameColor);
+}
+
+#if VDRVERSNUM < 10307
+/** Wrap the text to fit into the bitmap (taken from font.c / VDR 1.3.7). */
+char *Bitmap::textWrapper(const char *Text, int *p_lines)
+{
+ char *text = strdup(Text);
+ int lines = 1;
+
+ char *Blank = NULL;
+ char *Delim = NULL;
+ int w = 0;
+
+ stripspace(text); // strips trailing newlines
+
+ for (char *p = text; *p; ) {
+ if (*p == '\n') {
+ lines++;
+ w = 0;
+ Blank = Delim = NULL;
+ p++;
+ continue;
+ }
+ else if (isspace(*p))
+ Blank = p;
+ int cw = Width(*p);
+ if (w + cw > Width()) {
+ if (Blank) {
+ *Blank = '\n';
+ p = Blank;
+ continue;
+ }
+ else {
+ // Here's the ugly part, where we don't have any whitespace to
+ // punch in a newline, so we need to make room for it:
+ if (Delim)
+ p = Delim + 1; // let's fall back to the most recent delimiter
+ char *s = MALLOC(char, strlen(text) + 2); // The additional '\n' plus the terminating '\0'
+ int l = p - text;
+ strncpy(s, text, l);
+ s[l] = '\n';
+ strcpy(s + l + 1, p);
+ free(text);
+ text = s;
+ p = text + l;
+ continue;
+ }
+ }
+ else
+ w += cw;
+ if (strchr("-.,:;!?_", *p)) {
+ Delim = p;
+ Blank = NULL;
+ }
+ p++;
+ }
+ if (p_lines != NULL)
+ *p_lines = lines;
+ return text;
+}
+#endif
diff --git a/bitmap.h b/bitmap.h
new file mode 100644
index 0000000..c212570
--- /dev/null
+++ b/bitmap.h
@@ -0,0 +1,53 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: bitmap.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_BITMAP_H
+#define VDR_SUDOKU_BITMAP_H
+
+#include "sudoku.h"
+#include <vdr/config.h>
+#include <vdr/osdbase.h>
+#include <vdr/osd.h>
+
+// Compatibility to older vdr versions
+#if VDRVERSNUM < 10307
+ #define tColor eDvbColor
+#endif
+
+
+namespace SudokuPlugin
+{
+
+ //--- class SudokuPlugin::Bitmap ---------------------------------------------
+
+ /** Plugin-specific version of the bitmap class */
+ class Bitmap : public cBitmap
+ {
+ public:
+
+ /** Constructor */
+ Bitmap(int width, int height);
+
+ /** Constructor for a bitmap with frame */
+ Bitmap(int width, int height, tColor frameColor, tColor backgroundColor);
+
+ /** Write a text into the bitmap. */
+ void text(const char* text, bool centered = true);
+
+ /** Draw a frame into the bitmap. */
+ void frame(int x1, int y1, int x2, int y2, tColor frameColor);
+
+#if VDRVERSNUM < 10307
+ /** Wrap the text to fit into the bitmap (taken from font.c / VDR 1.3.7). */
+ char *textWrapper(const char *Text, int *p_lines);
+#endif
+ };
+
+} // namespace SudokuPlugin
+
+#endif // VDR_SUDOKU_BITMAP_H
diff --git a/generator.cpp b/generator.cpp
new file mode 100644
index 0000000..47e5e35
--- /dev/null
+++ b/generator.cpp
@@ -0,0 +1,128 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: generator.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#define USE_RAND
+#include "generator.h"
+#include "solver.h"
+#include "backtrack.h"
+#include "puzzle.h"
+#include <assert.h>
+
+using namespace Sudoku;
+using namespace BackTrack;
+
+
+//--- class Sudoku::Generator --------------------------------------------------
+
+/** Constructor */
+Generator::Generator(Puzzle& puzzle, unsigned int givens_count,
+ bool symmetric, unsigned int max_iter) :
+ Algorithm(*this, max_iter), puzzle(puzzle), symmetric(symmetric)
+{
+ assert(givens_count <= SDIM);
+
+ // Search a random Sudoku solution.
+ for (bool found = false; !found;)
+ {
+ sudoku.reset();
+ Solver solver(sudoku, true);
+ solver.find_next_solution();
+ found = solver.solution_is_valid();
+ }
+
+ // If symmetric pos_list contains only the first halve of all positions.
+ pos_count = SDIM;
+ free_count = SDIM - givens_count;
+ free_center = symmetric && pos_count % 2 != 0 && free_count % 2 != 0;
+ if (symmetric)
+ pos_count /= 2, free_count /= 2;
+
+ // Fill pos_list with positions in random order.
+ bool list[pos_count];
+ unsigned int p, i, c;
+ for (p = 0; p < pos_count; ++p)
+ list[p] = true;
+ for (i = 0; i < pos_count; ++i)
+ {
+ c = rand(pos_count - i) + 1;
+ for (p = 0; p < pos_count; ++p)
+ if (list[p])
+ if (--c == 0)
+ break;
+ assert(p < pos_count);
+ list[p] = false;
+ pos_list[i] = p;
+ }
+}
+
+/** Set the element to the first sibling. */
+void Generator::set_first_at(unsigned int level)
+{
+ assert(level < free_count);
+ free_list[level] = 0;
+}
+
+/** Set the element to the next sibling. */
+void Generator::set_next_at(unsigned int level)
+{
+ assert(level < free_count);
+ ++free_list[level];
+}
+
+/** Reset the element. */
+void Generator::reset_at(unsigned int level)
+{
+}
+
+/** Check if the element is set to the last sibling. */
+bool Generator::is_last_at(unsigned int level) const
+{
+ assert(level < free_count);
+ return free_list[level] >= pos_count - 1;
+}
+
+/** Check if the element is valid (following elements ignored). */
+bool Generator::is_valid_at(int level) const
+{
+ assert(level < int(free_count));
+
+ // free_list contains ordered indices to pos_list.
+ if (level > 0 && free_list[level] <= free_list[level - 1])
+ return false;
+ if (level >= 0 && free_list[level] > pos_count - (free_count - level))
+ return false;
+
+ // Fill list with marks for givens.
+ bool given_marks[SDIM];
+ int i;
+ for (i = 0; i < SDIM; ++i)
+ given_marks[i] = true;
+ for (i = 0; i <= level; ++i)
+ {
+ Pos p = pos_list[free_list[i]];
+ given_marks[p] = false;
+ if (symmetric)
+ given_marks[p.symmetric()] = false;
+ }
+ if (free_center)
+ given_marks[Pos::center()] = false;
+
+ // Set givens in puzzle and check if it has only one solution.
+ puzzle.set_givens(sudoku, given_marks);
+ Solver solver(puzzle);
+ solver.find_next_solution();
+ assert(solver.solution_is_valid());
+ solver.find_next_solution();
+ return !solver.solution_is_valid();
+}
+
+/** Check if the level is the last possible level. */
+bool Generator::is_last_level(int level) const
+{
+ return level >= int(free_count) - 1;
+}
diff --git a/generator.h b/generator.h
new file mode 100644
index 0000000..8266b84
--- /dev/null
+++ b/generator.h
@@ -0,0 +1,77 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: generator.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_GENERATOR_H
+#define VDR_SUDOKU_GENERATOR_H
+
+#include "sudoku.h"
+#include "backtrack.h"
+#include "puzzle.h"
+
+
+namespace Sudoku
+{
+
+ //--- class Sudoku::Generator ------------------------------------------------
+
+ /** Implementation of a backtracking algorithm to generate Sudoku puzzles
+ *
+ * To generate Sudoku puzzles two nested backtracking algorithms are used.
+ * First a random Sudoku solution is searched. Then the algorithm tries to
+ * remove some numbers so that only the requested number of givens remains.
+ * Each puzzle is checked with the nested solver algorithm if there is only
+ * one solution.
+ *
+ * Example:
+ *
+ * \code
+ * Puzzle puzzle;
+ * Generator generator(puzzle, 36);
+ * generator.find_next_solution();
+ * bool found = generator.solution_is_valid();
+ * \endcode
+ */
+ class Generator : public BackTrack::Algorithm, public BackTrack::Solution
+ {
+ Puzzle& puzzle;
+ Puzzle sudoku;
+ unsigned int free_list[SDIM];
+ unsigned int free_count;
+ Pos pos_list[SDIM];
+ unsigned int pos_count;
+ bool symmetric;
+ bool free_center;
+
+ public:
+
+ /** Constructor */
+ Generator(Puzzle& puzzle, unsigned int givens_count,
+ bool symmetric = true, unsigned int max_iter = 0);
+
+ /** Set the element to the first sibling. */
+ virtual void set_first_at(unsigned int level);
+
+ /** Set the element to the next sibling. */
+ virtual void set_next_at(unsigned int level);
+
+ /** Reset the element. */
+ virtual void reset_at(unsigned int level);
+
+ /** Check if the element is set to the last sibling. */
+ virtual bool is_last_at(unsigned int level) const;
+
+ /** Check if the element is valid (following elements ignored). */
+ virtual bool is_valid_at(int level) const;
+
+ /** Check if the level is the last possible level. */
+ virtual bool is_last_level(int level) const;
+ };
+
+} // namespace Sudoku
+
+#endif // VDR_SUDOKU_GENERATOR_H
diff --git a/i18n.cpp b/i18n.cpp
new file mode 100644
index 0000000..62ef544
--- /dev/null
+++ b/i18n.cpp
@@ -0,0 +1,247 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: i18n.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#include "i18n.h"
+#include <vdr/config.h>
+
+
+const tI18nPhrase SudokuPlugin::Phrases[] = {
+ { "Sudoku", // English
+ "Sudoku", // Deutsch / German
+ "", // Slovenski / Slovenian
+ "", // Italiano / Italian
+ "", // Nederlands / Dutch
+ "", // Português / Portuguese
+ "", // Français / French
+ "", // Norsk / Norwegian
+ "", // suomi / Finnish
+ "", // Polski / Polish
+ "", // Español / Spanish
+ "", // ÅëëçíéêÜ / Greek
+ "", // Svenska / Swedish
+ "", // Românã / Romanian
+ "", // Magyar / Hungarian
+ "", // Català / Catalanian
+#if VDRVERSNUM > 10302
+ "", // ÀãááÚØÙ / Russian
+#if VDRVERSNUM > 10307
+ "", // Hrvatski / Croatian
+#if VDRVERSNUM > 10313
+ "", // Eesti / Estonian
+#if VDRVERSNUM > 10316
+ "", // Dansk / Danish
+#endif
+#endif
+#endif
+#endif
+ },
+ { "Sudoku - generate and solve Number Place puzzles", // English
+ "Sudoku - Erzeugen und Lösen von Zahlenpuzzles", // Deutsch / German
+ "", // Slovenski / Slovenian
+ "", // Italiano / Italian
+ "", // Nederlands / Dutch
+ "", // Português / Portuguese
+ "", // Français / French
+ "", // Norsk / Norwegian
+ "", // suomi / Finnish
+ "", // Polski / Polish
+ "", // Español / Spanish
+ "", // ÅëëçíéêÜ / Greek
+ "", // Svenska / Swedish
+ "", // Românã / Romanian
+ "", // Magyar / Hungarian
+ "", // Català / Catalanian
+#if VDRVERSNUM > 10302
+ "", // ÀãááÚØÙ / Russian
+#if VDRVERSNUM > 10307
+ "", // Hrvatski / Croatian
+#if VDRVERSNUM > 10313
+ "", // Eesti / Estonian
+#if VDRVERSNUM > 10316
+ "", // Dansk / Danish
+#endif
+#endif
+#endif
+#endif
+ },
+ { "Givens count", // English
+ "Anzahl vorgegebener Zahlen", // Deutsch / German
+ "", // Slovenski / Slovenian
+ "", // Italiano / Italian
+ "", // Nederlands / Dutch
+ "", // Português / Portuguese
+ "", // Français / French
+ "", // Norsk / Norwegian
+ "", // suomi / Finnish
+ "", // Polski / Polish
+ "", // Español / Spanish
+ "", // ÅëëçíéêÜ / Greek
+ "", // Svenska / Swedish
+ "", // Românã / Romanian
+ "", // Magyar / Hungarian
+ "", // Català / Catalanian
+#if VDRVERSNUM > 10302
+ "", // ÀãááÚØÙ / Russian
+#if VDRVERSNUM > 10307
+ "", // Hrvatski / Croatian
+#if VDRVERSNUM > 10313
+ "", // Eesti / Estonian
+#if VDRVERSNUM > 10316
+ "", // Dansk / Danish
+#endif
+#endif
+#endif
+#endif
+ },
+ { "Symmetric givens", // English
+ "Vorgegebene Zahlen symmetrisch anordnen", // Deutsch / German
+ "", // Slovenski / Slovenian
+ "", // Italiano / Italian
+ "", // Nederlands / Dutch
+ "", // Português / Portuguese
+ "", // Français / French
+ "", // Norsk / Norwegian
+ "", // suomi / Finnish
+ "", // Polski / Polish
+ "", // Español / Spanish
+ "", // ÅëëçíéêÜ / Greek
+ "", // Svenska / Swedish
+ "", // Românã / Romanian
+ "", // Magyar / Hungarian
+ "", // Català / Catalanian
+#if VDRVERSNUM > 10302
+ "", // ÀãááÚØÙ / Russian
+#if VDRVERSNUM > 10307
+ "", // Hrvatski / Croatian
+#if VDRVERSNUM > 10313
+ "", // Eesti / Estonian
+#if VDRVERSNUM > 10316
+ "", // Dansk / Danish
+#endif
+#endif
+#endif
+#endif
+ },
+ { "Mark errors", // English
+ "Fehler markieren", // Deutsch / German
+ "", // Slovenski / Slovenian
+ "", // Italiano / Italian
+ "", // Nederlands / Dutch
+ "", // Português / Portuguese
+ "", // Français / French
+ "", // Norsk / Norwegian
+ "", // suomi / Finnish
+ "", // Polski / Polish
+ "", // Español / Spanish
+ "", // ÅëëçíéêÜ / Greek
+ "", // Svenska / Swedish
+ "", // Românã / Romanian
+ "", // Magyar / Hungarian
+ "", // Català / Catalanian
+#if VDRVERSNUM > 10302
+ "", // ÀãááÚØÙ / Russian
+#if VDRVERSNUM > 10307
+ "", // Hrvatski / Croatian
+#if VDRVERSNUM > 10313
+ "", // Eesti / Estonian
+#if VDRVERSNUM > 10316
+ "", // Dansk / Danish
+#endif
+#endif
+#endif
+#endif
+ },
+ { "Mark ambiguous numbers", // English
+ "Unklare Zahlen markieren", // Deutsch / German
+ "", // Slovenski / Slovenian
+ "", // Italiano / Italian
+ "", // Nederlands / Dutch
+ "", // Português / Portuguese
+ "", // Français / French
+ "", // Norsk / Norwegian
+ "", // suomi / Finnish
+ "", // Polski / Polish
+ "", // Español / Spanish
+ "", // ÅëëçíéêÜ / Greek
+ "", // Svenska / Swedish
+ "", // Românã / Romanian
+ "", // Magyar / Hungarian
+ "", // Català / Catalanian
+#if VDRVERSNUM > 10302
+ "", // ÀãááÚØÙ / Russian
+#if VDRVERSNUM > 10307
+ "", // Hrvatski / Croatian
+#if VDRVERSNUM > 10313
+ "", // Eesti / Estonian
+#if VDRVERSNUM > 10316
+ "", // Dansk / Danish
+#endif
+#endif
+#endif
+#endif
+ },
+ { "Transparency (%)", // English
+ "Transparenz (%)", // Deutsch / German
+ "", // Slovenski / Slovenian
+ "", // Italiano / Italian
+ "", // Nederlands / Dutch
+ "", // Português / Portuguese
+ "", // Français / French
+ "", // Norsk / Norwegian
+ "", // suomi / Finnish
+ "", // Polski / Polish
+ "", // Español / Spanish
+ "", // ÅëëçíéêÜ / Greek
+ "", // Svenska / Swedish
+ "", // Românã / Romanian
+ "", // Magyar / Hungarian
+ "", // Català / Catalanian
+#if VDRVERSNUM > 10302
+ "", // ÀãááÚØÙ / Russian
+#if VDRVERSNUM > 10307
+ "", // Hrvatski / Croatian
+#if VDRVERSNUM > 10313
+ "", // Eesti / Estonian
+#if VDRVERSNUM > 10316
+ "", // Dansk / Danish
+#endif
+#endif
+#endif
+#endif
+ },
+ { "Congratulations!\nPress OK to start a new puzzle", // English
+ "Herzlichen Glückwunsch!\nOK startet ein neues Puzzle", // Deutsch / German
+ "", // Slovenski / Slovenian
+ "", // Italiano / Italian
+ "", // Nederlands / Dutch
+ "", // Português / Portuguese
+ "", // Français / French
+ "", // Norsk / Norwegian
+ "", // suomi / Finnish
+ "", // Polski / Polish
+ "", // Español / Spanish
+ "", // ÅëëçíéêÜ / Greek
+ "", // Svenska / Swedish
+ "", // Românã / Romanian
+ "", // Magyar / Hungarian
+ "", // Català / Catalanian
+#if VDRVERSNUM > 10302
+ "", // ÀãááÚØÙ / Russian
+#if VDRVERSNUM > 10307
+ "", // Hrvatski / Croatian
+#if VDRVERSNUM > 10313
+ "", // Eesti / Estonian
+#if VDRVERSNUM > 10316
+ "", // Dansk / Danish
+#endif
+#endif
+#endif
+#endif
+ },
+ { NULL }
+};
diff --git a/i18n.h b/i18n.h
new file mode 100644
index 0000000..7e75648
--- /dev/null
+++ b/i18n.h
@@ -0,0 +1,23 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: i18n.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_I18N_H
+#define VDR_SUDOKU_I18N_H
+
+#include "sudoku.h"
+#include <vdr/i18n.h>
+
+
+namespace SudokuPlugin
+{
+
+ extern const tI18nPhrase Phrases[];
+
+} // namespace SudokuPlugin
+
+#endif // VDR_SUDOKU_I18N_H
diff --git a/menu.cpp b/menu.cpp
new file mode 100644
index 0000000..2a4e422
--- /dev/null
+++ b/menu.cpp
@@ -0,0 +1,244 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menu.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#include "menu.h"
+#include "puzzle.h"
+#include "setup.h"
+#include "bitmap.h"
+#include "i18n.h"
+#include <vdr/config.h>
+#include <vdr/osdbase.h>
+#include <vdr/osd.h>
+#include <vdr/font.h>
+
+// Compatibility to older vdr versions
+#if VDRVERSNUM < 10307
+ #define tColor eDvbColor
+ #define DrawRectangle Fill
+ #define DrawBitmap SetBitmap
+ #define cOsdProvider cOsd
+ #define NewOsd OpenRaw
+ struct tArea { int x1, y1, x2, y2, bpp; };
+ #define SetAreas(a,n) Create(a->x1, a->y1,\
+ a->x2 - a->x1 + 1, a->y2 - a->y1 + 1,\
+ a->bpp, true)
+ #define Color GetColor
+ #define savePalette(bitmap) savePalette(2)
+ #define SetPalette(palette, area) Width('X')
+#endif
+
+using namespace SudokuPlugin;
+using namespace Sudoku;
+
+
+// Definitions for grid structure
+#define CELL_SIZE 42
+#define CELL_POS(i) ((i) * (CELL_SIZE + 2) + (i)/RDIM * 3 + 5)
+#define GRID_SIZE (DIM * (CELL_SIZE + 2) + DIM/RDIM * 3 + 5)
+
+// Definitions for grid colors
+#define TRANS(c,t) tColor(((c) & 0x00FFFFFF) | (0xFF * (100-(t))/100)<<24)
+#define GRID_COLOR clrWhite
+#define CURSUR_COLOR clrBlue
+#define NUMBER_FG clrWhite
+#define NUMBER_BG clrBlack
+#define ERROR_FG clrWhite
+#define ERROR_BG clrRed
+#define AMBIG_FG clrWhite
+#define AMBIG_BG clrMagenta
+#define MARKED_FG clrWhite
+#define MARKED_BG clrGreen
+#define GIVEN_FG clrBlack
+#define GIVEN_BG clrCyan
+
+
+//--- class SudokuPlugin::Menu -------------------------------------------------
+
+/** Constructor */
+Menu::Menu(const SetupData& setup, Puzzle& puzzle, Pos& curr) :
+ cOsdObject(true), setup(setup), puzzle(puzzle), curr(curr)
+{
+ xPos = (720 - GRID_SIZE) / 2;
+ yPos = (576 - GRID_SIZE) / 2;
+ osd = NULL;
+ info = NULL;
+ infoText = NULL;
+ new_puzzle_request = false;
+}
+
+/** Destructor */
+Menu::~Menu()
+{
+ delete info;
+ delete osd;
+}
+
+/** Display the menu on the OSD. */
+void Menu::Show()
+{
+ int x1 = xPos, y1 = yPos;
+ int x2 = xPos + GRID_SIZE - 1, y2 = yPos + GRID_SIZE -1;
+
+ osd = cOsdProvider::NewOsd(0, 0);
+ if (osd)
+ {
+ tArea areas[] = { x1, y1, x2, y2, 4 };
+ osd->SetAreas(areas, 1);
+ paint();
+ }
+}
+
+/** Process user events. */
+eOSState Menu::ProcessKey(eKeys key)
+{
+ eOSState state = cOsdObject::ProcessKey(key);
+ if (state == osUnknown)
+ {
+ if (key == kBack)
+ return osEnd;
+ if (new_puzzle_request)
+ {
+ if (key == kOk)
+ {
+ new_puzzle_request = false;
+ puzzle.generate(setup.givens_count, setup.symmetric);
+ }
+ }
+ else
+ {
+ switch (key)
+ {
+ case kLeft:
+ case kLeft|k_Repeat:
+ curr = curr.prev_col();
+ break;
+ case kRight:
+ case kRight|k_Repeat:
+ curr = curr.next_col();
+ break;
+ case kUp:
+ case kUp|k_Repeat:
+ curr = curr.prev_row();
+ break;
+ case kDown:
+ case kDown|k_Repeat:
+ curr = curr.next_row();
+ break;
+ case k0:
+ case k1:
+ case k2:
+ case k3:
+ case k4:
+ case k5:
+ case k6:
+ case k7:
+ case k8:
+ case k9:
+ puzzle.set(curr, key - k0);
+ break;
+ case kRed:
+ puzzle.set(curr, puzzle.next_number(curr));
+ break;
+ case kGreen:
+ puzzle.toggle_mark(curr);
+ break;
+ case kYellow:
+ if (puzzle.next_free(curr) <= Pos::last())
+ curr = puzzle.next_free(curr);
+ break;
+ case kBlue:
+ if (puzzle.untouched())
+ puzzle.generate(setup.givens_count, setup.symmetric);
+ else
+ puzzle.reset();
+ break;
+ default:
+ return osContinue;
+ }
+ }
+ if (puzzle.solved())
+ {
+ new_puzzle_request = true;
+ infoText = tr("Congratulations!\nPress OK to start a new puzzle");
+ }
+ paint();
+ state = osContinue;
+ }
+ return state;
+}
+
+/** Paint all pieces of the menu. */
+void Menu::paint()
+{
+ int trans = setup.transparency;
+ tColor fg, bg = TRANS(GRID_COLOR, trans);
+ int x1 = xPos, y1 = yPos;
+ int x2 = xPos + GRID_SIZE - 1, y2 = yPos + GRID_SIZE -1;
+
+ // Save and restore palette to reduce flickering.
+ cPalette savePalette(*osd->GetBitmap(0));
+ osd->DrawRectangle(x1, y1, x2, y2, bg);
+ osd->SetPalette(savePalette, 0);
+
+ // Paint all cells.
+ for (Pos p = Pos::first(); p <= Pos::last(); p = p.next())
+ {
+ fg = NUMBER_FG, bg = NUMBER_BG;
+ if (puzzle.given(p))
+ fg = GIVEN_FG, bg = GIVEN_BG;
+ else if (puzzle.marked(p))
+ fg = MARKED_FG, bg = MARKED_BG;
+ else if (setup.mark_errors && puzzle.error(p))
+ fg = ERROR_FG, bg = ERROR_BG;
+ else if (setup.mark_ambiguous && puzzle.ambiguous(p))
+ fg = AMBIG_FG, bg = AMBIG_BG;
+ fg = TRANS(fg, trans);
+ bg = TRANS(bg, trans);
+
+ // Paint the background of the cell.
+ x1 = xPos + CELL_POS(p.col()), y1 = yPos + CELL_POS(p.row());
+ x2 = x1 + CELL_SIZE - 1, y2 = y1 + CELL_SIZE - 1;
+ osd->DrawRectangle(x1, y1, x2, y2, bg);
+
+ // Paint the content of the cell.
+ if (puzzle.get(p) != 0)
+ {
+ char txt[2] = { '0' + puzzle.get(p), 0 };
+#if VDRVERSNUM < 10307
+ osd->SetFont(fontFix);
+ osd->Text(x1 + max((CELL_SIZE - osd->Width(txt)) / 2, 0),
+ y1 + max((CELL_SIZE - cOsd::LineHeight()) / 2, 0),
+ txt, fg, bg);
+#else
+ const cFont* font = cFont::GetFont(fontFix);
+ osd->DrawText(x1, y1, txt, fg, bg, font, CELL_SIZE, CELL_SIZE, taCenter);
+#endif
+ }
+ }
+
+ // Paint the cursor.
+ bg = TRANS(CURSUR_COLOR, trans);
+ x1 = xPos + CELL_POS(curr.col()), y1 = yPos + CELL_POS(curr.row());
+ x2 = x1 + CELL_SIZE - 1, y2 = y1 + CELL_SIZE - 1;
+ osd->DrawRectangle(x1 - 5, y1 - 5, x2, y1, bg);
+ osd->DrawRectangle(x1 - 5, y1, x1, y2 + 5, bg);
+ osd->DrawRectangle(x1, y2, x2 + 5, y2 + 5, bg);
+ osd->DrawRectangle(x2, y1 - 5, x2 + 5, y2, bg);
+
+ // Paint info window.
+ if (infoText)
+ {
+ if (!info)
+ info = new Bitmap(GRID_SIZE - 20, 60);
+ info->text(infoText);
+ osd->DrawBitmap(xPos + 10, yPos + 10, *info);
+ infoText = NULL;
+ }
+
+ osd->Flush();
+}
diff --git a/menu.h b/menu.h
new file mode 100644
index 0000000..30d9819
--- /dev/null
+++ b/menu.h
@@ -0,0 +1,66 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menu.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_MENU_H
+#define VDR_SUDOKU_MENU_H
+
+#include "sudoku.h"
+namespace SudokuPlugin { class SetupData; class Bitmap; }
+namespace Sudoku { class Puzzle; class Pos; }
+#include <vdr/config.h>
+#include <vdr/osdbase.h>
+#include <vdr/osd.h>
+
+// Compatibility to older vdr versions
+#if VDRVERSNUM < 10307
+ #define cOsd_ cOsdBase
+#else
+ #define cOsd_ cOsd
+#endif
+
+
+namespace SudokuPlugin
+{
+
+ //--- class SudokuPlugin::Menu -----------------------------------------------
+
+ /** Main menu of the plugin */
+ class Menu : public cOsdObject
+ {
+ const SetupData& setup;
+ Sudoku::Puzzle& puzzle;
+ Sudoku::Pos& curr;
+ int xPos, yPos;
+ cOsd_* osd;
+ Bitmap* info;
+ const char* infoText;
+ bool new_puzzle_request;
+
+ public:
+
+ /** Constructor */
+ Menu(const SetupData& setup, Sudoku::Puzzle& puzzle, Sudoku::Pos& curr);
+
+ /** Destructor */
+ virtual ~Menu();
+
+ /** Display the menu on the OSD. */
+ virtual void Show();
+
+ /** Process user events. */
+ virtual eOSState ProcessKey(eKeys key);
+
+ private:
+
+ /** Paint all pieces of the menu. */
+ void paint();
+ };
+
+} // namespace SudokuPlugin
+
+#endif // VDR_SUDOKU_MENU_H
diff --git a/puzzle.cpp b/puzzle.cpp
new file mode 100644
index 0000000..803c130
--- /dev/null
+++ b/puzzle.cpp
@@ -0,0 +1,260 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: puzzle.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#include "puzzle.h"
+#include "generator.h"
+#include <assert.h>
+
+using namespace Sudoku;
+
+
+//--- class Sudoku::Numbers ----------------------------------------------------
+
+/** Constructor */
+Numbers::Numbers()
+{
+ reset();
+}
+
+/** Destructor */
+Numbers::~Numbers()
+{
+}
+
+/** Remove all numbers. */
+void Numbers::reset()
+{
+ for (unsigned int i = 0; i < SDIM; ++i)
+ content[i] = 0;
+}
+
+/** Set numbers from contents of sudoku if marked in marks. */
+void Numbers::set_contents(const Numbers& sudoku, const bool marks[SDIM])
+{
+ for (unsigned int i = 0; i < SDIM; ++i)
+ if (marks[i])
+ content[i] = sudoku.get(i);
+ else
+ content[i] = 0;
+}
+
+/** Set the number into this cell. */
+void Numbers::set(Pos pos, unsigned int number)
+{
+ assert (pos <= Pos::last());
+ assert (0 <= number && number <= DIM);
+ content[pos] = number;
+}
+
+/** Get the number from this cell. */
+unsigned int Numbers::get(Pos pos) const
+{
+ assert (pos <= Pos::last());
+ assert (0 <= content[pos] && content[pos] <= DIM);
+ return content[pos];
+}
+
+
+//--- class Sudoku::Puzzle -----------------------------------------------------
+
+/** Constructor */
+Puzzle::Puzzle(unsigned int givens_count, bool symmetric)
+{
+ if (givens_count == 0)
+ clear_givens();
+ else
+ generate(givens_count, symmetric);
+}
+
+/** Reset the puzzle. */
+void Puzzle::reset()
+{
+ unsigned int i;
+
+ // Fill the puzzle with the givens.
+ for (i = 0; i < SDIM; ++i)
+ Numbers::set(i, givens.get(i));
+
+ // Compute possible numbers for all cells.
+ for (i = 0; i < SDIM; ++i)
+ compute_numbers(i);
+
+ // Reset marked cells.
+ for (i = 0; i < SDIM; ++i)
+ marks[i] = false;
+}
+
+/** Set the number into this cell. */
+void Puzzle::set(Pos pos, unsigned int number)
+{
+ assert (pos <= Pos::last());
+ assert (0 <= number && number <= DIM);
+
+ if (!given(pos) && get(pos) != number)
+ {
+ Numbers::set(pos, number);
+
+ // Refresh possible numbers of all affected cells.
+ for (Pos p = Pos::first(); p <= Pos::last(); p = p.next())
+ if (p.col() == pos.col() || p.row() == pos.row() || p.reg() == pos.reg())
+ compute_numbers(p);
+ }
+}
+
+/** Generate a new puzzle. */
+void Puzzle::generate(unsigned int givens_count, bool symmetric)
+{
+ // Search a random non-ambiguous puzzle.
+ for (bool found = false; !found;)
+ {
+ Generator generator(*this, givens_count, symmetric, symmetric ? 500 : 2000);
+ generator.find_next_solution();
+ found = generator.solution_is_valid();
+ }
+ reset();
+}
+
+/** Set givens from contents of sudoku if marked in given_marks. */
+void Puzzle::set_givens(const Numbers& sudoku, const bool given_marks[SDIM])
+{
+ givens.set_contents(sudoku, given_marks);
+ reset();
+}
+
+/** Remove all givens. */
+void Puzzle::clear_givens()
+{
+ givens.reset();
+ reset();
+}
+
+/** No cells set? */
+bool Puzzle::untouched() const
+{
+ unsigned int i;
+
+ for (i = 0; i < SDIM; ++i)
+ if (get(i) != givens.get(i))
+ return false;
+
+ return true;
+}
+
+/** Is the number in this cell given? */
+bool Puzzle::given(Pos pos) const
+{
+ assert (pos <= Pos::last());
+ return givens.get(pos) != 0;
+}
+
+/** Is there an error on this position? */
+bool Puzzle::error(Pos pos) const
+{
+ assert (pos <= Pos::last());
+ return !correct(pos);
+}
+
+/** Is the number in this cell ambiguous? */
+bool Puzzle::ambiguous(Pos pos) const
+{
+ assert (pos <= Pos::last());
+ return get(pos) != 0 && count[pos] > 1;
+}
+
+/** All cells set and no errors? */
+bool Puzzle::solved() const
+{
+ unsigned int i;
+
+ for (i = 0; i < SDIM; ++i)
+ if (get(i) == 0 || !correct(i))
+ return false;
+
+ return true;
+}
+
+/** Is this cell marked? */
+bool Puzzle::marked(Pos pos) const
+{
+ assert (pos <= Pos::last());
+ return marks[pos];
+}
+
+/** Toggle the mark for this cell. */
+void Puzzle::toggle_mark(Pos pos)
+{
+ assert (pos < Pos::last());
+ marks[pos] = !marks[pos];
+}
+
+/** Get the next free cell with minimal possible numbers. */
+Pos Puzzle::next_free(Pos pos) const
+{
+ unsigned int min_count = DIM+1, min_index = SDIM, i;
+
+ for (pos = (pos+1)%SDIM, i = 0; i < SDIM; ++i, pos = (pos+1)%SDIM)
+ if (get(pos) == 0 && count[pos] < min_count)
+ min_count = count[pos], min_index = pos;
+
+ return min_index;
+}
+
+/** Get the next possible number for this cell. */
+unsigned int Puzzle::next_number(Pos pos)
+{
+ assert (pos <= Pos::last());
+ unsigned int n = get(pos);
+ unsigned int i;
+
+ if (!given(pos))
+ for (n = (n+1)%(DIM+1), i = 0; i < DIM+1; ++i, n = (n+1)%(DIM+1))
+ if (numbers[pos][n])
+ break;
+
+ return n;
+}
+
+/** Get the count of possible numbers for this cell. */
+unsigned int Puzzle::numbers_count(Pos pos)
+{
+ assert (pos <= Pos::last());
+ return count[pos];
+}
+
+/** Compute all possible numbers for this cell. */
+void Puzzle::compute_numbers(Pos pos)
+{
+ assert(pos <= Pos::last());
+ unsigned int i;
+
+ // Fill list with all numbers.
+ for (i = 1; i <= DIM; ++i)
+ numbers[pos][i] = true;
+
+ // Disable numbers found in row, column or region.
+ for (Pos p = Pos::first(); p <= Pos::last(); p = p.next())
+ if (p != pos &&
+ (p.col() == pos.col() || p.row() == pos.row() || p.reg() == pos.reg()))
+ numbers[pos][get(p)] = false;
+
+ // Count the possible numbers.
+ count[pos] = 0;
+ for (i = 1; i <= DIM; ++i)
+ if (numbers[pos][i])
+ ++count[pos];
+
+ // 0 is always possible.
+ numbers[pos][0] = true;
+}
+
+/** Is the number in this cell a possible number? */
+bool Puzzle::correct(Pos pos) const
+{
+ assert(pos <= Pos::last());
+ return count[pos] != 0 && numbers[pos][get(pos)];
+}
diff --git a/puzzle.h b/puzzle.h
new file mode 100644
index 0000000..4083350
--- /dev/null
+++ b/puzzle.h
@@ -0,0 +1,163 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: puzzle.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_PUZZLE_H
+#define VDR_SUDOKU_PUZZLE_H
+
+#include "sudoku.h"
+
+
+/** Sudoku puzzle
+ *
+ * A Sudoku puzzle consists of 9 x 9 cells subdivided into 9 regions with 3 x 3
+ * cells. The rules are simple. There have to be the numbers from 1 to 9 in
+ * every row, column and region.
+ */
+namespace Sudoku
+{
+
+ /** Regions, rows/columns and square dimension of the puzzle */
+ enum
+ {
+ /** Regions dimension. Width and height of a region */
+ RDIM = 3,
+
+ /** Dimension. Number of cells in a row, column or region */
+ DIM = RDIM * RDIM,
+
+ /** Square dimension. Number of cells in the whole puzzle */
+ SDIM = DIM * DIM
+ };
+
+
+ //--- class Sudoku::Pos ------------------------------------------------------
+
+ /** Position in a Sudoku */
+ class Pos
+ {
+ unsigned int pos;
+ public:
+ Pos(unsigned int col, unsigned int row) : pos(col + row * DIM) {}
+ Pos(unsigned int pos = 0) : pos(pos) {}
+ operator unsigned int() const { return pos; }
+ static Pos first() { return 0; }
+ static Pos last() { return SDIM-1; }
+ Pos next() const { return pos + 1; }
+ unsigned int col() const { return pos % DIM; }
+ unsigned int row() const { return pos / DIM; }
+ unsigned int reg() const { return (col() / RDIM) + RDIM * (row() / RDIM); }
+ static Pos center() { return SDIM / 2; }
+ Pos symmetric() const { return SDIM - 1 - pos; }
+ Pos prev_col() const { return col() > 0 ? pos - 1 : pos; }
+ Pos next_col() const { return col() < DIM-1 ? pos + 1 : pos; }
+ Pos prev_row() const { return row() > 0 ? pos - DIM : pos; }
+ Pos next_row() const { return row() < DIM-1 ? pos + DIM : pos; }
+ };
+
+
+ //--- class Sudoku::Numbers --------------------------------------------------
+
+ /** Numbers of a Sudoku */
+ class Numbers
+ {
+ unsigned int content[SDIM];
+
+ public:
+
+ /** Constructor */
+ Numbers();
+
+ /** Destructor */
+ virtual ~Numbers();
+
+ /** Remove all numbers. */
+ virtual void reset();
+
+ /** Set numbers from contents of sudoku if marked in marks. */
+ virtual void set_contents(const Numbers& sudoku, const bool marks[SDIM]);
+
+ /** Set the number into this cell. */
+ virtual void set(Pos pos, unsigned int number);
+
+ /** Get the number from this cell. */
+ virtual unsigned int get(Pos pos) const;
+ };
+
+
+ //--- class Sudoku::Puzzle ---------------------------------------------------
+
+ /** Sudoku puzzle */
+ class Puzzle : public Numbers
+ {
+ Numbers givens;
+ bool marks[SDIM];
+ bool numbers[SDIM][DIM+1];
+ unsigned int count[SDIM];
+
+ public:
+
+ /** Constructor */
+ Puzzle(unsigned int givens_count = 0, bool symmetric = true);
+
+ /** Reset the puzzle. */
+ virtual void reset();
+
+ /** Set the number into this cell. */
+ virtual void set(Pos pos, unsigned int number);
+
+ /** Generate a new puzzle. */
+ void generate(unsigned int givens_count, bool symmetric = true);
+
+ /** Set givens from contents of sudoku if marked in given_marks. */
+ void set_givens(const Numbers& sudoku, const bool given_marks[SDIM]);
+
+ /** Remove all givens. */
+ void clear_givens();
+
+ /** No cells set? */
+ bool untouched() const;
+
+ /** Is the number in this cell given? */
+ bool given(Pos pos) const;
+
+ /** Is there an error on this position? */
+ bool error(Pos pos) const;
+
+ /** Is the number in this cell ambiguous? */
+ bool ambiguous(Pos pos) const;
+
+ /** All cells set and no errors? */
+ bool solved() const;
+
+ /** Is this cell marked? */
+ bool marked(Pos pos) const;
+
+ /** Toggle the mark for this cell. */
+ void toggle_mark(Pos pos);
+
+ /** Get the next free cell with minimal possible numbers. */
+ Pos next_free(Pos pos = Pos::last()) const;
+
+ /** Get the next possible number for this cell. */
+ unsigned int next_number(Pos pos);
+
+ /** Get the count of possible numbers for this cell. */
+ unsigned int numbers_count(Pos pos);
+
+private:
+
+ /** Compute all possible numbers for this cell. */
+ void compute_numbers(Pos pos);
+
+ /** Is the number in this cell a possible number? */
+ bool correct(Pos pos) const;
+ };
+
+} // namespace Sudoku
+
+#endif // VDR_SUDOKU_PUZZLE_H
diff --git a/setup.cpp b/setup.cpp
new file mode 100644
index 0000000..eb1ad80
--- /dev/null
+++ b/setup.cpp
@@ -0,0 +1,80 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: setup.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#include "setup.h"
+#include "i18n.h"
+#include <strings.h>
+
+using namespace SudokuPlugin;
+
+
+//--- class SudokuPlugin::SetupData --------------------------------------------
+
+/** Constructor
+ *
+ * Initialize the parameters of the plugin with standard values.
+ */
+SetupData::SetupData()
+{
+ givens_count = 36;
+ symmetric = 1;
+ mark_errors = 1;
+ mark_ambiguous = 1;
+ transparency = 50;
+}
+
+/** Parse the parameters of the plugin.
+ *
+ * This method is called for each parameter the plugin has previously
+ * stored in the global setup data.
+ */
+bool SetupData::parse(const char* name, const char* value)
+{
+ if (!strcasecmp(name, "GivensCount"))
+ givens_count = atoi(value);
+ else if (!strcasecmp(name, "Symmetric"))
+ symmetric = atoi(value);
+ else if (!strcasecmp(name, "MarkErrors"))
+ mark_errors = atoi(value);
+ else if (!strcasecmp(name, "MarkAmbiguous"))
+ mark_ambiguous = atoi(value);
+ else if (!strcasecmp(name, "Transparency"))
+ transparency = atoi(value);
+ else
+ return false;
+ return true;
+}
+
+
+//--- class SudokuPlugin::SetupPage --------------------------------------------
+
+/** Constructor */
+SetupPage::SetupPage(SetupData& setup) :
+ setup(setup), data(setup)
+{
+ Add(new cMenuEditIntItem(tr("Givens count"), &data.givens_count, 26, 81));
+ Add(new cMenuEditBoolItem(tr("Symmetric givens"), &data.symmetric));
+ Add(new cMenuEditBoolItem(tr("Mark errors"), &data.mark_errors));
+ Add(new cMenuEditBoolItem(tr("Mark ambiguous numbers"),
+ &data.mark_ambiguous));
+ Add(new cMenuEditIntItem(tr("Transparency (%)"), &data.transparency, 0, 100));
+}
+
+/** Store the parameters of the plugin.
+ *
+ * The parameters of the plugin are stored into the global setup data file.
+ */
+void SetupPage::Store()
+{
+ setup = data;
+ SetupStore("GivensCount", setup.givens_count);
+ SetupStore("Symmetric", setup.symmetric);
+ SetupStore("MarkErrors", setup.mark_errors);
+ SetupStore("MarkAmbiguous", setup.mark_ambiguous);
+ SetupStore("Transparency", setup.transparency);
+}
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..8aaa3b3
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,60 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: setup.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_SETUP_H
+#define VDR_SUDOKU_SETUP_H
+
+#include "sudoku.h"
+#include <vdr/menuitems.h>
+
+
+namespace SudokuPlugin
+{
+
+ //--- class SudokuPlugin::SetupData ------------------------------------------
+
+ /** Setup parameters of the plugin */
+ class SetupData
+ {
+ public:
+ int givens_count;
+ int symmetric;
+ int mark_errors;
+ int mark_ambiguous;
+ int transparency;
+
+ /** Constructor */
+ SetupData();
+
+ /** Parse the parameters of the plugin. */
+ bool parse(const char* name, const char* value);
+ };
+
+
+ //--- class SudokuPlugin::SetupPage ------------------------------------------
+
+ /** Setup menu page to adjust the parameters of the plugin */
+ class SetupPage : public cMenuSetupPage
+ {
+ SetupData& setup;
+ SetupData data;
+
+ public:
+
+ /** Constructor */
+ SetupPage(SetupData& setup);
+
+ protected:
+
+ /** Store the parameters of the plugin. */
+ virtual void Store();
+ };
+
+} // namespace SudokuPlugin
+
+#endif // VDR_SUDOKU_SETUP_H
diff --git a/solver.cpp b/solver.cpp
new file mode 100644
index 0000000..9355d33
--- /dev/null
+++ b/solver.cpp
@@ -0,0 +1,95 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: solver.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#define USE_RAND
+#include "solver.h"
+#include "backtrack.h"
+#include "puzzle.h"
+#include <assert.h>
+
+using namespace Sudoku;
+using namespace BackTrack;
+
+
+//--- class Sudoku::Solver -----------------------------------------------------
+
+/** Constructor */
+Solver::Solver(Puzzle& puzzle, bool random_init, unsigned int max_iter) :
+ Algorithm(*this, max_iter), puzzle(puzzle), random_init(random_init)
+{
+ free_count = 0;
+ for (Pos p = Pos::first(); p <= Pos::last(); p = p.next())
+ if (!puzzle.given(p))
+ ++free_count;
+}
+
+/** Set the element to the first sibling. */
+void Solver::set_first_at(unsigned int level)
+{
+ assert(level < free_count);
+ const Pos p = puzzle.next_free();
+ assert (p <= Pos::last());
+
+ free_list[level] = p;
+ puzzle.set(p, 0);
+
+ if (level == 0)
+ random = random_init;
+
+ unsigned int i, count = puzzle.numbers_count(p);
+ if (count != 0)
+ {
+ puzzle.set(p, puzzle.next_number(p));
+
+ if (random)
+ for (count = rand(count), i = 0; i < count; ++i)
+ puzzle.set(p, puzzle.next_number(p));
+ }
+ else
+ puzzle.set(p, 1);
+}
+
+/** Set the element to the next sibling. */
+void Solver::set_next_at(unsigned int level)
+{
+ assert(level < free_count);
+ Pos p = free_list[level];
+ unsigned int n = puzzle.next_number(p);
+ if (n != 0)
+ puzzle.set(p, n);
+}
+
+/** Reset the element. */
+void Solver::reset_at(unsigned int level)
+{
+ assert(level < free_count);
+ puzzle.set(free_list[level], 0);
+ random = false;
+}
+
+/** Check if the element is set to the last sibling. */
+bool Solver::is_last_at(unsigned int level) const
+{
+ assert(level < free_count);
+ return puzzle.next_number(free_list[level]) == 0;
+}
+
+/** Check if the element is valid (following elements ignored). */
+bool Solver::is_valid_at(int level) const
+{
+ assert(level < int(free_count));
+ if (level < 0)
+ return puzzle.solved();
+ return !puzzle.error(free_list[level]);
+}
+
+/** Check if the level is the last possible level. */
+bool Solver::is_last_level(int level) const
+{
+ return level >= int(free_count) - 1;
+}
diff --git a/solver.h b/solver.h
new file mode 100644
index 0000000..65cf87e
--- /dev/null
+++ b/solver.h
@@ -0,0 +1,104 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: solver.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_SOLVER_H
+#define VDR_SUDOKU_SOLVER_H
+
+#include "sudoku.h"
+#include "backtrack.h"
+#include "puzzle.h"
+
+
+namespace Sudoku
+{
+
+ //--- class Sudoku::Solver ---------------------------------------------------
+
+ /** Implementation of a backtracking algorithm to solve Sudoku puzzles
+ *
+ * The algorithm tries to set numbers in all free cells of the puzzle
+ * sticking to the rules of Sudoku puzzles.
+ *
+ * There are three ways to use this class:
+ *
+ * 1. Solve a Sudoku puzzle with some numbers given:
+ *
+ * \code
+ * Puzzle puzzle(36); // Generate a random puzzle with 36 givens.
+ * Solver solver(puzzle);
+ * solver.find_next_solution();
+ * if (solver.solution_is_valid())
+ * {
+ * // Do something with the puzzle.
+ * ...
+ * }
+ * solver.find_next_solution();
+ * bool more_than_one_solution = solver.solution_is_valid();
+ * \endcode
+ *
+ * 2. Search a random Sudoku solution:
+ *
+ * \code
+ * Puzzle puzzle; // Generate an empty puzzle without givens.
+ * Solver solver(puzzle, true);
+ * solver.find_next_solution();
+ * if (solver.solution_is_valid())
+ * {
+ * // Do something with the puzzle.
+ * ...
+ * }
+ * \endcode
+ *
+ * 3. Search all Sudoku solutions:
+ *
+ * \code
+ * Puzzle puzzle; // Generate an empty puzzle without givens.
+ * Solver solver(puzzle);
+ * solver.find_next_solution(true);
+ * while (solver.solution_is_valid())
+ * {
+ * // Do something with the puzzle.
+ * ...
+ * solver.find_next_solution(true);
+ * }
+ * \endcode
+ */
+ class Solver : public BackTrack::Algorithm, public BackTrack::Solution
+ {
+ Puzzle& puzzle;
+ Pos free_list[SDIM];
+ unsigned int free_count;
+ bool random_init, random;
+
+ public:
+
+ /** Constructor */
+ Solver(Puzzle& puzzle, bool random_init = false, unsigned int max_iter = 0);
+
+ /** Set the element to the first sibling. */
+ virtual void set_first_at(unsigned int level);
+
+ /** Set the element to the next sibling. */
+ virtual void set_next_at(unsigned int level);
+
+ /** Reset the element. */
+ virtual void reset_at(unsigned int level);
+
+ /** Check if the element is set to the last sibling. */
+ virtual bool is_last_at(unsigned int level) const;
+
+ /** Check if the element is valid (following elements ignored). */
+ virtual bool is_valid_at(int level) const;
+
+ /** Check if the level is the last possible level. */
+ virtual bool is_last_level(int level) const;
+ };
+
+} // namespace Sudoku
+
+#endif // VDR_SUDOKU_SOLVER_H
diff --git a/sudoku.cpp b/sudoku.cpp
new file mode 100644
index 0000000..1c9ab86
--- /dev/null
+++ b/sudoku.cpp
@@ -0,0 +1,114 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: sudoku.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#include "sudoku.h"
+#include "puzzle.h"
+#include "menu.h"
+#include "setup.h"
+#include "i18n.h"
+#include <vdr/plugin.h>
+
+
+/** 'Sudoku' is a VDR plugin to generate and solve Number Place puzzles. */
+namespace SudokuPlugin
+{
+
+ /** Version number of the plugin */
+ static const char* VERSION = "0.1.0";
+
+ /** Short description of the plugin's purpose */
+ static const char* DESCRIPTION =
+ "Sudoku - generate and solve Number Place puzzles";
+
+ /** Name of the entry in VDR's main menu */
+ static const char* MAINMENUENTRY = "Sudoku";
+
+
+ //--- class SudokuPlugin::Plugin ---------------------------------------------
+
+ /** Main class of the VDR plugin 'Sudoku' */
+ class Plugin : public cPlugin
+ {
+ SetupData setup;
+ Sudoku::Puzzle puzzle;
+ Sudoku::Pos curr;
+
+ public:
+
+ /** Version number of the plugin */
+ virtual const char* Version() { return VERSION; }
+
+ /** Localized short description of the plugin's purpose */
+ virtual const char* Description() { return tr(DESCRIPTION); }
+
+ /** Perform the startup actions of the plugin. */
+ virtual bool Start();
+
+ /** Localized name of the entry in VDR's main menu */
+ virtual const char* MainMenuEntry() { return tr(MAINMENUENTRY); }
+
+ /** OSD object that shows the plugin's main menu */
+ virtual cOsdObject* MainMenuAction();
+
+ /** Setup menu page to adjust the parameters of the plugin */
+ virtual cMenuSetupPage* SetupMenu();
+
+ /** Parse the parameters of the plugin. */
+ virtual bool SetupParse(const char* name, const char* value);
+ };
+
+} // namespace SudokuPlugin
+
+
+using namespace SudokuPlugin;
+
+
+//--- class SudokuPlugin::Plugin -----------------------------------------------
+
+/** Perform the startup actions of the plugin.
+ *
+ * This method is called once at VDR's startup.
+ */
+bool Plugin::Start()
+{
+ RegisterI18n(Phrases);
+ puzzle.generate(setup.givens_count, setup.symmetric);
+ curr = curr.center();
+ return true;
+}
+
+/** OSD object that shows the plugin's main menu
+ *
+ * This method is called every time the plugin's main menu entry is selected.
+ */
+cOsdObject* Plugin::MainMenuAction()
+{
+ return new Menu(setup, puzzle, curr);
+}
+
+/** Setup menu page to adjust the parameters of the plugin
+ *
+ * This method is called every time the plugin's setup menu entry is selected.
+ */
+cMenuSetupPage* Plugin::SetupMenu()
+{
+ return new SetupPage(setup);
+}
+
+/** Parse the parameters of the plugin.
+ *
+ * This method is called for each parameter the plugin has previously
+ * stored in the global setup data.
+ */
+bool Plugin::SetupParse(const char* name, const char* value)
+{
+ return setup.parse(name, value);
+}
+
+/** "Magic" hook that allows VDR to load the plugin into its memory */
+VDRPLUGINCREATOR(Plugin); // Don't touch this!
diff --git a/sudoku.h b/sudoku.h
new file mode 100644
index 0000000..a7309d2
--- /dev/null
+++ b/sudoku.h
@@ -0,0 +1,24 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: sudoku.h 11 2005-10-28 01:00:01Z tom $
+ */
+
+#ifndef VDR_SUDOKU_H
+#define VDR_SUDOKU_H
+
+
+#ifdef USE_RAND
+#include <stdlib.h>
+#include <time.h>
+/** Random number 0 .. max-1 */
+static unsigned int rand(unsigned int max)
+{
+ static unsigned int seed = time(NULL);
+ return (unsigned int)((double)max * rand_r(&seed) / (RAND_MAX + 1.0));
+}
+#endif // USE_RAND
+
+#endif // VDR_SUDOKU_H
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 0000000..cd02cfb
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,41 @@
+#
+# Sudoku: A plugin for the Video Disk Recorder
+#
+# See the README file for copyright information and how to reach the author.
+#
+# $Id: Makefile 11 2005-10-28 01:00:01Z tom $
+
+# Define STATIC_LINK=1 to force static linking
+#STATIC_LINK = 1
+
+# Define WITH_TEST=1 to include test procedures
+#WITH_TEST = 1
+
+PROGRAM = sudoku_generator
+
+SRCS = ../puzzle.cpp ../generator.cpp ../solver.cpp ../backtrack.cpp
+
+VERSION = $(shell grep 'static const char\* VERSION *=' ../sudoku.cpp | \
+ awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+CXX ?= g++
+CXXFLAGS ?= -O2 -Wall -Woverloaded-virtual
+DEFINES += -D_GNU_SOURCE -DVERSION=\"$(VERSION)\"
+
+ifdef STATIC_LINK
+ CXXFLAGS += -static
+endif
+
+ifdef WITH_TEST
+ DEFINES += -DWITH_TEST
+endif
+
+### Targets:
+
+all: $(PROGRAM)
+
+$(PROGRAM): $(PROGRAM).cpp $(SRCS) $(SRCS:%.cpp=%.h)
+ $(CXX) $(CXXFLAGS) $(DEFINES) $(INCLUDES) -o $@ $(PROGRAM).cpp $(SRCS)
+
+clean:
+ @-rm -f $(PROGRAM) core* *~
diff --git a/tools/sudoku_generator.cpp b/tools/sudoku_generator.cpp
new file mode 100644
index 0000000..a0d3e4b
--- /dev/null
+++ b/tools/sudoku_generator.cpp
@@ -0,0 +1,378 @@
+/*
+ * Sudoku: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: sudoku_generator.cpp 11 2005-10-28 01:00:01Z tom $
+ */
+
+#include "../puzzle.h"
+#include "../solver.h"
+#include "../generator.h"
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+
+using namespace Sudoku;
+
+
+void print_copyleft(unsigned int givens_count)
+{
+ printf("Sudoku with %d givens generated by sudoku_generator %s\n"
+ " Copyright (C) 2005, Thomas Günther <tom@toms-cafe.de>\n"
+ " This puzzle can be used without any limitations.\n"
+ "\n", givens_count, VERSION);
+}
+
+void print_usage()
+{
+ printf("Usage: sudoku_generator [-n|--non-sym] [-d|--dump] [<givens_count>]\n"
+ " Generate a Sudoku puzzle.\n"
+ " givens_count Number of givens (<= 81). Default is 36.\n"
+ " Less than 26 givens takes very long.\n"
+ " -n, --non-sym Generate a non-symmetric Sudoku puzzle.\n"
+ " -d, --dump Dump the generated Sudoku (don't print).\n"
+ "\n"
+ " sudoku_generator -s|--solve <sudoku_dump>\n"
+ " Solve a Sudoku puzzle.\n"
+ " sudoku_dump String with 81 * 1-9 or _ (+ ignored).\n"
+ "\n"
+ " sudoku_generator -p|--print <sudoku_dump>\n"
+ " Print a Sudoku puzzle.\n"
+ " sudoku_dump String with 81 * 1-9 or _ (+ ignored).\n"
+ "\n"
+#ifdef WITH_TEST
+ " sudoku_generator -t|--test\n"
+ " Perform some test procedures.\n"
+ "\n"
+#endif
+ " sudoku_generator -h|--help\n"
+ " Print this help.\n"
+ "\n");
+}
+
+void print_sudoku(const Numbers* sudoku_list[], unsigned int count,
+ unsigned int givens_count = 0)
+{
+ printf("\n");
+ for (unsigned int row = 0; row <= DIM; ++row)
+ {
+ if (row % RDIM == 0)
+ {
+ for (unsigned int idx = 0; idx < count; ++idx)
+ {
+ printf(" ");
+ for (unsigned int col = 0; col < DIM; ++col)
+ {
+ if (col % RDIM == 0)
+ printf(" ");
+ printf("- ");
+ }
+ printf(" ");
+ }
+ printf("\n");
+ }
+ if (row < DIM)
+ {
+ for (unsigned int idx = 0; idx < count; ++idx)
+ {
+ printf(" ");
+ for (unsigned int col = 0; col < DIM; ++col)
+ {
+ if (col % RDIM == 0)
+ printf("| ");
+ unsigned int n = sudoku_list[idx]->get(Pos(col, row));
+ if (n)
+ printf("%d ", n);
+ else
+ printf(" ");
+ }
+ printf("| ");
+ }
+ printf("\n");
+ }
+ }
+ printf("\n");
+ if (givens_count != 0)
+ print_copyleft(givens_count);
+}
+
+void print_sudoku(const Numbers& sudoku, unsigned int givens_count = 0)
+{
+ const Numbers* sudoku_list[] = { &sudoku };
+ print_sudoku(sudoku_list, 1, givens_count);
+}
+
+void print_sudoku(const Numbers& sudoku1, const Numbers& sudoku2,
+ unsigned int givens_count = 0)
+{
+ const Numbers* sudoku_list[] = { &sudoku1, &sudoku2 };
+ print_sudoku(sudoku_list, 2, givens_count);
+}
+
+void dump_sudoku(const Numbers& sudoku)
+{
+ for (unsigned int row = 0; row < DIM; ++row)
+ {
+ for (unsigned int col = 0; col < DIM; ++col)
+ {
+ unsigned int n = sudoku.get(Pos(col, row));
+ if (n)
+ printf("%d", n);
+ else
+ printf("_");
+ }
+ if (row < DIM-1)
+ printf("+");
+ }
+ printf("\n");
+}
+
+int generate_puzzle(unsigned int givens_count, bool non_sym, bool dump)
+{
+ Puzzle puzzle;
+ Generator generator(puzzle, givens_count, !non_sym);
+ generator.find_next_solution();
+ if (!generator.solution_is_valid())
+ return 1;
+ if (dump)
+ dump_sudoku(puzzle);
+ else
+ print_sudoku(puzzle, givens_count);
+ return 0;
+}
+
+Numbers dump_to_numbers(const char *dump)
+{
+ Numbers numbers;
+ for (Pos p = Pos::first(); *dump && p <= Pos::last(); ++dump)
+ {
+ if (*dump != '+')
+ {
+ if (*dump > '0' && *dump - '0' <= DIM)
+ numbers.set(p, *dump - '0');
+ p = p.next();
+ }
+ }
+ return numbers;
+}
+
+int solve_puzzle(const char *dump)
+{
+ Numbers numbers(dump_to_numbers(dump));
+ bool given_marks[SDIM];
+ for (Pos p = Pos::first(); p <= Pos::last(); p = p.next())
+ given_marks[p] = numbers.get(p) != 0;
+ Puzzle puzzle;
+ puzzle.set_givens(numbers, given_marks);
+ Solver solver(puzzle);
+ solver.find_next_solution();
+ if (!solver.solution_is_valid())
+ return 1;
+ print_sudoku(numbers, puzzle);
+ solver.find_next_solution();
+ if (!solver.solution_is_valid())
+ return 0;
+ printf("Error: Sudoku has more than one solution!\n");
+ return 1;
+}
+
+int print_puzzle(const char *dump)
+{
+ Numbers numbers(dump_to_numbers(dump));
+ print_sudoku(numbers);
+ return 0;
+}
+
+#ifdef WITH_TEST
+bool test_search_first()
+{
+ bool correct = true;
+ printf("Search the first Sudoku!\n");
+ Puzzle puzzle;
+ Solver solver(puzzle);
+ solver.find_next_solution();
+ if (solver.solution_is_valid())
+ print_sudoku(puzzle);
+ else
+ correct = false, printf("Error: Sudoku is invalid!\n");
+ printf("Search the second Sudoku!\n");
+ solver.find_next_solution();
+ if (solver.solution_is_valid())
+ print_sudoku(puzzle);
+ else
+ correct = false, printf("Error: Sudoku is invalid!\n");
+ return correct;
+}
+
+bool test_search_random()
+{
+ bool correct = true;
+ printf("Search a random Sudoku!\n");
+ Puzzle puzzle;
+ Solver solver(puzzle, true);
+ solver.find_next_solution();
+ if (solver.solution_is_valid())
+ print_sudoku(puzzle);
+ else
+ correct = false, printf("Error: Sudoku is invalid!\n");
+ printf("Search another random Sudoku!\n");
+ solver.reset();
+ solver.find_next_solution();
+ if (solver.solution_is_valid())
+ print_sudoku(puzzle);
+ else
+ correct = false, printf("Error: Sudoku is invalid!\n");
+ return correct;
+}
+
+bool test_generate_symmetric()
+{
+ bool correct = true;
+ printf("Generate a random Sudoku with 36 symmetric givens!\n");
+ Puzzle puzzle;
+ Generator generator(puzzle, 36);
+ generator.find_next_solution();
+ if (generator.solution_is_valid())
+ print_sudoku(puzzle);
+ else
+ correct = false, printf("Error: Sudoku is invalid!\n");
+ printf("Solve the generated Sudoku!\n");
+ Solver solver(puzzle);
+ solver.find_next_solution();
+ if (solver.solution_is_valid())
+ print_sudoku(puzzle);
+ else
+ correct = false, printf("Error: Sudoku is invalid!\n");
+ solver.find_next_solution();
+ if (solver.solution_is_valid())
+ correct = false, print_sudoku(puzzle),
+ printf("Error: Sudoku has more than one solution!\n");
+ else
+ printf("Sudoku has only one solution!\n");
+ printf("\n");
+ return correct;
+}
+
+bool test_generate_non_symmetric()
+{
+ bool correct = true;
+ printf("Generate a random Sudoku with 26 non-symmetric givens!\n");
+ Puzzle puzzle;
+ Generator generator(puzzle, 26, false);
+ generator.find_next_solution();
+ if (generator.solution_is_valid())
+ print_sudoku(puzzle);
+ else
+ correct = false, printf("Error: Sudoku is invalid!\n");
+ printf("Solve the generated Sudoku!\n");
+ Solver solver(puzzle);
+ solver.find_next_solution();
+ if (solver.solution_is_valid())
+ print_sudoku(puzzle);
+ else
+ correct = false, printf("Error: Sudoku is invalid!\n");
+ solver.find_next_solution();
+ if (solver.solution_is_valid())
+ correct = false, print_sudoku(puzzle),
+ printf("Error: Sudoku has more than one solution!\n");
+ else
+ printf("Sudoku has only one solution!\n");
+ printf("\n");
+ return correct;
+}
+
+int test_sudoku()
+{
+ unsigned int count = 0;
+ unsigned int error = 0;
+ ++count;
+ if (!test_search_first())
+ ++error;
+ ++count;
+ if (!test_search_random())
+ ++error;
+ ++count;
+ if (!test_generate_symmetric())
+ ++error;
+ ++count;
+ if (!test_generate_non_symmetric())
+ ++error;
+ if (error > 0)
+ printf("%d errors in %d tests\n", error, count);
+ else
+ printf("All %d tests correct\n", count);
+ if (error > 0)
+ return 1;
+ return 0;
+}
+#endif // WITH_TEST
+
+int main(int argc, char* argv[])
+{
+ static const struct option long_options[] =
+ {
+ { "non-sym", no_argument, NULL, 'n' },
+ { "dump", no_argument, NULL, 'd' },
+ { "solve", no_argument, NULL, 's' },
+ { "print", no_argument, NULL, 'p' },
+#ifdef WITH_TEST
+ { "test", no_argument, NULL, 't' },
+#endif
+ { "help", no_argument, NULL, 'h' },
+ { NULL }
+ };
+#ifdef WITH_TEST
+ static const char* options = "ndspth";
+#else
+ static const char* options = "ndsph";
+#endif
+ bool non_sym = false;
+ bool dump = false;
+ bool solve = false;
+ bool print = false;
+ bool test = false;
+ bool help = false;
+ bool error = false;
+ int c;
+ while ((c = getopt_long(argc, argv, options, long_options, NULL)) != -1)
+ {
+ switch (c)
+ {
+ case 'n': non_sym = true; break;
+ case 'd': dump = true; break;
+ case 's': solve = true; break;
+ case 'p': print = true; break;
+#ifdef WITH_TEST
+ case 't': test = true; break;
+#endif
+ case 'h': help = true; break;
+ default: error = true;
+ }
+ }
+ int arg_count = argc - optind;
+
+ unsigned int givens_count = 36;
+ if ((arg_count == 0 ||
+ (arg_count == 1 && sscanf(argv[optind], "%u", &givens_count) == 1)) &&
+ givens_count > 0 && givens_count <= SDIM &&
+ !solve && !print && !test && !help && !error)
+ return generate_puzzle(givens_count, non_sym, dump);
+
+ if (solve && arg_count == 1 && strlen(argv[optind]) >= SDIM &&
+ !non_sym && !dump && !test && !help && !error)
+ return solve_puzzle(argv[optind]);
+
+ if (print && arg_count == 1 && strlen(argv[optind]) >= SDIM &&
+ !non_sym && !dump && !test && !help && !error)
+ return print_puzzle(argv[optind]);
+
+#ifdef WITH_TEST
+ if (test && arg_count == 0 &&
+ !non_sym && !dump && !print && !help && !error)
+ return test_sudoku();
+#endif
+
+ print_usage();
+ return 2;
+}