Question

I need help creating a list for each of the 9 3x3 blocks in sudoku. so I have a list of lists representing the original sudoku board (zero means empty):

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

I need to turn these into a list of lists containing the 3x3 blocks. So for example:

[[2,0,0,0,0,0,0,4,8],[etc]]

i tried creating one list called "blocks" containing 9 other lists with just zeroes in each list. so it looked like:

blocks=[[0,0,0,0,0,0,0,0,0],[etc]

then i used a while loop to change the values in the list:

BLOCK_COUNT=0
BOARD_COUNT=0
while BLOCK_COUNT<len(blocks):
    blocks[BLOCK_COUNT][0]=board[BOARD_COUNT][BOARD_COUNT]
    blocks[BLOCK_COUNT][1]=board[BOARD_COUNT][BOARD_COUNT+1]
    blocks[BLOCK_COUNT][2]=board[BOARD_COUNT][BOARD_COUNT+2]
    blocks[BLOCK_COUNT][3]=board[BOARD_COUNT+1][BOARD_COUNT]
    blocks[BLOCK_COUNT][4]=board[BOARD_COUNT+1][BOARD_COUNT+1]
    blocks[BLOCK_COUNT][5]=board[BOARD_COUNT+1][BOARD_COUNT+2]
    blocks[BLOCK_COUNT][6]=board[BOARD_COUNT+2][BOARD_COUNT]
    blocks[BLOCK_COUNT][7]=board[BOARD_COUNT+2][BOARD_COUNT+1]
    blocks[BLOCK_COUNT][8]=board[BOARD_COUNT+2][BOARD_COUNT+2]
    BLOCK_COUNT+=1
    BOARD_COUNT+=3

This however gives me an index error. if I create 2 of those while loops with "BLOCK_COUNT" being 3 and 6 respectively then i get a better answer but it still doesn't give me the correct 3x3 block for some. So i'm pretty much at a loss for how to do this. Thanks.

Was it helpful?

Solution

def getBlocks(board):
    answer = []
    for r,c in itertools.product(range(3), repeat=2):
        answer.append([board[r+i][c+j] for i,j in itertools.product(range(0, 9, 3), repeat=2)])
    return answer

Of course, you could replace the whole thing with just one list comprehension:

answer = [[board[r+i][c+j] for i,j in itertools.product(range(0, 9, 3), repeat=2)]
          for r,c in itertools.product(range(3), repeat=2)]

In case you are interested in a version that doesn't use any built-ins to do any heavy lifting:

def getBlocks(board):
    answer = []
    for r in range(3):
        for c in range(3):
            block = []
            for i in range(3):
                for j in range(3):
                    block.append(board[3*r + i][3*c + j])
            answer.append(block)
    return answer

So what's happening here?:

Well, first, we decide to iterate over the 9 blocks that we want. These are governed by the r and c variables. This is also why we multiply them by 3 when we access the numbers on the board (because each block is a square of side 3).

Next, we want to iterate over the elements in each block. Translation: Lookup the numbers within each 3x3 block. The index of each element within the block is governed by i and j. So we have i and j that govern the elements we want to access, along with r and c, which are their offsets from the board itself, determining the location of the "block" we want. Now we're off to the races.

For each r and c (notice that each loops over range(3), so there are 9 (r,c) pairs - the 9 blocks that we are after), loop over the 9 elements in the block (the 9 (i,j) pairs). Now, simply access the elements based on their relative locations from the (r,c) offsets (3*r gives the first row of the relevant block, and adding i gives the row of the required element. Similarly, 3*c gives the first column of the relevant block, and adding j gives the column of the required element. Thus, we have the coordinates of the element we want). Now, we add the element to block.

Once we've looped over all the elements in the block, we add the block itself to the answer, and presto! we're done

OTHER TIPS

You can do this with a combination of reshape and transpose when you use numpy.

edit - sorry - hit enter too soon:

import numpy as np
board=[[2,0,0,0,0,0,0,6,0],
       [0,0,0,0,7,5,0,3,0],
       [0,4,8,0,9,0,1,0,0],
       [0,0,0,3,0,0,0,0,0],
       [3,0,0,0,1,0,0,0,9],
       [0,0,0,0,0,8,0,0,0],
       [0,0,1,0,2,0,5,7,0],
       [0,8,0,7,3,0,0,0,0],
       [0,9,0,0,0,0,0,0,4]]

t = np.array(board).reshape((3,3,3,3)).transpose((0,2,1,3)).reshape((9,9));
print t

Output:

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

should work, in python3 you might replace "(m/3)*3" with "int(m/3)*3"

[[board[(m/3)*3+i][(m%3)*3+j] for i in range(3) for j in range(3)] for m in range(9)]

this uses no builtins and is faster 3 nested for loops

def get_boxes(board):
    boxes = []
    for i in range(9): 
        if i == 0 or i % 3 == 0:  
            box_set_1 = board[i][:3] + board[i + 1][:3] + board[i + 2][:3]  
            boxes.append(box_set_1)
            box_set_2 = board[i][3:6] + board[i + 1][3:6] + board[i + 2][3:6]
            boxes.append(box_set_2)
            box_set_3 = board[i][6:] + board[i + 1][6:] + board[i + 2][6:]
            boxes.append(box_set_3)
def get_boxes(board):    
    boxes = []
    for i in range(9): 
        if i == 0 or i % 3 == 0:  
            box_set_1 = board[i][:3] + board[i + 1][:3] + board[i + 2][:3]  
            boxes.append(box_set_1)
            box_set_2 = board[i][3:6] + board[i + 1][3:6] + board[i + 2][3:6]
            boxes.append(box_set_2)
            box_set_3 = board[i][6:] + board[i + 1][6:] + board[i + 2][6:]
            boxes.append(box_set_3)
    return boxes
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top