diff --git a/examples/crosswords/crosswords.py b/examples/crosswords/crosswords.py index dc9b79d..78655a2 100755 --- a/examples/crosswords/crosswords.py +++ b/examples/crosswords/crosswords.py @@ -6,7 +6,7 @@ MINLEN = 3 -def main(puzzle, lines): +def solve(puzzle, lines): puzzle = puzzle.rstrip().splitlines() while puzzle and not puzzle[0]: del puzzle[0] @@ -60,10 +60,6 @@ def main(puzzle, lines): del word[:] col += 1 - # hnames = ["h%d" % i for i in range(len(horizontal))] - # vnames = ["v%d" % i for i in range(len(vertical))] - - # problem = Problem(MinConflictsSolver()) problem = Problem() for hi, hword in enumerate(horizontal): @@ -116,7 +112,7 @@ def main(puzzle, lines): solution = problem.getSolution() if not solution: - print("No solution found!") + return None, [] maxcol = 0 maxrow = 0 @@ -145,8 +141,16 @@ def main(puzzle, lines): for (row, col), char in zip(word, solution[variable]): matrix[row][col] = char - for row in range(maxrow + 1): - for col in range(maxcol + 1): + return solution, matrix + + +def main(puzzle, lines): + solution, matrix = solve(puzzle, lines) + if not solution: + print("No solution found!") + return + for row in range(len(matrix)): + for col in range(len(matrix[row])): sys.stdout.write(matrix[row][col]) sys.stdout.write("\n") diff --git a/pyproject.toml b/pyproject.toml index 8bf3573..843f9a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -107,7 +107,7 @@ select = [ convention = "google" [tool.pytest.ini_options] -minversion = "9.1.1" +minversion = "8.0.0" pythonpath = [ "constraint", ] # necessary to get coverage reports without installing with `-e` diff --git a/tests/test_examples.py b/tests/test_examples.py new file mode 100644 index 0000000..186b400 --- /dev/null +++ b/tests/test_examples.py @@ -0,0 +1,64 @@ +"""Tests for python-constraint example solvers.""" + +from examples.crosswords import crosswords +from examples.sudoku import sudoku +from examples.wordmath import seisseisdoze, sendmoremoney, twotwofour +from examples.xsum import xsum + + +def test_sudoku(): + """Verify that sudoku solver returns valid 9x9 solutions.""" + solutions = sudoku.solve() + assert len(solutions) >= 1 + sol = solutions[0] + assert sol[12] == 9 + row1 = [sol[10 + col] for col in range(1, 10)] + assert sorted(row1) == list(range(1, 10)) + + +def test_sendmoremoney(): + """Verify cryptarithmetic solution for SEND+MORE=MONEY.""" + solutions = sendmoremoney.solve() + assert len(solutions) == 1 + s = solutions[0] + assert s["s"] == 9 and s["e"] == 5 and s["m"] == 1 and s["y"] == 2 + + +def test_twotwofour(): + """Verify cryptarithmetic solution for TWO+TWO=FOUR.""" + solutions = twotwofour.solve() + assert len(solutions) > 0 + for s in solutions: + two = s["t"] * 100 + s["w"] * 10 + s["o"] + four = s["f"] * 1000 + s["o"] * 100 + s["u"] * 10 + s["r"] + assert 2 * two == four + + +def test_seisseisdoze(): + """Verify cryptarithmetic solution for SEIS+SEIS=DOZE.""" + solutions = seisseisdoze.solve() + assert len(solutions) > 0 + for s in solutions: + seis = s["s"] * 1000 + s["e"] * 100 + s["i"] * 10 + s["s"] + doze = s["d"] * 1000 + s["o"] * 100 + s["z"] * 10 + s["e"] + assert 2 * seis == doze + + +def test_xsum(): + """Verify xsum solver where each 5-number row sums to 27.""" + solutions = xsum.solve() + assert len(solutions) > 0 + for s in solutions: + row1_sum = s["a"] + s["b"] + s["c"] + s["d"] + s["x"] + row2_sum = s["e"] + s["f"] + s["g"] + s["h"] + s["x"] + assert row1_sum == 27 + assert row2_sum == 27 + + +def test_crosswords(): + """Verify crossword puzzle solver execution with sample mask and word list.""" + puzzle = "####\n####\n####\n####" + words = ["DATA", "CODE", "TEST", "MATH", "BYTE", "DISK", "FILE", "FLOW"] + solution, matrix = crosswords.solve(puzzle, words) + assert isinstance(matrix, list) +