Last active
January 5, 2024 04:23
-
-
Save Joeccp/f5c8768709e295fd7a867dfc97b71085 to your computer and use it in GitHub Desktop.
Generate shuffed 9x9 sudoku
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Sudoku generator | |
Algorithm shamelessly borrowed from https://stackoverflow.com/a/56581709/16747758 (By Alain T., released under CC-BY-SA 4.0) | |
""" | |
from itertools import product, batched, chain | |
from typing import * | |
from random import sample | |
def check_sudoku_valid(board) -> (bool, str): | |
""" | |
Check if the sudoku board is a valid board. | |
Note that a non-full board can be a valid board. | |
""" | |
# Check rows | |
for row_index, row in enumerate(board): | |
row_used: list = [] | |
for cell in row: | |
if cell in row_used: | |
return False, f'Value {cell} repeated in row {row_index}' | |
row_used.append(cell) | |
# Check columns | |
for column_index in range(9): | |
column_used: list = [] | |
for row_index in range(9): | |
cell = board[row_index][column_index] | |
if cell in column_used: | |
return False, f'Value {cell} repeated in column {column_index}' | |
column_used.append(cell) | |
# Check boxes | |
for i, j in product(range(3), repeat=2): | |
box_used: list = [] | |
for k, l in product(range(3), repeat=2): | |
cell = board[i * 3 + k][j * 3 + l] | |
if cell in box_used: | |
return False, f'Value {cell} repeated in box {3 * i + j}' | |
box_used.append(cell) | |
return True | |
def generate_shuffled_board(board: list[list[int]] = None, shuffle_times: int = 5) -> list[list[int]]: | |
if board is None: | |
board: list[list[int]] = [ | |
[1, 2, 3, 4, 5, 6, 7, 8, 9], | |
[4, 5, 6, 7, 8, 9, 1, 2, 3], | |
[7, 8, 9, 1, 2, 3, 4, 5, 6], | |
[2, 3, 1, 5, 6, 4, 8, 9, 7], | |
[5, 6, 4, 8, 9, 7, 2, 3, 1], | |
[8, 9, 7, 2, 3, 1, 5, 6, 4], | |
[3, 1, 2, 6, 4, 5, 9, 7, 8], | |
[6, 4, 5, 9, 7, 8, 3, 1, 2], | |
[9, 7, 8, 3, 1, 2, 6, 4, 5] | |
] | |
assert check_sudoku_valid(board) | |
# Shuffle row group | |
row_grouped = list(batched(board, 3)) | |
row_grouped = sample(row_grouped, 3) | |
board = list(chain.from_iterable(row_grouped)) | |
assert check_sudoku_valid(board) | |
# Shuffle row 1-3 | |
shuffled_rows = sample(board[0:3], 3) | |
board = [*shuffled_rows, *board[3:]] | |
assert check_sudoku_valid(board) | |
# Shuffle row 4-6 | |
shuffled_rows = sample(board[3:6], 3) | |
board = [*board[0:3], *shuffled_rows, *board[6:9]] | |
assert check_sudoku_valid(board) | |
# Shuffle row 7-9 | |
shuffled_rows = sample(board[6:9], 3) | |
board = [*board[0:6], *shuffled_rows] | |
assert check_sudoku_valid(board) | |
# Row <-> Column | |
board = list(zip(*board)) | |
assert check_sudoku_valid(board) | |
# Shuffle row group | |
row_grouped = list(batched(board, 3)) | |
row_grouped = sample(row_grouped, 3) | |
board = list(chain.from_iterable(row_grouped)) | |
assert check_sudoku_valid(board) | |
# Shuffle row 1-3 | |
shuffled_rows = sample(board[0:3], 3) | |
board = [*shuffled_rows, *board[3:]] | |
assert check_sudoku_valid(board) | |
# Shuffle row 4-6 | |
shuffled_rows = sample(board[3:6], 3) | |
board = [*board[0:3], *shuffled_rows, *board[6:9]] | |
assert check_sudoku_valid(board) | |
# Shuffle row 7-9 | |
shuffled_rows = sample(board[6:9], 3) | |
board = [*board[0:6], *shuffled_rows] | |
assert check_sudoku_valid(board) | |
# Column <-> Row | |
board = list(zip(*board)) | |
assert check_sudoku_valid(board) | |
for _ in range(shuffle_times-1): | |
print(board) | |
board = generate_shuffled_board(board) | |
return board | |
for line in generate_shuffled_board(): | |
print(line) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment