Skip to content

Instantly share code, notes, and snippets.

@Frank-Buss
Created April 20, 2025 07:43
Show Gist options
  • Save Frank-Buss/94b6bb0737b1b11d49794413fb37f953 to your computer and use it in GitHub Desktop.
Save Frank-Buss/94b6bb0737b1b11d49794413fb37f953 to your computer and use it in GitHub Desktop.
def solve_puzzle(matrix):
"""
Solves the n×n puzzle where allowed moves are:
(1) rotate a row,
(2) rotate a column,
(3) add 1 to all entries in a row,
(4) add 1 to all entries in a column.
Returns a list of moves (as tuples) that transforms the matrix into a constant matrix,
or an empty list if no solution is possible.
"""
n = len(matrix)
total = sum(sum(row) for row in matrix)
if total % n != 0:
print("No solution possible: total sum is not 0 modulo n.")
return []
moves = []
# --- Step 1: Row rotations ---
# We fix row 0 as our base. Compute its difference pattern.
base = matrix[0]
base_diffs = [base[j] - base[0] for j in range(n)]
row_rotations = [0] * n # record rotation for each row (0 means no rotation)
rotated_rows = [None] * n
rotated_rows[0] = base[:] # no rotation for row 0
# For each other row, find a rotation so that its differences match base_diffs.
for i in range(1, n):
found = False
for r in range(n):
rotated = matrix[i][r:] + matrix[i][:r]
# Compute differences relative to the first element in the rotated row.
diffs = [rotated[j] - rotated[0] for j in range(n)]
if diffs == base_diffs:
row_rotations[i] = r
rotated_rows[i] = rotated
found = True
break
if not found:
print(f"No valid rotation found for row {i}. No solution possible.")
return []
# Record the row rotation moves.
for i in range(n):
if row_rotations[i] != 0:
# A positive shift r means "rotate row i to the left by r"
moves.append(("rotate_row", i, row_rotations[i]))
# --- Step 2: Compute row and column additions ---
# After rotations, each row i becomes: B[i] where B[i][j] = B[i][0] + (base[j] - base[0]).
# Let r_i = B[i][0]. To equalize rows, we can add (max(r_i) - r_i) to row i.
r_vals = [row[0] for row in rotated_rows]
R_max = max(r_vals)
row_adds = [R_max - r for r in r_vals]
# For the columns: note that in the base row the j-th entry is base[j] = base[0] + delta_j.
# To cancel out these differences, add (max(delta) - delta) to column j,
# where delta[j] = base[j] - base[0] and max(delta) is the maximum value among these.
delta = [base[j] - base[0] for j in range(n)]
D_max = max(delta)
col_adds = [D_max - d for d in delta]
# Define the final target: after row additions and column additions, every cell becomes:
# (B[i][0] + (base[j]-base[0])) + (R_max - B[i][0]) + (D_max - (base[j]-base[0])) = R_max + D_max.
target = R_max + D_max
# Record row addition moves.
for i in range(n):
for _ in range(row_adds[i]):
moves.append(("add_row", i))
# Record column addition moves.
for j in range(n):
for _ in range(col_adds[j]):
moves.append(("add_col", j))
return moves
def rotate_row(matrix, i, r):
"""Rotate row i to the left by r positions."""
n = len(matrix)
matrix[i] = matrix[i][r:] + matrix[i][:r]
return matrix
def rotate_column(matrix, j, r):
"""Rotate column j upward by r positions."""
n = len(matrix)
column = [matrix[i][j] for i in range(n)]
rotated_column = column[r:] + column[:r]
for i in range(n):
matrix[i][j] = rotated_column[i]
return matrix
def add_to_row(matrix, i):
"""Add 1 to all entries in row i."""
n = len(matrix)
for j in range(n):
matrix[i][j] += 1
return matrix
def add_to_column(matrix, j):
"""Add 1 to all entries in column j."""
n = len(matrix)
for i in range(n):
matrix[i][j] += 1
return matrix
def print_matrix(matrix):
"""Print the matrix in a formatted way."""
for row in matrix:
print(" ".join(f"{x:2d}" for x in row))
print()
def apply_moves(matrix, moves):
"""Apply the list of moves to the matrix and show the result after each move."""
current_matrix = [row[:] for row in matrix] # Deep copy of the matrix
print("Initial matrix:")
print_matrix(current_matrix)
for idx, move in enumerate(moves, 1):
if move[0] == "rotate_row":
_, i, r = move
current_matrix = rotate_row(current_matrix, i, r)
print(f"Move {idx}: Rotate row {i} to the left by {r} positions:")
elif move[0] == "rotate_col":
_, j, r = move
current_matrix = rotate_column(current_matrix, j, r)
print(f"Move {idx}: Rotate column {j} upward by {r} positions:")
elif move[0] == "add_row":
_, i = move
current_matrix = add_to_row(current_matrix, i)
print(f"Move {idx}: Add 1 to all entries in row {i}:")
elif move[0] == "add_col":
_, j = move
current_matrix = add_to_column(current_matrix, j)
print(f"Move {idx}: Add 1 to all entries in column {j}:")
print_matrix(current_matrix)
# Check if the resulting matrix is constant
first_value = current_matrix[0][0]
is_constant = all(current_matrix[i][j] == first_value for i in range(len(current_matrix)) for j in range(len(current_matrix)))
if is_constant:
print(f"The matrix has been successfully transformed into a constant matrix with value {first_value}.")
else:
print("The matrix is not constant after applying all moves.")
return current_matrix
# --- Example Usage ---
if __name__ == "__main__":
# Example 3x3 matrix.
matrix = [
[3, 1, 2],
[2, 3, 1],
[1, 2, 3]
]
solution = solve_puzzle(matrix)
if solution:
print("Solution moves:")
for move in solution:
print(move)
print("\nExecuting moves:")
final_matrix = apply_moves(matrix, solution)
else:
print("No solution exists for the given matrix.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment