I'm doing the traditional "Sudoku Puzzle Checker" activity, and I've only been able to figure out how to check the rows so far. As per instruction, I'm suppose to check (in 3 separate functions), the rows, columns, and subgrids (the 3x3 squares) of a solved sudoku puzzle (given in a .csv file). I understand how to do the columns (add 9 each time, 9 times starting numbers ranging from 0-8) and the subgrids (range of 3 numbers, add 6 to get to the next range of 3 numbers e.t.c) but I'm confused as how to implement these concepts into my code. Here's what I have right now:
def load_puzzle(filename):
file = open(filename, 'r')
puzzle = list(file)
#the puzzle currently looks like this:
['5,3,4,6,7,8,9,1,2\n', '6,7,2,1,9,5,3,4,8\n', '1,9,8,3,4,2,5,6,7\n', '8,5,9,7,6,1,4,2,3\n', '4,2,6,8,5,3,7,9,1\n', '7,1,3,9,2,4,8,5,6\n', '9,6,1,5,3,7,2,8,4\n', '2,8,7,4,1,9,6,3,5\n', '3,4,5,2,8,6,1,7,9\n']
print_puzzle(puzzle)
def print_puzzle(puzzle):
print(" ")
count = 0
while count <= 8:
line = list(puzzle[count])
line = [x for x in line if x != ',']
line.remove('\n')
line.insert(3, '|')
line.insert(7, '|')
if count == 3 or count == 6:
print("---------------------")
fresh = ' '.join(line)
count += 1
print('''
Checking puzzle...
''')
delimiter = ','
together = delimiter.join(puzzle)
new = list(together)
new[:] = [x for x in new if x != ',']
new[:] = [x for x in new if x != '\n']
check_rows(new)
#the puzzle now looks like this:
['5', '3', '4', '6', '7', '8', '9', '1', '2', '6', '7', '2', '1', '9', '5', '3', '4', '8', '1', '9', '8', '3', '4', '2', '5', '6', '7', '8', '5', '9', '7', '6', '1', '4', '2', '3', '4', '2', '6', '8', '5', '3', '7', '9', '1', '7', '1', '3', '9', '2', '4', '8', '5', '6', '9', '6', '1', '5', '3', '7', '2', '8', '4', '2', '8', '7', '4', '1', '9', '6', '3', '5', '3', '4', '5', '2', '8', '6', '1', '7', '9']
def check_numbers(numbers):
my_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
numbers.sort()
if numbers == my_list:
return True
else:
return False
def check_rows(n):
count = 0
start = 0
while count <= 8:
row = n[start:(start + 9)]
if check_numbers(row) is True:
count += 1
start += 9
elif check_numbers(row) is False:
break
if count == 9:
print("Rows okay...")
else:
print("Error in row", count)
check_columns(n)
def check_columns(n):
count = 0
start = 0
while count <= 8:
col = n[start::9]
if check_numbers(col) is True:
count += 1
start += 1
elif check_numbers(col) is False:
break
if count == 9:
print("Columns okay...")
else:
print("Error in row", count)
def check_subgrids(n):
filename = input("Enter file name of solved sudoku puzzle: ")
load_puzzle(filename)
I'm looking for a way to find the columns and subgrids similar to how I found the rows (i.e. row = n[start:(start + 9)]) if that's possible. I'm a beginner, so I'm also happy to learn about different tools/ways I could improve my code!
Edit: I've solved my problem with the check_columns function (code updated) but still would appreciate some guidance for the check_subgrid function!
Related
Today I was solving Project Euler's problem #43
Problem and I ran into a somewhat interesting problem. I don't understand why is my code so fast?
from itertools import permutations
def main():
numbers1_9 = [0,1,2,3,4,5,6,7,8,9]
list_of_all_permutations = list(permutations(numbers1_9, 10))
length_of_my_list = len(list_of_all_permutations)
number_of_times_it_ran=0
result = []
for n in list_of_all_permutations:
number_of_times_it_ran+=1
if n[0] == 0:
continue
elif n[3] % 2 == 0 and (n[2]+n[3]+n[4]) % 3 == 0 and n[5] % 5 ==0 and int(str(n[4])+str(n[5])+str(n[6])) % 7 == 0 and (n[5]+n[7]-n[6]) % 11 == 0 and int(str(n[6])+str(n[7])+str(n[8])) % 13 == 0 and int(str(n[7])+str(n[8])+str(n[9])) % 17 == 0:
temp_list = []
for digits_of_n in n:
temp_list.append(str(digits_of_n))
result.append(int("".join(temp_list)))
print(f"Added {temp_list}, Remaining: {length_of_my_list-number_of_times_it_ran}")
print(f"The code ran {number_of_times_it_ran} times and the result is {sum(result)}")
if __name__ == "__main__":
main()
I mean it went through the for loop 3,628,800 times, checked all those parameters, and only took a second.
Added ['1', '4', '0', '6', '3', '5', '7', '2', '8', '9'], Remaining: 3142649
Added ['1', '4', '3', '0', '9', '5', '2', '8', '6', '7'], Remaining: 3134251
Added ['1', '4', '6', '0', '3', '5', '7', '2', '8', '9'], Remaining: 3124649
Added ['4', '1', '0', '6', '3', '5', '7', '2', '8', '9'], Remaining: 2134649
Added ['4', '1', '3', '0', '9', '5', '2', '8', '6', '7'], Remaining: 2126251
Added ['4', '1', '6', '0', '3', '5', '7', '2', '8', '9'], Remaining: 2116649
The code ran 3628800 times, and the result is 16695334890
This is the output. The code finished in 1.3403266999521293 seconds.
It runs so quickly because of the short-circuiting feature of logical operators. The first three conditions in the if statement are easy to calculate, and they filter out the vast majority (around 97%) of all the permutations, so you hardly ever need to execute the more expensive operations like int(str(n[4])+str(n[5])+str(n[6])).
So when you have a bunch of conditions that you're connecting with and, and the order that they're tested doesn't matter for the logic, you should put the ones that are easiest to test or are most likely to fail first.
Let's say I have the following list that contains other lists:
episodes = [
['1', '2', '3', '4', '5', '6', '7'],
['1', '2', '3', '4', '5', '1', '2', '3', '4', '5', '6'],
['1', '2', '3', '1', '2', '3', '4', '5', '6', '1', '2', '3', '4', '5', '6', '1', '2', '3', '4', '1', '2', '3']
]
Each list refer to episodes of TV-shows. For example, the first list has one season with 7 episodes, whereas the last list has five seasons with season one having 3 episodes, season 2 6 episodes and so on. I would like to save the total number of episodes for each TV-show by adding the total number of episodes for each season of the TV-show. In other words, first list is just taking the last element of that list, but the last list I have to add 3 & 6 & 6 & 4 & 3.
I hope you understand what I'm trying to do. I thought about using indexing and see where the element '1' lies in each list with more than one season so I can choose the element before (number of episodes of previous season) and so on. But it gets a bit tricky doing it for all other seasons as well.
if you just want the total number of episodes regardless of seasons just count the length of the each show list.
episodes = [
['1', '2', '3', '4', '5', '6', '7'],
['1', '2', '3', '4', '5', '1', '2', '3', '4', '5', '6'],
['1', '2', '3', '1', '2', '3', '4', '5', '6', '1', '2', '3', '4', '5', '6', '1', '2', '3', '4', '1', '2', '3']
]
print(*[len(show) for show in episodes], sep="\n")
OUTPUT
7
11
22
If I understand you correctly you can just sum up the length of each list, i.e. sum(map(len, episodes))?
I came up with something like this to check for number of episodes in each season:
episodes = [
['1', '2', '3', '4', '5', '6', '7', "8", "9", "10", "11"],
['1', '2', '3', '4', '5',
'1', '2', '3', '4', '5', '6'],
['1', '2', '3',
'1', '2', '3', '4', '5', '6',
'1', '2', '3', '4', '5', '6',
'1', '2', '3', '4',
'1', '2', '3']
]
def count_episodes(list_of_episodes):
all_episodes = [e for l in list_of_episodes for e in l]
previous_episode = 0
season = 1
seasons = {}
tmp_list = []
for i in all_episodes:
if previous_episode > int(i):
seasons["season "+str(season)] = tmp_list
tmp_list = []
season += 1
previous_episode = int(i)
tmp_list.append(i)
if len(tmp_list) > 0:
seasons["season "+str(season)] = tmp_list
for i in seasons:
print(i + " has {} episodes".format(len(seasons[i])))
count_episodes(episodes)
OUTPUT
season 1 has 11 episodes
season 2 has 5 episodes
season 3 has 6 episodes
season 4 has 3 episodes
season 5 has 6 episodes
season 6 has 6 episodes
season 7 has 4 episodes
season 8 has 3 episodes
simpler solution
At the end, it is sth as simple as:
list(map(len, episodes))
## [7, 11, 22]
If all episodes are listed always, then you can just count the total number of episodes - it will be always the same as if you determined the maximum numbers and summed them up.
slighlty more elaborate solution
from functools import reduce
def list_to_max_seasons(lst, first_element='1'):
return reduce(lambda l, x: l + [x] if x == first_element else l[:-1] + [x], lst, [])
def sum_max_episodes(lol):
return [(lambda l: sum([int(x) for x in l]))(list_to_max_seasons(il)) for il in lol]
Test by:
sum_max_episodes(episodes)
## [7, 11, 22]
more elaborate (recursive) solution
These solutions are not very pythonic, I admit.
But they are quite universal.
def list_to_seasons(l, acc=[], by='1', tmp=[]):
if l == []:
return acc+[tmp]
elif l[0] == by:
if tmp == []:
return list_to_seasons(l[1:], acc=[], by=by, tmp=[l[0]])
else:
return list_to_seasons(l[1:], acc=acc+[tmp], by=by, tmp=[l[0]])
else:
return list_to_seasons(l[1:], acc=acc, by=by, tmp=tmp+[l[0]])
list_to_seasons(['1','2','3','1','2','1','2','3','1','1'])
## [['1', '2', '3'], ['1', '2'], ['1', '2', '3'], ['1'], ['1']]
Or:
def list_to_max_seasons(l, acc=[], by='1', last=None):
if l == []:
return acc+[last]
elif l[0] == by:
if last is None:
return list_to_max_seasons(l[1:], acc=[], by=by, last=l[0])
else:
return list_to_max_seasons(l[1:], acc=acc+[last], by=by, last=l[0])
else:
return list_to_max_seasons(l[1:], acc=acc, by=by, last=l[0])
list_to_max_seasons(['1','2','3','1','2','1','2','3','1','1'])
## ['3', '2', '3', '1', '1']
Then:
def sum_max_episodes(lol):
return [(lambda l: sum([int(x) for x in l]))(list_to_max_seasons(il)) for il in lol]
Test by:
sum_max_episodes(episodes)
## [7, 11, 22]
Currently making Sudoku in my CompSci class, I'm using recursion to check my rows and make sure that there are no duplicates (I'll do columns and 3x3's later) but I'm running into an issue of my index going out of range. Now I know that means that it's going outside of the list but for some reason I can't figure out how it is.
Here is my recursion method for covering all of the rows. I'm importing a default 0 as the row initially and therefore is goes from 0 all the way to 8 and when it reaches 8, it'll return(essentially a break).
def winCheck(self, row):
if row == 8:
return ''
for num in range (1,10): #for EACH values 1-9
count = 0
for j in range(9):
if (self.board[row][j] == str(num)):
count += 1
if (count!=1): #MUST have a count of 1
print("wrong!")
return False
elif count == 1:
print("good!")
row= row + 1
game.winCheck(row)
return True
Here is my list for my playing board and the original board (those can't be modified)
for i in range(9):
self.board[i] = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ]
self.origBoard[i] = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ]
# [[' ', '1', '9', '3', '7', '4', '6', '5', '2'],
# ['5', '7', '6', '1', '8', '2', '9', '4', '3'],
# ['3', '4', '2', '5', '9', '6', '7', '1', '8'],
# ['9', '2', '1', '7', '5', '3', '8', '6', '4'],
# ['6', '3', '8', '4', '1', '9', '5', '2', '7'],
# ['4', '5', '7', '6', '2', '8', '1', '3', '9'],
# ['1', '8', '5', '2', '3', '7', '4', '9', '6'],
# ['7', '6', '3', '9', '4', '1', '2', '8', '5'],
# ['2', '9', '4', '8', '6', '5', '3', '7', ' ']]
#raw data set for testing win conditions
game.winCheck(row) --> return game.winCheck(row)
I need to count the number of separate regions in an array.
An example array is below. I can count the number of unique strings but if there are two distinct islands like in the grid below where 64733 is in the upper left and bottom right my function won't properly count the number of regions.
Can anyone help me to find a way to count the number of regions if two of the regions are comprised of the same numbers? Im writing in python 2.x.
|64733|20996|92360|92360|04478|04478|04478|04478|04478|98101
|64733|92360|92360|92360|04478|04478|04478|04478|04478|04478
|64733|92360|29136|92360|04478|04478|04478|04478|04478|04478
|64733|92360|29136|92360|04478|04478|04478|04478|04478|04478
|92360|92360|92360|92360|04478|04478|04478|04478|04478|04478
|04478|04478|04478|04478|04478|04478|04478|04478|04478|04478
|04478|04478|04478|04478|04478|04478|04478|04478|04478|04478
|04478|04478|04478|04478|04478|04478|04478|04478|04478|04478
|04478|04478|04478|04478|04478|04478|04478|04478|04478|64773
|04478|04478|04478|04478|04478|04478|04478|04478|64773|64773
The input is a 3d array and looks like
[[['6', '4', '7', '3', '3'],
['2', '0', '9', '9', '6'],
['9', '2', '3', '6', '0'],
['9', '2', '3', '6', '0'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8'],
['9', '8', '1', '0', '1']],
[['6', '4', '7', '3', '3'],
['9', '2', '3', '6', '0'],
['9', '2', '3', '6', '0'],
['9', '2', '3', '6', '0'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8'],
['0', '4', '4', '7', '8']],
[['6', '4', '7', '3', '3'],
['9', '2', '3', '6', '0'],
This is not the complete input (because it was huge) but it gets the point across i think
So would be where any unique symbol string of numbers lies and the total number of adjacent strings that are identical (adjacent being up down left right, not diagonal).
enter code here
You didn't post your full array, so I made some assumptions about the original pip separated value you gave us. I've written this in Python 3, but I think it should work in Python 2 only modifying the print function calls to statements.
arr = [["64733","20996","92360","92360","04478","04478","04478","04478","04478","98101"],
["64733","92360","92360","92360","04478","04478","04478","04478","04478","04478"],
["64733","92360","29136","92360","04478","04478","04478","04478","04478","04478"],
["64733","92360","29136","92360","04478","04478","04478","04478","04478","04478"],
["92360","92360","92360","92360","04478","04478","04478","04478","04478","04478"],
["04478","04478","04478","04478","04478","04478","04478","04478","04478","04478"],
["04478","04478","04478","04478","04478","04478","04478","04478","04478","04478"],
["04478","04478","04478","04478","04478","04478","04478","04478","04478","04478"],
["04478","04478","04478","04478","04478","04478","04478","04478","04478","64773"],
["04478","04478","04478","04478","04478","04478","04478","04478","64773","64773"]]
x = len(arr)
y = len(arr[0])
#create a new array the same size as the original
regions = [[None for _ in range(y)] for _ in range(x)]
print(regions)
label = 0
queue = []
def check_neighbor(i, j, v):
if not regions[i][j] and arr[i][j] == v:
regions[i][j] = label
queue.insert(0, (i, j))
for i in range(x):
for j in range(y):
#don't check an already labelled region
if regions[i][j]: continue
label += 1 #new label
regions[i][j] = label
queue = [(i, j)]
v = arr[i][j]
#keep checking neighbours until we run out
while queue:
(X, Y) = queue.pop()
if X > 0:
check_neighbor(X-1, Y, v)
if X < x-1:
check_neighbor(X+1, Y, v)
if Y > 0:
check_neighbor(X, Y-1, v)
if Y < y-1:
check_neighbor(X, Y+1, v)
print(regions)
print(label) # this is the number of regions
Hi you might remember this program if you are a regular here. I have solved many of the bugs but am stumped by one. The error is:
File "/Users/administrator/Desktop/war.py", line 62, in <module>
player1.extend(player1[range(warcardvalue1)])
TypeError: list indices must be integers, not list
the code is:
import random
cards = ['ace', 'ace', 'ace', 'ace', '1', '1', '1', '1', '2', '2', '2', '2', '3', '3', '3', '3', '4', '4', '4', '4', '5', '5', '5', '5', '6', '6', '6', '6', '7', '7', '7', '7', '8', '8', '8', '8', '9', '9', '9', '9', '10', '10', '10', '10', 'jack', 'jack', 'jack', 'jack', 'queen', 'queen', 'queen', 'queen', 'king', 'king', 'king', 'king']
order = ['ace', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'jack', 'queen', 'king']
warcardvalue0 = 0
warcardvalue1 = 0
print "shuffling cards"
random.shuffle(cards)
print "lets play"
player0 = cards[1::2]
player1 = cards[::2]
while (len(player0) > 0 or len(player1) > 0):
nextcard0 = player0[0]
nextcard1 = player1[0]
cardplayed0 = order.index(nextcard0)
cardplayed1 = order.index(nextcard1)
if cardplayed0 > cardplayed1:
player0.append(nextcard0)
player0.append(nextcard1)
player0.remove(nextcard0)
player1.remove(nextcard1)
elif cardplayed0 < cardplayed1:
player1.append(nextcard1)
player1.append(nextcard0)
player1.remove(nextcard1)
player0.remove(nextcard0)
elif cardplayed0 == cardplayed1:
while warcardvalue0 == warcardvalue1:
if len(player0) >= 3:
warcard0 = player0[3]
elif len(player0) < 3:
warcard0 = player0[len(player0)-1]
if len(player1) >= 3:
warcard1 = player1[3]
elif len(player1) < 3:
warcard1 = player1[len(player1)-1]
warcardvalue0 = order.index(warcard0)
warcardvalue1 = order.index(warcard1)
if warcardvalue0 > warcardvalue1:
player0.extend(player0[range(warcardvalue0)])
player0.extend(player1[range(warcardvalue1)])
player0.extend(player0[range(warcardvalue0)])
player1.extend(player1[range(warcardvalue1)])
elif warcardvalue0 < warcardvalue1:
player1.extend(player1[range(warcardvalue1)])
player1.extend(player0[range(warcardvalue0)])
player1.extend(player1[range(warcardvalue1)])
player0.extend(player0[range(warcardvalue0)])
else:
print "another war!"
if len(player1) == 0:
print "player1 won!"
elif len(player0) == 0:
print "player0 won!"
I think the problem is that you cant use range in lists but I'm not sure.
I think the problem is that you cant use range in lists but I'm not sure.
The problem is that you can't index a list with a list.
Try this instead:
player1.extend(player1[:warcardvalue1])
Seems a bit odd to want to do it though....