2

I am writing a script to efficiently solve a sudoku puzzle, but there's one part of my code that I think is extremely ugly and want to streamline.

def square(cell):

    rows='ABCDEFGHI'
    cols='123456789'

    cell_row = cell[0][0]
    cell_col = cell[0][1]

    if cell_row in rows[0:3]:
        x = 'A'
    if cell_row in rows[3:6]:
        x = 'B'
    if cell_row in rows[6:9]:
        x = 'C'
    if cell_col in cols[0:3]:
        y = 'a'
    if cell_col in cols[3:6]:
        y = 'b'
    if cell_col in cols[6:9]:
        y = 'c'

    return (['Aa','Ab','Ac','Ba','Bb','Bc','Ca','Cb','Cc'].index(x+y))+1

Given that a sudoku board is comprised of 9 3x3 squares the purpose of this function is to take the coordinates of a cell on the board and return the number of the 3x3 square to which the cell belongs (where the square in the top left is number 1, and the bottom right is number 9). The input 'cell' is in the form ['A5', 6] where A indicates the row, 5 the column and 6 the value of the cell.

The code that I have works but there's got to be a much more efficient or presentable way of doing it. I would be grateful for any suggestions.

ggordon
  • 259
  • 1
  • 3
  • 16

3 Answers3

1

I was able to make a greatly simplified version of your formula. I started by assigning both the row and column a 0-based index. Then I used integer division to only get the information about what 3-block the square is in. Since moving down a 3-block of rows increases the index by 3 while moving to the right only increases it by 1, I multiply the row index by 3 after the division. Here's the finished function:

def square(cell):
    coords = (ord(cell[0][0]) - 65,int(cell[0][1]) - 1)
    return 3 * (coords[0] // 3) + coords[1] // 3 + 1
Blair
  • 6,623
  • 1
  • 36
  • 42
1

Personally, I don't think magic numbers like '65' and '97' make the solution more presentable! How about:

def square(cell):
    rows = 'ABCDEFGHI'

    cell_row = rows.index(cell[0][0])
    cell_col = int(cell[0][1]) - 1

    return 3 * (cell_row // 3) + cell_col // 3 + 1
cdlane
  • 40,441
  • 5
  • 32
  • 81
0

Edit: Fixed offset by 1 - even though I would rather start at 0 as you'll probably want to use the returned value as an index for another (sub-)array.

And as I cannot comment on other answers yet just my 2 cents here: cdlane's answer is slightly slower than the one presented here. If you get rid of the .lower() (I assume you don't care about fail safes at this point) and use Brien's answer you gain another slight performance boost. I don't know how often you'll evaluate square() but maybe it's worth to ditch readability for performance ;)

I think the attached snippet should do the trick.

def square(cell):
    # http://www.asciitable.com/
    # https://docs.python.org/3/library/functions.html#ord
    row = ord(cell[0][0].lower()) - 97
    column = int(cell[0][1])-1
    return 3*(row//3) +  column//3 + 1
B. Scholz
  • 136
  • 2