How to break out of a nested while loop - python

I am having trouble breaking out of while loops. Here is my code
while (True):
if (dem_arr[randx, randy] > -100):
ticker = 0
while stack:
x, y = stack.pop()
mask[x, y] = True
for dx, dy in neighbors:
nx, ny = x + dx, y + dy
print ticker
if (0 <= nx < dem_arr.shape[0] and 0 <= ny < dem_arr.shape[1] and dem_arr[x, y] > -100 and dem_arr[nx, ny] > -100 and not mask[nx, ny] and abs(dem_arr[nx, ny] - dem_arr[x, y]) <= 1): #set elevation differnce
stack.append((nx, ny)) #if point is selected (true) array position gets added to stack and process runs over again
if ((nx, ny) not in counterStack):
counterStack.append((nx, ny))
dem_copy[(nx, ny)] = 8888
if (ticker >= 121):
print 'ticker ticked'
#if in this for loop need to break out of while stack:
else:
ticker += 1
else:
print '!!!Point chosen has no data!!!'
randx = random.randint(0, row-1) #array begins at position 0,0
randy = random.randint(0, col-1)
continue
What I need to happen is if (ticker >= 121):is entered I need to break out of the while stack:and while(True).Any ideas on how to do this?

A simplified example illustrating the concept of using functions to control the inner loop:
stack = range(1, 500)
def stack_loop():
ticker = 0
while stack:
x = stack.pop()
# Your implementation here
if ticker >= 121:
print("Ticker ticked")
return True
else:
print("Ticker increased")
ticker += 1
return False
while True:
if stack_loop():
break
Move the inner loop's logic to an external function and use the return statement to control if you have to break out of the main loop or not.
Hope it helps :)
EDIT: You could also move the entire block to the function and simply return from it:
stack = range(1, 500)
def main_loop():
while True:
ticker = 0
while stack:
x = stack.pop()
# Your implementation here
if ticker >= 121:
print("Ticker ticked")
return
else:
print("Ticker increased")
ticker += 1
main_loop()

One possible solution is to use a variable to keep track (breakout in this case):
while (True):
if (dem_arr[randx, randy] > -100):
ticker = 0
breakout = False
while stack and not breakout:
x, y = stack.pop()
mask[x, y] = True
for dx, dy in neighbors:
nx, ny = x + dx, y + dy
print ticker
if (0 <= nx < dem_arr.shape[0] and 0 <= ny < dem_arr.shape[1] and dem_arr[x, y] > -100 and dem_arr[nx, ny] > -100 and not mask[nx, ny] and abs(dem_arr[nx, ny] - dem_arr[x, y]) <= 1): #set elevation differnce
stack.append((nx, ny)) #if point is selected (true) array position gets added to stack and process runs over again
if ((nx, ny) not in counterStack):
counterStack.append((nx, ny))
dem_copy[(nx, ny)] = 8888
if (ticker >= 121):
print 'ticker ticked'
#if in this for loop need to break out of while stack:
breakout = True
break
else:
ticker += 1
else:
print '!!!Point chosen has no data!!!'
randx = random.randint(0, row-1) #array begins at position 0,0
randy = random.randint(0, col-1)
continue

Consider the comments already made. In addition, think about the while loop. While True: is inherently an infinite loop. You could return to the caller from within a function, you could break in the same level as the loop, or you could replace True with an expression that starts False and becomes True under the appropriate condition.
edit:
You aren't programming in Java or C anymore. No need to put parentheses around "True". :) - Or the other conditionals.

Related

How would I be able to have this section of code re-check X,Y and run again based off that data?

from src.common import config, settings, utils
import time
import math
from src.routine.components import Command
from src.common.vkeys import press, key_down, key_up
class Adjust(Command):
"""Fine-tunes player position using small movements."""
def __init__(self, x, y, max_steps=5):
super().__init__(locals())
self.target = (float(x), float(y))
self.max_steps = settings.validate_nonnegative_int(max_steps)
def main(self):
counter = self.max_steps
toggle = True
error = utils.distance(config.player_pos, self.target)
while config.enabled and counter > 0 and error > settings.adjust_tolerance:
if toggle:
d_x = self.target[0] - config.player_pos[0]
threshold = settings.adjust_tolerance / math.sqrt(2)
if abs(d_x) > threshold:
walk_counter = 0
if d_x < 0:
key_down('left')
while config.enabled and d_x < -1 * threshold and walk_counter < 60:
time.sleep(0.05)
walk_counter += 1
d_x = self.target[0] - config.player_pos[0]
key_up('left')
else:
key_down('right')
while config.enabled and d_x > threshold and walk_counter < 60:
time.sleep(0.05)
walk_counter += 1
d_x = self.target[0] - config.player_pos[0]
key_up('right')
counter -= 1
else:
d_y = self.target[1] - config.player_pos[1]
if abs(d_y) > settings.adjust_tolerance / math.sqrt(2):
if d_y < 0:
time.sleep(0.25)
press(Key.ROPE, 1, up_time=0.1)
time.sleep(2)
# press(Key.JUMP, 1, up_time=0.1)
# time.sleep(0.175)
# UpJump('up').main()
else:
key_down('down')
time.sleep(0.05)
press(Key.JUMP, 3, down_time=0.1)
key_up('down')
time.sleep(0.5)
counter -= 1
error = utils.distance(config.player_pos, self.target)
toggle = not toggle
This section of code is from a bot i'm working on for a game, essentially. The bot checks my X and Y and will make my character move left or right to adjust for an X,Y I give it. The issue with this is if I over-jump the target, since my character walks through the correct (X,Y) while overshooting, it will consider itself as done.
I want it to sleep for a second or two after running once, then recheck my (X,Y) and rerun if needed to avoid overshooting.
I've been trying for a while, and want to avoid just running the same thing tons of times

Multithreading in python with matplotlib

Alright, I think it's finally time to call on every python user's best friend: Stack Overflow.
Bear in mind that I am at a bit of a beginner level in python, so obvious solutions and optimisations might not have occurred to me.
My Error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow drag regions should only be invalidated on the Main Thread!'
abort() called
terminating with uncaught exception of type NSException
There is a stack overflow question on this error as well but under a different context but my attempts to fix the error using backend "Agg" with matplotlib didn't work. There were no longer any threading errors but matplotlib errors which didn't make any sense (as in they shouldn't have been there) appeared. This error was described in the link above in the apple developer support page and I couldn't implement those solutions either (prob cuz im a bad programmer).
Note: I'm using macOS, and this error only seems to happen on macOS with matplotlib.
Also the error shouldn't happen in my case because I'm trying to allow only the first thread to access the display function (which might be the part which is going wrong?)
I've been making this little evolution simulator (a little similar to this one) which I'm still on the starting stage of. Here is the code:
import random
import math
from matplotlib import pyplot as plt
import threading
class Element:
default_attr = {
"colour": "#000000",
"survival": 75,
"reproduction": 50,
"energy": 150,
"sensory_range": 100,
"genetic_deviation": 5,
"socialization": 20,
"position": (0, 0,),
"objective_attained": False,
"socialization_attained": False
}
__slots__ = (
"colour",
"survival",
"reproduction",
"energy",
"sensory_range",
"genetic_deviation",
"socialization",
"position",
"objective_attained",
"socialization_attained",
)
def __init__(self, **attributes):
Element.__slots__ = tuple((i + "s" for i in self.__slots__))
self.default_attr.update(attributes)
for key, value in self.default_attr.items():
setattr(self, key, value)
for key, value in self.default_attr.items():
try:
setattr(Element, key + "s", getattr(Element, key + "s") + [value])
except AttributeError:
setattr(Element, key + "s", [value])
def move(self, objective_colour, delay, height, width, energy=None):
if energy is None:
energy = self.energy
lock = threading.RLock()
event = threading.Event()
objective_positions = tuple((p for i, p in enumerate(Element.positions) if Element.colours[i] == objective_colour))
positions = tuple((p for i, p in enumerate(Element.positions) if Element.colours[i] == self.colour and p != self.position))
objectives_in_range = []
for objective in objective_positions:
if ((objective[0] - self.position[0])**2 + (objective[1] - self.position[1])**2)**0.5 <= self.sensory_range:
objectives_in_range.append([objective[0] - self.position[0], objective[1] - self.position[1]])
objectives = tuple(sorted(objectives_in_range, key=lambda x: (x[0]**2 + x[1]**2)**0.5))
positions_in_range = []
for pos in positions:
if ((pos[0] - self.position[0])**2 + (pos[1] - self.position[1])**2)**0.5 <= self.sensory_range:
positions_in_range.append([pos[0] - self.position[0], pos[1] - self.position[1]])
positions = tuple(sorted(positions_in_range, key=lambda x: (x[0]**2 + x[1]**2)**0.5))
if positions:
cluster = [0, 0]
for pos in positions:
cluster[0] += pos[0] + self.position[0]
cluster[1] += pos[1] + self.position[0]
midpoint = (cluster[0] / len(positions) - self.position[0], cluster[1] / len(positions) - self.position[1],)
try:
distance = 100 / (midpoint[0] ** 2 + midpoint[1] ** 2) ** 0.5 * (height if height > width else width) / 100
except ArithmeticError:
distance = 100
if self.socialization <= distance:
self.socialization_attained = True
if self.objective_attained is False and not objectives and self.socialization_attained is False and not positions and energy > self.energy*0.5:
direction = math.radians(random.uniform(0.0, 360.0))
old_position = self.position
self.position = (self.position[0] + math.sin(direction), self.position[1] + math.cos(direction),)
if 90 <= direction <= 270:
self.position = (self.position[0] * -1, self.position[1] * -1,)
for i, position in enumerate(Element.positions):
if position == old_position and Element.colours[i] == self.colour:
Element.positions[i] = self.position
break
with lock:
if not event.is_set():
display(delay, height, width)
event.set()
event.clear()
self.move(objective_colour, delay, height, width, energy - 1)
elif self.objective_attained is False and energy > 0 and objectives:
try:
x, y = math.sin(math.atan(objectives[0][0] / objectives[0][1])), math.cos(math.atan(objectives[0][0] / objectives[0][1]))
if objectives[0][1] < 0:
x *= -1
y *= -1
except ArithmeticError:
x, y = 1 if objectives[0][0] > 0 else -1, 0
old_position = self.position
self.position = tuple(map(lambda x, y: x + y, self.position, (x, y,)))
for i, position in enumerate(Element.positions):
if position == old_position and Element.colours[i] == self.colour:
Element.positions[i] = self.position
break
if (self.position[0] - old_position[0] - objectives[0][0])**2 + (self.position[1] - old_position[1] - objectives[0][1])**2 <= 1:
self.objective_attained = True
with lock:
for i, position in enumerate(Element.positions):
if [int(position[0]), int(position[1])] == [objectives[0][0] + old_position[0], objectives[0][1] + old_position[1]] and Element.colours[i] == objective_colour:
Element.positions.pop(i)
Element.colours.pop(i)
break
with lock:
if not event.is_set():
display(delay, height, width)
event.set()
# a little confusion here, do threads pause over here until all threads have exited the with lock statement or not? If not I need to change the line below.
event.clear()
if self.objective_attained is True:
self.move(objective_colour, delay, height, width, (energy - 1) * 1.5)
else:
self.move(objective_colour, delay, height, width, energy - 1)
elif self.socialization_attained is False and energy > 0 and positions and self.socialization > distance:
try:
x, y = math.sin(math.atan(midpoint[0] / midpoint[1])), math.cos(math.atan(midpoint[0] / midpoint[1]))
if midpoint[1] < 0:
x *= -1
y *= -1
except ArithmeticError:
x, y = 1 if midpoint[0] > 0 else -1, 0
old_position = self.position
self.position = tuple(map(lambda x, y: x + y, self.position, (x, y,)))
for i, position in enumerate(Element.positions):
if position == old_position and Element.colours[i] == self.colour:
Element.positions[i] = self.position
break
with lock:
if not event.is_set():
display(delay, height, width)
event.set()
event.clear()
self.move(objective_colour, delay, height, width, energy - 1)
else:
for thread in globals() ["threads"]:
thread.join()
# a little confusion here too on whether this would wait till all threads reach this statement before joining them
def display(delay, height, width):
x = tuple((i[0] for i in Element.positions)) + (0, width,)
y = tuple((i[1] for i in Element.positions)) + (0, height,)
c = tuple(Element.colours) + ("#FFFFFF",) * 2
plt.scatter(x, y, c=c)
plt.show()
plt.pause(delay)
plt.close()
r = lambda x: random.randint(0, x)
elements = tuple((Element(position=(r(200), r(200),)) for i in range(10))) + tuple((Element(position=(r(200), r(200),), colour="#FF0000") for i in range(10)))
[Element(colour="#00FF00", position=(r(200), r(200),), energy=0, reproduction=0) for i in range(20)]
globals() ["threads"] = []
for organism in elements:
globals() ["threads"].append(threading.Thread(target=organism.move, args=("#00FF00", 0.02, 200, 200,)))
globals() ["threads"][-1].start()
This is a big chunk of code but this is my first time using multithreading so I don't know where the error could pop up, though I have narrowed it down to this section fs.
Sry for the eyesore, ik this is a really long question, but I would be really grateful
if u could help!
This issue goes by a few names, the most common of which is "cross-threading". This occurs when you perform GUI operations (in your case, matplotlib calls) from non-GUI threads. This is a no-no regardless of OS.
To solve the problem, ensure that you're making matplotlib calls from the main thread. A good starting point is on line 176: UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.

Newton Recursive Method for Square Root Problem in Python

For a=13 and a precision epsilon=10^-7. How many times do you apply the newton recursion formula in newton_sqrt(13,10^-7)? Hint: use global variables.
My current newton_sqrt(a, epsilon) function is the following:
def newton_sqrt(a, epsilon):
global count
if a < 0:
print("Error: a < 0")
return -1
elif a == 0.0:
return 0
else:
x = abs(a)
newx = 0.5*(x + a/x)
if abs(x - newx) > epsilon:
newton_sqrt(newx, epsilon)
count = count + 1
if not abs(x-newx) > epsilon:
print (count)
return newx
newton_sqrt(13, 0.000001)
For whatever reason, I get
918488688 None
as my output.
Please help.
There is no output since you never reach the print line:
basically, you have:
if x:
if not x:
print(something)
what you want, i'm guessing is:
if x:
#do something
else:
#do somthing else
not knowing the math of your function I would change it into:
def newton_sqrt(a, epsilon, count):
if a < 0:
print("Error: a < 0")
return -1
elif a == 0.0:
return 0
else:
x = abs(a)
newx = 0.5*(x + a/x)
if abs(x - newx) > epsilon:
count = count + 1
newton_sqrt(newx, epsilon, count)
else:
print (count)
return newx
which will give you:
newton_sqrt(13, 0.000001, 0)
23
First, let's be clear that your newton_sqrt() function doesn't work. Either you're trying to instrument the recursion depth to fix it, or you're unaware it's broken.
A working newton_sqrt() would be along the lines of:
import sys
def newton_sqrt(a, epsilon, x=None):
if a < 0:
print("Error: a < 0", file=sys.stderr)
return -1
if a == 0:
return 0
if x is None: # initial guess
x = a
new_x = (x + a / x) / 2 # refine guess
if abs(new_x * new_x - a) < epsilon: # test guess
return new_x
return newton_sqrt(a, epsilon, new_x) # (better) guess again
print(newton_sqrt(13, 1e-06))
Once that's working, instrumenting the recursion depth using a global variable, count, is simple:
import sys
count = 0
def newton_sqrt(a, epsilon, x=None):
global count
count += 1
if a < 0:
print("Error: a < 0", file=sys.stderr)
return -1
if a == 0:
return 0
if x is None: # initial guess
x = a
new_x = (x + a / x) / 2 # refine guess
if abs(new_x * new_x - a) < epsilon: # test guess
return new_x
return newton_sqrt(a, epsilon, new_x) # (better) guess again
print(newton_sqrt(13, 1e-06), count)
OUTPUT
> python3 test.py
3.6055513629176015 5
>
Where 3.6055513629176015 is the square root of 13 and 5 is the recursion depth needed to compute it with an error of less than 1e-06.

My A-star implementation seems very slow, need advice and help on what I am doing wrong

My tests of my implementations of Dijkstra and A-Star have revealed that my A-star implementation is approximately 2 times SLOWER. Usually equivalent implementations of Dijkstra and A-star should see A-star beating out Dijkstra. But that isn't the case here and so it has led me to question my implementation of A-star. So I want someone to tell me what I am doing wrong in my implementation of A-star.
Here is my code:
from copy import deepcopy
from math import inf, sqrt
import maze_builderV2 as mb
if __name__ == '__main__':
order = 10
space = ['X']+['_' for x in range(order)]+['X']
maze = [deepcopy(space) for x in range(order)]
maze.append(['X' for x in range(order+2)])
maze.insert(0, ['X' for x in range(order+2)])
finalpos = (order, order)
pos = (1, 1)
maze[pos[0]][pos[1]] = 'S' # Initializing a start position
maze[finalpos[0]][finalpos[1]] = 'O' # Initializing a end position
mb.mazebuilder(maze=maze)
def spit():
for x in maze:
print(x)
spit()
print()
mazemap = {}
def scan(): # Converts raw map/maze into a suitable datastructure.
for x in range(1, order+1):
for y in range(1, order+1):
mazemap[(x, y)] = {}
t = [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]
for z in t:
if maze[z[0]][z[1]] == 'X':
pass
else:
mazemap[(x, y)][z] = [sqrt((pos[0]-z[0])**2+(pos[1]-z[1])**2),
sqrt((finalpos[0]-z[0])**2+(finalpos[1]-z[1])**2)] # Euclidean distance to destination (Heuristic)
scan()
unvisited = deepcopy(mazemap)
distances = {}
paths = {}
# Initialization of distances:
for node in unvisited:
if node == pos:
distances[node] = [0, sqrt((finalpos[0]-node[0])**2+(finalpos[1]-node[1])**2)]
else:
distances[node] = [inf, inf]
while unvisited != {}:
curnode = None
for node in unvisited:
if curnode == None:
curnode = node
elif (distances[node][0]+distances[node][1]) < (distances[curnode][0]+distances[curnode][1]):
curnode = node
else:
pass
for childnode, lengths in mazemap[curnode].items():
# Length to nearby childnode - G length, Euclidean (Heuristic) length from curnode to finalpos - H length
# G length + H length < Euclidean length to reach that childnode directly + Euclidean length to finalpos from that childnode = Better path found, update known distance and paths
if lengths[0] + lengths[1] < distances[childnode][0] + distances[childnode][1]:
distances[childnode] = [lengths[0], lengths[1]]
paths[childnode] = curnode
unvisited.pop(curnode)
def shortestroute(paths, start, end):
shortestpath = []
try:
def rec(start, end):
if end == start:
shortestpath.append(end)
return shortestpath[::-1]
else:
shortestpath.append(end)
return rec(start, paths[end])
return rec(start, end)
except KeyError:
return False
finalpath = shortestroute(paths, pos, finalpos)
if finalpath:
for x in finalpath:
if x == pos or x == finalpos:
pass
else:
maze[x[0]][x[1]] = 'W'
else:
print("This maze not solvable, Blyat!")
print()
spit()
For those who find my code too messy and can't bother to read the comments I added to help with the reading... Here is a gist of my code:
Creates a mazemap (all the coordinates and its connected neighbors along with their euclidean distances from that neighboring point to the start position (G Cost) as well as to the final position (H Cost)... in a dictionary)
start position is selected as the current node. All distances to other nodes is initialised as infinity.
For every node we compare the total path cost i.e is the G cost + H cost. The one with least total cost is selected as then next current node. Each time we select new current node, we add that node to a dictionary that keeps track of through which node it was reached, so that it is easier to backtrack and find our path.
Process continues until current node is the final position.
If anyone can help me out on this, that would be great!
EDIT: On account of people asking for the maze building algorithm, here it is:
# Maze generator - v2: Generates mazes that look like city streets (more or less...)
from copy import deepcopy
from random import randint, choice
if __name__ == "__main__":
order = 10
space = ['X']+['_' for x in range(order)]+['X']
maze = [deepcopy(space) for x in range(order)]
maze.append(['X' for x in range(order+2)])
maze.insert(0, ['X' for x in range(order+2)])
pos = (1, 1)
finalpos = (order, order)
maze[pos[0]][pos[1]] = 'S' # Initializing a start position
maze[finalpos[1]][finalpos[1]] = 'O' # Initializing a end position
def spit():
for x in maze:
print(x)
blocks = []
freespaces = [(x, y) for x in range(1, order+1) for y in range(1, order+1)]
def blockbuilder(kind):
param1 = param2 = 0
double = randint(0, 1)
if kind == 0:
param2 = randint(3, 5)
if double:
param1 = 2
else:
param1 = 1
else:
param1 = randint(3, 5)
if double:
param2 = 2
else:
param2 = 1
for a in range(blockstarter[0], blockstarter[0]+param2):
for b in range(blockstarter[1], blockstarter[1]+param1):
if (a+1, b) in blocks or (a-1, b) in blocks or (a, b+1) in blocks or (a, b-1) in blocks or (a, b) in blocks or (a+1, b+1) in blocks or (a-1, b+1) in blocks or (a+1, b-1) in blocks or (a-1, b-1) in blocks:
pass
else:
if a > order+1 or b > order+1:
pass
else:
if maze[a][b] == 'X':
blocks.append((a, b))
else:
spaces = [(a+1, b), (a-1, b), (a, b+1), (a, b-1)]
for c in spaces:
if maze[c[0]][c[1]] == 'X':
break
else:
maze[a][b] = 'X'
blocks.append((a, b))
for x in range(1, order+1):
for y in range(1, order+1):
if (x, y) in freespaces:
t = [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]
i = 0
while i < len(t):
if maze[t[i][0]][t[i][1]] == 'X' or (t[i][0], t[i][1]) == pos or (t[i][0], t[i][1]) == finalpos:
del t[i]
else:
i += 1
if len(t) > 2:
blockstarter = t[randint(0, len(t)-1)]
kind = randint(0, 1) # 0 - vertical, 1 - horizontal
blockbuilder(kind)
else:
pass
# rch = choice(['d', 'u', 'r', 'l'])
b = 0
while b < len(blocks):
block = blocks[b]
t = {'d': (block[0]+2, block[1]), 'u': (block[0]-2, block[1]),
'r': (block[0], block[1]+2), 'l': (block[0], block[1]-2)}
rch = choice(['d', 'u', 'r', 'l'])
z = t[rch]
# if z[0] > order+1 or z[1] > order+1 or z[0] < 1 or z[1] < 1:
# Decreased chance of having non solvable maze being generated...
if z[0] > order-2 or z[1] > order-2 or z[0] < 2+2 or z[1] < 2+2:
pass
else:
if maze[z[0]][z[1]] == 'X':
if randint(0, 1):
set = None
if rch == 'u':
set = (z[0]+1, z[1])
elif rch == 'd':
set = (z[0]-1, z[1])
elif rch == 'r':
set = (z[0], z[1]-1)
elif rch == 'l':
set = (z[0], z[1]+1)
else:
pass
if maze[set[0]][set[1]] == '_':
# Checks so that no walls that block the entire way are formed
# Makes sure maze is solvable
sets, count = [
(set[0]+1, set[1]), (set[0]-1, set[1]), (set[0], set[1]+1), (set[0], set[1]-1)], 0
for blyat in sets:
while blyat[0] != 0 and blyat[1] != 0 and blyat[0] != order+1 and blyat[1] != order+1:
ch = [(blyat[0]+1, blyat[1]), (blyat[0]-1, blyat[1]),
(blyat[0], blyat[1]+1), (blyat[0], blyat[1]-1)]
suka = []
for i in ch:
if ch not in suka:
if maze[i[0]][i[1]] == 'X':
blyat = i
break
else:
pass
suka.append(ch)
else:
pass
else:
blyat = None
if blyat == None:
break
else:
pass
else:
count += 1
if count < 1:
maze[set[0]][set[1]] = 'X'
blocks.append(set)
else:
pass
else:
pass
else:
pass
b += 1
mazebuilder(maze, order)
spit()
Sorry for leaving this out!
Just at a quick glance, it looks like you don't have a closed set at all?? Your unvisited structure appears to contain every node in the map. This algorithm is not A* at all.
Once you fix that, make sure to change unvisited from a list to a priority queue also.

Player on Player collision in pygame

I'm trying to create a collision detection between 4 controllable characters on an RPG battle map. Here is the function I'm using
def player_collission(Lord_x,Lord_y,Journeyman_x,Journeyman_y,Archer_x,Archer_y,
Cleric_x,Cleric_y):
print("Running")
if abs(Lord_x - Journeyman_x) <= 0 and abs(Lord_y - Journeyman_y) <= 0:
print("Colission detected")
return True
elif abs(Lord_x - Archer_x) <= 0 and abs(Lord_y - Archer_y) <= 0:
print("Colission detected")
return True
elif abs(Lord_x - Cleric_x) <= 0 and abs(Lord_y == Cleric_y) <= 0:
print("Colission detected")
return True
elif abs(Journeyman_x - Archer_x) <= 0 and abs(Journeyman_y - Archer_y) <= 0:
print("Colission detected")
return True
elif abs(Journeyman_x - Cleric_x) <= 0 and abs(Journeyman_y - Cleric_y) <= 0:
print("Colission detected")
return True
elif abs(Archer_x - Cleric_x) <= 0 and abs(Archer_y == Cleric_y) <= 0:
print("Colission detected")
return True
else:
return False #I didnt use classes so it has alot of if statements
if player_up:
p_collide = player_collission(Lord_x,Lord_y,Journeyman_x,Journeyman_y,Archer_x,Archer_y,
Cleric_x,Cleric_y)
if current_player == "lord":
if p_collide != True:
Lord_y -= tile_increment
if Lord_y <= 0:
Lord_y = 50
What happens is that the characters still move into each other but it detects the collision after it has already moved into each other and freezes all movement. I'm not sure how to re arrange it to make it work properly.
You detect collision when it has already happened. This is why you see characters overlapping.
Instead, you should detect if a collision is going to happen, an prevent a motion that would lead to that.
An example:
def move(coords, velocity):
"""Moves coords according to velocity."""
x, y = coords # Unpack a 2-tuple.
vx, vy = velocity
return (x + vx, y + vy)
tom_coords = (0, 0) # Tom is in the corner.
tom_v = (1, 1) # Tom moves by diagonal.
jerry_coords = (5, 0) # Jerry is a bit away from Tom.
jerry_v = (0, 1) # Jerry moves vertically.
while True:
new_tom_coords = move(tom_coords, tom_v) # Tom moves without fear.
new_jerry_coords = move(jerry_coords, jerry_v)
if new_jerry_coords == new_tom_coords: # Would be a collision!
new_jerry_coords = jerry_coords # Back to previous tile.
vx, vy = jerry_v
jerry_v = (-vx, -vy) # Jerry runs back.
print("Collision imminent, Jerry runs away!")
else:
jerry_coords = new_jerry_coords # Only update if no collision.
# Could also check collisions with walls, etc.
tom_coords = new_tom_coords
# Not inside pygame, so just print it and wait for a key press.
print('Tom:', tom_coords, 'Jerry:', jerry_coords)
input("Enter to continue, Ctrl+C to stop ")
Run it in and see how Tom and Jerry come close to each other but never occupy the same tile.

Categories

Resources