Attribute error: Object has no attribute Python - python

I am trying to program a version of conway's game of life however I keep getting the message 'Cell' Object Has no attribute 'nextState' when it seems like it should declare the value of nextState before asking to reference it. here is my code:
from tkinter import *
root = Tk()
class Cell (Button):
Dead = 0
Live = 1
def __init__ (self,parent):
Button.__init__(self,parent, relief = "raised" , width = 2 , borderwidth = 1 , command = self.onpress)
self.displayState(Cell.Dead)
def onpress (self):
if self.state == Cell.Live:
self.displayState(Cell.Dead)
elif self.state == Cell.Dead:
self.displayState(Cell.Live)
def setNextState (self , Neighbours):
if self.state == Cell.Live and (Neighbours < 2 or Neighbours > 3):
self.nextState = Cell.Dead
elif self.state == Cell.Dead and Neighbours == 3:
self.nextState = Cell.Live
elif self.state == Cell.Dead and Neighbours != 3:
self.nextState = self.state
def stepToNextState(self):
self.displayState(self.nextState)
def displayState (self , newstate):
self.state = newstate
if self.state == Cell.Live:
self["bg"] = "black"
if self.state == Cell.Dead:
self["bg"] = "white"
class Grid:
def __init__(self,parent,sizex,sizey):
self.sizex = sizex
self.sizey = sizey
self.cells = []
for a in range (0,self.sizex):
rowcells = []
for b in range (0, self.sizey):
c = Cell(parent)
c.grid(row=b , column=a)
rowcells.append(c)
self.cells.append(rowcells)
def step (self):
cells = self.cells
for x in range (0,self.sizex):
if x==0: x_down = self.sizex-1
else: x_down = x-1
if x==self.sizex-1: x_up = 0
else: x_up = x+1
for y in range(0,self.sizey):
if y==0: y_down = self.sizey-1
else: Y_down = y-1
if y==self.sizey-1: y_up = 0
else: y_up = y+1
sum = cells[x_down][y].state + cells[x_up][y].state + cells[x][y_down].state + cells[x][y_up].state + cells[x_down][y_down].state +cells[x_up][y_up].state + cells[x_down][y_up].state + cells[x_up][y_down].state
cells[x][y].setNextState(sum)
for row in cells:
for cell in row:
cell.stepToNextState()
def clear(self):
for row in self.cells:
for cell in row:
cell.displayState(Cell.Dead)
if __name__ == "__main__":
frame = Frame(root)
frame.pack()
grid = Grid(frame,25,25)
bottomFrame = Frame(root)
bottomFrame.pack (side = BOTTOM)
buttonStep = Button(bottomFrame , text="Step" , command=grid.step)
buttonStep.pack(side = LEFT)
buttonClear = Button(bottomFrame, text = "Clear", command=grid.clear)
buttonClear.pack(side=LEFT , after=buttonStep)
root.mainloop()
The error message is:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1442, in __call__
return self.func(*args)
File "C:\Users\Owner\Desktop\Other\Programs & Misc\Python\Tyler's Game of Life.py", line 65, in step
cell.stepToNextState()
File "C:\Users\Owner\Desktop\Other\Programs & Misc\Python\Tyler's Game of Life.py", line 27, in stepToNextState
self.displayState(self.nextState)
AttributeError: 'Cell' object has no attribute 'nextState'
If anyone could point out where the error is occuring / what is causing it and possibly a way to fix it I would be very grateful.

The issue appears to be that your for row in cells loop is inside of your previous for x in range(0, self.sizex) loop. Here's what the step method should look like if you get it correctly indented:
def step (self):
cells = self.cells
for x in range (0,self.sizex):
if x==0: x_down = self.sizex-1
else: x_down = x-1
if x==self.sizex-1: x_up = 0
else: x_up = x+1
for y in range(0,self.sizey):
if y==0: y_down = self.sizey-1
else: Y_down = y-1
if y==self.sizey-1: y_up = 0
else: y_up = y+1
sum = cells[x_down][y].state + cells[x_up][y].state + cells[x][y_down].state + cells[x][y_up].state + cells[x_down][y_down].state +cells[x_up][y_up].state + cells[x_down][y_up].state + cells[x_up][y_down].state
cells[x][y].setNextState(sum)
for row in cells: # unindent these
for cell in row: # lines by one
cell.stepToNextState() # level each
If all the indentation issues are taken care of (or were not in the original code), there's still an issue that may cause an issue in certain situations. The issue is that the Cell.setNextState method doesn't handle every situation. Specifically, it doesn't set nextState if a cell is alive and should stay so (it has two or three living neighbors). The lack of an else on your chain of if and elif statements should have raised this as a red flag for me, but I overlooked it the first time I examined the function.
Here's how it can be fixed:
def setNextState (self , Neighbours):
if self.state == Cell.Live and (Neighbours < 2 or Neighbours > 3):
self.nextState = Cell.Dead
elif self.state == Cell.Dead and Neighbours == 3:
self.nextState = Cell.Live
else: # remove the conditions on this block, all the state changes were handled above
self.nextState = self.state

Related

Why do I get AttributeError: 'NoneType' object has no attribute 'contains'?

I am fairly new to coding so this might be fairly simple. I have been stuck on this error in my code for a while. I copied the code that I think will be important. The problem occurs when I call the highlightSide function as this checks squares[i][j].contains(x, y). I figure that since it says that the 'NoneType' object, then this would mean that there is a problem in the creation of the squares in the 2d array, but I don't know for sure. If this is the problem, how should I go about fixing this because I tried a variety of possible solutions, but they all resulted in the error being conveyed in a different way?
def highlightSide(x, y):
rows = len(squares)
cols = len(squares[0])
for i in range(rows):
for j in range(cols):
if squares[i][j].contains(x, y):
side = squares[i][j].highlightSide(x,y)
break
else:
continue
break
def newGame():
#random chance of who starts the new game
playersTurn = random.randint(0, 1) > 0
#set up the squares
squares = np.empty((GAME_SIZE, GAME_SIZE), dtype=object)
for i in range(GAME_SIZE):
for j in range(GAME_SIZE):
squares[i][j] = (createSquare(w, dotX(j), dotY(i), BOX))
#Create square from rectangle
class createSquare:
def __init__(self, canvas,x,y,length):
self.canvas = canvas
self.length = length
self.length = height
self.bot = y + length
self.left = x
self.right = x + length
self.top = y
self.highlight = None
self.NumSelected = 0
self.owner = None
#look into to make sure it work
#to see if in the range of the square
def contains(self, x, y):
if y>self.bot and x < self.right and y <= self.top and y >= self.left:
return True
else:
return False
def highlightSide(self, x, y):
#calcualte the distance to each side
dBot = self.bot - y
dLeft = x - self.left
dRight = self.right - x
dTop = y - self.top
#find which of them is the closest
dClosest = min(dBot, dLeft, dRight, dTop)
#make sure the color changes to highlighted color for closest if doesn't already have line
if dClosest == dBot and not self.sideBot.selected:
self.highlight = constants.BOT
elif dClosest == dLeft and not self.sideLeft.selected:
self.highlight = constants.LEFT
elif dClosest == dRight and not self.sideRight.selected:
self.highlight = constants.RIGHT
elif dClosest == dTop and not self.sideTop.selected:
self.highlight = constants.Top
#return the highlight
return self.highlight

While Not Loop running more times than intended

I have a problem where I am trying to make a word search puzzle generator and I have run into multiple problems throughout the day. (Thanks to this community I've solved most of them!)
I have another problem now where I have a loop that should find a spot to place a word, place it, and move on to the next word. Instead it is finding all possible spots the word can be and placing the word in all of them. I only want each word to appear once.
I thought that the lines while not placed and placed = true would handle this but it isn't working.
Thanks in advance for any help, and here is my code:
import tkinter as tk
import random
import string
handle = open('dictionary.txt')
words = handle.readlines()
handle.close()
grid_size = 10
words = [ random.choice(words).upper().strip() \
for _ in range(5) ]
print ("The words are:")
print(words)
grid = [ [ '_' for _ in range(grid_size) ] for _ in range(grid_size) ]
orientations = [ 'leftright', 'updown', 'diagonalup', 'diagonaldown' ]
class Label(tk.Label):
def __init__(self, parent, **kwargs):
super().__init__(parent, **kwargs, font=("Courier", 44))
#self.bind('<Button-1>', self.on_click)
#def on_click(self, event):
#w = event.widget
#row, column = w.grid_info().get('row'), w.grid_info().get('column')
#print('coord:{}'.format((row, column)))
#w.destroy()
class App(tk.Tk):
def __init__(self):
super().__init__()
for row in range(grid_size):
for column in range(grid_size):
for word in words:
word_length = len(word)
placed = False
while not placed:
orientation = random.choice(orientations)
if orientation == 'leftright':
step_x = 1
step_y = 0
if orientation == 'updown':
step_x = 0
step_y = 1
if orientation == 'diagonalup':
step_x = 1
step_y = -1
if orientation == 'diagonaldown':
step_x = 1
step_y = 1
x_position = random.randrange(grid_size)
y_position = random.randrange(grid_size)
ending_x = x_position + word_length*step_x
ending_y = y_position + word_length*step_y
if ending_x < 0 or ending_x >= grid_size: continue
if ending_y < 0 or ending_y >= grid_size: continue
failed = False
for i in range(word_length):
character = word[i]
new_position_x = x_position + i*step_x
new_position_y = y_position + i*step_y
character_at_new_position = grid[new_position_x][new_position_y]
if character_at_new_position != '_':
if character_at_new_position == character:
continue
else:
failed = True
break
if failed:
continue
else:
for i in range(word_length):
character = word[i]
new_position_x = x_position + i*step_x
new_position_y = y_position + i*step_y
grid[new_position_x][new_position_y] = character
if ( grid[row][column] == grid[new_position_x][new_position_y] ):
grid[row][column] = grid[new_position_x][new_position_y]
Label(self, text=character).grid(row=row, column=column)
placed = True
#if ( grid[row][column] == '_' ):
#txt = random.SystemRandom().choice(string.ascii_uppercase)
#Label(self, text=txt).grid(row=row, column=column)
if __name__ == '__main__':
App().mainloop()
I can assure you that your expectation of while loop is correct.
In [1]: placed = False
In [2]: i = 0
In [3]: while not placed:
...: i += 1
...: print(i)
...: if i == 5:
...: placed = True
...:
1
2
3
4
5
Given that, my suspicion is that your code always hit continue, which means it never hits the statement placed = True, hence infinite loop. So I suggest you check if your condition to continue is as expected.
Hope this helps!

presenting a menu multple times with Tkinter

I'm trying to build a simple 'Connect 4' game. In the game, I'd like a menu with radiobuttons to present itself to the user at every turn, so that he/she could pick the next move.
I've tried putting the menu into a "while" loop, but it simply doesn't do any action. I don't know how to fix it, because I don't understand exactly how tkinter works. I've seen some other questions touching on this subject, but I still can't figure out how to fix it.
Below is the code, along with the two classes I used along with it. The menu I'm trying to present in a loop is in 'present_columns_choice', which is being used in a loop in 'handle_two_humans'
Would be grateful for any help. Thanks!
from game import *
from tkinter import *
HUMAN = 0
COMPUTER = 1
GRID_SIZE = 50
NUM_ROWS = 6
NUM_COLUMNS = 7
COLOR_A = "red"
COLOR_B = "blue"
class GameGUI:
def __init__(self, root):
self.__root = root
self.__player_A = None
self.__player_B = None
def assign_player(self, player, identity):
if player == "player A":
self.__player_A = identity
elif player == "player B":
self.__player_B = identity
print("Player A is: " + str(self.__player_A))
print("Player B is: " + str(self.__player_B))
def present_player_choice(self):
self.ask_choose_player("player A")
self.ask_choose_player("player B")
Button(self.__root, text="OK", command=quit).pack(anchor=W)
def ask_choose_player(self, player):
Label(self.__root, text="Who would you like to play " + player + "?").pack(anchor=W)
var = IntVar()
Radiobutton(self.__root, text="human", variable=var,
command=lambda:self.assign_player(player, HUMAN), value=1).pack(anchor=W)
Radiobutton(self.__root, text="computer", variable=var,
command=lambda:self.assign_player(player, COMPUTER), value=2).pack(anchor=W)
def get_playerA(self):
return self.__player_A
def get_playerB(self):
return self.__player_B
def handle_two_humans(self):
game = Game()
canvas_width = GRID_SIZE*NUM_COLUMNS
canvas_height = GRID_SIZE*NUM_ROWS
canvas = Canvas(self.__root, width=canvas_width, height=canvas_height)
canvas.pack()
for row_ind in range(NUM_ROWS):
for column_ind in range(NUM_COLUMNS):
canvas.create_rectangle(column_ind*GRID_SIZE, row_ind*GRID_SIZE,
(column_ind+1)*GRID_SIZE, (row_ind+1)*GRID_SIZE)
while not IS_GAME_WON:
self.present_columns_choice(game, canvas)
def add_disc(self, game, column, canvas):
current_player = game.get_current_player()
if current_player == PLAYER_A:
self.fill_square(game, canvas, COLOR_A, column)
elif current_player == PLAYER_B:
self.fill_square(game, canvas, COLOR_B, column)
game.make_move(column)
def present_columns_choice(self, game, canvas):
columns = game.get_board().get_available_columns()
var = IntVar()
Label(self.__root, text="The following columns are still available. "
"Where would you like to place your disc?").pack(anchor=W)
for ind, column in enumerate(columns):
shown_column = column+1
Radiobutton(self.__root, text=shown_column, padx=20, variable=var, value=ind,
command=lambda column=column: self.add_disc(game, column, canvas)).pack(anchor=W)
Button(self.__root, text="OK", command=quit).pack(anchor=W)
def fill_square(self, game, canvas, color, column):
""" Fills square of column chosen by player. """
row = game.get_board().get_available_row(column)
canvas.create_rectangle(column*GRID_SIZE, row*GRID_SIZE, (column+1)*GRID_SIZE,
(row+1)*GRID_SIZE, fill = color)
if __name__ == '__main__':
root = Tk()
gui = GameGUI(root)
gui.handle_two_humans()
mainloop()
Here's the Game class, which was used here:
from board import *
PLAYER_A = 1
PLAYER_B = 2
INITIAL_ROW = 0
INITIAL_COLUMN = 0
FINAL_ROW = 5
FINAL_COLUMN = 6
ILLEGAL_LOCATION_MSG = "Illegal location."
ILLEGAL_MOVE_MSG = "Illegal move."
IS_GAME_WON = False
WINNER = None
class Game:
def __init__(self):
self.__current_player = PLAYER_A
self.__board = Board()
self.__is_game_won = False
self.__winner = None
def make_move(self, column):
""" Makes move and updates board and current player, if column is a valid choice and game is ongoing. """
possible_winner = self.__current_player
if self.__board.is_col_illegal(column) or self.__is_game_won:
raise Exception(ILLEGAL_MOVE_MSG)
self.do_move(column)
if self.__board.is_win(column):
self.__is_game_won = True
self.__winner = possible_winner
def do_move(self, column):
""" Actual implementation of the move. """
if self.__current_player == PLAYER_A:
self.__board.update_board(column, PLAYER_A)
self.__current_player = PLAYER_B
elif self.__current_player == PLAYER_B:
self.__board.update_board(column, PLAYER_B)
self.__current_player = PLAYER_A
def get_winner(self):
""" Returns winner, or None if there is none. """
return self.__winner
def get_player_at(self, row, col):
""" Returns the player whose disc is at the given position in the game. """
if row < INITIAL_ROW or row > FINAL_ROW or col < INITIAL_COLUMN or col > FINAL_COLUMN:
raise Exception(ILLEGAL_LOCATION_MSG)
return self.__board.get_board()[row][col]
def get_current_player(self):
""" Returns current_player. """
return self.__current_player
def get_board(self):
""" Returns board."""
return self.__board
And here's Board, which is used in Game:
NUM_ROWS = 6
NUM_COLUMNS = 7
INITIAL_VALUE = None
WIN_COUNT = 4
FIRST_ROW = 5
LAST_ROW = 0
class Board:
def __init__(self):
self.__playboard = []
self.__available_rows_list = NUM_COLUMNS*[NUM_ROWS-1]
initial_row = NUM_COLUMNS * [INITIAL_VALUE]
for i in range(NUM_ROWS):
self.__playboard.append(initial_row.copy())
def get_available_columns(self):
""" Returns all columns that still have empty space in them. """
available_columns = []
for col in range(len(self.__available_rows_list)):
if self.__available_rows_list[col] >= 0:
available_columns.append(col)
return available_columns
def get_playboard(self):
""" Returns board. """
return self.__playboard
def update_board(self, col, val):
""" Updates current status of board. """
row = self.__available_rows_list[col]
self.__playboard[row][col] = val
self.__update_row(col)
def __update_row(self, col):
""" Updates available_row_list. """
self.__available_rows_list[col] = self.__available_rows_list[col] - 1
def __is_col_available(self, col):
""" Checks if given col has empty spaces left on the playboard. """
if self.__available_rows_list[col] < 0:
return False
return True
def __is_col_exist(self, col):
""" Checks if given column is within the capacity of the playboard. """
if col < 0 or col >= NUM_COLUMNS:
return False
return True
def is_col_illegal(self, col):
""" Checks if given column is an illegal option. """
if not self.__is_col_available(col) or not self.__is_col_exist(col):
return True
return False
def print_playboard(self):
for row in self.__playboard:
print(row)
def is_win(self, col):
""" Checks if current state of board resulted in a win. """
row = self.__available_rows_list[col]+1
if self.__check_vertical_win(row, col) or self.__check_horizontal_win(row, col) or \
self.__check_decreasing_diagonal_win(row, col) or self.__check_increasing_diagonal_win(row, col):
return True
return False
def __check_increasing_diagonal_win(self, original_row, original_col):
""" Checks if player has won in the increasing diagonal direction. """
count = 1
player = self.__playboard[original_row][original_col]
col = original_col + 1
row = original_row - 1
while self.__is_col_exist(col) and row >= LAST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col + 1
row = row - 1
# Then: undergo same process, this time in the opposite direction.
col = original_col - 1
row = original_row + 1
while self.__is_col_exist(col) and row <= FIRST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col - 1
row = row + 1
def __check_decreasing_diagonal_win(self, original_row, original_col):
""" Checks if player has won in the decreasing diagonal direction. """
count = 1
player = self.__playboard[original_row][original_col]
col = original_col + 1
row = original_row + 1
while self.__is_col_exist(col) and row <= FIRST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col + 1
row = row + 1
# Then: undergo same process, this time in the opposite direction.
col = original_col - 1
row = original_row - 1
while self.__is_col_exist(col) and row >= LAST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col - 1
row = row - 1
def __check_vertical_win(self, original_row, col):
""" Checks if player has won in the horizontal direction. """
count = 1
player = self.__playboard[original_row][col]
row = original_row + 1
while row <= FIRST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
row = row + 1
def __check_horizontal_win(self, row, original_col):
""" Checks if player has won in the horizontal direction. """
count = 1
player = self.__playboard[row][original_col]
col = original_col + 1
while self.__is_col_exist(col) and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col + 1
# Then: undergo same process, this time in the opposite direction (the left).
col = original_col - 1
while self.__is_col_exist(col) and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col - 1
def get_available_row(self, column):
""" Returns the row which will be filled if you choose this column. """
return self.__available_rows_list[column]
The while loop inside handle_two_humans() will block the tkinter mainloop.
Since you do the move if a radiobutton is selected in the menu, why don't you just do the move when you click on the board?
Create a function check_move() in GameGUI class:
def check_move(self, game, column, canvas):
if not game.get_winner():
self.add_disc(game, column, canvas)
And modify handle_two_humands() as below:
def handle_two_humans(self):
game = Game()
canvas_width = GRID_SIZE*NUM_COLUMNS
canvas_height = GRID_SIZE*NUM_ROWS
canvas = Canvas(self.__root, width=canvas_width, height=canvas_height)
canvas.pack()
for row_ind in range(NUM_ROWS):
for column_ind in range(NUM_COLUMNS):
canvas.create_rectangle(column_ind*GRID_SIZE, row_ind*GRID_SIZE,
(column_ind+1)*GRID_SIZE, (row_ind+1)*GRID_SIZE)
# bind mouse click event to perform move
# e.x//GRID_SIZE will get the clicked column
canvas.bind('<Button-1>', lambda e: self.check_move(game, e.x//GRID_SIZE, canvas))

Python A* implementation

I am currently working on my Python game, in ika, which uses python 2.5
I decided to use A* pathfinding for the AI. However, I find it too slow for my needs (3-4 enemies can lag the game, but I would like to supply up to 4-5 without problems). I know, that such complex search like A* is not mean to be scripted in python, but I am pretty sure, that my pathfinder is also implemented in the wrong way.
My question is: How can I speed up this algorithm?
I wrote my own binary heap, and there are some try: except: lines inside some functions. Those lines can create large overhead? Are there better methods maintaining the open list?
I supplied the algorithm with graphics interface, for testing purposes (when the pathfinder finishes searching, it will write the number of iterations and seconds it takes to find the path, inside the ika.txt file. Also, Pressing A will do a complete search, and S does that step by step.)
Graphical version:
http://data.hu/get/6084681/A_star.rar
Also, here is a pastebin version:
http://pastebin.com/9N8ybX5F
Here is the main code I use for pathfinding:
import ika
import time
class Node:
def __init__(self,x,y,parent=None,g=0,h=0):
self.x = x
self.y = y
self.parent = parent
self.g = g
self.h = h
def cost(self):
return self.g + self.h
def equal(self,node):
if self.x == node.x and self.y == node.y:
return True
else:
return False
class Emerald_Pathfinder:
def __init__(self):
pass
def setup(self,start,goal):
self.start = start
self.goal = goal
self.openlist = [None,start] # Implemented as binary heap
self.closedlist = {} # Implemented as hash
self.onopenlist = {} # Hash, for searching the openlist
self.found = False
self.current = None
self.iterations = 0
def lowest_cost(self):
pass
def add_nodes(self,current):
nodes = []
x = current.x
y = current.y
self.add_node(x+1,y,current,10,nodes)
self.add_node(x-1,y,current,10,nodes)
self.add_node(x,y+1,current,10,nodes)
self.add_node(x,y-1,current,10,nodes)
# Dont cut across corners
up = map.is_obstacle((x,y-1),x,y-1)
down = map.is_obstacle((x,y+1),x,y+1)
left = map.is_obstacle((x-1,y),x-1,y)
right = map.is_obstacle((x+1,y),x+1,y)
if right == False and down == False:
self.add_node(x+1,y+1,current,14,nodes)
if left == False and up == False:
self.add_node(x-1,y-1,current,14,nodes)
if right == False and up == False:
self.add_node(x+1,y-1,current,14,nodes)
if left == False and down == False:
self.add_node(x-1,y+1,current,14,nodes)
return nodes
def heuristic(self,x1,y1,x2,y2):
return (abs(x1-x2)+abs(y1-y2))*10
def add_node(self,x,y,parent,cost,list):
# If not obstructed
if map.is_obstacle((x,y),x,y) == False:
g = parent.g + cost
h = self.heuristic(x,y,self.goal.x,self.goal.y)
node = Node(x,y,parent,g,h)
list.append(node)
def ignore(self,node,current):
# If its on the closed list, or open list, ignore
try:
if self.closedlist[(node.x,node.y)] == True:
return True
except:
pass
# If the node is on the openlist, do the following
try:
# If its on the open list
if self.onopenlist[(node.x,node.y)] != None:
# Get the id number of the item on the real open list
index = self.openlist.index(self.onopenlist[(node.x,node.y)])
# If one of the coordinates equal, its not diagonal.
if node.x == current.x or node.y == current.y:
cost = 10
else:
cost = 14
# Check, is this items G cost is higher, than the current G + cost
if self.openlist[index].g > (current.g + cost):
# If so, then, make the list items parent, the current node.
self.openlist[index].g = current.g + cost
self.openlist[index].parent = current
# Now resort the binary heap, in the right order.
self.resort_binary_heap(index)
# And ignore the node
return True
except:
pass
return False
def resort_binary_heap(self,index):
m = index
while m > 1:
if self.openlist[m/2].cost() > self.openlist[m].cost():
temp = self.openlist[m/2]
self.openlist[m/2] = self.openlist[m]
self.openlist[m] = temp
m = m / 2
else:
break
def heap_add(self,node):
self.openlist.append(node)
# Add item to the onopenlist.
self.onopenlist[(node.x,node.y)] = node
m = len(self.openlist)-1
while m > 1:
if self.openlist[m/2].cost() > self.openlist[m].cost():
temp = self.openlist[m/2]
self.openlist[m/2] = self.openlist[m]
self.openlist[m] = temp
m = m / 2
else:
break
def heap_remove(self):
if len(self.openlist) == 1:
return
first = self.openlist[1]
# Remove the first item from the onopenlist
self.onopenlist[(self.openlist[1].x,self.openlist[1].y)] = None
last = self.openlist.pop(len(self.openlist)-1)
if len(self.openlist) == 1:
return last
else:
self.openlist[1] = last
v = 1
while True:
u = v
# If there is two children
if (2*u)+1 < len(self.openlist):
if self.openlist[2*u].cost() <= self.openlist[u].cost():
v = 2*u
if self.openlist[(2*u)+1].cost() <= self.openlist[v].cost():
v = (2*u)+1
# If there is only one children
elif 2*u < len(self.openlist):
if self.openlist[2*u].cost() <= self.openlist[u].cost():
v = 2*u
# If at least one child is smaller, than parent, swap them
if u != v:
temp = self.openlist[u]
self.openlist[u] = self.openlist[v]
self.openlist[v] = temp
else:
break
return first
def iterate(self):
# If the open list is empty, exit the game
if len(self.openlist) == 1:
ika.Exit("no path found")
# Expand iteration by one
self.iterations += 1
# Make the current node the lowest cost
self.current = self.heap_remove()
# Add it to the closed list
self.closedlist[(self.current.x,self.current.y)] = True
# Are we there yet?
if self.current.equal(self.goal) == True:
# Target reached
self.goal = self.current
self.found = True
print self.iterations
else:
# Add the adjacent nodes, and check them
nodes_around = self.add_nodes(self.current)
for na in nodes_around:
if self.ignore(na,self.current) == False:
self.heap_add(na)
def iterateloop(self):
time1 = time.clock()
while 1:
# If the open list is empty, exit the game
if len(self.openlist) == 1:
ika.Exit("no path found")
# Expand iteration by one
self.iterations += 1
# Make the current node the lowest cost
self.current = self.heap_remove()
# Add it to the closed list
self.closedlist[(self.current.x,self.current.y)] = True
# Are we there yet?
if self.current.equal(self.goal) == True:
# Target reached
self.goal = self.current
self.found = True
print "Number of iterations"
print self.iterations
break
else:
# Add the adjacent nodes, and check them
nodes_around = self.add_nodes(self.current)
for na in nodes_around:
if self.ignore(na,self.current) == False:
self.heap_add(na)
time2 = time.clock()
time3 = time2-time1
print "Seconds to find path:"
print time3
class Map:
def __init__(self):
self.map_size_x = 20
self.map_size_y = 15
self.obstructed = {} # Library, containing x,y couples
self.start = [2*40,3*40]
self.unit = [16*40,8*40]
def is_obstacle(self,couple,x,y):
if (x >= self.map_size_x or x < 0) or (y >= self.map_size_y or y < 0):
return True
try:
if self.obstructed[(couple)] != None:
return True
except:
return False
def render_screen():
# Draw the Character
ika.Video.DrawRect(map.start[0],map.start[1],map.start[0]+40,map.start[1]+40,ika.RGB(40,200,10),1)
# Draw walls
for x in range(0,map.map_size_x):
for y in range(0,map.map_size_y):
if map.is_obstacle((x,y),x,y) == True:
ika.Video.DrawRect(x*40,y*40,(x*40)+40,(y*40)+40,ika.RGB(168,44,0),1)
# Draw openlist items
for node in path.openlist:
if node == None:
continue
x = node.x
y = node.y
ika.Video.DrawRect(x*40,y*40,(x*40)+40,(y*40)+40,ika.RGB(100,100,100,50),1)
# Draw closedlist items
for x in range(0,map.map_size_x):
for y in range(0,map.map_size_y):
try:
if path.closedlist[(x,y)] == True:
ika.Video.DrawRect(x*40,y*40,(x*40)+20,(y*40)+20,ika.RGB(0,0,255))
except:
pass
# Draw the current square
try:
ika.Video.DrawRect(path.current.x*40,path.current.y*40,(path.current.x*40)+40,(path.current.y*40)+40,ika.RGB(128,128,128), 1)
except:
pass
ika.Video.DrawRect(mouse_x.Position(),mouse_y.Position(),mouse_x.Position()+8,mouse_y.Position()+8,ika.RGB(128,128,128), 1)
# Draw the path, if reached
if path.found == True:
node = path.goal
while node.parent:
ika.Video.DrawRect(node.x*40,node.y*40,(node.x*40)+40,(node.y*40)+40,ika.RGB(40,200,200),1)
node = node.parent
# Draw the Target
ika.Video.DrawRect(map.unit[0],map.unit[1],map.unit[0]+40,map.unit[1]+40,ika.RGB(128,40,200),1)
def mainloop():
while 1:
render_screen()
if mouse_middle.Pressed():
# Iterate pathfinder
if path.found == False:
path.iterateloop()
elif mouse_right.Pressed():
# Iterate pathfinder by one
if path.found == False:
path.iterate()
elif ika.Input.keyboard["A"].Pressed():
# Iterate pathfinder
if path.found == False:
path.iterateloop()
elif ika.Input.keyboard["S"].Pressed():
# Iterate pathfinder by one
if path.found == False:
path.iterate()
elif mouse_left.Position():
# Add a square to the map, to be obstructed
if path.iterations == 0:
x = mouse_x.Position()
y = mouse_y.Position()
map.obstructed[(int(x/40),int(y/40))] = True
# Mouse preview
x = mouse_x.Position()
y = mouse_y.Position()
mx = int(x/40)*40
my = int(y/40)*40
ika.Video.DrawRect(mx,my,mx+40,my+40,ika.RGB(150,150,150,70),1)
ika.Video.ShowPage()
ika.Input.Update()
map = Map()
path = Emerald_Pathfinder()
path.setup(Node(map.start[0]/40,map.start[1]/40),Node(map.unit[0]/40,map.unit[1]/40))
mouse_middle = ika.Input.mouse.middle
mouse_right = ika.Input.mouse.right
mouse_left = ika.Input.mouse.left
mouse_x = ika.Input.mouse.x
mouse_y = ika.Input.mouse.y
# Initialize loop
mainloop()
I appreciate any help!
(sorry for any spelling mistakes, English is not my native language)
I think a proper implementation in python will be fast enough for your purposes. But the boost library has an astar implementation and python bindings. https://github.com/erwinvaneijk/bgl-python

update_idletasks difficulty in python tkinter

I'm having trouble calling .update_idletasks() to redraw my canvas ( at the end of the .set_up() Class-method ).
If I use self.canv.update_idletasks( self ), the canvas draws the objects I want but gives the error
TypeError: update_idletasks() takes exactly 1 argument (2 given)
If I use self.canv.update_idletasks(), the canvas remains blank but doesn't produce any errors.
from Tkinter import *
class Animation(Frame):
def __init__(self,parent=None):
Frame.__init__(self,parent)
self.pack()
self.generation = 1
self.epoch = 1
self.set_up()
def set_up(self):
greeting_text = 'Generation ' + str(self.generation) + ', Epoch ' + str(self.epoch)
header = Label(self,text=greeting_text)
header.pack()
anframe = Frame(self,relief=SUNKEN)
anframe.pack(side='left',padx=10,pady=10)
self.canv = Canvas(anframe,width=800, height=800, bg='white') # 0,0 is top left corner
self.canv.pack(expand=YES, fill=BOTH,side='left')
buframe = Frame(self,relief=RAISED)
buframe.pack(side='right',fill=X,padx=10,pady=5)
start = Button(buframe,text='START',width=10,command=self.animate)
start.pack(expand=YES,fill=BOTH,side='top')
back = Button(buframe,text='Back',width=10)
back.pack(expand=YES,fill=BOTH,side='bottom')
nextgo= Button(buframe,text='Next',width=10)
nextgo.pack(expand=YES,fill=BOTH,side='bottom')
path = 'C:/Desktop/LearnNet/' + str(self.generation) + '_' + str(self.epoch) + '.txt'
data = open(path,'r')
lines = data.readlines()
food,moves = [],[]
for item in lines:
if item.strip() == 'f':
dat_type = 1
continue
elif item.strip() == 'a':
dat_type = 2
continue
if dat_type == 1:
temp = item.strip()
temp = item.split()
food.append([int(temp[0]),int(temp[1])])
if dat_type == 2:
temp = item.strip()
temp = item.split()
moves.append([int(temp[0]),int(temp[1]),int(temp[2])])
photos = []
for i in xrange(len(food)):
temp=PhotoImage(file='C:/Desktop/LearnNet/Food.gif')
photos.append(temp)
self.canv.create_image(food[i][0]*20,food[i][1]*20,image=photos[i],anchor=NW)
start_pos = moves[0]
picpath = self.orientation(start_pos[2])
animal = PhotoImage(file=picpath)
self.canv.create_image(moves[0][0]*20,moves[0][1]*20,image=animal,anchor=NW)
self.canv.update_idletasks(self)
def animate(self):
return 1
def orientation(self,angle):
if angle == 0:
picpath = 'C:/Desktop/LearnNet/PEast.gif'
elif angle == 90:
picpath = 'C:/Desktop/LearnNet/PNorth.gif'
elif angle == 180:
picpath = 'C:/Desktop/LearnNet/PWest.gif'
else:
picpath = 'C:/Desktop/LearnNet/PSouth.gif'
return picpath
if __name__ == '__main__': Animation().mainloop()
self in python is actually syntactic sugar.
In other words, when you say self.animate(), python translates it to Animation.animate(self). That's why you define the class methods with that "self" argument -- it's passed implicitly.
self.canv.update_idletasks(self) is evaluating to something like Canvas.update_idletasks(self.canv, self).
I found a solution by looking at some similar code. self.canv.get_tk_widgets().update_idletasks() does the trick, thought I am not quite sure WHY this works, If anyone could explain or point me to some reading. Thanks

Categories

Resources