I am making game sort of like Minecraft using python. I have a world that the user can walk around and look around in but I don't know how to make it so they can break and place blocks.
I need to know how to calculate the block that they are looking at from a 3d array of the blocks in the world (blocks, format:[[[a,b,c],[d,e,f],[g,h,i]],[[j,k,l],[m,n,o],[p,q,r]],[[s,t,u],[v,w,x],[y,z,0]]]), their position (x,y,z) and head rotation (xrot,yrot).
I also only need it in a certain distance away from where they are, maybe 5 blocks. I tried to find a function for a line and kind of follow it but that didn't work out and I looked around on the internet and I couldn't find what I needed.
I need to be able to figure out which block they would break or where a new block would go based of the side they are looking at.
I need to find which face of which cube I am looking at. This is the code I made but some of the math must be off because it isn't working.
def get_looking_at(xrot, yrot, xpos, ypos, zpos, blocks, reach):
xrot, yrot = math.radians(xrot), math.radians(yrot)
xform = sin(xrot)*cos(yrot)+xpos
yform = sin(yrot)+ypos
zform = -(cos(xrot)*cos(yrot))+zpos
xforward = xform-xpos >= 0
yforward = yform-ypos >= 0
zforward = zform-zpos >= 0
if xforward:
xset = [floor(x+xpos+.5)+.5 for x in range(reach)]
else:
xset = [floor((-x)+xpos+.5)-.5 for x in range(reach)]
if yforward:
yset = [ceil(y+ypos) for y in range(reach)]
else:
yset = [floor((-y)+ypos) for y in range(reach)]
if zforward:
zset = [floor(z+zpos+.5)+.5 for z in range(reach)]
else:
zset = [floor((-x)+xpos+.5)-.5 for x in range(reach)]
xint = []
yint = []
zint = []
for x in xset:
y = ((yform-ypos)*x)/(xform-xpos)
z = ((zform-zpos)*x)/(xform-xpos)
xint.append((x, y+ypos, z+zpos))
for y in yset:
x = ((xform-xpos)*y)/(yform-ypos)
z = ((zform-zpos)*y)/(yform-ypos)
yint.append((x+xpos, y, z+zpos))
for z in zset:
x = ((xform-xpos)*z)/(zform-zpos)
y = ((yform-ypos)*z)/(zform-zpos)
zint.append((x+xpos,y+ypos,z))
intercepts = dict()
for pos in xint:
intercepts[(pos[0]-xpos)**2+(pos[1]-ypos)**2+(pos[2]-zpos)**2] = (pos[0], pos[1], pos[2], "x")
for pos in yint:
intercepts[(pos[0]-xpos)**2+(pos[1]-ypos)**2+(pos[2]-zpos)**2] = (pos[0], pos[1], pos[2], "y")
for pos in zint:
intercepts[(pos[0]-xpos)**2+(pos[1]-ypos)**2+(pos[2]-zpos)**2] = (pos[0], pos[1], pos[2], "z")
indices = [x for x in intercepts]
indices.sort()
for index in indices:
connection = intercepts[index]
if xforward:
x = floor(connection[0]+.5)
xdir = "e"
else:
x = ceil(connection[0]-.5)
xdir = "w"
if yforward:
y = floor(connection[1])
ydir = "d"
else:
y = floor(connection[1])+1
ydir = "u"
if zforward:
z = ceil(connection[2]-.5)
zdir = "n"
else:
z = floor(connection[2]+.5)
zdir = "s"
print(x,y,z)
try:
if blocks.get_data(x, y, z) != None:
if math.sqrt(index) <= reach:
if connection[3] == "x":
return x, y, z, xdir
if connection[3] == "y":
return x, y, z, ydir
if connection[3] == "z":
return x, y, z, zdir
else:
return
else:
continue
except IndexError:
continue
return
You could make a sphere of contact around the player and use a radius "protruding" from the player's face.
Radius r would be the maximum distance the user could look at a block and still be able to affect it.
Using triangles you could detect if the end of the radius is inside a block or not, etc.
Related
I am having a difficulty in implementing drawing a tan function in python since it doesn't look smooth, and when having reached 90/180, it doesn't look nice, so im looking for some improvements on this part.
def tan_wave():
pyautogui.click()
theta = 0
step = 10
length = 10
curr_x, curr_y = pyautogui.position()
prev = (curr_x, curr_y)
decrease_flag = False
while theta <= 180:
if (theta % 90) == 0:
theta -= 0.99999
decrease_flag = True
x = curr_x + theta
y = curr_y - math.tan(math.radians(theta))*length
print(x, y, theta)
pyautogui.click(*prev)
pyautogui.dragTo(x, y)
pyautogui.click(x, y)
prev = (x, y)
if decrease_flag:
theta += 0.99999
decrease_flag = False
theta += step
print('Done')
tan_wave()
I am trying to create a plot that dynamically changes as the length of the x and y data sets change.
I got it to work by plotting the plot each loop, but that is not an efficient way to accomplish this.
I use the variable self.line, in line 165 to initialize this plot. At line 228 I change the plot self.ax2.plot(self.stepData, self.nAlive, 'b-')
I am trying to use this instead to just change the data: ```self.line.set_data = (self.stepData, self.nAlive)
Here is my code:
import random
import numpy as np
import matplotlib.pyplot as plt
# ====================================================================================
class Person:
def __init__(self, position):
self.xpos = position[0]
self.ypos = position[1]
self.alive = True
self.trapped = False # if all people are trapped, need to end program
self.distance = None # distance to closest neighbor
def move(self, xmax, ymax, bc, taken):
""" moves person, if possible, to an adjacent corner """
# cannot step where someone else is currently standing
taken[self.xpos, self.ypos] = False # moving from current spot
disallowed = set() # empty set object; will add disallowed directions
if bc == 'wall':
if self.ypos == ymax or taken[self.xpos, self.ypos + 1]:
disallowed.add('north')
if self.xpos == xmax or taken[self.xpos + 1, self.ypos]:
disallowed.add('east')
if self.ypos == 0 or taken[self.xpos, self.ypos - 1]:
disallowed.add('south')
if self.xpos == 0 or taken[self.xpos - 1, self.ypos]:
disallowed.add('west')
elif bc == 'periodic':
if (self.ypos == ymax and taken[self.xpos, (self.ypos + 1) % ymax]) \
or (self.ypos < ymax and taken[self.xpos, self.ypos + 1]):
disallowed.add('north')
if (self.xpos == xmax and taken[(self.xpos + 1) % xmax, self.ypos]) \
or (self.xpos < xmax and taken[self.xpos + 1, self.ypos]):
disallowed.add('east')
if (self.ypos == 0 and taken[self.xpos, (self.ypos - 1) % ymax]) \
or (self.ypos > 0 and taken[self.xpos, self.ypos - 1]):
disallowed.add('south')
if (self.xpos == 0 and taken[(self.xpos - 1) % xmax, self.ypos]) \
or (self.xpos > 0 and taken[self.xpos - 1, self.ypos]):
disallowed.add('west')
# Use the set method 'difference' to get set of allowed directions
allowed = {'north', 'east', 'south', 'west'}.difference(disallowed)
if len(allowed) == 0:
self.trapped = True # cannot move anymore
else:
"""
Randomly pick from the allowed directions; need to convert set
object to a list because random.choice doesn't work on sets
"""
self.direction = random.choice(list(allowed))
if self.direction == 'north':
if (bc == 'wall' and self.ypos < ymax) or bc == 'periodic':
self.ypos += 1
elif self.direction == 'east':
if (bc == 'wall' and self.xpos < xmax) or bc == 'periodic':
self.xpos += 1
elif self.direction == 'south':
if (bc == 'wall' and self.ypos > 0) or bc == 'periodic':
self.ypos -= 1
elif self.direction == 'west':
if (bc == 'wall' and self.xpos > 0) or bc == 'periodic':
self.xpos -= 1
"""
With periodic boundary conditions, it's possible that (xpos, ypos) could
be off the grid (e.g., xpos < 0 or xpos > xmax). The Python modulo
operator can be used to give exactly what we need for periodic bc. For
example, suppose xmax = 20; then if xpos = 21, 21 % 20 = 1; if xpos = -1,
-1 % 20 = 19. (Modulo result on a negative first argument may seem
strange, but it's intended for exactly this type of application. Cool!)
If 0 <= xpos < xmax, then modulo simply returns xpos. For example,
0 % 20 = 0, 14 % 20 = 14, etc. Only special case is when xpos = xmax, in
which case we want to keep xpos = xmax and not xpos % xmax = 0
"""
if self.xpos != xmax:
self.xpos = self.xpos % xmax
if self.ypos != ymax:
self.ypos = self.ypos % ymax
def proximity(self, xmax, ymax, bc, people):
"""
Finds distance from closest neighbor, will calculate actual distance over diagonals, assuming 1 square is
1 ft^2. If no one else is in range (less than 6 feet away), return None.
"""
distance = None
for person in people:
if person is not self and person.alive: # can only get infected by other alive people
x = abs(self.xpos - person.xpos)
y = abs(self.ypos - person.ypos)
if bc == 'periodic': # check other direction (across boundaries) for periodic bc
tempX1 = None
tempY1 = None
for i in range(2):
if tempX1 is None:
tempX1 = (self.xpos - 0) + (xmax - person.xpos) # check distance in one direction
else:
tempX2 = (person.xpos - 0) + (xmax - self.xpos) # check distance in other direction
if tempX2 < tempX1:
tempX1 = tempX2
if tempY1 is None:
tempY1 = (self.ypos - 0) + (ymax - person.ypos) # check distance in one direction
else:
tempY2 = (person.ypos - 0) + (ymax - self.ypos) # check distance in other direction
if tempY2 < tempY1:
tempY1 = tempY2
if tempX1 < x:
x = tempX1
if tempY1 < y:
y = tempY1
if x >= 6 or y >= 6:
pass # not close enough to infect
else: # need to find distance
temp = np.sqrt(x ^ 2 + y ^ 2)
if distance is None or temp < distance:
distance = temp
if distance is not None and distance >= 6:
distance = None
return distance
def gambleYourLife(self, distance):
if distance is not None: # chance of dying!!
p = 0.5 * np.e ** (-0.3 * distance)
if np.random.binomial(1, p) == 1:
self.alive = False
# ====================================================================================
class Earth:
def __init__(self, people, gridSize, bc, nSteps):
# if nSteps = None, goes on until 1 person left
"""
Grid class takes people inputs, along with size, boundary conditions, and number of maximum steps, and runs
on a random walk until one person is left or until nSteps is reached, depending on user input.
"""
self.people = people
self.xmax = gridSize[0]
self.ymax = gridSize[1]
self.bc = bc
self.point = []
self.nSteps = nSteps
self.nAlive = [len(self.people)] # keep track of number of people alive after each step
self.stepData = [0] # list of each step
# array to keep track of points that have are taken
self.taken = np.zeros([self.xmax + 1, self.ymax + 1], dtype=bool)
fig, (self.ax1, self.ax2) = plt.subplots(1, 2) # create new figure window and ax (plot) attributes to Earth obj
self.ax1.set_xlim(0, self.xmax)
self.ax1.set_ylim(0, self.ymax)
self.ax2.set_xlim(0, nSteps)
self.ax2.set_ylim(0, len(people) + 10)
self.line, = self.ax2.plot(self.stepData, self.nAlive, 'b-')
self.ax2.plot(self.stepData, self.nAlive, '--')
self.ax2.set_xlabel('Number of steps')
self.ax2.set_ylabel('Number of people alive')
self.ax2.set_autoscalex_on(True)
# self.ax2.autoscale_view(True, True, False)
for p in self.people:
pnt, = self.ax1.plot([p.xpos], [p.ypos], 'bo')
self.taken[p.xpos, p.ypos] = True
self.point.append(pnt)
def go(self):
step = 1
while not all([p.trapped for p in self.people]) and (self.nSteps is None or step < self.nSteps):
currAlive = 0 # number of alive each round
for i, p in enumerate(self.people):
if not p.trapped and p.alive:
p.move(self.xmax, self.ymax, self.bc, self.taken)
# update grid
self.point[i].set_data(p.xpos, p.ypos)
self.point[i].set_marker('o')
self.taken[p.xpos, p.ypos] = True
"""
When using periodic boundary conditions, a position on a
wall is identical to the corresponding position on the
opposite wall. So if a walker visits (x, ymax) then
(x, 0) must also be marked as visited; if a walker vists
(0, y) then (xmax, y) must also be marked as visited; etc.
"""
if self.bc == 'periodic':
if p.xpos == self.xmax:
self.taken[0, p.ypos] = True
elif p.xpos == 0:
self.taken[self.xmax, p.ypos] = True
if p.ypos == self.ymax:
self.taken[p.xpos, 0] = True
elif p.ypos == 0:
self.taken[p.xpos, self.ymax] = True
# plot path lines
if p.direction == 'north':
self.ax1.vlines(p.xpos, p.ypos - 1, p.ypos)
elif p.direction == 'east':
self.ax1.hlines(p.ypos, p.xpos - 1, p.xpos)
elif p.direction == 'south':
self.ax1.vlines(p.xpos, p.ypos + 1, p.ypos)
elif p.direction == 'west':
self.ax1.hlines(p.ypos, p.xpos + 1, p.xpos)
# determine proximity to others and potentially die
neighbor = p.proximity(self.xmax, self.ymax, self.bc, self.people)
p.gambleYourLife(neighbor)
if not p.alive:
self.point[i].set_color('r')
else: # still alive
currAlive += 1
# update plot
self.nAlive.append(currAlive)
self.stepData.append(step)
# self.line.set_data = (self.stepData, self.nAlive)
self.ax2.plot(self.stepData, self.nAlive, 'b-')
step += 1
plt.pause(0.2)
# ====================================================================================
def program(nPeople=10, gridSize=(20, 20), bc='wall', nSteps=100):
initPositions = set() # set of tuple of initial position of each person
flock = [] # initialize - list of all people
for p in range(nPeople):
while True:
x = random.randint(0, gridSize[0]) # randomly place person on graph, only one person per point
y = random.randint(0, gridSize[1])
if (x, y) not in initPositions:
break
initPositions.add((x, y))
tempPerson = Person(position=(x, y))
flock.append(tempPerson) # add person to list of people
flock = tuple(flock) # turn list into tuple (not sure why... not sure if necessary)
pandemic = Earth(flock, gridSize, bc, nSteps)
pandemic.go()
# main program =======================================================================
program()
You have to turn on the interactive mode with the command plt.ion(), or to show the figure "not blocked" with the argument block=False using fig.show(block=False).
Here is an example of using plt.ion():
# %%
# first cell ------------------------------
import matplotlib.pyplot as plt
x = [1,2,3]
y = [1,7,5]
plt.ion() # interactive mode on
fig,ax = plt.subplots()
line, = ax.plot(x,y)
fig.show()
# %%
# second cell ------------------------------
x.append(4)
y.append(10)
line.set_data(x,y) # set new data
ax.relim() # recompute the data limits
ax.autoscale_view() # automatic axis scaling
# %%
# third cell: just a radom example to plot sequentially ---------------------
from random import randint
for i in range(5):
x.append(x[-1]+1)
y.append(randint(0,10))
line.set_data(x,y) # set new data
ax.relim() # recompute the data limits
ax.autoscale_view() # automatic axis scaling
plt.pause(0.5)
I want to check if the mouse clicked on a line on Tkinter canvas or not, if on a line then which line.
I had made this to detect mouse clicks.
class Link:
def __init__(self,Node1,Node2,canvas,width=5):
if self not in canvas.LinkList:
self.start_coor = Node1.Centre
self.final_coor = Node2.Centre
self.Canvas = canvas
self.Width = width
self.Shape = canvas.create_line(self.start_coor,self.final_coor,width=width)
Node1.connected(Node2)
self.Canvas.LinkList.append(self)
self.Nodes = [Node1,Node2]
self.Clicked = False
dy = self.final_coor[1] - self.start_coor[1]
dx = self.final_coor[0] - self.start_coor[0]
self.m = dy/dx
self.c = self.start_coor[1] - self.m*self.start_coor[0]
def onLineCheck(self,x,y,field=False):
#y = mx + c
#y - mx - c = 0
if not field:
field = self.Width
if (x < self.start_coor[0] and x < self.final_coor[1]) or (x > self.start_coor[0] and x > self.final_coor[1]) or (y < self.start_coor[1] and y < self.final_coor[1]) or (y > self.start_coor[1] and y > self.final_coor[1]):
return False
temp = y - (self.m*x) - self.c
if abs(temp) <= field:
return True
return False
class InputCanvas(Canvas):
def __init__(self,master=None, **kw):
super().__init__(master,**kw)
self.NodeList = []
self.LinkList = []
self.Mode = "Nodes"
def anyLinkClicked(self,e):
x,y = getMousePosition(e)
for l in self.LinkList:
if l.onLineCheck(x,y):
return l
return False
Every time when a link is created, it will automatically append itself to the canvas.LinkList. I am sure this part of the code is working properly.
So far the program works well with 1 line on Canvas(even if I remove it and draw a new one it is still working) but cannot handle more than 1 line, it can only respond to the first line created. Even if I remove the first line, the second created line won't work.
I've tried printing out the result of each onLineCheck(), it seems like the loop is looping properly through each line but it is not catching mouse clicks.
Any idea to help?
The issue is on the following line:
if (x < self.start_coor[0] and x < self.final_coor[1]) or (x > self.start_coor[0] and x > self.final_coor[1]) or (y < self.start_coor[1] and y < self.final_coor[1]) or (y > self.start_coor[1] and y > self.final_coor[1]):
return False
x < self.final_coor[1] should be x < self.final_coor[0]
x > self.final_coor[1] should be x > self.final_coor[0]
Also you should also cater vertical line, i.e. dx is zero as your code will raise ZeroDivisionError: division by zero.
You can use Canvas.find_overlapping() function to find which Link is clicked:
def anyLinkClicked(self, e):
x, y = getMousePosition(e)
found = self.find_overlapping(x, y, x, y)
if found:
for l in self.LinkList:
if found[0] == l.Shape:
return l
return False
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.
I am making a puzzle game with Python, it's supposed to be a 3x3 slide puzzle. I've made a class that stores name/id and x,y coordinates.
In the function up() I want to move the asterisk (*) up one row and in theory it should work but apparently not. I have a function that finds the class instance associated with two coordinates (find()) and it returns an instance of the class called symbol.
Layout of the slide puzzle:
1 2 3
4 5 6
7 8 *
When I try to assign the new values to the class instance above me (represented by the 6) nothing gets assigned. I would like to use the global keyword but that seems like such a hassle because then I would have to check every coordinate and then say what variable to change.
This is a puzzle game so it's really important that the player can move around without issues. I haven't tried anything else since I don't know how to proceed from this point.
class symbol:
def __init__(self, x, y, val):
self.x = x
self.y = y
self.val = val
s1 = symbol(1, 1, "1")
s2 = symbol(2, 1, "2")
s3 = symbol(3, 1, "3")
s4 = symbol(1, 2, "4")
s5 = symbol(2, 2, "5")
s6 = symbol(3, 2, "6")
s7 = symbol(1, 3, "7")
s8 = symbol(2, 3, "8")
s9 = symbol(3, 3, "*")
def getPos():
xPos = 0
yPos = 0
for element in symbols:
if element.val == "*":
xPos = element.x
yPos = element.y
else:
pass
return xPos, yPos
def find(x, y):
xPos = 0
yPos = 0
found = symbol(100, 100, "FIND")
for element in symbols:
if element.x == x and element.y == y:
found.x = x
found.y = y
found.val = element.val
else:
pass
return found
def up():
x, y = getPos()
if y > 1:
newBlock = find(x, y-1)
myBlock = find(x, y)
myBlock.val = newBlock.val
newBlock.val = "*"
clear()
draw()
print(f"myBlock: {myBlock.val} ({myBlock.x}, {myBlock.y}), newBlock: {newBlock.val} ({newBlock.x}, {newBlock.y})")
else:
pass
#cannot go higher
The problem is that your find function is making a new symbol and returning that. When up() modifies the result of find(), it's just changing some copy that lives outside of (what I assume is) your list of symbols.
One solution would be to just return the element from the list in find. i.e.
for element in symbols:
if element.x == x and element.y == y:
return element
return None