tdoku-lib是基于优化求解器tdoku改造的动态库和静态库,它的存储库地址 https://github.com/hackerzhuli/tdoku-lib
1.拉取源代码
root@DESKTOP-59T6U68:/mnt/c/d# git clone https://github.com/hackerzhuli/tdoku-lib.git
Cloning into 'tdoku-lib'...
remote: Enumerating objects: 1230, done.
remote: Counting objects: 100% (339/339), done.
remote: Compressing objects: 100% (77/77), done.
remote: Total 1230 (delta 288), reused 284 (delta 255), pack-reused 891 (from 1)
Receiving objects: 100% (1230/1230), 72.96 MiB | 3.20 MiB/s, done.
Resolving deltas: 100% (885/885), done.
Updating files: 100% (27/27), done.
2.编译
root@DESKTOP-59T6U68:/mnt/c/d# cd tdoku-lib
root@DESKTOP-59T6U68:/mnt/c/d/tdoku-lib# docker start gcc
gcc
root@DESKTOP-59T6U68:/mnt/c/d/tdoku-lib# docker exec -it gcc bash
root@6ae32a5ffcde:/# cd /par/tdoku-lib/
root@6ae32a5ffcde:/par/tdoku-lib# ./BUILD.sh
-- The C compiler identification is GNU 14.2.0
-- The CXX compiler identification is GNU 14.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/local/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /par/tdoku-lib/build
[ 6%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_simd.cc.o
[ 12%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_basic.cc.o
[ 18%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_scc.cc.o
/par/tdoku-lib/src/solver_dpll_triad_scc.cc:20:11: error: 'uint16_t' does not name a type
20 | constexpr uint16_t kNumLiterals = kNumBoxes * kNumPosClausesPerBox * kNumValues * 2;
| ^~~~~~~~
/par/tdoku-lib/src/solver_dpll_triad_scc.cc:11:1: note: 'uint16_t' is defined in header '<cstdint>'; this is probably fixable by adding '#include <cstdint>'
10 | #include <vector>
+++ |+#include <cstdint>
11 |
...
/par/tdoku-lib/src/solver_dpll_triad_scc.cc:526:38: error: 'Literal' was not declared in this scope
526 | if (result_.asserted[Literal(box, elm, val)]) {
| ^~~~~~~
/par/tdoku-lib/src/solver_dpll_triad_scc.cc: At global scope:
/par/tdoku-lib/src/solver_dpll_triad_scc.cc:540:65: error: 'uint32_t' has not been declared
540 | size_t TdokuSolverDpllTriadScc(const char *input, size_t limit, uint32_t configuration,
| ^~~~~~~~
make[2]: *** [CMakeFiles/tdoku_object.dir/build.make:104: CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_scc.cc.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:93: CMakeFiles/tdoku_object.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
编译出错。
按照编译的提示,在solver_dpll_triad_scc.cc的开头加上#include <cstdint>,重新编译通过
root@6ae32a5ffcde:/par/tdoku-lib# ./BUILD.sh
...
[ 6%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_simd.cc.o
[ 12%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_basic.cc.o
[ 18%] Building CXX object CMakeFiles/tdoku_object.dir/src/solver_dpll_triad_scc.cc.o
[ 25%] Building CXX object CMakeFiles/tdoku_object.dir/src/util.cc.o
[ 31%] Building CXX object CMakeFiles/tdoku_object.dir/src/generate.cc.o
[ 37%] Building CXX object CMakeFiles/tdoku_object.dir/src/solve.cc.o
make[2]: warning: Clock skew detected. Your build may be incomplete.
[ 37%] Built target tdoku_object
[ 43%] Linking CXX static library libtdoku_static.a
[ 43%] Built target tdoku_static
[ 50%] Linking CXX shared library libtdoku_shared.so
[ 50%] Built target tdoku_shared
[ 56%] Building CXX object CMakeFiles/run_tests.dir/test/run_tests.cc.o
[ 62%] Building CXX object CMakeFiles/run_tests.dir/src/util.cc.o
[ 68%] Building CXX object CMakeFiles/run_tests.dir/src/solver_dpll_triad_simd.cc.o
[ 75%] Linking CXX executable run_tests
[ 75%] Built target run_tests
[ 81%] Building CXX object CMakeFiles/grid_lib.dir/src/grid_lib.cc.o
[ 87%] Linking CXX static library libgrid_lib.a
[ 87%] Built target grid_lib
[ 93%] Building CXX object CMakeFiles/grid_tools.dir/src/grid_tools.cc.o
[100%] Linking CXX executable grid_tools
[100%] Built target grid_tools
make[1]: warning: Clock skew detected. Your build may be incomplete.
make: warning: Clock skew detected. Your build may be incomplete.
root@6ae32a5ffcde:/par/tdoku-lib#
3.执行
执行编译出来的run_tests文件,显示PASS: tdoku
root@6ae32a5ffcde:/par/tdoku-lib/build# ./run_tests
Error opening test/test_puzzles
root@6ae32a5ffcde:/par/tdoku-lib/build# cd ..
root@6ae32a5ffcde:/par/tdoku-lib# build/run_tests
PASS: tdoku
再编译示例文件,
c
#include "../include/tdoku.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char **argv) {
size_t limit = argc > 1 ? atoll(argv[1]) : 10000;
char *puzzle = NULL;
char solution[81];
size_t size, guesses;
while (getline(&puzzle, &size, stdin) != -1) {
if (strlen(puzzle) < 81 || puzzle[0] == '#') continue;
solution[0] = '\0';
size_t count = SolveSudoku(puzzle, limit, 0, solution, &guesses);
if (limit > 1 && count == 1) {
SolveSudoku(puzzle, 1, 0, solution, &guesses);
}
printf("%.81s:%ld:%.81s\n", puzzle, count, solution);
}
}
slove求解文件中的数独题目,空格用"."表示。结果输出到控制台,格式是题目:解序号:解
root@6ae32a5ffcde:/par/tdoku-lib# gcc example/solve.c build/libtdoku_static.a -O3 -o solve -lstdc++ -lm
root@6ae32a5ffcde:/par/tdoku-lib# unzip data.zip
root@6ae32a5ffcde:/par/tdoku-lib# ./solve < data/puzzles0_kaggle
..2..76416712.....5..3..28.46......9.35.18.6...7.93..4.9.5.61...5..7...3..48...2.:1:382957641671284935549361287468725319935418762127693854293546178856172493714839526
...6.2..9.3..1.6..1.238.5.4.15...96....94.....27..38.58.42..3.7.....8.....6.7125.:1:748652139539714682162389574415827963683945721927163845854296317271538496396471258
^C
示例还有python程序
python
import sys
from ctypes import *
class Tdoku:
def __init__(self):
self.__tdoku = CDLL("build/libtdoku_shared.so")
self.__solve = self.__tdoku.TdokuSolverDpllTriadSimd
self.__solve.restype = c_ulonglong
self.__constrain = self.__tdoku.TdokuConstrain
self.__constrain.restype = c_bool
self.__minimize = self.__tdoku.TdokuMinimize
self.__minimize.restype = c_bool
def Solve(self, puzzle):
if type(puzzle) is str:
puzzle = str.encode(puzzle)
limit = c_ulonglong(1)
config = c_ulong(0)
solution = create_string_buffer(81)
guesses = c_ulonglong(0)
count = self.__solve(c_char_p(puzzle), limit, config, solution, pointer(guesses))
if count:
return count, solution.value.decode(), guesses.value
else:
return 0, "", guesses
def Count(self, puzzle, limit=2):
if type(puzzle) is str:
puzzle = str.encode(puzzle)
limit = c_ulonglong(limit)
config = c_ulong(0)
solution = create_string_buffer(81)
guesses = c_ulonglong(0)
count = self.__solve(c_char_p(puzzle), limit, config, solution, pointer(guesses))
return count
def Constrain(self, partial_puzzle):
if type(partial_puzzle) is str:
buffer = create_string_buffer(str.encode(partial_puzzle))
else:
buffer = create_string_buffer(partial_puzzle)
pencilmark = c_bool(False)
self.__constrain(pencilmark, buffer)
return buffer.value
def Minimize(self, non_minimal_puzzle):
if type(non_minimal_puzzle) is str:
buffer = create_string_buffer(str.encode(non_minimal_puzzle))
else:
buffer = create_string_buffer(non_minimal_puzzle)
pencilmark = c_bool(False)
monotonic = c_bool(False)
self.__minimize(pencilmark, monotonic, buffer)
return buffer.value
if __name__ == '__main__':
tdoku = Tdoku()
if len(sys.argv) > 1:
filename = sys.argv[1]
else:
filename = 'data/puzzles2_17_clue'
with open(filename, 'r') as f:
for puzzle in f.readlines():
if len(puzzle) >= 81 and not puzzle.startswith('#'):
count, solution, guesses = tdoku.Solve(puzzle)
print("%.81s:%lu:%.81s:%lu" % (puzzle, count, solution, guesses))
这次还多出来一列猜测数
root@6ae32a5ffcde:/par/tdoku-lib# python3 example/solve.py data/puzzles0_kaggle|more
.5..83.17...1..4..3.4..56.8....3...9.9.8245....6....7...9....5...729..861.36.72.4:1:652483917978162435314975628825736149791824563436519872269348751547291386183657294:0
2.6.3......1.65.7..471.8.5.5......29..8.194.6...42...1....428..6.93....5.7.....13:1:256734198891265374347198652514683729728519436963427581135942867689371245472856913:0
Traceback (most recent call last):
File "/par/tdoku-lib/example/solve.py", line 73, in <module>
print("%.81s:%lu:%.81s:%lu" % (puzzle, count, solution, guesses))
BrokenPipeError: [Errno 32] Broken pipe
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
BrokenPipeError: [Errno 32] Broken pip
用49150道17个未知数的题目测试性能,并与dlx程序比较
root@6ae32a5ffcde:/par/tdoku-lib# time ./solve < data/puzzles2_17_clue >17result.txt
real 0m0.622s
user 0m0.229s
sys 0m0.017s
root@6ae32a5ffcde:/par/1230# time ./dlxline <sudoku17.txt >sudoku17outdlx.txt
real 0m1.568s
user 0m1.122s
sys 0m0.073s
tdoku用时只有dlx的40%。采用不同的文件是因为两个程序要求的空格符不同,一个是.,另一个是0。