I set 3 arrays to the same thing, changing a single entry in one of them also changes the other two arrays. How can I make the three arrays separate? - python

I am making a puzzle game in a command terminal. I have three arrays for the level, originlevel, which is the unaltered level that the game will return to if you restart the level. Emptylevel is the level without the player. Level is just the level. I need all 3, because I will be changing the space around the player.
def Player(matrix,width):
originlevel = matrix
emptylevel = matrix
emptylevel[PlayerPositionFind(matrix)]="#"
level = matrix
The expected result is that it would set one entry to "#" in the emptylevel array, but it actually sets all 3 arrays to the same thing! My theory is that the arrays are somehow linked because they are originally said to the same thing, but this ruins my code entirely! How can I make the arrays separate, so changing one would not change the other?
I should not that matrix is an array, it is not an actual matrix.
I tried a function which would take the array matrix, and then just return it, thinking that this layer would unlink the arrays. It did not. (I called the function IHATEPYTHON).
I've also read that setting them to the same array is supposed to do this, but I didn't actually find an answer how to make them NOT do that. Do I make a function which is just something like
for i in range(0,len(array)):
newarray.append(array[i])
return newarray
I feel like that would solve the issue but that's so stupid, can I not do it in another way?

This issue is caused by the way variables work in Python. If you want more background on why this is happening, you should look up 'pass by value versus pass by reference'.
In order for each of these arrays to be independent, you need to create a copy each time you assign it. The easiest way to do that is to use an array slice. This means you will get a new copy of the array each time.
def Player(matrix,width):
originlevel = matrix[:]
emptylevel = matrix[:]
emptylevel[PlayerPositionFind(matrix)]="#"
level = matrix[:]

Related

Changing iteration order during nested iteration

Given two associative arrays, one array contains pointers to 3d point coordinates, the other array contains a hash/dictionary of surfaces. For every point in the first array, there will be only one matching surface found in the second array (where the point lay on the surface.)
We need to iterate through the points to find the matching surface (to then get the unit vector [ijk points] normal to the surface at that point.)
Brute force could iterate through every item in each list, breaking the iteration once each surface data point is found. Though I’ve already found in writing earlier versions of this program, astronomically numerous calculations will be performed, and I need to be efficient.
There will always be more points than surfaces, and the surfaces will be adjacent, meaning as I iteration through the points in a certain order, it’s more likely than not that the next point will be on the same surface as the last.
I’m wondering if I can run a loop which, for example,
for point n:
for surface i:
does the point lay on the surface? if so, break
…and if the last ‘i’ value was 5, begin the next iteration at i=5 (and if the point wasn’t on surface 5, continue iterating through each surface.) It would be better if I could have it iterate in a order like: not 5? try 6; not 6? try 4——
Expanding on that idea, imagine that ‘i’ were organized in an 2d array. I.e:
[1,2,3]
[4,5,6]
[7,8,9]
And for n points:
For i surfaces: (continuing where I left off,) not 4? try 2; not 2? try 8.
I’m wondering if a ‘for’ loop won’t give me the versatility I need. (By the way, the program will likely be written in either Python or .NET) I’m thinking that I can make a while loop and write some sort of logic that will iterate the way I want. Am I trying to reinvent the wheel? Am I on the right track?
This is only a partial answer, because your question doesn't have a lot of specifics on what your actual code is. But, that said, one thing to note is that the variable from a for loop retains its value even after the loop has ended. So this will print 5:
for i in range(1000):
if i == 5:
break
print(i)
So you can easily check after the inner loop what value it ended on. And then you can do whatever you want with that value. For instance, you could look at it on the next run through the outer loop and fix things up so that the inner loop starts at some other place.
A for loop will almost surely give you the versatility you need, because you can use a for loop to iterate over many kinds of things, including some custom iterator that you create. So for instance you could do something like this:
def best_order_to_loop(all_surfaces, previous_stopping_point):
# some logic here
yield next_value
previous_stopping_point = None
for point in points:
surfaces_in_order = best_order_to_loop(all_surfaces, previous_stopping_point)
for surface in surfaces_in_order:
# do whatever
previous_stopping_point = surface
Again, this is just a sketch and I'm not sure I'm 100% understanding your setup. But it seems like you're saying "if the previous loop stopped at X, then based on that I want the next loop to loop in such-and-such order". If that is the case you can write a function like best_order_to_loop that determines how the next inner loop will go, based on the previous stopping point.

Problems storing a matrix in Python

So I have written a program in Python that takes a matrix from user's input and modifies it. From this modification I am able to pull out the inverse of the original matrix. To prove if the inverse is correct, I would like to do something like this:
matrix=input_from_the_user
matrix_untouched=input_from_the_user
... #act on **matrix** and turn it into its inverse, so that now **matrix** is no more
#the
original: it is equal to its inverse
test=product_of_matrices(matrix,matrix_untouched)
print(test)
I would expect the output to be the identity matrix. It is not: it looks like the variable matrix_untouched turns into matrix even though I never touch it after defining it. I have tried to print matrix_untouched at different steps of the program. From the first modification I make on matrix, also matrix_untouched is modified in the same way. How can I keep its value unaltered?

Python: Numpy Array : cant access/reference to a numpy array from another class

I have a data acquisation class that takes data and saves it into a numpy array.
voltage = float((data.decode())[0:-2]) * 1000
print(voltage)
self.xxList = np.append(self.xxList, [voltage])
Those lines are in a while loop which is managed by a thread. I return the "self.xxlist" with a simple getter:
def get_xlist(self):
return self.xxList
Then i try to have a reference to the same list in another class, which of course has the instance of my data acquistion class.
self.mySerial = SerialFirat(self)
self.xaList = self.mySerial.get_xlist()
This doesn't work with numpy - The self.xaList always stays the same (empty) and doesnt update on any acquired data - but works with a regular python list which uses simple .append(data).
I guess this might be due the way an element is appended to a numpy array, which creates a new list and returns the reference to it, each time an element is appended. The list that i referenced is the first list and the newly created lists have some different adress so the referenced list always stays the same.
I couldnt find a work around to make it function like a normal python list. I would appriciate any help and a clarification if my conclusion on why it doesnt work is correct.
PS: I use the data to plot a live graph but the list - xaList - i feed to the plotting function is always empty and nothings is being plotted. If i directly feed the xxList (the List i write the serialData in) it works but that really leads to a crappy object oriented design

How to define a callable function whenever the value of any element in the list gets changed?

I know this question is kind of simple and silly but I got stymied of searching the internet. Consider we have a 2-dimensional list in Python which represents a game board of hex and its elements would be changed by some function (like playing stone at some cell in the game board).
What I am looking for is a tool in Python that could define a function to be called whenever the value of any element in the array gets changed.
I already found the function trace in tkinter which calls a function when StringVar,DoubleVar and so on get changed.
I was wondering if a similar one could be found for simple lists or even numpy lists.
Your requirements:
2-dimensinal list in python which represents a game board of hex
and its elements would be changed by some function (like playing stone at some cell in the game board).
a function to be called whenever the value of any element in the array gets changed.
The straight forward way to implement this is to define a class representing the board and actions. It will contain the 2d list (could be numpy array, but that may not be necessary).
It would also define methods that change the list, and perform the recording/callback.
class Board():
def __init__(...)
self.list2d=[] # 2d nested list
def record_play(...):
<action when a cell is changed>
def play(...):
<change self.list2d>
self.record_play(...)
As long a the Board object controls all the changes, you don't need a more generic tracking tool, or even a subclass of list or array (though those are possible). Just make sure you call the tracking function each time you call the change function.
If you were doing this across different classes and kinds of objects it could be worth while constructing something more abstract. But for a one-off case, just do the obvious.

Confusion about numpy's apply along axis and list comprehensions

Alright, so I apologize ahead of time if I'm just asking something silly, but I really thought I understood how apply_along_axis worked. I just ran into something that might be an edge case that I just didn't consider, but it's baffling me. In short, this is the code that is confusing me:
class Leaf(object):
def __init__(self, location):
self.location = location
def __len__(self):
return self.location.shape[0]
def bulk_leaves(child_array, axis=0):
test = np.array([Leaf(location) for location in child_array]) # This is what I want
check = np.apply_along_axis(Leaf, 0, child_array) # This returns an array of individual leafs with the same shape as child_array
return test, check
if __name__ == "__main__":
test, check = bulk_leaves(np.random.ran(100, 50))
test == check # False
I always feel silly using a list comprehension with numpy and then casting back to an array, but I'm just nor sure of another way to do this. Am I just missing something obvious?
The apply_along_axis is pure Python that you can look at and decode yourself. In this case it essentially does:
check = np.empty(child_array.shape,dtype=object)
for i in range(child_array.shape[1]):
check[:,i] = Leaf(child_array[:,i])
In other words, it preallocates the container array, and then fills in the values with an iteration. That certainly is better than appending to the array, but rarely better than appending values to a list (which is what the comprehension is doing).
You could take the above template and adjust it to produce the array that you really want.
for i in range(check.shape[0]):
check[i]=Leaf(child_array[i,:])
In quick tests this iteration times the same as the comprehension. The apply_along_axis, besides being wrong, is slower.
The problem seems to be that apply_along_axis uses isscalar to determine whether the returned object is a scalar, but isscalar returns False for user-defined classes. The documentation for apply_along_axis says:
The shape of outarr is identical to the shape of arr, except along the axis dimension, where the length of outarr is equal to the size of the return value of func1d.
Since your class's __len__ returns the length of the array it wraps, numpy "expands" the resulting array into the original shape. If you don't define a __len__, you'll get an error, because numpy doesn't think user-defined types are scalars, so it will still try to call len on it.
As far as I can see, there is no way to make this work with a user-defined class. You can return 1 from __len__, but then you'll still get an Nx1 2D result, not a 1D array of length N. I don't see any way to make Numpy see a user-defined instance as a scalar.
There is a numpy bug about the apply_along_axis behavior, but surprisingly I can't find any discussion of the underlying issue that isscalar returns False for non-numpy objects. It may be that numpy just decided to punt and not guess whether user-defined types are vector or scalar. Still, it might be worth asking about this on the numpy list, as it seems odd to me that things like isscalar(object()) return False.
However, if as you say you don't care about performance anyway, it doesn't really matter. Just use your first way with the list comprehension, which already does what you want.

Categories

Resources