This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 2 years ago.
I was trying to make chess playing algorithm that "bruteforces" possible options and choosing the best.
To do this, I wrote class, which represents board situation on board(showed the parts that used in bad code).
class Chess:
def __init__(self):
#Here is the board 2D array - enemy is downside.
self.board = [[ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK], [PAWN for i in range(8)], [EMPTY for i in range(8)], [EMPTY for i in range(8)], [EMPTY for i in range(8)], [EMPTY for i in range(8)], [ENEMYPAWN for i in range(8)], [ENEMYROOK, ENEMYKNIGHT, ENEMYBISHOP, ENEMYKING, ENEMYQUEEN, ENEMYBISHOP, ENEMYKNIGHT, ENEMYROOK]]
def WriteBoard(self):
WriteBoard(self.board)
def Moove(self, x1, y1, x2, y2):
if x1 >= 8 or x1 < 0 or x2 >= 8 or x2 < 0 or y1 >= 8 or y1 < 0 or y2 >= 8 or y2 < 0:
raise IndexError("Parameter is not correct.")
return
#WARNING: Not checking if moove correct.
self.board[y2][x2] = self.board[y1][x1]
self.board[y1][x1] = EMPTY
Where:
EMPTY = 0
PAWN = 2
ROOK = 17
KNIGHT = 10
BISHOP = 14
QUEEN = 45
KING = 60
ENEMYPAWN = -2
ENEMYROOK = -17
ENEMYKNIGHT = -10
ENEMYBISHOP = -14
ENEMYQUEEN = -45
ENEMYKING = -60
...Next part is function that returns possible moves getting Chess variable and x, y as parameters:
def PossibleMooves(chessBoard, x, y):
possibleMooves = []
target = chessBoard.board[y][x]
if target == EMPTY:
return possibleMooves
helpVar = chessBoard
if target == PAWN:
try:
if helpVar.board[y + 1][x] == EMPTY:
helpVar.Moove(x, y, x, y + 1)
possibleMooves += [res]
index += 1
helpVar = chessBoard
except IndexError as e:
... #print(e)
elif target == ROOK:
...
... #And so on...
return possibleMooves
Please note that try...except statement helps to establish correctness of move(index like [y + 1][x] can not exist)
But the problem is:
Variable chessBoard changing together with helpVar, and variable that were given to function.
You can check it with this code:
chess = Chess()
print(chess.board[1][1])
results = PossibleMooves(chess, 1, 1)
print(chess.board[1][1])
Output should be:
2
2
But its:
2
0
helpVar = chessBoard means that every change you make to helpVar will be reflected in chessBoard. They point to the same object. If you want to avoid it - clone chessBoard and work with a copy.
See here about copy in python. (Look at deepcopy)
Related
I am trying to implement the BFS algorithm but python is giving me an error that the ellipsis object is not sub scriptable.
I am unsure what these means because as far as I am aware this type should not be Ellipsis?
TypeError: 'ellipsis' object is not subscriptable
Causing error:
visited[starting_row][starting_col] = True
Function:
def findRoute(self, x1, y1, x2, y2):
grid = self.grid
print(grid)
starting_row, starting_col = x1, y1
# Creating 2 seperate queues for X and Y.
x_queue, y_queue = deque(), deque()
number_of_moves = 0
number_of_nodes_in_current_layer = 1
number_of_nodes_in_next_layer = 0
end_reached = False
# Up/Down/Right/Left directions
direction_row = [-1, 1, 0, 0]
direction_col = [0, 0, 1, -1]
visited = ...
x_queue.append(starting_row)
y_queue.append(starting_col)
visited[starting_row][starting_col] = True
while len(x_queue) > 0:
x = x_queue.dequeue()
y = y_queue.dequeue()
if x == x2 & y == y2:
end_reached = True
break
# for(i = 0; i < 4; i++):
# Loop through direction.
for i in range(0, 4):
new_row = x + direction_row[i]
new_col = x + direction_col[i]
#Validate position
# Skip locations not in grid.
if new_row < 0 or new_col < 0 or new_row >= self.height or new_col >= self.width:
continue
# Skip locations already visited / cells blocked by walls.
if visited[new_row][new_col] or grid[new_row][new_col]:
continue
x_queue.enqueue(new_row)
y_queue.enqueue(new_col)
visited[new_row][new_col] = True
number_of_nodes_in_next_layer += 1
if number_of_nodes_in_current_layer == 0:
number_of_nodes_in_current_layer = number_of_nodes_in_next_layer
number_of_nodes_in_next_layer = 0
number_of_moves += 1
if end_reached:
return number_of_moves
return -1
return grid[1][2]
Any help would be appreciated, thanks.
Your code has this line:
visited = ...
This ... is not commonly used, but it is a native object. The documentation on Ellipsis has:
The same as the ellipsis literal “...”. Special value used mostly in conjunction with extended slicing syntax for user-defined container data types. Ellipsis is the sole instance of the types.EllipsisType type.
As the error message states, this object is not subscriptable, yet that is exactly what you tried to do with:
visited[starting_row][starting_col] = True
I suppose you didn't really intend to use visited = ..., and that you were planning to complete this statement later and then forgot about it. It should be:
visited = [[False] * len(row) for row in grid]
I am a beginner in programming so I hope my question will be clear:
I have a .csv file that gives me in 2 columns the coordinates in X and Y of a mouse during a 15-min test in an elevated-plus maze (this file was generated by Bonsai for mouse video tracking).
I would like to design a code that creates a new column in the same excel file, named "behavior". This new column will be attributed values when the mouse is entering a specific region of the elevated-plus maze. Whether it is in the center (attribute 0), in the open arm (attribute 1) and in closed arms (attribute 2) and depending on the time.
time (s)
coord X
coord Y
behaviour
0
...
...
1
1
...
...
1
2
...
...
0
3
...
...
...
I have some elements of code that could help.
I have an error saying that: ValueError: Length of values (1) does not match length of index (12832).
def calculate_distance(bonsai_file, frame_rate, coords_list):
x = bonsai_file['mouseX']
y = bonsai_file['mouseY']
total_dist = []
OA_left_dist = []
OA_right_dist = []
CA_left_dist = []
CA_right_dist = []
CT_dist = []
behavior = []
for i in bonsai_file.index.values.tolist()[:-2]:
a = i
b = a+1
dist = (((x[a] - x[b])*0.0943)**2+((y[a] - y[b])*0.0943)**2)**0.5
total_dist.append(dist)
if coords_list[0].contains_point((x[a], y[a])):
OA_left_dist.append(dist)
behavior.append(0)
elif coords_list[1].contains_point((x[a], y[a])):
OA_right_dist.append(dist)
behavior.append(1)
elif coords_list[2].contains_point((x[a], y[a])):
CA_left_dist.append(dist)
behavior.append(2)
elif coords_list[3].contains_point((x[a], y[a])):
CA_right_dist.append(dist)
behavior.append(3)
elif coords_list[4].contains_point((x[a], y[a])):
CT_dist.append(dist)
behavior.append(4)
Many thanks guys for your help!
Best,
Yoni
I need to print out a list of rockets with their own positions (x and y) using list comprehension (need to use list comprehension for homework).
I have an issue currently when I print the list, it first prints (0,0) for 9 times before it prints the assigned x and y values for each rocket. I am very new to python, so please bear with me.
class Rocket:
## Fill in the rest of the class definition
def __init__ (self, x=0,y=0):
self.x = x
self.y = y
def moveup(self):
self.y += 1
rocket = Rocket(0,0)
print("Starting position is " , rocket.x, rocket.y)
direction = input("What direction do you want to go?")
if direction == "up":
print("you went up")
rocket.moveup()
print("Position: ", rocket.x, rocket.y)
else:
print("Nothing happened")
#-------------------------------------------------------------------------------------
rockets = [Rocket() for x in range(0,10)]
rockets.append(Rocket(0,0))
rockets.append(Rocket(1,1))
rockets.append(Rocket(2,2))
rockets.append(Rocket(3,3))
rockets.append(Rocket(4,4))
rockets.append(Rocket(5,5))
rockets.append(Rocket(6,6))
rockets.append(Rocket(7,7))
rockets.append(Rocket(8,8))
rockets.append(Rocket(9,9))
for rocket in rockets:
print(rocket.x,rocket.y)
my output is :
Starting position is 0 0
What direction do you want to go?up
you went up
Position: 0 1
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
I think I partially know what is going on, when I first make the list it makes, each rocket 0,0 and when I append, it creates a new rocket instead of editing them. I guess my main question is how do I edit an index of the array to correct this?
You don't need the list comprehension and the appends. Just initialize the list with the rockets you want in the list comprehension
rockets = [Rocket(i, i) for i in range(10)]
please observe that when calling
rockets = [Rocket() for x in range(0,10)]
you create 10 instances of class Rocket and put them on the list rockets. Call is supplied with no parameters an thus default values are used as defined in constructor (Rocket: ... def __init__ (self, x=0,y=0)).
This is equivalent to calling rockets.append(Rocket(0, 0)) 10 times. Then you create the remaining 10 by hand
rockets.append(Rocket(0,0))
...
rockets.append(Rocket(9,9))
so the output is justified
and when I append, it creates a new rocket instead of editing them
That`s exactly what it does .You may want to use array subscription to get the object from an array to use its methods or edit its properties
e.g.
for r in rockets:
r.moveup()
for r in rockets:
r.x = r.y*r.y
I am trying to make a Python program that churns out a solved sudoku puzzle. It randomly generates coordinates for a tile, and if that tile already has a number in it, it tries again. It then generates a number between 1 and 9 to put there, and if that number isn't already in that row, column, or section, it'll assign the value and add those coordinates to the list of occupied tiles. Once all the tiles are filled, it's supposed to exit the loop and return the completed grid.
The trouble is, it's always stopping for no reason after about 70 loops, causing the program to freeze.
Here is the code for the function I'm talking about:
def populate(grid):
usedCoords = []
populated = False
while not populated:
x = random.randrange(len(grid))
y = random.randrange(len(grid))
while [x,y] in usedCoords:
x = random.randrange(len(grid))
y = random.randrange(len(grid))
value = random.randrange(1, len(grid) + 1)
if not rowCheck(grid, x, y, value) and not columnCheck(grid, x, y, value) and not squareCheck(grid, x, y, value):
grid[x][y] = value
usedCoords.append([x,y])
print(len(usedCoords))
if len(usedCoords) == len(grid) ** 2:
populated = True
return grid
And here is the code for the functions it references:
def rowCheck(grid, x, y, value):
for i in range(len(grid)):
if not i == x:
if grid[i][y] == value:
return True
return False
def columnCheck(grid, x, y, value):
for i in range(len(grid)):
if not i==y:
if grid[x][i] == value:
return True
return False
def squareCheck(grid, x, y, value):
grid2 = [0] * (sectionSide) #new grid for the specific section
for i in range(len(grid2)):
grid2[i] = [0] * sectionSide
for i in range(x - (sectionSide - 1), x + sectionSide): #scanning only nearby coordinates
for j in range(y - (sectionSide - 1), y + sectionSide):
try:
if i // sectionSide == x // sectionSide and j // sectionSide == y // sectionSide:
grid2[i][j] = grid[x][y]
except IndexError:
pass
for i in range(len(grid2)):
for j in range(len(grid2[i])):
if grid2[i][j] == value and not (i == x and j == y):
return True
return False
There may be other issues, but a big problem with your code is that it has no way to backtrack if it finds it's created a board state that cannot be solved. Consider what would happen if your code put the following values on the first two rows of the board:
1 2 3 4 5 6 7 8 9
4 5 6 7 8 1 2 3
The numbers that have been placed so far are all legal, but there is no number that you can put in the last space of the second row. I'd guess that your code is eventually getting stuck when it creates a bunch of board positions like this, which cannot take any value. If there are no legal moves left it can make, it will keep on looping forever.
You need a more sophisticated algorithm to avoid this issue.
Below, I'm trying to code a Crank-Nicholson numerical solution to the Navier-Stokes equation for momentum (simplified with placeholders for time being), but am having issues with solving for umat[timecount,:], and keep getting the error "ValueError: setting an array element with a sequence". I'm extremely new to Python, does anyone know what I could do differently to avoid this problem?
Thanks!!
def step(timesteps,dn,dt,Numvpts,Cd,g,alpha,Sl,gamma,theta_L,umat):
for timecount in range(0, timesteps+1):
if timecount == 0:
umat[timecount,:] = 0
else:
Km = 1 #placeholder for eddy viscosity
thetaM = 278.15 #placeholder for theta_m for time being
A = Km*dt/(2*(dn**2))
B = (-g*dt/theta_L)*thetaM*np.sin(alpha)
C = -dt*(1/(2*Sl) + Cd)
W_arr = np.zeros(Numvpts+1)
D = np.zeros(Numvpts+1)
for x in (0,Numvpts): #creating the vertical veocity term
if x==0:
W_arr[x] = 0
D[x] = 0
else:
W_arr[x] = W_arr[x-1] - (dn/Sl)*umat[timecount-1,x-1]
D = W_arr/(4*dn)
coef_mat_u = Neumann_mat(Numvpts,D-A,(1+2*A),-(A+D))
b_arr_u = np.zeros(Numvpts+1) #the array of known quantities
umat_forward = umat[timecount-1,2:Numvpts]
umat_center = umat[timecount-1,1:Numvpts-1]
umat_backward = umat[timecount-1,0:Numvpts-2]
b_arr_u = np.zeros(Numvpts+1)
for j in (0,Numvpts):
if j==0:
b_arr_u[j] = 0
elif j==Numvpts:
b_arr_u[j] = 0
else:
b_arr_u[j] = (A+D[j])*umat_backward[j]*(1-2*A)*umat_center[j] + (A-D[j])*umat_forward[j] - C*(umat_center[j]*umat_center[j]) - B
umat[timecount,:] = np.linalg.solve(coef_mat_u,b_arr_u)
return(umat)
Please note that,
for i in (0, 20):
print(i),
will give result 0 20 not 0 1 2 3 4 ... 20
So you have to use the range() function
for i in range(0, 20 + 1):
print(i),
to get 0 1 2 3 4 ... 20
I have not gone through your code rigorously, but I think the problem is in your two inner for loops:
for x in (0,Numvpts): #creating the vertical veocity term
which is setting values only at zero th and (Numvpts-1) th index. I think you must use
for x in range(0,Numvpts):
Similar is the case in (range() must be used):
for j in (0,Numvpts):
Also, here j never becomes == Numvpts, but you are checking the condition? I guess it must be == Numvpts-1
And also the else condition is called for every index other than 0? So in your code the right hand side vector has same numbers from index 1 onwards!
I think the fundamental problem is that you are not using range(). Also it is a good idea to solve the NS eqns for a small grid and manually check the A and b matrix to see whether they are being set correctly.