Python, moving object in xy axis - python

So, i'm doing little game with python and pyglet, but i'm stuck with moving the object in xy axis.
I have object A which is dictionary, it has x-coordinate, y-coordinate and speedvectors for x and y.
When i launch this object A it flies like it should, the problem is i'm moving it like this.
objectA["y"] = objectA.get("y") + objectA.get("ySpeed")
objectA["x"] = objectA.get("x") + objectA.get("xSpeed")
So the coordinates are moving rapidly like first objextA x is 130 then its 160 etc. When i'm trying to do some collision things, object wont stop because it doesn't register hit, it skips over the block (or atleast i think it does so). Any tips how i should actually do this?

Your code is correct. I tested it in an empty script and it worked fine
Try this in a empty script and look at the results. It should first print 0 and then print 10:
objectA = {"x": 0, "y": 0, "xSpeed": 1, "ySpeed": 1}
print(objectA["x"])
for _ in range(10):
objectA["x"] = objectA.get("x") + objectA.get("xSpeed")
print(objectA["x"])
It might be something else in your code that causes the problem.
Btw, this is a shorter way of writing your posted code (it does exactly the same):
objectA["x"] += objectA["xSpeed"]
objectA["y"] += objectA["ySpeed"]

Related

Visualize Pathfinding Algorithm

I was doing a pathfinding visualizer in pygame and I pretty much finished but there's still one thing that I do not like about the algorithm part of it and it's the fact that when you press the visualize algorithm button it shows you the shortest path in yellow and all of the nodes the algorithm has visited ever in light blue but it shows you instantaneously and I want it to color the nodes accordingly step by step to actually reach the effect of visualizing (like in here https://clementmihailescu.github.io/Pathfinding-Visualizer/#), I tried to write some code in the function that seemed like it would have worked as intended but it didn't, here is the code:
# Breadth First Search Algorithm
def bfs(graph, start, goal):
explored = []
# Queue for traversing the
# graph in the BFS
queue = [[start]]
# If the desired node is
# reached
if start == goal:
return
# Loop to traverse the graph
# with the help of the queue
while queue:
path = queue.pop(0)
node = path[-1]
y, x = node
# Codition to check if the
# current node is not visited
if node not in explored and nodes_rows[x][y].color is not BLACK:
nodes_rows[x][y].color = LIGHT_BLUE
neighbours = graph[node]
# Loop to iterate over the
# neighbours of the node
for neighbour in neighbours:
new_path = list(path)
new_path.append(neighbour)
queue.append(new_path)
# Condition to check if the
# neighbour node is the goal
if neighbour == goal:
new_path.remove(start)
new_path.remove(goal)
return new_path
explored.append(node)
return None
The nodes_rows[x][y].color == color_name is the code that is responsible for coloring nodes on the grid which is represented by a dictionary(I provided it so it's gonna be easier for you to understand how coloring works in general in my program). The problem with that implementation is when I do add the coloring part at if statement to color all the neighbors it does it instantly on the grid without showing a kind of an animation that shows the coloring process node by node, my question is can I do it so it colors them each iteration rather than all at once by adding something to this code and not writing a new one and if I do need to write a new one that what is the instructions how can I do so?
Here is what I mean by coloring all at once like it does for now:
https://cdn.discordapp.com/attachments/772816508015083552/832303260911272046/PowerPoint_-_1_2021-04-15_20-13-35_Trim.mp4
Edit:
try:
while True:
if not ticks or pygame.time.get_ticks() - ticks >= 500:
ticks = pygame.time.get_ticks()
nodes = next(algorithm)
if nodes_rows[nodes[-1][1]][nodes[-1][0]].color != BLUE:
nodes_rows[nodes[-1][1]][nodes[-1][0]].color = LIGHT_BLUE
pygame.display.update()
except StopIteration:
pass
Tried doing it with yield and if I print it it does yield a list every half a second with a new explored node at the end like intended but it updates it all at once after waiting total amount of ticks I tried playing with the indent of display.update() but didn't work either I don't even know what to do at this point
Thanks to everyone contributing to help <3
Per the comments above, here is a simple example of a generator to help you grasp the idea.
def counter(x):
for i in range(x):
yield i
c = counter(3)
In: next(c)
Out: 0
In: next(c)
Out: 1
In: next(c)
Out: 2
What's happening is that every time you call next, the function will continue to run until it reaches the next yield, at which point it will return the yielded value.
It will also remember where it left off, so the next time you call next, the function will continue where it left off.
In your application, this could be used to yield the list of explored locations, then draw those locations in whatever color you like, call next(bfs) to step forward and yield the next list of explored locations, and so on until of course you find the solution and run out of items to yield.
One more example, perhaps a little more closely related to what you are trying to do:
def make_path():
path = []
i = 0
while True:
path.append(i)
i += 1
yield path
c = make_path()
for _ in range(6):
print(next(c))
Out: [0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
i think the problem is that you do not update the canvas in your while queue loop.
the program will execute your bfs algorithm and then it will update the canvas.
i honestly don't use pygame very regularly, but i think to force the canvas to repaint you need to stick a pygame.display.update() inside your while loop.
Pygame is not my forte but, I think there are some missing things in your project:
1.- You don't really control when colors are shown on your screen. This can be achieved with this:
pygame.display.update()
Documentation: https://devdocs.io/pygame/ref/display#pygame.display.update
Usually when working with graphics, you add a color, and when then next screen painting update comes you see it, what you must do is to force the painting so you can animate safely.
2.- Coloring animations are not being done by default.
I couldn't help noticing this in your initial question: "it does it instantly on the grid without showing a kind of an animation that shows the coloring process node by node". If you want an animation like the example linked above (Pathfinding visualizer), I'm afraid you have to do it manually. Try creating a test with a white square and start painting growing circles inside interpolating colors, until you reach the walls and paint the full square. This should be similar to what are you trying to accomplish.
3.- Perhaps you should add some stops when you are animating your canvas.
The refresh rate of your hardware is way too faster than your human eye.
To properly see a coloring animation you should try adding execution stops, when interpolating colors.
nodes_rows[x][y].color = Color(r, g, b) # Start with a color and interpolate incrementing or decrementing r, g and b until your reach a final color.
pygame.display.update() # Update your screen
pygame.time.wait(1000) # In milliseconds, add some time wait so screen can be painted, if time is long enough perhaps screen updates meanwhile and you do not need to update the screen.
4.- (Optional) Parallel painting: Using threads.
If this does not work right for you, add threads.
As I stated before, pygame is not my forte, but consider adding threads to animate each square color. I've found a post here explaining this.
using threading in pygame
I hope this helps you and have a happy coding experience! :D

Reading from a CSV file and using the data to talk to pygame

Having a lot of problems with everything today it seems, first time asking a question and I can't even get my code on here correctly!
Essentially what I'm hoping to do, is to import data from a csv file and use it to select and display images using pygame e.g.
screen.blit(row[0],(0,0))
Where row[0] is Rat1 in the csv file, which has been defined in my code as:
Rat1 = pygame.image.load('Rat1.jpg').convert()
However this throws up "argument 1 must be pygame.Surface, not str", which is fair enough, but I'm really struggling to find a way around this and have found some rather bizarre goings on, bizarre to me at least.
I'm new to this, so the best way I can think to get around this, is to change the row[0] in the csv file to 1, and then to import that to my program and create an integer variable from it, e.g.
x = row[0]
int(x)
if x == 1:
x = Rat1
and then plug x in to pygame, e.g.
screen.blit(x,(0,0))
This works if I just have x = Rat1 as a global variable, however doing it as above doesn't change x to = 1, it stays as row[x] so it just doesn't like it.
It boils down to this happening when I tried to test it a bit...
import csv
out = open("CSVTest.csv","rb")
data = csv.reader(out)
data = [row for row in data]
out.close()
print row[0] #this causes it to print a 1, so I know
#it's working and reading as it should
x = row[0] #make a variable
int(x) #doesn't throw up an error, so I assume it
#has changed the csv string to an integer
print x #prints a 1 again
if x == 1:
print "hello?" #doesn't print, so clearly doesn't
#recognise x as an integer
if x == 49: #I'm getting desperate now, ASCII 1?!
print "hello?!" #No joy
So what on earth is it, it doesn't seem to be your standard string, as won't convert obviously in to an integer.
I've tried pygame.image.fromstring(), where the answer probably lies, but I can't get it to work.
Can anyone point out what is wrong with it all and how I can easily call data from a csv file and at least get it recognised as an integer or even better, inserted in to a bit of pygame code and displayed?
I've read things from csv files and displayed images with pygame without a hitch, but getting the two to mate seems tough, beyond me certainly.
Any help is much appreciated!
int() is the Python standard built-in function to convert a string into an integer value. You call it with a string containing a number as the argument, and it returns the number converted to an actual integer:
print int("1") + 1
The above prints 2.
If you know the structure of your list (that it simply contains lists, only one level), you could do this:
T2 = [map(int, x) for x in T1]
Or...
Try this.
x = "1"
x is a string because it has quotes around it, but it has a number in it.
x = int(x)
Since x has the number 1 in it, I can turn it in to a integer.
To see if a string is a number, you can do this.
def is_number(var):
try:
if var == int(var):
return True
except Exception:
return False
x = "1"
y = "test"
x_test = is_number(x)
print(x_test)
It should print to IDLE True because x is a number.
y_test = is_number(y)
print(y_test)
It should print to IDLE False because y in not a number.

Python for loop executing once for size 2 array

There seems to be something strange going on in this loop. I tried to debug it, and I have no explanation for what is going on.
This code is from another Stack Overflow post, and I made some edits to it.
modelImages = ['/home/lie/Desktop/dylan.jpg','/home/lie/Desktop/melissa.jpg']
for modelImage in modelImages:
**print modelImage**
template=cv2.imread(modelImage)
templateg = cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
keys = surf.detect(templateg)
keys,desc = surfDescriptorExtractor.compute(templateg, keys)
count = 0
for h,des in enumerate(desc):
des = np.array(des,np.float32).reshape((1,64))
retval, results, neigh_resp, dists = knn.find_nearest(des,1)
res,dist = int(results[0][0]),dists[0][0]
if dist<0.1: # draw matched keypoints in red color
count=count + 1
print "space"**
The important parts have asterisks. This is a portion of the code that was suppose to identify similarities among images of faces. What the code does is not important. The strange part is that this loop is executing 1 time for an array of size two.
The output is:
/home/lie/Desktop/dylan.jpg
/home/lie/Desktop/melissa.jpg
space
Notice that both strings in modelImages are printed before space. By the way this is part of a function that is called from a loop. This seems to be more of a python issue than an opencv issue. It almost seems like there is a hidden continue statment
Thanks

Python: if condition changing value

I have the following code that generates a x_d and x_y. I then want to add or subtract these values from the last calculated x and y (returned from config.get_last_point()), and store it in the latest point.
def generate_asv_configuration(
asv_count, generate_left_concavity, corner_angle=None):
# Create a configuration
config = Configuration(generate_left_concavity)
for i in range(2, asv_count):
# Calculate the angle to be used in the calculations
turning_angle = turning_angle - delta_angle
# Calculate the delta-x, and -y.
x_d = MAX_BOOM_LENGTH * math.cos(turning_angle)
y_d = MAX_BOOM_LENGTH * math.sin(turning_angle)
# print generate_left_concavity
if (i % 2) == 0:
print '1: Left, i: {0}'.format(i)
x = config.get_last_point()[0] - x_d
y = config.get_last_point()[1] - y_d
else:
print '2: Right, i: {0}'.format(i)
x = config.get_last_point()[0] + x_d
y = config.get_last_point()[1] + y_d
config.add_point((x, y))
The problem I'm having is that code generates an image similar to . That looks good, the different points have varying angles (you can see that some are almost closed, others are very open). However, when I change the first if condition to (i % 2) == 0 and generate_left_concavity, and I call it with generate_left_concavity to True, I guess something similar to . The problem is, there is really open polygons.
Unfortunately, I've tried a few different if conditions, and whenever I have generate_left_concavity in the condition, it always generates differently. I have even tried nested if conditions.
I believe I've even tried having the above two conditions, then in a later condition, I check if generate_left_concavity, if so, I add 2 * x_d to compensate. It still generates the images similar to .
I don't see how much of my code could directly affect the generation of x and y calculations based on an if condition, but I could be wrong. I can guarantee, however, that they are always entering the same condition branch, but generate differently.
Not really an answer but: If I think something weird is going on in a conditional, I try to make the conditional suites as simple as possible to eliminate or separate possible problem code. Yours could be refactored:
if (i % 2) == 0:
print '1: Left, i: {0}'.format(i)
x_d, y_d = -x_d, -y_d
else:
print '2: Right, i: {0}'.format(i)
x = config.get_last_point()[0] + x_d
y = config.get_last_point()[1] + y_d
I've looked into a bit more, and it turns out that when I'm trying to generate a left-concavity open polygon, the range of angles that are possible are different to the possible angles for a right-concavity open polygon. Once I found out that if I find the min/max allowed angles for the concavity that I am generating, it was correctly selecting an angle within the bounds, therefore, generating the way I want :) Thanks everyone for you help and guidance!

Python recursion depth exceeded limit exceeded, and don't know how to delete recursion

Maybe the problem can be solved by deleting all those functions, can't it?
However, i really don't know what to do to get the source work.
By the way, it just simulates a horse in a chesstable, going around and around, randomly, trying to visit each square once; and I get a recursion depth exceeded error.
import random
def main():
global tries,moves
tries,moves=0,0
restart()
def restart():
global a,indexes,x,y
a=[[0 for y in range(8)] for x in range(8)] #Costrutto chic
indexes=[x for x in range(8)]
#Random part
x=random.randint(0,7)
y=random.randint(0,7)
a[x][y]=1
start()
def start():
global i,indexes,moves,tries
i=0
random.shuffle(indexes) #List filled with random numbers that i'll use as indexes
while i<=7:
if indexes[i]==0:
move(-2,-1)
elif indexes[i]==1:
move(-2,1)
elif indexes[i]==2:
move(-1,-2)
elif indexes[i]==3:
move(-1,2)
elif indexes[i]==4:
move(1,-2)
elif indexes[i]==5:
move(1,2)
elif indexes[i]==6:
move(2,-1)
elif indexes[i]==7:
move(2,1)
i+=1
for _ in a:
if 0 in _:
print "Wasted moves: %d"%(moves)
tries+=1
moves=0
restart()
print "Success obtained in %d tries"%(tries)
def move(column,row):
global x,y,a,moves
try: b=a[x+row][y+column]
except IndexError: return 0
if b==0 and 0<=x+row<=7 and 0<=y+column<=7:
x=x+row
y=y+column
a[x][y]=1
moves+=1
start()
else: return 0
try :main()
#except: print "I couldn't handle it" <-Row added to prevent python from returning a huge amount of errors
EDIT: This is the modified version, which still does not works, but at least it's an improvement:
import random
def move((column,row),x,y):
try: cell=squares_visited[x+row][y+column]
except IndexError: return x,y ## NONE TYPE OBJECT
if cell==0 and 0<=x+row<=7 and 0<=y+column<=7:
x+=row
y+=column
squares_visited[x][y]=1
return x,y ## NONE TYPE OBJECT
squares_visited=[[0] * 8 for _ in range(8)]
x=random.randint(0,7)
y=random.randint(0,7)
squares_visited[x][y]=1
moves=[(-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)]
indexes=list(range(8))
tries=0
print "The horse starts in position %d,%d"%(x,y)
while True:
random.shuffle(indexes)
for _ in indexes:
cells=move(moves[indexes[_]],x,y) ##Passing as arguments x and y looks weird
x=cells[0]
y=cells[1]
#If you out this for cicle, there are no legal moves anymore(due to full completion with 1, or to lack of legit moves)
for _ in squares_visited:
if 0 in _:
squares_visited=[[0] * 8 for _ in range(8)]
tries+=1
else:
print "You managed to do it in %d tries."%(tries)
This code has a lot of problems -- enough that it's worth going over in full:
import random
def main():
global tries,moves
The first of many examples of over-use of global variables. When possible, pass parameters; or create a class. This is a general strategy that will help you construct more comprehensible (and thus more debuggable) algorithms; and in a general sense, this is part of why your code fails -- not because of any particular bug, but because the complexity of your code makes it hard to find bugs.
tries,moves=0,0
restart()
def restart():
global a,indexes,x,y
Why do you name your board a? That's a terrible name! Use something descriptive like squares_visited.
a=[[0 for y in range(8)] for x in range(8)] #Costrutto chic
indexes=[x for x in range(8)]
Minor: in python 2, [x for x in range(8)] == range(8) -- they do exactly the same thing, so the list comprehension is unnecessary. In 3, it works a little differently, but if you want a list (rather than a range object) just pass it to list as in (list(range(8))).
#Random part
x=random.randint(0,7)
y=random.randint(0,7)
a[x][y]=1
start()
So my understanding of the code so far is that a is the board, x and y are the starting coordinates, and you've marked the first spot visited with a 1. So far so good. But then things start to get hairy, because you call start at the end of restart instead of calling it from a top-level control function. That's theoretically OK, but it makes the recursion more complicated than necessary; this is another part of your problem.
def start():
global i,indexes,moves,tries
Argh more globals...
i=0
random.shuffle(indexes) #List filled with random numbers that i'll use as indexes
while i<=7:
if indexes[i]==0:
move(-2,-1)
elif indexes[i]==1:
move(-2,1)
elif indexes[i]==2:
move(-1,-2)
elif indexes[i]==3:
move(-1,2)
elif indexes[i]==4:
move(1,-2)
elif indexes[i]==5:
move(1,2)
elif indexes[i]==6:
move(2,-1)
elif indexes[i]==7:
move(2,1)
i+=1
Ok, so what you're trying to do is go through each index in indexes in sequence. Why are you using while though? And why is i global?? I don't see it being used anywhere else. This is way overcomplicated. Just use a for loop to iterate over indexes directly, as in
for index in indexes:
if index==0:
...
Ok, now for the specific problems...
for _ in a:
if 0 in _:
print "Wasted moves: %d"%(moves)
tries+=1
moves=0
restart()
print "Success obtained in %d tries"%(tries)
I don't understand what you're trying to do here. It seems like you're calling restart every time you find a 0 (i.e. an unvisited spot) on your board. But restart resets all board values to 0, so unless there's some other way to fill the board with 1s before hitting this point, this will result in an infinite recursion. In fact, the mutual recursion between move and start might be able to achieve that in principle, but as it is, it's way too complex! The problem is that there's no clear recursion termination condition.
def move(column,row):
global x,y,a,moves
try: b=a[x+row][y+column]
except IndexError: return 0
if b==0 and 0<=x+row<=7 and 0<=y+column<=7:
x=x+row
y=y+column
a[x][y]=1
moves+=1
start()
else: return 0
Here, in principle, the idea seems to be that if your move hits a 1 or goes off the board, then the current branch of the recursion terminates. But because i and indexes are global above in start, when start is re-called, it re-shuffles indexes and resets i to 0! The result is sheer chaos! I can't even begin to comprehend how that will effect the recursion; it seems likely that because i gets reset at the beginning of start every time, and because every successful call of move results in a call of start, the while loop in start will never terminate!
I suppose it's possible that eventually this process will manage to visit every square, at which point things might work as expected, but as it is, this is too complex even to predict.
try :main()
#except: print "I couldn't handle it" <-Row added to prevent python from returning a huge amount of errors
Not sure what you mean by that last line, but it doesn't sound like a good sign -- you're papering over an error instead of finding the root cause.
I'm going to play with this code a bit and see if I can get it to behave marginally better by de-globalizing some of its state... will report back soon.
Update:
Ok I de-globalized indexes as described above. I then replaced the start/restart recursion with an infinite loop in restart, a return statement in start where the call to restart used to be, and a sys.exit() at the end of start (to break out of the infinite loop on success). The result behaves more as expected. This is still poor design but it works now, in the sense that it recursively tries a bunch of random paths until every local position has been visited.
Of course it still doesn't ever succeed; it just keeps looping. Actually finding a solution will probably require a lot more rethinking of this algorithm! But following my above suggestions should help some, at least.
start() and move() call each other, making it an indirect recursive call BUT the move() return startment get out of move() and notout of the recursion.
You see, when you are calling a function, that calls a function that calls a functions, it all goes in a stack that reference each calls. When you get a your final result, you are supposed to go backward, and unstack these function calls.
Here, you don't, you call move(), that calls start(), and it it returns something then you just keep going deeper in the stack.
Try to make an iterative version of your code. Recursion is hard, start with something easier.
If you do want to persist in the recursive version, make move() call itself, and then go backward in the stack from it self once it reach the out condition. It will be clearer than dealing with recursive calls from two functions.
BTW:
Avoid using global variables. Either pass the data as arguments, or use a class. I would use argument passing, it will force you to come up with a better algo that this one.
the while loop is not necessary. Replace it with a for loop on indexes
the huge if/elif statement is not necessary, replace it with a dictionary
You should end up with somthing like this:
for i in indexes:
move(*MOVES[i])
MOVES, being a dict of values of i associated with params for move().
you may want to use generators instead of your list comprehensions, but that would require some algo changes. It could be better for your memory footprint. At the very least, make this shorter:
[x for x in range(8)] can be written range(8)
[[0 for y in range(8)] for x in range(8)] can be written [[0] * 8 for x in range(8)]
range() can be replaced by xrange()

Categories

Resources