Python sudoku checker - python

I'm working on an assignment for my CIS class in python. We have to code a Sudoku checker. In a 9x9 board we obviously have to check each row, col and 3x3 square for duplicates. I'm a little stuck on the idea of how to check the numbers by a 3x3 square. Below is my code for checking each row and col, if someone could help me a little with an outline or an approach just something for checking each 3x3 square that would be amazing!
self.columns = [ ]
for col in range(9):
col_tiles = [ ]
self.columns.append(col_tiles)
for row in range(9):
col_tiles.append(self.tiles[row][col])
self.squares = [ ]
for col in range(1, 10, 3):
for row in range(1, 10, 3):
square_tiles = [ ]
self.squares.append(square_tiles)
for x in range(3):
for y in range(3):
square_tiles.append(self.tiles[x][y])

This assumes you have the freedom to read the data and structure how you want. We want a set of unique values 1-9 for each row/column/3x3 grid, so one way is to either use a set or a list comparison (we'll use set here to make it cleaner). If we create a set equal to the numbers from 1 to 9, we have a point against which we can compare all of our other groups. Assume a structure like this (from here):
In [1]: r1 = [9,3,2,5,4,8,1,7,6]
In [2]: r2 = [1,8,7,9,2,6,5,4,3]
In [3]: r3 = [5,4,6,3,7,1,2,8,9]
# Continues....
Where each row represents a full row of data. Now lets create a section of that data that represents the first three rows, pull out one grid and compare the contents to our set:
In [4]: sec1 = [r1, r2, r3]
In [5]: nums = set(range(1, 10))
In [6]: nums == set(n for row in sec1 for n in row[:3])
Out[6]: True
This iterates over the first three rows and returns the first three elements in each of those rows. To get a better visual, here is the equivalent for-loop code to make it a bit easier to decipher:
result = set()
for row in sec1:
for n in row[:3]:
result.add(n)
Since our set of numbers includes everything from 1-9, we know it is valid. To move to the second, we range the row[:3] to row[3:6] (and row[6:9] after that). You'll then need to handle this for the next two sections as well. I'll leave it to you as to how to wrap this in a more dynamic structure (note the multiples of three), but hopefully this will get you started :)

Whenever you're having trouble coming up with an algorithm, just ask yourself: "How would I solve this manually, if the only way I could be given the problem was by a computer".
In other words, if I asked you to check the top left 3x3 grid, your eyes would just go to the top left corner and add up numbers. But if I said, check the top left 3x3 grid, and didn't actually give you the board, you'd say, "OK, give me the top left 3x3 grid".
And I'd say "How?"
And you'd say, "Imagine the tiles are numbered by rows and columns. I want the tiles in spots (0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), and (2,2)"
Does that help?

Here's what I would do: create 3 dictionaries, one for the rows, one for the columns, and one for the 3x3 squares.
while you loop through each element in the sudoku puzzle, keep track of your row and column (trivial), and use if statements to keep track of which 3x3 square you're in (a bit more involved)
then just send each element to the corresponding row, column, and 3x3 square dictionary, and compare at the end.
This way you only need to inspect each element once.
EDIT: also, set will probably be useful

This function will do. "sample" gives the randomness, so every time you run this you will get a different one.
from random import sample
def generate_sudoku_checker():
random_list = sample([1,2,3,4,5,6,7,8,9],9)
random_list = random_list + random_list[:9]
for i in range(3):
for j in range(3):
print(random_list[i+j*3:i+j*3+9])

Here is my solution to this :
Funtion:
def check_sudoku(lis):
n = len(lis)
digit = 1 #start from one
while (digit<=n):
i=0
while i<n: # go through each row and column
row_count=0
column_count=0
j=0
while j < n: # for each entry in the row / column
if lis[i][j] == digit: # check row count
row_count = row_count+1
if lis[j][i]== digit :
column_count = column_count+1
j=j+1
if row_count !=1 or column_count!=1:
return False
i=i+1 # next row/column
digit = digit+1 #next digit
return True

Late to the party but this worked for me:
def insert_sudoku():
puzzle = []
for i in range(9):
print("You've entered", len(puzzle), "rows so far")
row = input("Enter a row")
if len(row) < 9:
print("Not enough numbers on this row")
return insert_sudoku()
elif len(row) > 9:
print("Too many numbers. Try again!")
return insert_sudoku()
try:
row = [int(dig) for dig in row]
puzzle.append(row)
except:
print("Whoops, looks like you didn't enter only numbers somewhere. Try again!")
return insert_sudoku()
validate_entries(puzzle)
def validate_entries(puzzle):
check = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b1, b2, b3, b4, b5, b6, b7, b8, b9 = [], [], [], [], [], [], [], [], []
for i in range(9):
z = []
for x in range(9):
z.append(puzzle[i][x])
puzzle.append(z)
for i in range(3):
b1 += (puzzle[i][:3])
b4 += (puzzle[i][3:6])
b7 += (puzzle[i][6:])
for i in range(3,6):
b2 += (puzzle[i][:3])
b5 += (puzzle[i][3:6])
b8 += (puzzle[i][6:])
for i in range(6,9):
b3 += (puzzle[i][:3])
b6 += (puzzle[i][3:6])
b9 += (puzzle[i][6:])
puzzle.append(b1)
puzzle.append(b2)
puzzle.append(b3)
puzzle.append(b4)
puzzle.append(b5)
puzzle.append(b6)
puzzle.append(b7)
puzzle.append(b8)
puzzle.append(b9)
for iter in puzzle:
if sorted(iter) != check:
print("No")
return
print("Yes")
insert_sudoku()
Inspired by this article
EDIT: Indentation might be off from copy + pasting the code.

What my answer adds is the use of a list comprehension to extract the tiles from the board.
"""
# good
board=[
[2,9,5,7,4,3,8,6,1],
[4,3,1,8,6,5,9,2,7],
[8,7,6,1,9,2,5,4,3],
[3,8,7,4,5,9,2,1,6],
[6,1,2,3,8,7,4,9,5],
[5,4,9,2,1,6,7,3,8],
[7,6,3,5,2,4,1,8,9],
[9,2,8,6,7,1,3,5,4],
[1,5,4,9,3,8,6,7,2]
]
"""
# bad
board = [
[1,9,5,7,4,3,8,6,2],
[4,3,1,8,6,5,9,2,7],
[8,7,6,1,9,2,5,4,3],
[3,8,7,4,5,9,2,1,6],
[6,1,2,3,8,7,4,9,5],
[5,4,9,2,1,6,7,3,8],
[7,6,3,5,2,4,1,8,9],
[9,2,8,6,7,1,3,5,4],
[2,5,4,9,3,8,6,7,1]
]
def check(l):
# each digit 1-9 should occur once
for n in range(1,10):
try:
l.index(n)
except ValueError:
return False
return True
# check the rows
for row in board:
print(check(row))
# check the columns
for column in [ [ board[r][c] for r in range(9) ] for c in range(9) ]:
print(check(column))
# check the tiles
for tile in [[board[r][c] for r in range(row, row + 3) for c in range(col, col + 3)] for row in range(0, 9, 3) for col in range(0, 9, 3)]:
print(check(tile))

This is my solution. I also want to confirm the time and space complexity of this code:
"""
Sample input 1:
295743861
431865927
876192543
387459216
612387495
549216738
763524189
928671354
154938672
Output: YES!
Sample input 2
195743862
431865927
876192543
387459216
612387495
549216738
763524189
928671354
254938671
Output: NOPE!!
"""
##################Solution############################################
def get_input():
#Get the input in form of strings and convert into list
print("Enter the board here: ")
lines = []
while True:
line = input()
if line:
lines.append(line)
else:
break
final = [(list(i)) for i in lines]
return final
def row_check(board):
# row check function which will be used in other two functions as well
text = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
x = True
for row in board:
if sorted(row) == text:
x = True
else:
x = False
return x
def col_check(board):
# Getting the list of 9 lists containing column elements
i = 0
j = 0
cols = [[], [], [], [], [], [], [], [], []]
for j in range(0, 9):
for i in range(0, 9):
cols[j].append(board[i][j])
return (row_check(cols))
def tile_check(board):
#Getting the list of 9 lists converting each tile of 3x3 into 9 element list
lst =[[],[],[],[],[],[],[],[],[]]
i = 0
j = 0
k = 0
while k<9:
for r in range(i,i+3):
for c in range(j, j+3):
lst[k].append(board[r][c])
j = j +3
k = k +1
if j == 9:
j = 0
i = i+3
return (row_check(lst))
#main program
c = get_input()
if row_check(c) and col_check(c) and tile_check(c):
print("YES!")
else:
print("NOPE!!")

Related

Creating a new matrix under specified condition from user inputted matrix

As a newbie to python, I've come across a task that I'm having trouble completing. I am supposed to create a new matrix, taking into consideration the original one, inputted by the user, where each element corresponds to the number of adjacent elements greater or equal to the corresponding one in the original matrix. Since English is not my native language, I might not have presented it properly so here is an example:
input:
3x3 matrix
9 14 13
3 0 7
8 15 15
output:
3x3 matrix
2 5 2
1 0 1
2 5 3
So, if it isn't clear, the new matrix determines how many adjacent elements are greater or equal to an element in the original one. 9 is greater than 3 & 0, so that results in "2", 14 is greater than all the adjacent ones so it prints out "5", etc... It also takes diagonals into consideration, of course.
So far, I've got down the input of the original matrix but I'm unsure how to proceed further. I am not someone who's got access to university materials, professors or peer help and my experimentation and search online has been futile so far. I do not need a complete solution, rather than pointers and concept explanation.
This is the code so far:
# matrix input
rOne = int(input("Number of rows:"))
cOne = int(input("Number of columns:"))
# initialize matrix
matrixOne = []
print("Enter elements rowwise:")
# user input
for i in range(rOne): # for loop za redove
a =[]
for j in range(cOne): # for loop za kolone
a.append(int(input()))
matrixOne.append(a)
# print matrix one
for i in range(rOne):
for j in range(cOne):
print(matrixOne[i][j], end = " ")
print()
Here is a function that can do the exact thing:
def adj_matrix(matrixOne, rOne, cOne):
new_lst = []
for i in range(rOne):
a = []
for j in range(cOne):
count = 0
x, y = (i, j) # matrix values here
cells = list(starmap(lambda a,b: (x+a, y+b), product((0,-1,+1), (0,-1,+1)))) # this will find all the adjacent index
filtered_cell = [p for p in cells if (sum(p)>=0 and prod(p)>=0)] # this filters out all the negative indexs
filtered_cell = [p for p in filtered_cell if p[0]<rOne and p[1]<cOne] # this filters out index that are greater than matrix
for z in filtered_cell:
if matrixOne[i][j] >= matrixOne[z[0]][z[1]]:
count += 1
a.append(count-1)
new_lst.append(a)
return new_lst
also import:
from itertools import product, starmap
from math import prod
Actually managed to solve the thing, feels amazing :D
def get_neighbor_elements(current_row, current_col, total_rows, total_cols):
neighbors = []
for i in [-1, 0, 1]: # red pre, isti red, red posle
for j in [-1, 0, 1]: # kolona pre, ista kolona, kolona posle
row = current_row + i
col = current_col + j
if row < 0 or col < 0 or row >= total_rows or col >= total_cols: # preskace se ako se izaslo iz granica matrice
continue
if row == current_row and col == current_col:# ako su red i kolona isti, preskace se(to je taj isti element)
continue
neighbor = [row, col]
neighbors.append(neighbor)
return neighbors
def make_new_matrix(old_matrix):
new_matrix = []
for i in range(len(old_matrix)):
new_matrix.append([])
for i in range(len(old_matrix)): # iteriramo kroz redove stare matrice
for j in range(len(old_matrix[i])): # iteriramo kroz kolone stare matrice
neighbors = get_neighbor_elements(i, j, len(old_matrix), len(old_matrix[i])) # dobavljamo komsije
count = 0
for neighbor in neighbors: # sad gledamo da li je trenutni element veci ili jednak susednim
if old_matrix[i][j] >= old_matrix[neighbor[0]][neighbor[1]]:
count += 1
new_matrix[i].append(count)
return new_matrix
def print_matrix(matrix):
for i in range(len(matrix)):
for j in range(len(matrix[i])):
print(str(matrix[i][j]) + " ", end='')
print()
if __name__ == '__main__':
matrix = [[12, 10], [2, 10]]
print("Old matrix: ")
print_matrix(matrix)
new_matrix = make_new_matrix(matrix)
print("New matrix")
print_matrix(new_matrix)

How to display number sequences in rows and columns in Python 3?

I have a coding assignment to input row and column length, and create a power table. THe example below is for 5 rows, 5 columns.
The code I have so far prints the correct number of rows and columns, but I haven't been able to get the calculations to work. It just shows a table of 1's, five by five.
rows = int(input("Enter a number of rows: "))
cols = int(input("Enter a number of columns: "))
x = 1
y = 1
z = 1
line = ""
while x <= cols :
line = line + format(y**cols, "4d")
x = x + 1
while z <= rows :
print(line)
z = z + 1
The basic problem is that you need to nest your loops. Your second problem is that you never change y. What you do at the moment is to compute the power sequence for 1 into five different lines -- and then you print that last line only five times. Try two changes:
Compute a line, then print it immediately. Then you go to the next line.
Use the correct variable.
After changes:
while z <= rows:
while x <= cols:
line = line + format(x**cols, "4d") # Note the variable change
x = x + 1
print(line)
z = z + 1
Also, look up the for statement, as this will simplify things. After that, look up list comprehension for even more compression.
Here is a way to do it that preserves padding no matter what:
def grid(rows, cols, padding):
max_num_len = len(str(rows**cols))
return '\n'.join([
''.join(['{{:>{}}}'.format(max_num_len+padding).format((row+1)**(col+1))
for col in range(cols)])
for row in range(rows)
])
print(grid(5, 5, 3))
Instead, try creating a 2D array in Python such as a 2D list.
Matrix = [[0 for x in range(5)] for y in range(5)]
for i in range(5):
for j in range(5):
Matrix[i][j]=j^i
Then, print the data you need using nested for loops.
for i in range (5):
for j in range(5):
print(Matrix[j][i])

taking n*n matrix input by user in python

I am starting to code in python. When I was to take two inputs from user with a space between the two inputs my code was like
min, p = input().split(" ")
min=int(min)
p=float(p)
which worked fine. In another such problem I am to take a n*n matrix as user input which I declared as arr=[[0 for i in range(n)] for j in range(n)]
printing the arr gives a fine matrix(in a single row though) but I am to replace each element '0'with a user input so I use nested loops as
for i in range(0,n)
for j in range(0,n)
arr[i][j]=input()
this also worked fine but with a press of 'enter' button after each element. In this particular problem the user will input elements in one row at space instead of pressing 'enter' button. I wanted to know how to use split in this case like in first case above, keeping in mind the matrix is n*n where we don't know what is n. I prefer to avoid using numpy being a beginner with python.
You can do this:
rows = int(input("Enter number of rows in the matrix: "))
columns = int(input("Enter number of columns in the matrix: "))
matrix = []
print("Enter the %s x %s matrix: "% (rows, columns))
for i in range(rows):
matrix.append(list(map(int, input().rstrip().split())))
Now you input in the console values like this:
Enter number of rows in the matrix: 2
Enter number of columns in the matrix: 2
Enter the 2 x 2 matrix:
1 2
3 4
#Take matrix size as input
n=int(input("Enter the matrix size"))
import numpy as np
#initialise nxn matrix with zeroes
mat=np.zeros((n,n))
#input each row at a time,with each element separated by a space
for i in range(n):
mat[i]=input().split(" ")
print(mat)
You can try this simple approach (press enter after each digit...works fine)::
m1=[[0,0,0],[0,0,0],[0,0,0]]
for x in range (0,3):
for y in range (0,3):
m1[x][y]=input()
print (m1)
Try something like this instead of setting the matrix one by one using existing list(s):
# take input from user in one row
nn_matrix = raw_input().split()
total_cells = len(nn_matrix)
# calculate 'n'
row_cells = int(total_cells**0.5)
# calculate rows
matrix = [nn_matrix[i:i+row_cells] for i in xrange(0, total_cells, row_cells)]
Example:
>>> nn_matrix = raw_input().split()
1 2 3 4 5 6 7 8 9
>>> total_cells = len(nn_matrix)
>>> row_cells = int(total_cells**0.5)
>>> matrix = [nn_matrix[i:i+row_cells] for i in xrange(0, total_cells, row_cells)]
>>> matrix
[['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]
>>>
>>> import math
>>> line = ' '.join(map(str, range(4*4))) # Take input from user
'0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15'
>>> items = map(int, line.split()) # convert str to int
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
>>> n = int(math.sqrt(len(items))) # len(items) should be n**2
4
>>> matrix = [ items[i*n:(i+1)*n] for i in range(n) ]
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]
Well if matrix is n*n that means with first input line you know number of input lines (and no, it's impossible for input() to not end with key enter is pressed). So you need something like this:
arr = []
arr.append(input().split())
for x in range(len(arr[0]) - 1):
arr.append(input().split())
I used range(len(arr[0]) - 1) so it inputs rest of lines (because matrix width and height is same and one first line is already read from input).
Also I used .split() without " " as parameter because it's default parameter.
Try with below,
r=int(input("enter number of rows"));
c=int(input("enter number of columns"));
mat=[];
for row in range(r):
a=[]
for col in range(c):
a.append(row*col);
mat.append(a)
print mat;
print("Enter The row and column :")
row,col=map(int,input().split())
matrix = []
print("Enter the entries rowwise:")
# For user input
for i in range(row): # for loop for row entries
a =[]
for j in range(col): # for loop for column entries
a.append(int(input()))
matrix.append(a)
for i in range(row):
for j in range(col):
print(matrix[i][j], end = " ")
print()
n= 10 # n is the order of the matrix
matrix = [[int(j) for j in input().split()] for i in range(n)]
print(matrix)
r = int(input("Enret Number of Raws : "))
c = int(input("Enter Number of Cols : "))
a=[]
for i in range(r):
b=[]
for j in range(c):
j=int(input("Enter Number in pocket ["+str(i)+"]["+str(j)+"]"))
b.append(j)
a.append(b)
for i in range(r):
for j in range(c):
print(a[i][j],end=" ")
print()

How to let user enter two-dimensional list?

Scenario, a two-dimensional list with any number of rows and columns, and the program returns a list of the row and column indices of the maximum value in the list. Example
print max_position([[2,4],[6,0],[2,6]])
list visualised:
2,6,2
4,0,6
result be [(1,0),(2,1)]
Now, how can I allow the user to enter any rows or columns of two-dimensional list to work for my code?
The code:
def max_position(list2D):
if not list2D:
return []
else:
maxi = list2D[0][0]
pos = [] #initialise with no position
for row in range(len(list2D)):
for col in range(len(list2D[row])):
if (list2D[row][col] == maxi):
if (row,col) != (0,0):
pos.append((row,col))
elif (list2D[row][col] > maxi): # new maximum found
pos = [(row,col)]
maxi = list2D[row][col]
return pos
import ast
data = raw_input("Enter your 2D array in the form [[], []]:")
x = ast.literal_eval(data)
# in
[[1,2],[3,4],[5,6]]
# out
x
[[1, 2], [3, 4], [5, 6]]
type(x)
<type 'list'>
This does not do much in the way of error handling, they must enter a syntactically correct 2D array, but it'll do the trick.
How about something like this. This would let you enter in one line at a time each sublist and add it to the overall list.
mylist = []
done = False
while not done:
line = raw_input()
if line != '':
mylist += [line.split(',')]
else:
done = True
print mylist
print "Enter space seperated values, or leave blank to finish"
print list(iter(lambda : map(int,raw_input().split()),[]))
is a fun way to do it :P
of coarse it like the other answers does not actually locate the indices in the resulting array

How to find the position of first instance of duplicates in two equal length, sorted lists

I have two random lists of same length, in range of 0 to 99.
lista = [12,34,45,56,66,80,89,90]
listb = [13,30,56,59,72,77,80,85]
I need to find the first instance of a duplicate number, and in what list it is from.
In this example, I need to find the number '56' in listb, and get the index i = 2
Thanks.
Update:
After running it a couple of times, I got this error:
if list_a[i] == list_b[j]:
IndexError: list index out of range
like #Asterisk suggested, my two lists are equal length and sorted, both i and j are set to 0 at the beginning.
that bit is part of a genetic crossover code:
def crossover(r1,r2):
i=random.randint(1,len(domain)-1) # Indices not at edges of domain
if set(r1) & set(r2) == set([]): # If lists are different, splice at random
return r1[0:i]+r2[i:]
else: # Lists have duplicates
# Duplicates At Edges
if r1[0] == r2[0]: # If [0] is double, retain r1
return r1[:1]+r2[1:]
if r1[-1] == r2[-1]: # If [-1] is double, retain r2
return r1[:-1]+r2[-1:]
# Duplicates In Middle
else: # Splice at first duplicate point
i1, i2 = 0, 0
index = ()
while i1 < len(r1):
if r1[i1] == r2[i2]:
if i1 < i2:
index = (i1, r1, r2)
else:
index = (i2, r2, r1)
break
elif r1[i1] < r2[i2]:
i1 += 1
else:
i2 += 1
# Return A Splice In Relation To What List It Appeared First
# Eliminates Further Duplicates In Original Lists
return index[2][:index[0]+1]+index[1][index[0]+1:]
The function takes 2 lists and returns one.
domain is a list of 10 tupples: (0,99).
As I said, the error doesn't happen every time, only once in a while.
I appreciate your help.
I'm not a python guy, but this is an algorithm question...
You maintain an index into each list and you look at the elements at those two list positions.
Whichever list has the smallest element at the current position, you move to the next element in that list.
When you find an element that is the same as the other list's current element, that is your smallest duplicate.
If you reach the end of either list, there are no duplicates.
If you're looking for all the duplicates, you can use something like this:
list_a = [12,34,45,56,66,80,89,90]
list_b = [13,30,56,59,72,77,80,85]
set_a = set(list_a)
set_b = set(list_b)
duplicates = set_a.intersection(set_b)
# or just this:
# duplicates = [n for n in list_a if n in list_b]
for duplicate in duplicates:
print list_a.index(duplicate)
To get the smallest index of a duplicate in either list:
a_min = min(map(list_a.index, duplicates))
b_min = min(map(list_b.index, duplicates))
if a_min < b_min:
print 'a', a_min, list_a[a_min]
else:
print 'b', b_min, list_b[b_min]
If not, this should work a bit better:
duplicate = None
for n in set_a:
if n in set_b:
duplicate = n
break
if duplicate is not None:
print list_a.index(duplicate)
lista = [12,34,45,56,66,80,89,90]
listb = [13,30,56,59,72,77,80,85]
i, j = 0, 0
while i < len(lista):
if lista[i] == listb[j]:
if i < j:
print i, lista
else:
print j, listb
break
elif lista[i] < listb[j]:
i += 1
else:
j += 1
>>>
2 [13, 30, 56, 59, 72, 77, 80, 85]
Assumptions: both lists have the same length, and they are sorted
Just scan all the lists at position 0, then 1, then 2, ... Keep track of what you've seen (you can query a set in O(1) time).
def firstDuplicate(*lists):
seen = {}
for i,tup in enumerate(zip(*lists)):
for listNum,value in enumerate(tup):
position = (listNum,i)
if value in seen:
return value, [seen[value], position]
else:
seen[value] = position
Demo:
>>> value,positions = firstDuplicate(lista,listb)
>>> value
56
>>> positions
[(1, 2), (0, 3)]
(Does not generalize to N lists... yet. Would need a minor tweak to use a defaultdict(set), insert all indices as a tuple together, then check for duplicates.)

Categories

Resources