deep lerning number guesser with python(tensorflow) - python

I made a deep learning number guesser with python(in jupyter notebookand I used ten)when I run the code it should open a empty window(with pygame) that I can draw numbers to train the deep learning but I get tow AttributeErrors this is my code:
import tensorflow as tf
import pygame
import matplotlib.pyplot as plt
import numpy as np
from tkinter import *
from tkinter import messagebox
class pixel(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = (255,2555,255)
self.neighbors = []
def draw(self, surface):
pygame.draw.rect(surface, self.color, (self.x, self.y, self.x + self.width, self.y + self.height))
def getNeighbors(self, g):
j = self.x // 20
i = self.y // 20
rows = 28
cols = 28
if i < cols -1:
self.neighbors.append(g.pixels[i + 1][j])
if i > 0:
self.neighbors.append(g.pixels[i - 1][j])
if j < rows -1:
self.neighbors.append(g.pixels[i][j + 1])
if j > 0:
self.neighbors.append(g.pixels[i - 1][j + 1])
if j > 0 and i > 0:
self.neighbors.append(g.pixels[i - 1][j - 1])
if j + 1 < rows and i > -1 and i - 1 > 0:
self.neighbors.append(g.pixels[i - 1][j + 1])
if j - 1 < rows and i < cols - 1 and j - 1 > 0:
self.neighbors.append(g.pixels[i + 1][j - 1])
if j < rows - 1 and i < cols - 1:
self.neighbors.append(g.pixels[i + 1][j + 1])
class grid(object):
pixels = []
def __init__(self, row, col, width, height):
self.rows = row
self.cols = col
self.len = row * col
self.width = width
self.height = height
self.generatePixels
pass
def draw(self, surface):
for row in self.pixels:
for col in row:
col.draw(surface)
def generatePixels(self):
x_gap = self.width // self.cols
y_gap = self.height // self.rows
self.pixels = []
for r in range(self.rows):
self.pixels.append([])
for c in range(self.cols):
self.pixels[r].append(pixel(x_gap * c, y_gap * r, y_gap * r, x_gap, y_gap))
for r in range(self.rows):
for c in range(self.cols):
self.pixels[r][c].getNeighbors(self)
def clicked(self, pos):
try:
t = pos[0]
w = pos[1]
g1 = int(t) // self.pixels[0][0].width
g1 = int(t) // self.pixels[0][0].width
g2 = int(w) // self.pixels[0][0].height
return self.pixels[g2][g1]
except:
pass
def convert_binary(self):
li = self.pixels
newMatrix = [[] for x in range(len(li))]
for i in range(len(li)):
for j in range(len(li[i])):
if li[i][j].color == (255,225,255):
newMatrix[i].append(0)
else:
newMatrix[i].append(1)
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_test = tf.keras.utils.normalize(x_test, axis=1)
for row in range(28):
for x in range(28):
x_test[0][row][x] = newMatrix[row][x]
return x_test[:1]
def guess(li):
model = tf.keras.models.load_model('m.model')
predictions = model.predict(li)
print(predictions[0])
t = (np.argmax(predictions[0]))
print("I predict this number is a:", t)
window = Tk()
window = withdraw()
messagebox.showinfow("prediction", "I predict this number is a:" + str(t))
#plt.imshow(li[0], cmap=plt.cm.binary)
#pit.show()
def main():
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
li = g.convert_binary()
guess(li)
g.generatePixels()
if pygame.mouse.get_pressed()[0]:
pos = pygame.mouse.get_pos()
clicked = g.clicked(pos)
clicked.color = (0,0,0)
for n in clicked.neighbors:
n.color = (0,0,0)
if pygame.mouse.get_pressed()[2]:
try:
pos = pygame.mouse.get_pos()
clicked = g.clicked(pos)
clicked.color = (255,255,255)
except:
pass
g.draw(win)
pygame.display.update()
pygame.init()
width = height = 560
win = pygame.display.set_mode((width, height))
pygame.display.set_caption("Number Guesser")
g = grid(28, 28, width, height)
main()
this is the output:
pygame 2.0.1 (SDL 2.0.14, Python 3.8.8)
Hello from the pygame community. https://www.pygame.org/contribute.html
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-1-a4fa9a8a2b5c> in <module>
149 pygame.display.set_caption("Number Guesser")
150 g = grid(28, 28, width, height)
--> 151 main()
<ipython-input-1-a4fa9a8a2b5c> in main()
129 pos = pygame.mouse.get_pos()
130 clicked = g.clicked(pos)
--> 131 clicked.color = (0,0,0)
132 for n in clicked.neighbors:
133 n.color = (0,0,0)
AttributeError: 'NoneType' object has no attribute 'color'

g.clicked() is clearly returning None for you to get a NoneType object error when accessing the return value.
If we look at the clicked() method, we can see there's a try: ... except: pass construct. It means that any and all errors that might happen are just thrown out of the window, and since a function that doesn't explicitly return returns None, we can assume that's what happening.
Takeaway 1: Never, ever use try: except: like that. Just let the exception happen and handle it elsewhere.
Reasons why there might be some exception we don't know about in that function could be e.g.
an IndexError when unpacking the argument
an IndexError accessing self.pixels
a ZeroDivisionError
a NameError or an AttributeError if we've typoed something
anything else too, heck if we know
For the time being, let's look at what initializes self.pixels... Looks like generatePixels is the thing.
What calls generatePixels? Well... nothing, since the "call" to it in grid's __init__ is missing the call parentheses: self.generatePixels should be self.generatePixels().
Takeaway 2: Use an IDE or linter that warns you about stuff like that.
So, tracing that back:
self.pixels never gets initialized because generatePixels is not called.
An exception accessing self.pixels is swallowed by the bare except:.
You get a None from the clicked() function.
You try accessing the None and you get the exception.
While there are other clear issues in the code, you might want to start by
fixing the call to generatePixels()
unwrapping try: except:s

Related

Animate algorithm

I want to visualize an algorithm (Graham scan) in python with tkinter.
I want to animate the algorithm and I am stuck.
I basically want to draw and delete lines but I don't understand canvas.after() well enough to make it work.
draw_line() returns the line object but when I call it in canvas.after(..., draw_line, ...) I don't see a way to get the return value or how to call another canvas.after() to change the color/delete that line if the function draw_line() hasn't been called yet because of the delay.
Thanks in advance.
from tkinter import *
import math
import random
class Point:
def __init__(self, _x, _y, _a=0):
self.x = _x
self.y = _y
self.angle = _a
def get_co(self):
return self.x, self.y
def draw_hull(hull):
for i in range(len(hull) - 1):
canvas.create_line(hull[i][0], hull[i][1], hull[i + 1][0], hull[i + 1][1], fill="red", width=2)
def draw_line(p1, p2, color="yellow"):
return canvas.create_line(p1.x, p1.y, p2.x, p2.y, fill=color, width=2)
def convex_hull(list_points):
# find bottom point
bottom_point = Point(math.inf, math.inf)
for point in list_points:
if point[1] < bottom_point.y:
bottom_point = Point(point[0], point[1])
# calculate angles between the bottom point and the other points
points = []
for point in list_points:
if point != bottom_point.get_co():
new_point = Point(point[0], point[1])
angle = calculate_angle(bottom_point, new_point)
new_point.angle = angle
points.append(new_point)
# sort the points by angle
swaps = None
while swaps != 0:
swaps = 0
for i in range(len(points) - 1):
point1 = points[i]
point2 = points[i + 1]
if point1.angle > point2.angle:
points[i], points[i + 1] = points[i + 1], points[i]
swaps += 1
# go through the points and add them to the convex hull
# if the angle between 3 points ever exeeds 180 degrees, discard the middle point
hull = [bottom_point, points[0]]
i = 1
while i < len(points):
####### DRAW LINE #######
canvas.after(i*500, draw_line, hull[-2], hull[-1])
##############
# check angle
angle = calculate_angle(hull[-2], hull[-1], points[i])
if angle == -1:
########## DELETE LINE ##########
# change color of line to red and delete it a bit later
# canvas.itemconfig(line, fill="red")
# canvas.after(i*500+250, canvas.delete, line)
####################
# pop the point of the stack
hull.pop()
else:
########## CHANGE COLOR OF LINE ##########
# change color of line to green
# canvas.itemconfig(line, fill="green")
####################
# move to the next point
hull.append(points[i])
i += 1
# add bottom point again for loop
hull.append(bottom_point)
# give easy return list (with coordinate-tupels not class objects)
output = []
for point in hull:
output.append(point.get_co())
return output
def calculate_angle(point1, point2, point3=None):
if point3 is None:
if point2.x - point1.x == 0:
return 90
elif point2.x - point1.x > 0:
return math.degrees(math.atan((point2.y - point1.y)/(point2.x - point1.x)))
else:
return 180 - math.degrees(math.atan((point2.y - point1.y)/(point1.x - point2.x)))
else:
v1 = Point(point1.x - point2.x, point1.y - point2.y)
v2 = Point(point3.x - point2.x, point3.y - point2.y)
det = (v1.x * v2.y) - (v2.x * v1.y)
if det < 0:
return 1
else:
return -1
window = Tk()
window.geometry("1000x600")
canvas = Canvas(window, width=1000, height=600)
canvas.pack()
POINTSIZE = 2
points = []
for i in range(100):
x = random.randint(50, 950)
y = random.randint(50, 550)
points.append((x, y))
canvas.create_oval(x - POINTSIZE, y - POINTSIZE, x + POINTSIZE, y + POINTSIZE, fill="black")
hull = convex_hull(points)
# draw_hull(hull)
window.mainloop()
If you have questions about the code, let me know. Because I dont know where to start to explain, since I made major changes to your code.
Anyway, I would be glad if you share your code again, once you are done with, on CodeReview and please do let me know. Because it was fun to work with and your code seems incomplete to me.
Happy Coding:
import tkinter as tk
import random
import math
class Point:
def __init__(self, _x, _y, _a=0):
self.x = _x
self.y = _y
self.angle = _a
return None
def get_co(self):
return self.x, self.y
class Window(tk.Tk):
def __init__(self,_w,_h):
super().__init__()
self.POINTSIZE = 2
self.points = []
self.swaps = None
self.count = 1
self.delay = 200
self.title('Graham scan simulation')
self.toolbar = tk.Frame(self,background='grey')
self.refresh_button = tk.Button(self.toolbar,text='Refresh',
command=self.refresh)
self.start_button = tk.Button(self.toolbar,text='Start',
command = self.convex_hull)
self.canvas = tk.Canvas(self,width=_w,height=_h)
self.toolbar.pack(side=tk.TOP,fill=tk.BOTH,expand=True)
self.refresh_button.pack(side=tk.LEFT)
self.start_button.pack(side=tk.LEFT)
self.canvas.pack(side=tk.BOTTOM,fill=tk.BOTH,expand=True)
def generate_points(self):
for point_instance in self.points:
yield point_instance
def find_bottom_point(self):
bottom_point = Point(math.inf,math.inf)
for point in self.generate_points():
if point.y < bottom_point.y:
bottom_point = point
return bottom_point
def calculate_angle(self,point1, point2):
if point2.x - point1.x == 0:
return 90
elif point2.x - point1.x > 0:
return math.degrees(math.atan((point2.y - point1.y)/(point2.x - point1.x)))
else:
return 180 - math.degrees(math.atan((point2.y - point1.y)/(point1.x - point2.x)))
def calculate_angels_by_bottom_point(self,bottom_point):
for point in self.generate_points():
if point != bottom_point:
angle = self.calculate_angle(bottom_point,point)
point.angle = angle
def sort_points(self,event_variable):
if self.swaps != 0:
self.swaps = 0
for i in range(len(self.points)-1):
point1 = self.points[i]
point2 = self.points[i + 1]
if point1.angle > point2.angle:
self.points[i], self.points[i + 1] = self.points[i + 1], self.points[i]
self.swaps += 1
if self.swaps == 0:
event_variable.set(1)
self.after(20,self.sort_points,event_variable)
def check_angle(self,point1,point2,point3):
v1 = Point(point1.x - point2.x, point1.y - point2.y)
v2 = Point(point3.x - point2.x, point3.y - point2.y)
det = (v1.x * v2.y) - (v2.x * v1.y)
if det < 0:
return 1
else:
return -1
def draw_line(self,p1,p2,color='yellow'):
return self.canvas.create_line(p1.x,p1.y, p2.x,p2.y, fill='yellow',tags='line')
def clear_red_lines(self,p1,p2):
shapes = self.canvas.find_withtag('line')
for shape in shapes:
if self.canvas.itemcget(shape,'fill') == 'red':
coords = self.canvas.coords(shape)
overlapped = self.canvas.find_overlapping(*coords)
for i in overlapped:
coords2 = self.canvas.coords(i)
if coords == coords2:
self.canvas.delete(i)
self.canvas.delete(shape)
def animated_draw(self,hull):
if self.count != len(self.points):
line = self.draw_line(hull[-2],hull[-1])
check_mark = self.check_angle(hull[-2],hull[-1],self.points[self.count])
if check_mark == -1:
self.canvas.itemconfig(line,fill='red')
self.after(self.delay-100,lambda:self.clear_red_lines(hull[-2],hull[-1]))
hull.pop()
else:
self.canvas.itemconfig(line,fill='green')
hull.append(self.points[self.count])
self.count += 1
self.after(self.delay,self.animated_draw,hull)
def convex_hull(self):
bottom_point = self.find_bottom_point()
self.calculate_angels_by_bottom_point(bottom_point)
event_variable = tk.IntVar(self,value=0)
self.sort_points(event_variable)
self.wait_variable(event_variable)
self.points.pop(0)
self.animated_draw(hull = [bottom_point, self.points[0]])
def generate_listpoints(self,_amount):
'''using a generator for memory purpose'''
for i in range(_amount):
x = random.randint(50, 950)
y = random.randint(50, 550)
yield x,y
def refresh(self):
self.swaps = None
self.count = 1
self.points= []
self.populate_canvas()
def populate_canvas(self):
self.canvas.delete('all')
for x,y in self.generate_listpoints(100):
self.points.append(Point(x, y))#instead of creating throwing instances away.
self.canvas.create_oval(x - self.POINTSIZE,
y - self.POINTSIZE,
x + self.POINTSIZE,
y + self.POINTSIZE,
fill="black")
root = Window(1000,600)
root.mainloop()

I've been making conway's game of life in python, why doesn't it work?

So there must be something wrong with the code which detects wether it should be alive or not in Cell.update(), but the glider i hardcoded in is not working as intended. The first and second generations work as intended, but on the third it dies out. Anyone know what the problem is? I know the code is a bit messy, but I'm quite new to python so it is expected. Thanks in advance!
Here is the code:
import pygame
"""
rules:
1. Any live cell with two or three live neighbours survives.
2. Any dead cell with three live neighbours becomes a live cell.
3. All other live cells die in the next generation. Similarly, all other dead cells stay dead.
number cells on screen = 32x18
cell size = 30x30
"""
# variables
WIDTH = 960
HEIGHT = 540
TITLE = "Conway's Game Of Life"
GRID_COLOUR = (200, 200, 200)
BG_COLOUR = (255, 255, 255)
grid = [[False] * 32] * 18
cells = []
live_queue = []
die_queue = []
# window
wn = pygame.display.set_mode((WIDTH, HEIGHT), vsync=1)
pygame.display.set_caption(TITLE)
# classes
class Cell:
def __init__(self, x, y, alive, index_x, index_y):
self.x = x
self.y = y
self.alive = alive
self.indexX = index_x
self.indexY = index_y
def die(self):
self.alive = False
def live(self):
self.alive = True
def get_index(self):
return self.indexX, self.indexY
def update(self):
grid_temp = grid[self.indexY]
grid_temp.pop(self.indexY)
grid_temp.insert(self.indexY, self.alive)
grid.pop(self.indexY)
grid.insert(self.indexX, grid_temp)
adjacent_alive = 0
for i in cells:
if i.x == self.x - 30 and i.y == self.y and i.alive:
adjacent_alive += 1
elif i.x == self.x + 30 and i.y == self.y and i.alive:
adjacent_alive += 1
elif i.x == self.x and i.y == self.y - 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x and i.y == self.y + 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x - 30 and i.y == self.y - 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x - 30 and i.y == self.y + 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x + 30 and i.y == self.y - 30 and i.alive:
adjacent_alive += 1
elif i.x == self.x + 30 and i.y == self.y + 30 and i.alive:
adjacent_alive += 1
if self.alive:
if adjacent_alive < 2:
return False
elif adjacent_alive > 3:
return False
else:
return True
if not self.alive:
if adjacent_alive == 3:
return True
else:
return False
def render(self):
if self.alive:
pygame.draw.rect(wn, (0, 0, 0), (self.x, self.y, 30, 30))
# functions
def render_grid():
for y in range(0, HEIGHT, 30):
pygame.draw.line(wn, GRID_COLOUR, (0, y), (WIDTH, y))
for x in range(0, WIDTH, 30):
pygame.draw.line(wn, GRID_COLOUR, (x, 0), (x, HEIGHT))
def parse_to_x_y(x, y):
return x * 30, y * 30
def parse_to_index(x, y):
return int(x / 30), int(y / 30)
indexX = 0
indexY = 0
x_pos = 0
y_pos = 0
for y_ in range(18):
for x_ in range(32):
cells.append(Cell(x_pos, y_pos, False, indexX, indexY))
indexX += 1
x_pos += 30
y_pos += 30
x_pos = 0
indexY += 1
cells[2].live()
cells[35].live()
cells[65].live()
cells[66].live()
cells[67].live()
# main loop
fps = 1
clock = pygame.time.Clock()
while True:
# start_time = time.time()
wn.fill(BG_COLOUR)
for item in cells:
item.render()
render_grid()
# events loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
for item in cells:
if item.update():
live_queue.append(item)
else:
die_queue.append(item)
for i in live_queue:
i.live()
for i in die_queue:
i.die()
pygame.display.update()
clock.tick(fps)
# end_time = time.time()
# print(round(1 / (end_time - start_time)), "fps")
The problem is that you don't reset your queues in the main loop.
So add this before adding to the queues:
live_queue = [] # <----
die_queue = [] # <----
for item in cells:
if item.update():
live_queue.append(item)
else:
die_queue.append(item)
Some other remarks
You never use grid or grid_temp in a useful way. Even the operations you make on them are strange. Any way, you can just remove all references to them.
You never use the indexX or indexY attributes, nor the method around it, nor the corresponding arguments to the constructor. All that can go.
You should avoid scanning all the cells just to find the (up to) 8 neighbors of one cell: this has a bad impact on performance.
I agree with commenter Rabbid76, in that you need to update the entire grid at once, not cell by cell. This is usually done by using two separate grids, an "previous state" grid and a "new state grid". Loop through each position in the "new state" grid and calculate its number of live neighbors using the "previous state" grid. After the entire "new state" grid is calculated, you can copy to "new state" grid to the "old state" grid.
Another fatal flaw in your algorithm is grid = [[False] * 32] * 18. This will not work as expected in Python. With this code, each row is a reference to the same array. For instance, the expression grid[0] is grid[1] will evaluate to True. If you set a certain cell in the grid to true, the entire column will be set to true. You can fix this via the code:
grid=[]
for r in range(18):
row=[]
for c in range(32):
row.append(False)
grid.append(row)
Though it isn't directly related to the bug, I suggest a bit of a redesign of your algorithm. It is not really needed to encapsulate each cell in a class; doing so creates a redundancy between the grid and list of cells. This also leads you to identify cells by their pixel position (hence the i.x == self.x - 30 clause), which can easily lead to bugs. I suggest checking adjacent indices in the grid variable instead. Try looking into https://www.geeksforgeeks.org/conways-game-life-python-implementation/ for some inspiration.

Pygame displays black screen [duplicate]

This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Why is my PyGame application not running at all?
(2 answers)
Closed 2 years ago.
I'm trying to write a simple sokoban game in python 3.5 using Pygame, however when I run the code I just get a black background. I'm sure I'm just doing something wrong with the blit but still learning so not too sure.
Any help anyone can give would be greatly appreciated :)
import random, pygame, sys
from pygame.locals import *
from Classes import Maze, Move, Player, Box
maze = Maze()
WHITE = (255, 255, 255)
FPS = 30
WINWIDTH = 750
WINHEIGHT = 750
HALFHEIGHT = int(WINWIDTH/2)
HALFWIDTH = int(WINWIDTH/2)
#BASICFONT = pygame.font.Font('freesansbold.tff',100)
#Tile height and width in pixels
TILEWIDTH = 30
TILEHEIGHT = 30
TILEFLOORHEIGHT = 30
IMAGESDICT = {"WALL": pygame.image.load("C:/Users/Trail/Documents/College 2/Object Oriented Programming/Sokoban Implement/images/wall.bmp"),
"FLOOR": pygame.image.load(""C:/Users/Trail/Documents/College 2/Object Oriented Programming/Sokoban Implement/images/floor.bmp"),
"CRATE": pygame.image.load(""C:/Users/Trail/Documents/College 2/Object Oriented Programming/Sokoban Implement/images/object.bmp"),
"TARGET": pygame.image.load("C:/Users/Trail/Documents/College 2/Object Oriented Programming/Sokoban Implement/images/wall.bmp"object_store),
"PLAYER": pygame.image.load("C:/Users/Trail/Documents/College 2/Object Oriented Programming/Sokoban Implement/images/mover_left.bmp")}
TILEMAPPING = {"#":IMAGESDICT["WALL"],
" ":IMAGESDICT["FLOOR"],
"$":IMAGESDICT["CRATE"],
"#":IMAGESDICT["TARGET"],
"P":IMAGESDICT["PLAYER"]}
#Display surface
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAY = pygame.display.set_mode((WINWIDTH,WINHEIGHT))
pygame.display.set_caption("Sokoban")
def Build(maze):
maze.walls(10)
maze.targets(5)
maze.startPos()
mapSurfWidth = maze.getWidth() * TILEWIDTH
mapSurfHeight = maze.getHeight() * TILEHEIGHT
mapSurf = pygame.Surface((mapSurfWidth,mapSurfHeight))
mapSurf.fill(WHITE)
for h in range(maze.getHeight()):
for w in range(maze.getWidth()):
tile = pygame.Rect((w * TILEWIDTH, h * TILEFLOORHEIGHT, TILEWIDTH, TILEHEIGHT))
if maze.getPos(h,w) in TILEMAPPING:
baseTile = TILEMAPPING[maze.getPos(h,w)]
#Draw
mapSurf.blit(baseTile,tile)
return mapSurf
def main():
Build(maze)
main()
And my Maze class (This is indented in my code but not here for formatting):
class Maze:
def __init__(self):
self.width = 20
self.height = 10
#init
width = 20
height = 10
#Create 2D array for maze
self.maze = [[0 for i in range(width)] for j in range(height)]
#Create square grid
for i in range(width):
for j in range(height):
if j == 0 or j == height - 1:
self.maze[j][i] = "#"
elif i == 0 or i == width - 1:
self.maze[j][i] = "#"
else:
self.maze[j][i] = " "
def crates(self,level):
self.level = level
for i in range(0,level):
#Don't spawn here if wall is already generated
if self.maze[i+2][i+5] == "#":
self.maze[i+3][i+6] = "$"
else:
self.maze[i+2][i+5] = "$"
return self.maze
def walls(self,level):
self.level = level
#Semi working, needs randomised for play
for i in range(0,level):
for j in range(0,level):
#Shitty random gen
y = level / 2
x = randint(0,level)
y = randint(0,y)
#Shitty test random wall gen
if x % 3 == 0:
self.maze[y][x] = "#"
"""if (j % 3 == 0) and (i < 4):
self.maze[j][i] = "#"
elif (j % 2 == 0) and (i > 8):
self.maze[i][j] = "#"""
return self.maze
def targets(self,level):
self.level = level
#Test
for i in range(0,level):
self.maze[i+2][i+10] = "#"
return self.maze
def startPos(self):
x = randint(1,5)
y = randint(1,5)
self.maze[x][y] = "P"
return self.maze
def getWidth(self):
return self.width
def getHeight(self):
return self.height
def getPos(self,row,col):
return self.maze[row][col]

Diagonal lines of squares in grids

I have a python grid class in which I am trying to create a method to get the diagonal line of tiles that a certain tile belongs to. I have succeeded in doing this for going down from left to right in a diagonal line, and would like to know how to change it so that I can go from right to left by changing the "direction" parameter. Here is my method:
def getDiagonal(self, tile, direction = 1):
index = self.index(tile)
diagonal = []
currentIndex = [i - index[0] for i in index]
while currentIndex[1] != self.y:
diagonal.append(self[currentIndex[0]][currentIndex[1]])
currentIndex = [i + 1 for i in currentIndex]
return diagonal
And here is the entire module in which the Grid class is contained:
# Grid library for Pygame by Bobby Clarke
# GNU General Public License 3.0
# Version 1.1
import pygame
import math
from fractions import gcd
from functools import reduce
def _isEven(i):
return i % 2 == 0
def product(_list):
return reduce(lambda x, y: x * y, _list, 1)
def _range(start, stop, step=1):
"""Range function which can handle floats."""
while start < stop:
yield start
start += step
def _simplify(a, b):
hcf = gcd(a, b)
return (a / hcf, b / hcf)
class Tile(pygame.Rect):
def __init__(self, point, size, colour = None, imgs = [], tags = []):
self.size = [int(i) for i in size]
self.point = point
self.colour = colour
for img in imgs:
if isinstance(img, tuple):
imgs[imgs.index(img)] = pygame.image.fromstring(img[0],
img[1],
img[2])
self.imgs = imgs[:]
self.tags = tags[:]
pygame.Rect.__init__(self, self.point, self.size)
def __lt__(self, other):
return (self.point[0] < other.point[0] or
self.point[1] < other.point[1])
def __gt__(self, other):
return (self.point[0] > other.point[0] or
self.point[1] > other.point[1])
def __le__(self, other):
return (self.point[0] <= other.point[0] or
self.point[1] <= other.point[1])
def __ge__(self, other):
return (self.point[0] >= other.point[0] or
self.point[1] >= other.point[1])
def toData(self, imgFormat = "RGBA"):
return (self.point, self.size, self.colour,
[(pygame.image.tostring(img, imgFormat),
img.get_size(), imgFormat) for img in self.imgs], self.tags)
def fromData(data, baseTile = None):
tile = Tile(*data)
if baseTile and isinstance(baseTile, Tile):
baseTile = tile
else:
return tile
def getRect(self):
return self
def getColour(self):
return self.colour
def setColour(self, colour):
self.colour = colour
def getPoint(self):
return self.point
def addTag(self, *tags):
if isinstance(tags[0], list):
self.tags.extend(tags[0])
else:
self.tags.extend(tags)
def hasTag(self, tag):
return (tag in self.tags)
def delTag(self, tag):
self.tags.remove(tag)
def clearTags(self):
self.tags = []
def addImg(self, img, resize = False):
if isinstance(img, pygame.Surface):
if img.get_rect() != self and resize:
img = pygame.transform.scale(img, (self.size))
self.imgs.append(img)
elif img is not None:
raise TypeError("Images must be pygame.Surface object")
def delImg(self, img):
self.imgs.remove(img)
def clearImgs(self):
self.imgs = []
def isClicked(self):
return self.collidepoint(pygame.mouse.get_pos())
def draw(self, surface):
if self.colour is not None:
surface.fill(self.colour, self)
for img in self.imgs:
surface.blit(img, self)
class Grid():
def __init__(self, surface, num, colour = None, tiles = None,
force_square = False):
self.WIDTH = surface.get_width()
self.HEIGHT = surface.get_height()
self.surface = surface
aspect_ratio = _simplify(self.WIDTH, self.HEIGHT)
if isinstance(num, int):
if aspect_ratio == (1, 1) or force_square:
self.x = math.sqrt(num)
self.y = math.sqrt(num)
else:
self.x = aspect_ratio[0] * (num / product(aspect_ratio))
self.y = aspect_ratio[1] * (num / product(aspect_ratio))
else:
try:
self.x = num[0]
self.y = num[1]
except TypeError:
raise TypeError("2nd argument must be int or subscriptable")
self.tilesize = (self.WIDTH / self.x,
self.HEIGHT / self.y)
self.num = num
self.colour = colour
if tiles:
if hasattr(tiles, "__getitem__") and isinstance(tiles[0], Tile):
self.tiles = tiles
else:
self.tiles = [[Tile.fromData(tile) for tile in column]
for column in tiles]
else:
self.tiles = self.maketiles(colour)
def __getitem__(self, index):
return self.tiles[index]
def __setitem__(self, index, new):
self.tiles[index] = new
def __len__(self):
return len(self.tiles)
def index(self, tile):
for column in self.tiles:
if tile in column:
return self.tiles.index(column), column.index(tile)
def getTiles(self):
"""Get all tiles. Returns a generator"""
for column in self.tiles:
for tile in column:
yield tile
def tagSearch(self, tag):
"""Search for tiles by tag. Returns a generator"""
for tile in self.getTiles():
if tile.hasTag(tag):
yield tile
def pointSearch(self, point):
"""Search for tiles by point. Returns a tile"""
for tile in self.getTiles():
if tile.collidepoint(point):
return tile
def rectSearch(self, rect):
"""Search for tiles by rect. Returns a generator"""
for tile in self.getTiles():
if tile.colliderect(rect):
yield tile
def getColumn(self, i):
return self.tiles[i]
def getRow(self, i):
return [column[i] for column in self.tiles]
def checker(self, colour1, colour2 = None):
for column in self.tiles:
for tile in column:
if _isEven(self.tiles.index(column) + column.index(tile)):
tile.setColour(colour1)
else:
if colour2:
tile.setColour(colour2)
def getDiagonal(self, tile, direction = 1):
index = self.index(tile)
diagonal = []
currentIndex = [i - index[0] for i in index]
while currentIndex[1] != self.y:
diagonal.append(self[currentIndex[0]][currentIndex[1]])
currentIndex = [i + 1 for i in currentIndex]
return diagonal
def getBetweenTiles(self, tile1, tile2):
"""Inefficient and badly implemented"""
index1 = self.index(tile1)
index2 = self.index(tile2)
if index1[0] != index2[0] and index1[1] != index2[1]:
raise ValueError("Tiles must be in same row or column")
for column in self.tiles:
if tile1 in column and tile2 in column:
return column[column.index(tile1) : column.index(tile2)]
for i in range(self.y):
row = self.getRow(i)
if tile1 in row and tile2 in row:
return row[row.index(tile1) : row.index(tile2)]
def getSurroundingTiles(self, tile, adjacent = True, diagonal = True):
di = (0, 1, 0, -1, 1, 1, -1, -1)
dj = (1, 0, -1, 0, 1, -1, 1, -1)
# indices 0 - 3 are for horizontal, 4 - 7 are for vertical
index = list(self.getTiles()).index(tile)
max_x = self.x - 1 # Offset for 0 indexing
max_y = self.y - 1
i = int(math.floor(index / self.x))
j = int(index % self.y)
surroundingTiles = []
startat = 0 if adjacent else 4
stopat = 8 if diagonal else 4
for k in range(startat, stopat):
ni = i + di[k]
nj = j + dj[k]
if ni >= 0 and nj >= 0 and ni <= max_x and nj <= max_y:
surroundingTiles.append(self[ni][nj])
surroundingTiles.reverse()
return sorted(surroundingTiles)
def draw(self, drawGrid = False, gridColour = (0, 0, 0), gridSize = 1):
for tile in self.getTiles():
tile.draw(self.surface)
if drawGrid:
pygame.draw.rect(self.surface, gridColour, tile, gridSize)
def maketiles(self, colour):
"""Make the tiles for the grid"""
tiles = []
width = self.WIDTH / self.x
height = self.HEIGHT / self.y
for i in _range(0, self.WIDTH, width):
column = []
for j in _range(0, self.HEIGHT, height):
sq = Tile((i, j), (width, height), colour)
column.append(sq)
tiles.append(column)
return tiles
def toData(self):
return (self.num, self.colour,
[[tile.toData() for tile in column] for column in self.tiles])
def fromData(data, surface):
return Grid(*([surface] + list(data)))
Update:
I have pictorial examples of what I want to do here:
https://dl.dropboxusercontent.com/u/127476718/Images/this%20tile.png
https://dl.dropboxusercontent.com/u/127476718/Images/diags.png
To find the cells along the diagonal through another cell, you must go from this cell in the 4 diagonal directions. The following algorithm finds all cells along the diagonal in a grid of size rows x columns, starting with the cell (row, column):
cells_on_diagonals.append((row, column))
for dir in [(1, 1), (1, -1), (-1, 1), (-1, -1)]:
rn, cn = row + dir[1], column + dir[0]
while 0 <= cn < columns and 0 <= rn < rows:
cells_on_diagonals.append((rn, cn))
rn += dir[1]
cn += dir[0]
Minimal example
import pygame
pygame.init()
window = pygame.display.set_mode((350, 350))
clock = pygame.time.Clock()
grid_x, grid_y = 25, 25
tile_size, rows, columns = 20, 15, 15
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
mx, my = pygame.mouse.get_pos()
column, row = (mx - grid_x) // tile_size, (my - grid_y) // tile_size
cells_on_diagonals = []
if 0 <= column < columns and 0 <= row < rows:
cells_on_diagonals.append((row, column))
for dir in [(1, 1), (1, -1), (-1, 1), (-1, -1)]:
rn, cn = row + dir[1], column + dir[0]
while 0 <= cn < columns and 0 <= rn < rows:
cells_on_diagonals.append((rn, cn))
rn += dir[1]
cn += dir[0]
window.fill(0)
for row in range(rows):
for column in range(columns):
if (row, column) in cells_on_diagonals:
rect = (grid_x + column*tile_size, grid_y + row*tile_size, tile_size, tile_size)
pygame.draw.rect(window, "red", rect)
for column in range(columns+1):
x = grid_x + column*tile_size
pygame.draw.line(window, "white", (x, grid_y), (x, grid_x + rows*tile_size))
for row in range(rows+1):
y = grid_y + row*tile_size
pygame.draw.line(window, "white", (grid_x, y), (grid_x + columns*tile_size, y))
pygame.display.flip()
pygame.quit()
exit()

Python NameError: name -- syntax error [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
I have a compiler error “not defined” although there is a definition
from gasp import *
GRID_SIZE = 30
MARGIN = GRID_SIZE
BACKGROUND_COLOR = color.BLACK # Colors we use
WALL_COLOR = (0.6 * 255, 0.9 * 255, 0.9 * 255)
# The shape of the maze. Each character
# represents a different type of object
# % - Wall
# . - Food
# o - Capsule
# G - Ghost
# P - Chomp
# Other characters are ignored
the_layout = [
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%",
"%.....%.................%.....%",
"%o%%%.%.%%%.%%%%%%%.%%%.%.%%%o%",
"%.%.....%......%......%.....%.%",
"%...%%%.%.%%%%.%.%%%%.%.%%%...%",
"%%%.%...%.%.........%.%...%.%%%",
"%...%.%%%.%.%%% %%%.%.%%%.%...%",
"%.%%%.......%GG GG%.......%%%.%",
"%...%.%%%.%.%%%%%%%.%.%%%.%...%",
"%%%.%...%.%.........%.%...%.%%%",
"%...%%%.%.%%%%.%.%%%%.%.%%%...%",
"%.%.....%......%......%.....%.%",
"%o%%%.%.%%%.%%%%%%%.%%%.%.%%%o%",
"%.....%........P........%.....%",
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"]
class Immovable:
def is_a_wall(self):
return False
class Nothing(Immovable):
pass
class Maze:
def __init__(self):
self.have_window = False
self.game_over = False
self.set_layout(the_layout)
set_speed(20)
def set_layout(self, layout):
height = len(layout)
width = len(layout[0])
self.make_window(width, height)
self.make_map(width, height)
max_y = height - 1
for x in range( width ):
for y in range(height):
char = layout[max_y - y][x]
self.make_object((x, y), char)
def make_window(self, width, height):
grid_width = (width -1) * GRID_SIZE
grid_height = (height - 1) * GRID_SIZE
screen_width = 2 * MARGIN + grid_width
screen_height = 2 * MARGIN + grid_height
begin_graphics(screen_width, screen_height,"Chomp",BACKGROUND_COLOR)
def to_screen(self, point):
(x,y) = point
x = x * GRID_SIZE + MARGIN
y = y * GRID_SIZE + MARGIN
return(x,y)
def make_map(self, width, height):
self.width = width
self.height = height
self.map = []
for y in range(width):
new_row = []
for x in range(width):
new_row.append(Nothing())
self.map.append(new_row)
def make_object(self,point,charactor):
(x,y) = point
if charactor == "%":
self.map[y][x] = Wall(self,point)
def finished(self):
return self.game_over
def play(self):
update_when('next_tick')
def done(self):
end_graphics()
self.map = []
def object_at(self,point):
(x,y) = point
if y < 0 or y >= self.height:
return Nothing()
if x < 0 or x >= self.width:
return Nothing()
return self.map[y][x]
class Wall(Immovable):
def __init__(self, maze, point):
self.place = point # Store our position
self.screen_point = maze.to_screen(point)
self.maze = maze # Keep hold of Maze
self.draw()
def draw(self):
(screen_x, screen_y) = self.screen_point
dot_size = GRID_SIZE * 0.2
Circle(self.screen_point, dot_size,
color = WALL_COLOR, filled = 1)
(x, y) = self.place
neighbors = [ (x+1, y), (x-1, y)]
for neighbor in neighbors:
self.check_neighbor(neighbor)
def check_neighbor(self,neighbor):
maze = self.maze
object = maze.object_at(neighbor)
if object.is_a_wall():
here = self.screen_point
there = maze.to_screen(neighbor)
Line(here, there, color = WALL_COLOR,thickness = 2)
def is_a_wall(self):
return True
the_maze = Maze()
while not the_maze.finished():
the_maze.play()
the_maze.done()
I got this error..
Traceback (most recent call last): File "chomp.py", line 110, in
class Wall(Immovable): File "chomp.py", line 124, in Wall
for neighbor in neighbors: NameError: name '
neighbors' is not defined
I spent lot of time still can't find what's wrong, need some help
You never close the function call to Circle() two lines about line 122, that's probably it. You're probably missing an argument based on the trailing comma.
dot_size = GRID_SIZE * 0.2
Circle(self.screen_point, dot_size, # No closing parentheses
(x, y) = self.place
neighbors = [ (x+1, y), (x-1, y)]
for neighbor in neighbors:
self.check_neighbor(neighbor)
Circle(self.screen_point, dot_size,
missing something at the end of that line

Categories