I have to write a code for the N-queen chess board problem. I understand the theory behind it but dont understand how I should code it. In this exercise 0's represent spaces, and 1's represent queens)
so far I have only written:
import numpy as np
board=np.zeros((8,8))
board[0:,0]=1
Following this, I want to define what the rows in this board are and what the columns in this board are. So I am able to define collisions between the queens on the board.
Thank you.
I don't know how much I should be helping you (sounds like a homework), but my curiosity was piqued. So here's a preliminary exploration:
Representing a board as a 8x8 array of 0/1 is easy:
In [1783]: B=np.zeros((8,8),int)
But since a solution requires 1 queen per row, and only 1 per column, I can represent it as just a permutation of the column numbers. Looking online I found a solution, which I can enter as:
In [1784]: sol1=[2,5,1,6,0,3,7,4]
I can map that onto the board with:
In [1785]: B[np.arange(8),sol1]=1
In [1786]: B # easy display
Out[1786]:
array([[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 0, 0]])
How about testing this? Row and column sums are easy with numpy. For a valid solution these must all be 1:
In [1787]: B.sum(axis=0)
Out[1787]: array([1, 1, 1, 1, 1, 1, 1, 1])
In [1788]: B.sum(axis=1)
Out[1788]: array([1, 1, 1, 1, 1, 1, 1, 1])
Diagonals differ in length, but can also be summed
In [1789]: np.diag(B,0)
Out[1789]: array([0, 0, 0, 0, 0, 0, 0, 0])
and to look at the other diagonals, 'flip' columns:
In [1790]: np.diag(B[:,::-1],1)
Out[1790]: array([0, 1, 0, 0, 0, 0, 0])
I can generate all diagonals with a list comprehension (not necessarily the fastest way, but easy to test):
In [1791]: [np.diag(B,i) for i in range(-7,8)]
Out[1791]:
[array([0]),
array([0, 0]),
array([0, 0, 0]),
array([1, 0, 0, 0]),
array([0, 0, 0, 0, 1]),
array([0, 0, 0, 1, 0, 0]),
array([0, 1, 0, 0, 0, 0, 0]),
array([0, 0, 0, 0, 0, 0, 0, 0]),
array([0, 0, 0, 0, 0, 0, 1]),
array([1, 0, 0, 0, 0, 0]),
array([0, 0, 0, 1, 0]),
array([0, 1, 0, 0]),
array([0, 0, 0]),
array([0, 0]),
array([0])]
and for the other direction, with sum:
In [1792]: [np.diag(B[:,::-1],i).sum() for i in range(-7,8)]
Out[1792]: [0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0]
No diagonal can have a sum >1, but some may be 0.
If the proposed solution is indeed a permutation of np.arange(8) then it is guaranteed to satisfy the row and column sum test. That just leaves the diagonal tests. The board mapping may be nice for display purposes, but it isn't required to represent the solution. And it might not be the best way to test the diagonals.
A brute force solution is to generate all permutations, and test each.
In [1796]: len(list(itertools.permutations(range(8))))
Out[1796]: 40320
There are, of course, smarter ways of generating and test solutions.
A few months ago I worked on a Sudoku puzzle question
Why is translated Sudoku solver slower than original?
the initial question was whether lists or arrays were a better representation. But I found, on an AI site, that an efficient, smart solver can be written with a dictionary.
There are quite a number of SO questions tagged Python and involving 8-queens. Fewer tagged with numpy as well.
==========
Your initial setup:
board[0:,0]=1
would pass the row sum test, fail the column sum test, and pass the diagonals tests.
Related
So I am trying to create an NxN 2D array and then change its diagonal elemets to 1. Here is my code:
arr=[1,1,1,2,2,2]
table=[[0]*len(arr)]*len(arr)
for i in range(0,len(arr)):
table[i][i]=1
print(table)
However, whenever I run this code, I get this output:
[[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1]]
I am looking to get this:
[[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]]
I have been staring at my code for hours and I cannot figure out what's wrong
The interesting thing about this is that you are really only editing one list in the for loop, but there are just five pointers to that list. (In this case, the list would be [0, 0, 0, 0, 0, 0].) You can see this by printing the id of each list in table by using id():
>>> for t in table:
print(id(t))
2236544254464
2236544254464
2236544254464
2236544254464
2236544254464
2236544254464
Your numbers are likely different than mine, but they are all the same number, nevertheless. You also can see that the edits to one list are applied to the others in table by putting a print(table) statement after each index assignment statement.
So in order to 'fix' this, I would recommend using list comprehension instead. For example:
table = [[0]*len(arr) for _ in range(len(arr))]
If you checkout the ids of each list:
>>> for t in table:
print(id(t))
2236544617664
2236544616064
2236544616320
2236544615872
2236544618368
2236544622720
Since they are different, you can now use the method for changing only the diagonals:
>>> for i in range(0,len(arr)):
table[i][i]=1
>>> table
[[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]]
Your 2D "array" contains 6 lists which are the same list. Changes to any of those lists will also be reflected in the other lists. Consider this:
>>> l = [0] * 6
>>> x = [l]
>>> l[0] = 1
>>> l
[1, 0, 0, 0, 0, 0]
>>> x
[[1, 0, 0, 0, 0, 0]]
>>> x = [l, l, l]
>>> x
[[1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0]]
>>> x[-1][-1] = 100
>>> x
[[1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100]]
This is because the list x contains the list l, so any changes to l are also seen through the reference to the same list in x.
The problem is when multiplying mutable objects because it creates multiple references to the same mutable object.
You should initialise your table like this:
table = [[0 for j in range(len(arr))] for i in range(len(arr))]
or
table = [[0] * len(arr) for i in range(len(arr))]
which, despite the use of multiplication, works because each list is different.
You can create your table and populate it simultaneously in nested loops:
arr=[1,1,1,2,2,2]
table = []
for i in range(len(arr)):
table.append([0]*len(arr))
for j in range(len(arr)):
if i == j:
table[i][j] = 1
print(table)
#[[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]
Interesting.
Try to use numpy to avoid list trap:
import numpy as np
org_row = [0]*5
l = [org_row]*5
x = np.array(l, np.int32)
for i in range(len(x)):
x[i][i]=1
print(x)
output>:
output>
[[1 0 0 0 0]
[0 1 0 0 0]
[0 0 1 0 0]
[0 0 0 1 0]
[0 0 0 0 1]]
I have two list. first list is a maze. It start 'O' and must be finished 'X'.
maze_list=[[0, 1, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 'O'],
[0, 0, 1, 0, 1, 0],
[0, 1, 1, 1, 1, 0],
['X', 1, 0, 1, 0, 0],
[0, 1, 0, 1, 1, 1]]
path_list=[[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, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]
This part is finding start position.
column_size=len(maze_list)
row_size=len(maze_list[0])
def find_SF_position(X):
liste=[]
for i in range(column_size):
for j in range(column_size):
if maze_list[i][j]==X:
liste.append(i)
liste.append(j)
return liste
s_p=find_SF_position('O') #[1,5]
f_p=find_SF_position('X') #[4,0]
This part is main algorithm. x is for horizontal position. y is for vertical position
def solve_maze(maze,road,x,y):
global column_size
global row_size
road[y][x]=1
print(y,x)
#left
if x>0 and maze[y][x-1]==1 and road[y][x-1]==0:
return solve_maze(maze,road,x-1,y)
#up
if y>0 and maze[y-1][x]==1 and road[y][x-1]==0:
return solve_maze(maze,road,x,y-1)
#right
if x>row_size and maze[y][x+1]==1 and road[y][x-1]==0:
return solve_maze(maze,road,x+1,y)
#down
if y>column_size and maze[y+1][x]==1 and road[y][x-1]==0:
return solve_maze(maze,road,x,y+1)
if maze[x][y]=='X':
return path_list
solve_maze(maze_list,path_list,s_p[1],s_p[0])
print(path_list)
I can't understand why it isn't working. It's start 'O'(maze_list[1,5]), it fill maze_list[1,4] then stop.
Finally path_list must be like this
path_list=[[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 1, 0],
[0, 1, 1, 1, 1, 0],
[1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]
You have a few problems in your code:
First your right and down conditions are reversed: x can never be greater than row_size. What you want to check is that x is not on the right border, meaning: x < row_size - 1. Same logic goes for the down case
Seems like you have a little copy-paste issue there: for example the road condition for up should be: road[y-1][x]==0. Same logic goes to all other cases.
Your condition to finding the end has a problematic logic: You check if the current cell is the 'X', but each step is only taken if there is 1 in the next cell, so how will you get to the 'X'? For example, after fixing above errors, the output I got was:
[0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 1]
[0, 0, 0, 0, 1, 0]
[0, 1, 1, 1, 1, 0]
[0, 1, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0]
As you can see, the 'X' was missed as the condition for down was taken at (4, 1) and a dead-end was reached
Lastly, what happens if you reach a dead-end? Your algorithm always takes the first step with conditions met, but what happens when you encounter an intersection? You need to check all possible paths. That's the point of recursion. The way you did it now doesn't add much over a loop.
I'd like to label non-contiguous regions in an image with different labels.
I guess this should be possible with scikit-learn.
The image is stored for example in a 2D numpy.ndarray with zeroes and ones, the ones beeing different contiguous regions.
Let's have a look at the following very simple array where we have two contiguous regions of ones but these to regions are separated from each other by zeroes.
np.array([
[1, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 1],
[0, 1, 0, 1, 0, 1],
[1, 1, 0, 1, 1, 1]
], dtype = int)
the algorithm should label the top-left contiguous region with a label like '1' and the right bottom contiguous region with a second label '2'.
np.array([
[1, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 2],
[0, 1, 0, 2, 0, 2],
[1, 1, 0, 2, 2, 2]
], dtype = int)
Any hints how to do this?
import numpy as np
from skimage.measure import label
a = np.array([[1, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 1],
[0, 1, 0, 1, 0, 1],
[1, 1, 0, 1, 1, 1]], dtype = int)
label(a)
I have a very large 1d array with most elements being zero while nonzero elements are all clustered around some few islands separated by many zeros: (here is a smaller version of that for the purpose of a MWE)
In [1]: import numpy as np
In [2]: A=np.array([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,0,0,0,0,0,0,0,1,3,6,20,14,10,5,1,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,0,0,0,0,0,0,0,2,4,5,5,18,18,16,14,10,2,1,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,0,0,0,0,0,0,0,1,2,3,3,6,16,4,1,1,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,0,0,0,0,0,0,0])
I want to find the median and its position (even approximately) in terms of the index corresponding to the median value of each island. Not surprisingly, I am getting zero which is not what I desire:
In [3]: np.median(A)
Out[3]: 0.0
In [4]: np.argsort(A)[len(A)//2]
Out[4]: 12
In the case of a single island of nonzero elements, to work around this caveat and meet my requirement that only nonzero elements are physically meaningful, I remove all zeros first and then take the median of the remaining elements:
In [5]: masks = np.where(A>0)
In [6]: A[masks]
Out[6]: array([ 1, 3, 6, 20, 14, 10, 5, 1])
This time, I get the median of the new array correctly, however the position (index) would not be correct as it is evident and also pointed out in the comments as being ill-defined mathematically.
In [7]: np.median(A[masks])
Out[7]: 5.5
In [8]: np.argsort(A[masks])[len(A[masks])//2]
Out[8]: 2
According to this approximation, I know that real median is located in the third index of the modified array but I would like to translate it back into the format of the original array where the position (index) of the median should be somewhere in the middle of the first island of the nonzero elements corresponding to a larger index (where indices of zeros are all counted correctly). Also answered in the comments are two suggestions made to come up with the position of the median given one island of nonzero elements in the middle of a sea of zeros. But what if there is more than one such island? How could possibly one calculate the index corresponding to median of each island in the context of the original histogram array where zeros are all counted?
I am wondering if there is any easy way to calculate the position of the median in such arrays of many zeros. If not, what else should I add to my lines of code to make that possible after knowing the position in the modified array? Your help is great appreciated.
Based on the comment "A is actually a discrete histogram with many bins", I think what you want is the median of the values being counted. If A is an integer array of counts, then an exact (but probably very inefficient, if you have values as high as 1e7) formula for the median is
np.median(np.repeat(np.arange(len(A)), A)) # Do not use if A contains very large values!
Alternatively, you can use
np.searchsorted(A.cumsum(), 0.5*A.sum())
which will be the integer part of the median.
For example:
In [157]: A
Out[157]:
array([ 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, 0, 0, 0, 0, 0, 0, 0, 1, 3,
6, 20, 14, 10, 5, 1, 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, 0, 0, 0,
0, 0, 0, 0])
In [158]: np.median(np.repeat(np.arange(len(A)), A))
Out[158]: 35.5
In [159]: np.searchsorted(A.cumsum(), 0.5*A.sum())
Out[159]: 35
Another example:
In [167]: B
Out[167]:
array([ 0, 0, 0, 1, 100, 21, 8, 3, 2, 1, 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, 0, 0, 0, 0])
In [168]: np.median(np.repeat(np.arange(len(B)), B))
Out[168]: 4.0
In [169]: np.searchsorted(B.cumsum(), 0.5*B.sum())
Out[169]: 4
How do I find if a sequence of numbers exists in a two-dimensional list? i.e.
matrix: [[1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [0,
0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0]]
if [1,1,1] in matrix:
print("It's in there")
else: print("It's not there")
I guess I could turn every int into a string but is there a slicker way?
Using an iterator over each cell of the matrix, I've managed to get a basic idea of what you wanted to achieve in Python script.
matrix = [[1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0]]
matchCount = 0
lastNumber = None
for cell in matrix:
for number in cell:
if number == 1 and lastNumber == 1 or lastNumber == None:
matchCount += 1
if matchCount >= 3:
print("MATCH in cell " + str(cell))
lastNumber = number
matchCount = 0
lastNumber = None
What happens is, it steps into the cell. It it's the first iteration then allow entry into our iterator. We don't know if it's a match list yet, so push it back in our little list.
Stepping over and over, if we get enough matches in a row, then wonderful! Print we found a match in our matrix's cell!