I"m trying to make a sudoku puzzle generator (or at least the basics of one) for my project.
I'm approaching this by dividing the sudoku grid into 9 rows.
Each of the rows will be represented by a list and each list will have 9 elements to represent the nine squares that the row is made up of.
Now, I could go ahead and make 9 list (for each of the 9 rows) manually by doing
row_one = []
rwo_two = []
two_three = [] etc.

but I feel that there must be a better way to do this. So, is there a better way to make several variables with similar names like this?

You can do a list of lists...

rows=[[],[],[]...]
# you call a particular cell by doing
rows[3][4]

Edited 6 Years Ago by jice: n/a

You can do a list of lists...

rows=[[],[],[]...]
# you call a particular cell by doing
rows[3][4]

You can also think if it makes sense to divide the rows by 3 cell limits, you can also use tuples instead of lists.

(
((1,2,3)(4,5,6)(7,8,9))
((4,5,6)(7,8,9)(1,2,3))

......
((5,6,4)(8,9,1)(2,3,7))
)

Luck with the project,
Tony

You can also think if it makes sense to divide the rows by 3 cell limits, you can also use tuples instead of lists.

Luck with the project,
Tony

Thanks.. that's really helpful.
Thanks to jice too..

Something to think abour is also to use objects as cells (dict for example)
This way, you can use several lists to order the same cells different way.

For example

import pprint # don't worry abour this it is only to print the result quickly at the end

rows=[[0 for i in range(9)] for i in range(9)]
cols=[[0 for i in range(9)] for i in range(9)]
for i in range(9):
    for j in range(9):
        rows[i][j]={"value":(i+j) % 9 + 1}
        cols[j][i]=rows[i][j] # cols[j][i] and rows[i][j] are the SAME object
                              # altering one will alter the other

# Here is the print section.
# I use the pprint module and list comprehension to be quick on this part.
# This doesn't need to be understood ;-)
pprint.pprint([[elt["value"] for elt in row] for row in rows])
pprint.pprint([[elt["value"] for elt in col] for col in cols])

print 
rows[3][4]["value"]=1515

pprint.pprint([[elt["value"] for elt in row] for row in rows])
pprint.pprint([[elt["value"] for elt in col] for col in cols])

I didn't build the lists for the squares as it is a little more complicated and of no use for this example.
When you've done this, it is very quick and to verify all your groups...

I'm sorry.. I couldn't quite understand that. Could you please explain how that works? (Thanks for the example by the way!)

Sorry, i've been too fast

import pprint # don't worry abour this it is only to print the result quickly at the end

rows=[[0 for i in range(9)] for i in range(9)]
cols=[[0 for i in range(9)] for i in range(9)]
# these are called list comprehensions and are the same as
rows=[]
for i in range(9):
    rows.append([])
    for j in range(9):
        rows[-1].append(0)
# so now rows=[[0, 0, 0, 0... ], [0,0,0,0...  ] ... ]
cols=[]
for i in range(9):
    cols.append([])
    for j in range(9):
        cols[-1].append(0)
# this is to create 2 lists skeltons
# now, let's fill them
for i in range(9):
    for j in range(9):
        # here, instead of 0 in each 'cell', I put a dictionary with 1 key : 'value'
        # note that you can put others datas in this dictionnary (like hidden, shown or whatever)
        rows[i][j]={"value":(i+j) % 9 + 1} # I put whatever value. Call another function... It's here you choose the values
        cols[j][i]=rows[i][j] # cols[j][i] and rows[i][j] are the SAME object
                              # altering one will alter the other

# Here is the print section.
# I use the pprint module and list comprehension to be quick on this part.
# This doesn't need to be understood ;-)
pprint.pprint([[elt["value"] for elt in row] for row in rows])
pprint.pprint([[elt["value"] for elt in col] for col in cols])

print 
# WHAT IS IMPORTANT TO SEE IS HERE
rows[3][4]["value"]=1515
# I change a rows value and in the result, you'll see that cols have changed too
pprint.pprint([[elt["value"] for elt in row] for row in rows])
pprint.pprint([[elt["value"] for elt in col] for col in cols])

Is that somewhat clearer ?

Edited 6 Years Ago by jice: n/a

This discussion started the tapes of the Turing machines in my mind turning and I wanted to do some experimentation with string representation for the sudoku square. So here is the experiments end results for anybody interested.

As strings can not change their values, we must slice new strings and use little functional programming (my first love from reading article of Lisp 1981, when I was 16 ;-) )

"""
    Sudoku field by string and functional programming experiment
    Tony Veijalainen, Finland,  15.4.2010
    CC attribution licence
"""

s='\
123456789\
654789123\
256789456\
789123143\
356789133\
856567113\
956789466\
523789173\
456123798'

## some fail silently only giving complaint error handling
def sudoku_column(s,i):
    if 0<=i<=8: return s[i:81:9]
    else: print "Sudoku has only 9 columns (0..8). Got",i

def sudoku_row(s,j):
    if 0<=j<=8:
        i=sudoku_index(j,0)
        return s[i:i+9]
    else: print "Sudoku has only 9 rows (0..8). Got",j

def sudoku_minisquare(s,x,y):
    if x in range(3) and y in range(3): ## for variation different check as range is so small
        i=sudoku_index(x*3,y*3) ## starting corner
        s1=''
        for ss in range (i, i+3*9, 9):
            s1+=s[ss:ss+3]
        return s1
    else: print 'Wrong minisquare index (',x,',',y,')'

## Have no patience to put error checking here anymore
    
def sudoku_index(x,y): return x*9+y

def put_value(s,x,y,item):
    i= sudoku_index(x,y)
    return s[:i]+item+s[i+1:]

def minisquare(s1):
    ## insert newlines for printing for subsquare
     return s1[:3]+'\n'+s1[3:6]+'\n'+s1[6:9]+'\n'

def square(s):
    ## insert newlines for printing for square, another style for bigger square
    s1=''
    for ss in range(0,81,9):
        s1+=s[ss:ss+9]+'\n'
    return s1

## two formatters above could be generalized by sqr(len)

def correct(s):
    return set(s)==set('123456789')
                       
print 'put x to row 5, col 4'
print square((put_value(s,5,4,'x')))
print
print 's did not change'
print square(s)
print

s=put_value(s,5,5,'4')
print 'changed (5,5) correct to 4 after assignment back to s'
print square(s)

print 'this is middle subsquare (1,1), which has the changed value'
print minisquare(sudoku_minisquare(s,1,1))

print 'Checking if %s are correct' % "minizqares"
for i in range(3):
    for j in range(3):
        print (i,j),
        ms=sudoku_minisquare(s,i,j)
        if correct(ms):
            print 'OK:\n',minisquare(ms)
        else: print 'Fail:\n',minisquare(ms)

print 'Checking if %s are correct' % 'rows'
for i in range(9):
    r=sudoku_row(s,i)
    if correct(r):
        print i,'OK:  ',r
    else: print i,'Fail:',r

print
print 'Checking if %s are correct' % 'columns'
for i in range(9):
    c=sudoku_column(s,i)
    if correct(c):
        print i,' OK: ',c
    else: print i,'Fail:',c

Edited 6 Years Ago by pyTony: n/a

P.S.
Surely everything can be realized neatier by list comprehensions maybe. But I am not completely comfortable with them yet.

The generalisation remark sqr(len) was meaning check length of string and find square root of its length and format accordingly.
Tony

Edited 6 Years Ago by pyTony: n/a

well... as usual I've got stuck. I'm having trouble organizing the cells in the 3 x 3 blocks involved in sudoku. I've adopted the approach shown in post #6. i.e use lists in list to represent cells in rows. Can someone help?

well... as usual I've got stuck. I'm having trouble organizing the cells in the 3 x 3 blocks involved in sudoku. I've adopted the approach shown in post #6. i.e use lists in list to represent cells in rows. Can someone help?

From my code which I posted for string representation (take out error checking to simplify:

def sudoku_minisquare(s,x,y):
        i=sudoku_index(x*3,y*3) ## starting corner
        s1=''
        for ss in range (i, i+3*9, 9):
            s1+=s[ss:ss+3]
        return s1

So it

  1. gets the corner by multiplying the x and y cordidate (0..2,0..2)
  2. It takes next three next cells from that line and two next ones

There is 9 subsquares in the sudoku 3 x 3.

In python indexes start normally from 0,0 which is the first cell's address.

The subsquare which that belongs consist of cells of these indexes:
(0,0) (0,1) (0,2)
(1,0) (1,1) (1,2)
(2,0) (2,1) (2,2)

if you need to take second column subsquare from the second row of subsquares, the middle of sudoku square you must select

(3,3) (3,4) (3,5)
(4,3) (4,4) (4,5)
(4,3) (4,4) (4,5)

How we can find these indexes?
We wanted
subsquare (0,0)
and (0,0 to 2)
(1,0 to 2)
(2,0 to 2)
i.e. (0 to 2,0 to 2).

Solutions basic style of the loop is then

for row in range(3):
    for col in range(3):
           accessing the cell by row and col

Range is 3 as it is three values: 0,1,2.
Do you notice that the corner indexes of the second middle square (1,1) is just (1*3+0,1*3+0) as opposed to (0,0) squares top corner at (0*3+0,0*3+0)?

I let you finish the code. Short description of action was in the end of my previous message. Last words 'and two next ones' mean 'and the tree cells also from two following lines.

Tony

Edited 6 Years Ago by pyTony: n/a

This question has already been answered. Start a new discussion instead.