3 min read

Number Hooks

Table of Contents

Number hooks

In the grid below, enter nine 9’s in the outermost hook, eight 8’s in the next hook, then seven 7’s, six 6’s, and so on, down to the one 1 (already entered), so that the row and column sums match the values given along the border.

Solution

The code below provides the following solution to the above puzzle:

1 . 3 . . 6 7 . 9
2 2 3 . 5 6 7 8 9
3 . . . . . . 8 .
4 4 4 4 . 6 . . .
5 5 5 5 . 6 7 . 9
. . 6 . . 6 7 8 9
7 . 7 7 . . . 8 .
. 8 8 . . 8 . 8 .
9 . 9 . . 9 . 9 9

Python code

from z3 import *

def generate_hooks(size):
    hooks = []
    for n in range(1, size + 1):
        hook = []
        for i in range(n):
            for j in range(n):
                if i == n - 1 or j == n - 1:
                    hook.append((i, j))
        hooks.append(hook)
    return hooks


row_sums = [26, 42, 11, 22, 42, 36, 29, 32, 45]
col_sums = [31, 19, 45, 16, 5, 47, 28, 49, 45]


def solve_number_hook_puzzle():
    solver = Solver()

    # Create a 9x9 grid of integer variables
    grid = [[Int(f"cell_{i}_{j}") for j in range(9)] for i in range(9)]

    
    # Add constraints for row and column sums
    for i in range(9):
        solver.add(Sum(grid[i]) == row_sums[i])
        solver.add(Sum([grid[j][i] for j in range(9)]) == col_sums[i])

    # Generate hooks
    hooks = generate_hooks(9)

    # Add constraints for the hooks
    for i, hook in enumerate(hooks):
        value = i + 1  # Values from 1 to 9
        cells_in_hook = [grid[r][c] for r, c in hook]
        solver.add(Sum([If(cell == value, 1, 0) for cell in cells_in_hook]) == value)
        for r, c in hook:
            solver.add(Or(grid[r][c] == value, grid[r][c] == 0))

    # Ensure all numbers are between 0 and 9 (0 for empty cells)
    for row in grid:
        for cell in row:
            solver.add(And(cell >= 0, cell <= 9))

    # Check if the puzzle is solvable
    if solver.check() == sat:
        model = solver.model()
        return [[model.evaluate(grid[i][j]).as_long() for j in range(9)] for i in range(9)]
    else:
        return None

# Solve the puzzle
solution = solve_number_hook_puzzle()

# Print the solution
if solution:
    for row in solution:
        print(" ".join(map(lambda x: str(x) if x != 0 else '.', row)))
else:
    print("No solution found.")