I'm very sorry I'm asking this question, but my coding skills are not so great, so I can not solve this problem: there is a grid 5*5, and a task is to find minimal number of "lights", or "1" settled in a special way: in every 3*3 square of the big square, there must be exactly 4 "lights". Counting with a pen, I've got this minimal number equals 7 (the answer is right). So my solution looks like this:
#creates a list
grid = []
#creates lines
for row in range(5):
grid.append([])
#creates columns
for column in range(5):
grid[row].append(0)
#one "light" must be in a center
grid[2][2] = 1
#this array counts all "lights" and will notice when there are 4 of them
light_number = []
def counter():
for row in range(0, 3):
for column in range(0, 3):
if grid[row][column] == 1:
light_number.append(1)
print(len(light_number))
As expected, counter() works only for the first little 3*3 square. Wanting to have only one function for searching "lights" and not 9, I`ve tried to write something like this:
def counter():
#initial range of the counter
row_min = 0
row_max = 3
column_min = 0
column_max = 3
for i in range(9):
for row in range(row_min, row_max):
for column in range(column_min, column_max):
if grid[row][column] == 1:
#write it in a list
light_number.append(1)
column_min += 1
column_max += 1
row_min += 1
row_max += 1
#print a number of total lights
print(len(light_number))
But it doesn't work, saying that grid[row][column] == 1 is out of range.
So, the problem is:
I can't write working counter, which should automatically see all little squares 3*3
I don't know, how to write all combinations of "lights".
Please, if you have ANY idea, tell me. If you think there can be another solution, please, say also. Thanks in advance.
Until someone comes up with a smarter algorithm, I can offer you a brute-force solution to enumerate all grids.
Represent each row of a grid as a "binary" number from 0 (all lights in a row are off) to 31 (all lights are on). Then, a grid will be a 5-tuple of such numbers. There are 32^5 = 33554432 grids - something that is possible to brute-force within minutes, if done efficiently.
To check a number of lights (bits) in a 3x3 square that starts at row r and column c (where r and c are between 0 and 2), use bit shifts and masks:
s = (nbits[7 & (g[r + 0] >> (2 - c))]
+nbits[7 & (g[r + 1] >> (2 - c))]
+nbits[7 & (g[r + 2] >> (2 - c))])
where g is a grid and nbits holds the number of bits for each number from 0 to 7. If some s != 4, the grid is not valid, go on to the next one.
Putting it all together:
import itertools
# 0 1 2 3 4 5 6 7
nbits = [ 0,1,1,2,1,2,2,3 ]
def check(g):
for r in range(3):
for c in range(3):
s = (nbits[7 & (g[r + 0] >> (2 - c))]
+nbits[7 & (g[r + 1] >> (2 - c))]
+nbits[7 & (g[r + 2] >> (2 - c))])
if s != 4:
return False
return True
for g in itertools.product(range(32), repeat=5):
if check(g):
print g
for row in g:
print '{:05b}'.format(row)
print
The question was about learning something about programming. As far as I can see, a simple backtrack-mechanism should be used:
import numpy as np
#initialize the grid with the middle set to one
grid = np.zeros((5,5))
grid[2,2] = 1
First, we need a simple check function, that returns True if the global grid is
gracefully filled with ones:
# a method to check all sub squares starting at row and column 0 through 2
def checkgrid():
# row 0 through 2
for r in xrange(3):
# column 0 through 2
for c in xrange(3):
# sum up all entries of grid matrix
if grid[r:r+3, c:c+3].sum() != 4:
return False
return True
And here we go with the main method. The idea is the following: Every grid entry has a
unique identifier between zero and 24, its "idx". The aim is to find a valid configuration
where the six ones are spread correctly over the 24 grid entries (25 - middle entry).
All possible binom(24, 6)=134596 solutions are enumerated through a simple loop and a recursive call to place the remaining entries, until the check-method returns True the first time, i.e. when a valid configuration is found.
# method that is recursively applied to set the next one
def recursive_trial(first, depth, maxdepth):
# all ones are placed: check the grid
if depth == maxdepth:
return checkgrid()
# enumerate possible grid positions as idx == 5 * r + c
for idx in xrange(first, 25 - (maxdepth - depth + 1)):
# get row and column idx
r = idx / 5
c = idx % 5
# skip the middle
if grid[r,c] == 1:
continue
# set entry to one
grid[r,c] = 1
# call method recursively to place missing ones until 7 in the remainder of the array
if recursive_trial(idx + 1, depth + 1, maxdepth):
return True
# set entry back to zero
grid[r,c] = 0
# at this point, we failed with the current configuration.
return False
A call to
recursive_trial(0, 0, 6)
print grid
yields (in a matter of milliseconds)
[[ 0. 0. 1. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 1. 1. 1. 1. 1.]
[ 0. 0. 1. 0. 0.]
[ 0. 0. 0. 0. 0.]]
This is how I will solve it:
grid = [[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0]]
grid33total = [[0,0,0],[0,0,0],[0,0,0]]
for i in range(3):
for j in range(3):
grid33total[i][j] = sum(sum(x[0+i:3+i]) for x in grid[0+j:3+j])
total = sum(sum(x) for x in grid33total)
The array grid33total contains the number of "lights" for each of the 3x3 squares.
So, thankfully to efforts and help, I've came up with a solution.
import itertools
from pprint import pprint
import sys
def check(grid):
count = 0
for row in range(3):
for column in range(3):
s = 0
for right in range(3):
for down in range(3):
if grid[row+right][column+down] == 1:
s += 1
if s == 4:
count += 1
if count != 9:
return False
else:
return True
for n in range(4, 25):
for comb in itertools.combinations(range(25), n):
grid = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
for index in comb:
row = index // 5
column = index % 5
grid[row][column] = 1
if check(grid):
print(n)
pprint(grid)
sys.exit()
I've decided to use itertools.combinations.
row = index // 5
column = index % 5
grid[row][column] = 1
is a very interesting way to determine whether there must be "1" or "0". Program looks at the result of integer division (//), and that will be a row number, and then at the residual (%), that will be a column number. Then it places "1" here.
I know, it's not so beautiful and short, as nbits solution, but it's also a possible variant. On my computer it works just about five minutes.
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!!")