0

I have been trying to write a program that generates a Sudoku puzzle but my program doesn't seem to work. It would seem that the program takes too long to run as my 4X4 is able to generate results. The 2 print statements inserted are indeed printing '1's and '2's.

import random

board = []
for nine in range(9):
    board.append([0, 0, 0, 0, 0, 0, 0, 0, 0])

def sudoku():
    for index in range(81):
        row = index // 9
        col = index % 9
        while board[row][col] == 0:
            chosen = random.randint(1, 9)
            print(1)
            if chosen not in board[row]:
                if check_col(col, chosen) != 1:
                    if row < 3:
                        if col < 3:
                            if check_square(0, 0, chosen) != 1:
                                board[row][col] = chosen
                        elif col < 6:
                            if check_square(0, 3, chosen) != 1:
                                board[row][col] = chosen
                        else:
                            if check_square(0, 6, chosen) != 1:
                                board[row][col] = chosen
                                print(2)
                    elif row < 6:
                        if col < 3:
                            if check_square(3, 0, chosen) != 1:
                                board[row][col] = chosen
                        elif col < 6:
                            if check_square(3, 3, chosen) != 1:
                                board[row][col] = chosen
                        else:
                            if check_square(3, 6, chosen) != 1:
                                board[row][col] = chosen
                    else:
                        if col < 3:
                            if check_square(6, 0, chosen) != 1:
                                board[row][col] = chosen
                        elif col < 6:
                            if check_square(6, 3, chosen) != 1:
                                board[row][col] = chosen
                        else:
                            if check_square(6, 6, chosen) != 1:
                                board[row][col] = chosen


def check_col(col, chosen):
    check = 0
    for c_row in range(9):
        if chosen == board[c_row][col]:
            check = 1
    return check

def check_square(starting_row, starting_col, chosen):
    check = 0
    for c_add in range(3):
        if chosen in board[starting_row + c_add][starting_col:starting_col + 3]:
            check = 1
    return check

sudoku()
for printing in range(9):
    print(board[printing])
Fysu127
  • 7
  • 1
  • 2
  • "Doesn't seem to work" -- so determine if it *does* or *does not*. Insert `print` statements all along your code so you can *see* if it does do something or not. – Jongware Apr 16 '20 at 14:44
  • Hi! Thanks for the advice. I have edited the code to the above and they are indeed printing a lot of '1's and some '2's. – Fysu127 Apr 16 '20 at 14:56

1 Answers1

0

You can generate a random sudoku solution board where all numbers are filled in and then remove some of them to create the puzzle. This will ensure that the puzzle always has a solution. Making sure that it has exactly one solution is a bit more challenging (hint: you must leave at least 17 numbers for a 9x9 sudoku)

The algorithm below will generate a NxN random sudoku solution board instantly for N < 1000.

base  = 3
side  = base*base

# pattern for a baseline valid solution
def pattern(r,c): return (base*(r%base)+r//base+c)%side

# randomize rows, columns and numbers (of valid base pattern)
from random import sample
def shuffle(s): return sample(s,len(s)) 
rBase = range(base) 
rows  = [ g*base + r for g in shuffle(rBase) for r in shuffle(rBase) ] 
cols  = [ g*base + c for g in shuffle(rBase) for c in shuffle(rBase) ]
nums  = shuffle(range(1,base*base+1))

# produce board using randomized baseline pattern
board = [ [nums[pattern(r,c)] for c in cols] for r in rows ]

for line in board: print(line)

[6, 2, 5, 8, 4, 3, 7, 9, 1]
[7, 9, 1, 2, 6, 5, 4, 8, 3]
[4, 8, 3, 9, 7, 1, 6, 2, 5]
[8, 1, 4, 5, 9, 7, 2, 3, 6]
[2, 3, 6, 1, 8, 4, 9, 5, 7]
[9, 5, 7, 3, 2, 6, 8, 1, 4]
[5, 6, 9, 4, 3, 2, 1, 7, 8]
[3, 4, 2, 7, 1, 8, 5, 6, 9]
[1, 7, 8, 6, 5, 9, 3, 4, 2]

You can then remove some of the numbers from the sudoku solution to create the puzzle:

squares = side*side
empties = squares * 3//4
for p in sample(range(squares),empties):
    board[p//side][p%side] = 0

numSize = len(str(side))
for line in board: print("["+"  ".join(f"{n or '.':{numSize}}" for n in line)+"]")

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

For 4x4 up to 36x36 puzzles, you could make a nicer print of the board like this:

def expandLine(line):
    return line[0]+line[5:9].join([line[1:5]*(base-1)]*base)+line[9:13]
line0  = expandLine("╔═══╤═══╦═══╗")
line1  = expandLine("║ . │ . ║ . ║")
line2  = expandLine("╟───┼───╫───╢")
line3  = expandLine("╠═══╪═══╬═══╣")
line4  = expandLine("╚═══╧═══╩═══╝")

symbol = " 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"
nums   = [ [""]+[symbol[n] for n in row] for row in board ]
print(line0)
for r in range(1,side+1):
    print( "".join(n+s for n,s in zip(nums[r-1],line1.split("."))) )
    print([line2,line3,line4][(r%side==0)+(r%base==0)])

╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
║ 6 │   │   ║   │   │ 3 ║   │   │ 1 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │ 9 │   ║   │   │   ║   │   │ 3 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 4 │   │ 3 ║   │   │   ║ 6 │   │   ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║   │   │   ║ 5 │ 9 │   ║ 2 │   │ 6 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │   │   ║   │   │   ║   │   │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │   │ 7 ║   │   │   ║   │   │ 4 ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║   │   │   ║   │   │   ║ 1 │ 7 │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │   │ 2 ║   │   │ 8 ║   │   │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │   │ 8 ║   │   │   ║   │ 4 │ 2 ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
Alain T.
  • 40,517
  • 4
  • 31
  • 51