Python Tic Tac Toe using minimax does not make best move - python-3.x

I have been trying to get this to work for over a week now and cant seem to get it to choose the best possible move. Can someone take a look and help me out? I feel like I have missed something stupid.
Thanks!
from tkinter import *
import tkinter.messagebox
tk = Tk()
tk.title("Tic Tac Toe")
click = True
X = "X"
O = "O"
EMPTY = " "
TIE = "TIE"
NUM_SQUARES = 9
def new_board():
"""Create new game board."""
board = []
for square in range(NUM_SQUARES):
board.append(EMPTY)
return board
def Player1Win(board, i):
if(board[0]==1 and board[1]==1 and board[2]==1)or(board[0]==1 and board[3]==1 and board[6]==1)or(board[2]==1 and board[5]==1 and board[8]==1)or(board[3]==1 and board[4]==1 and board[5]==1)or(board[6]==1 and board[7]==1 and board[8]==1)or(board[0]==1 and board[4]==1 and board[8]==1)or(board[2]==1 and board[4]==1 and board[6]==1)or(board[1]==1 and board[4]==1 and board[7]==1)or(board[0]==1 and board[3]==1 and board[6]==1):
if(i==0):
tkinter.messagebox.showinfo("Winner X won")
return True
else:
return False
def Player2Win(board, i):
if(board[0]==0 and board[1]==0 and board[2]==0)or(board[0]==0 and board[3]==0 and board[6]==0)or(board[2]==0 and board[5]==0 and board[8]==0)or(board[3]==0 and board[4]==0 and board[5]==0)or(board[6]==0 and board[7]==0 and board[8]==0)or(board[0]==0 and board[4]==0 and board[8]==0)or(board[2]==0 and board[4]==0 and board[6]==0)or(board[1]==0 and board[4]==0 and board[7]==0):
if(i==0):
tkinter.messagebox.showinfo("Winner O won")
return True
else:
return False
board2=new_board()
board=new_board()
def legal_moves(board):
"""Create list of legal moves."""
moves = []
count = 0
for square in range(NUM_SQUARES):
if board[square] == EMPTY:
count += 1
moves.append(square)
print(count)
return moves
def minimax(board2):
global click
#Get all possible steps
moves=legal_moves(board2)
#Check copy board to win
if(Player1Win(board2,2) == True):
return 10
if(Player2Win(board2,2) == True):
return -10
if(len(moves)==0):
return 0
j = 1000
for i in moves:
if click:
click=True #change to Player X
board2[i]=0 #This is a copy of the board is not the main
else:
click=False #to change Player O
board2[i]=1 #This is a copy of the board is not the main
v = minimax(board2) # Recursive call functions
# # Select the minimum number for O and maximum for X
if j == 1000 or (click == False and j < v) or (click == True and v < j):
j = v
if click:
return j-1 # If player O
else:
return j+1 # If player X
def bestMove():
global click
# Get all possible steps
moves=legal_moves(board)
# Move all the data from the main board
for k in range(NUM_SQUARES):
board2.append(board[k])
j = 1000
best = -1
for i in moves:
if click:
click = False #change to Player X
board2[i]=0
else:
click = True #change to Player O
board2[i]=1
v = minimax(board2)
# Select the minimum number for O and maximum for X
if j == 1000 or (click == False and j < v) or (click == True and v < j):
j = v
best = i
return best
def Update(board):
global click
if button1["text"]=="X":
board[0]=1
if button2["text"]=="X":
board[1]=1
if button3["text"]=="X":
board[2]=1
if button4["text"]=="X":
board[3]=1
if button5["text"]=="X":
board[4]=1
if button6["text"]=="X":
board[5]=1
if button7["text"]=="X":
board[6]=1
if button8["text"]=="X":
board[7]=1
if button9["text"]=="X":
board[8]=1
if button1["text"]=="O":
board[0]=0
if button2["text"]=="O":
board[1]=0
if button3["text"]=="O":
board[2]=0
if button4["text"]=="O":
board[3]=0
if button5["text"]=="O":
board[4]=0
if button6["text"]=="O":
board[5]=0
if button7["text"]=="O":
board[6]=0
if button8["text"]=="O":
board[7]=0
if button9["text"]=="O":
board[8]=0
def move(i):
global click
click = False
if i == 0:
button1["text"] = "O"
board[0]=0
elif i == 1:
button2["text"] = "O"
board[1]=0
elif i == 2:
button3["text"] = "O"
board[2]=0
elif i == 3:
button4["text"] = "O"
board[3]=0
elif i == 4:
button5["text"] = "O"
board[4]=0
elif i == 5:
button6["text"] = "O"
board[5]=0
elif i == 6:
button7["text"] = "O"
board[6]=0
elif i == 7:
button8["text"] = "O"
board[7]=0
elif i == 8:
button9["text"] = "O"
board[8]=0
def checker(buttons):
global click
if buttons["text"] == " ":
buttons["text"] = "X"
click = True
Update(board)
best = bestMove()
move(best)
Player1Win(board, 0)
Player2Win(board, 0)
buttons = StringVar()
button1 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button1))
button1.grid(row=1,column=0,sticky = S+N+E+W)
button2 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button2))
button2.grid(row=1,column=1,sticky = S+N+E+W)
button3 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button3))
button3.grid(row=1,column=2,sticky = S+N+E+W)
button4 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button4))
button4.grid(row=2,column=0,sticky = S+N+E+W)
button5 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button5))
button5.grid(row=2,column=1,sticky = S+N+E+W)
button6 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button6))
button6.grid(row=2,column=2,sticky = S+N+E+W)
button7 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button7))
button7.grid(row=3,column=0,sticky = S+N+E+W)
button8 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button8))
button8.grid(row=3,column=1,sticky = S+N+E+W)
button9 = Button(tk,text=" ",font=('Times 26 bold'), height = 4, width = 8, command =lambda:checker(button9))
button9.grid(row=3,column=2,sticky = S+N+E+W)
tk.mainloop()
print ("Please Begin Play")

I would suggest you add print statements to see what is happening. Start with printing "click" for each pass through the for() loop and also print what the return (j +- 1) and the value for "i" right before the return statements (and please don't use "i", "l", or "O" as single digit variable names as they can look like numbers, i.e, o=1, o=l). You can handle the really, really long and really, really, confusing line a lot better with a list of win combinations.
## a simple example that will require some modification by you
def check_for_winner(player, board):
## fill in the rest yourself
win_combos=[[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 4, 8], [0, 3, 6]]
for x, y, z in win_combos:
print "checking", x, y, z
if board[x] == board[y] == board[z]:
print "**** We have a winner", player, x, y, z
return True
return False

Related

I keep getting "pygame.sprite.Sprite.add() argument after * must be an iterable, not int" error

I am trying to make a platforming game and I keep getting this error when I tried to add particles for when the character jumps, and I can't figure it out. Everytime I try and jump with the character the error pops up. I will need some help in order to fix this.
Code for the Level
import pygame
# Importing the necessary files
from tiles import Tile
from settings import tile_size, screen_width
from player import Player
from particles import ParticleEffect
class Level:
def __init__(self, level_data, surface):
# Level setup
self.display_surface = surface
self.setup_level(level_data)
self.world_shift = 0
self.current_x = 0
# Particles
self.dust_sprite = pygame.sprite.GroupSingle()
def setup_level(self, layout):
self.tiles = pygame.sprite.Group()
self.player = pygame.sprite.GroupSingle()
for row_index, row in enumerate(layout):
for column_index, cell in enumerate(row):
x = column_index * tile_size
y = row_index * tile_size
if cell == "X":
tile = Tile((x, y), tile_size)
self.tiles.add(tile)
if cell == "P":
player_sprite = Player((x, y), self.display_surface, self.jump_particles)
self.player.add(player_sprite)
def jump_particles(self, pos):
jump_particle_sprite = ParticleEffect(pos, 'Jump')
self.dust_sprite.add(jump_particle_sprite)
def scroll_x(self):
player = self.player.sprite
player_x = player.rect.centerx
direction_x = player.direction.x
if player_x < screen_width / 4 and direction_x < 0:
self.world_shift = 8
player.speed = 0
elif player_x > screen_width - (screen_width / 4) and direction_x > 0:
self.world_shift = -8
player.speed = 0
else:
self.world_shift = 0
player.speed = 8
# Checks for horizontal collisions with the tiles
def horizontal_collision(self):
player = self.player.sprite
player.rect.x += player.direction.x * player.speed
for sprite in self.tiles.sprites():
if sprite.rect.colliderect((player.rect)):
if player.direction.x < 0:
player.rect.left = sprite.rect.right
player.on_left = True
self.current_x = player.rect.left
elif player.direction.x > 0:
player.rect.right = sprite.rect.left
player.on_right = True
self.current_x = player.rect.right
if player.on_left == True and (player.rect.left < self.current_x or player.direction.x >= 0):
player.on_left = False
if player.on_right == True and (player.rect.left > self.current_x or player.direction.x <= 0):
player.on_right = False
def vertical_collision(self):
player = self.player.sprite
player.apply_gravity()
for sprite in self.tiles.sprites():
if sprite.rect.colliderect((player.rect)):
if player.direction.y > 0:
player.rect.bottom = sprite.rect.top
player.direction.y = 0
player.on_ground = True
elif player.direction.y < 0:
player.rect.top = sprite.rect.bottom
player.direction.y = 0
player.on_ceiling = True
if player.on_ground == True and player.direction.y < 0 or player.direction.y > 1:
player.on_ground = False
if player.on_ceiling == True and player.direction.y > 0:
player.on_ceiling = False
def run(self):
# Tiles for the level
self.tiles.update(self.world_shift)
self.tiles.draw(self.display_surface)
self.scroll_x()
# Dust Particles
self.dust_sprite.update(self.world_shift)
self.dust_sprite.draw(self.display_surface)
# Player for the level
self.player.update()
self.horizontal_collision()
self.vertical_collision()
self.player.draw(self.display_surface)
Code for the Class ParticleEffect
import pygame
from support import import_folder
class ParticleEffect(pygame.sprite.Sprite):
def _init__(self, pos, type):
super().__init__()
self.frame_index = 0
self.animation_speed = 0.5
if type == 'Jump':
self.frames = import_folder('Hero/Dust Particles/Jump')
if type == 'Land':
self.frames = import_folder('Hero/Dust Particles/Land')
self.image = self.frames[self.frame_index]
self.rect = self.image.get_rect(center = pos)
def animate(self):
self.frame_index += self.animation_speed
if self.frame_index >= len(self.frames):
self.kill()
else:
self.image = self.frames[int(self.frame_index)]
def update(self, x_shift):
self.animate()
self.rect.x += x_shift
import_folder is just a class used for loading images.
The full error is
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\player.py", line 109, in get_input
self.jump_particles(self.rect.midbottom)
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\level.py", line 35, in jump_particles
jump_particle_sprite = ParticleEffect(pos, 'Jump')
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\venv\lib\site-packages\pygame\sprite.py", line 115, in __init__
self.add(*groups)
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\venv\lib\site-packages\pygame\sprite.py", line 133, in add
self.add(*group)
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\venv\lib\site-packages\pygame\sprite.py", line 133, in add
self.add(*group)
TypeError: pygame.sprite.Sprite.add() argument after * must be an iterable, not int
You have a typo in the __init__() method in your ParticleEffect class that is causing this issue.
The def _init__(self, pos, type) is missing a underscore _ at the beginning.

Tkinter convert entry.get() to integer problem

I am coding a program with Tkinter to calculate wind values. It takes Rwy Heading, Wind Direction and Wind Speed to calculate the wind whether headwind, tailwind or crosswind with the calculated relevant wind speed.
I get this error:
Traceback (most recent call last):
File "C:\Users\altug\Desktop\PROJECTS\ÇALIŞMA.py", line 40, in <module>
rwy_var= int(rwy)
ValueError: invalid literal for int() with base 10: ''
I both tried IntVar() and int(str) method to convert string into integer but it didn't sort out the problem.
Below you can find my code:
ent1 = Entry(root)
ent1.grid(row = 0, column = 1)
ent2 = Entry(root)
ent2.grid(row = 1, column = 1)
ent3 = Entry(root)
ent3.grid(row = 2, column = 1)
rwy = ent1.get()
wind_direction = ent2.get()
wind_speed = ent3.get()
rwy_var= IntVar()
wind_direction_var= IntVar()
wind_speed_var = IntVar()
rwy_var= int(rwy)
wind_direction_var= int(wind_direction)
wind_speed_var = int(wind_speed)
x = rwy_var - wind_direction_var
radx = math.radians(x)
sinx = math.sin(radx)
cosx = math.cos(radx)
def htwind():
txt.delete(0.0, "end")
b = rwy_var + 90
a = rwy_var - 90
if b > 360:
b -= 360
elif a <0:
a+= 360
if x == abs(90):
result = 0
txt.insert(0.0, result +'\n')
elif a <= wind_direction_var or wind_direction_var<= b :
sh = wind_speed_var * cosx
result = "Headwind"+ " " + round(abs(sh))+ " " + "kt"
txt.insert(0.0, result +'\n')
elif a >= wind_direction_var or wind_direction_var >= b :
st = wind_speed_var * cosx
result = "Tailwind"+ " " + round(abs(st))+ " " + "kt"
txt.insert(0.0, result +'\n')
return ""
def xwind():
txt.delete(0.0, "end")
c=rwy_var-180
d= rwy_var + 180
if d > 360:
d -= 360
elif c<0:
c+= 360
if x == 0 or x == abs(180) or y == 0 or y == abs(180):
print("0")
elif c< wind_direction_var:
sxwl = wind_speed_var * sinx
rslt = "L"+""+round(abs(sxwl))+""+"kt"
txt.insert(0.0, rslt +'\n')
elif wind_direction_var<d:
sxwr = wind_speed_var * sinx
rslt = "R"+""+round(abs(sxwr))+""+"kt"
txt.insert(0.0, rslt +'\n')
return ""
txt = Text(root, width=6, height=2, wrap =WORD)
txt.grid(row =1, column = 1)
button_1 =Button(root, text = "search", command=lambda:[htwind(),xwind()])
button_1.grid(row =0, column = 5)
What is my mistake ?
Thanks in advance.
The IntVar is special in that it can't be directly converted to an int. To get its int value, do
rwy_var = rwy.get()

Is there any possible way to create a hitbox using tkinter frame?

I have a tkinter frame and 2 sprites, I can easily make my vel = 0 when I'm at the exact pos of the wall. The issue is, that inside the sprite (I need the character to stop when he hits the edge of the wall).
import tkinter ##SETUP##
from tkinter import *
import threading
from threading import Timer
window = Tk() ##WINDOW SETUP##
window.title("Project Gladiator, Pre-Alpha 0.3")
window.config(bg = "white")
frame = Frame(window, width = 1000, height = 1000)
frame.grid(row = 0, column = 0)
frame.focus_set()
Px = 50 #char pos ##VARIABLES##
Py = 50 #char pos
X = 5 #char Xcel
Xchange = 5 #sets X
Direction = "Down" #different sprites based on movement
Level = 0 #used for collision (starts from 0)
PlayerF1 = PhotoImage(file = "Mainchar.png") #replace by each frame ##MAIN CHAR##
Playerd = Label(frame, image = PlayerF1)
Playerd.place(x = Px, y = Py)
w = False #movement button presses
a = False #movement button presses
s = False #movement button presses
d = False #movement button presses
##########################################################################---LEVEL---DRAWING---##########################################################################
#TEXTURES#
Wallimg = PhotoImage(file = "Lategame-tile.png")
#TESTLEVELONE#
Walltest = Label(window, image = Wallimg)
WalltestX = 30
WalltestY = 30
##########################################################################---MOVEMENT---##########################################################################
def keypress(event):
if event.char == "w":
global w
global a
global s
global d
global Xchange
w = True
elif event.char == "a":
a = True
elif event.char == "s":
s = True
elif event.char == "d":
d = True
elif event.char == "`":
Console = Tk()
Console.title("Console")
Console.config(bg = "green")
Output = Label(Console, text = "Output", bg = "green", fg = "yellow", font = "none 9")
#output goes here...
Input = Label(Console, text = "Input", bg = "green", fg = "yellow", font = "none 9")
Commandline = Entry(Console, bg = "white")
def SubmitCommand():
Command = Commandline.get()
print(f"Command Submitted \"{Command}\"")
Commandline.delete(0, END)
Commandsub = Button(Console, text = "Submit", bg = "green", fg = "yellow", command = SubmitCommand)
Output.grid(row = 0, column = 0)
Input.grid(row = 2, column = 0)
Commandline.grid(row = 3, column = 0)
Commandsub.grid(row = 3, column = 1)
def keyup(event):
if event.char == "w":
global w
global a
global s
global d
w = False
elif event.char == "a":
a = False
elif event.char == "s":
s = False
elif event.char == "d":
d = False
def wpress():
def wcheck():
if w == True:
global Direction
global Py
global Px
global X
global Xchange
X = Xchange
Direction = "Up"
Py = Py - X
if Level == 0 and Py == 30 and Px == 30:
Py = Py + X
Playerd.place(x = Px, y = Py)
elif w == False:
X = 0
if a == True:
X = Xchange
Direction = "Right"
Px = Px - X
if Level == 0 and Py == 30 and Px == 30:
Px = Px + X
Playerd.place(x = Px, y = Py)
elif w == False:
X = 0
if s == True:
X = Xchange
Direction = "Down"
Py = Py + X
if Level == 0 and Py == 30 and Px == 30:
Py = Py - X
Playerd.place(x = Px, y = Py)
elif w == False:
X = 0
if d == True:
X = Xchange
Direction = "Left"
Px = Px + X
if Level == 0 and Py == 30 and Px == 30:
Px = Px - X
Playerd.place(x = Px, y = Py)
elif w == False:
X = 0
wpress()
c = Timer(0.001, wcheck)
c.start()
frame.bind("<Key>", keypress)
frame.bind("<KeyRelease>", keyup)
wpress()
##########################################################################---END---MOVEMENT---##########################################################################
##########################################################################---LEVELS---##########################################################################
def DrawTEST1(): #wall test
Walltest.place(x = WalltestX, y = WalltestY)
DrawTEST1()
window.mainloop()
The focus is on this part
def wpress():
def wcheck():
if w == True:
global Direction
global Py
global Px
global X
global Xchange
X = Xchange
Direction = "Up"
Py = Py - X
if Level == 0 and Py == 30 and Px == 30:
Py = Py + X
Playerd.place(x = Px, y = Py)
elif w == False:
X = 0
if a == True:
X = Xchange
Direction = "Right"
Px = Px - X
if Level == 0 and Py == 30 and Px == 30:
Px = Px + X
Playerd.place(x = Px, y = Py)
elif w == False:
X = 0
if s == True:
X = Xchange
Direction = "Down"
Py = Py + X
if Level == 0 and Py == 30 and Px == 30:
Py = Py - X
Playerd.place(x = Px, y = Py)
elif w == False:
X = 0
if d == True:
X = Xchange
Direction = "Left"
Px = Px + X
if Level == 0 and Py == 30 and Px == 30:
Px = Px - X
Playerd.place(x = Px, y = Py)
elif w == False:
X = 0
wpress()
c = Timer(0.001, wcheck)
c.start()
frame.bind("<Key>", keypress)
I have been pulling my hair out on this one for quite some time. If anyone can help then that would be great! Thanks in advance!
Not sure if you figured it out yet, but since I encountered something in the same vain as this, I'd like to share what I came up with.
Just keep in mind that Tkinter isn't exactly made for this sort of thing, and something like Pygame would be a better choice.
The simple way:
If your sprite is a simple one, like a square shape, just points in each direction slightly outside your sprite, and on each move check if that point is overlapping with the wall or not.
Example: if your sprite is 25x25, then you could have the center as x, y, and the point for collision detection to the right could then be x+26, y. The left could then be x-26, y.
The problem here is that you are using labels in a frame, so you'd either have to figure out the position with trail and error, or use the .bbox method.
The slightly more complicated way (but ultimately the easier way):
If your sprite has somewhat of an odd shape, and you want it to be more accurate, you could put it on a Canvas instead of a Frame. That gives you the option to draw out a polygon that you can trace around the sprite. Then have it move with the sprite, and simply check if that overlaps with a wall, enemy, bullet, trap or whatever else you can think of. This would give you far more flexibility.
Canvas is also a better choice in general if you want to do more complex things, as it allows you to move things around easier, draw out shapes, set tags ect. You can still put labels, buttons and all that good stuff on a canvas if you want those, no need to use a frame unless you are just packing stuff into it.
Lastly I would highly recommend using classes, it will make your life so much easier and is one of the major strengths of the language. They can be a bit confusing at first, but it is worth the time it takes to learn many times over. Once you get used to them, you'll wonder how you managed to do anything without them.

List in object gets overwritten

After some work I finished my first algorithm for a maze generator and now I am trying to make it visual in Pygame. I first let the algorithm generate a maze and then I make a visual representation of it.
Here I get into multiple problems, but I think they are all linked to the same thing which is that the first cell of the maze gets overwritten in some way. Because of this, what I get is totally not a maze at all but just some lines everywhere.
I tried putting the removal of walls in a seperate method, but that does not seem to work also. I looked if the remove walls method gets called at the first cell and it says it is true, but in some way the values of that cell gets overwritten.
Code:
import pygame
import random
WIDTH = 300
HEIGHT = 300
CellSize = 30
Rows = int(WIDTH/30)
Columns = int(HEIGHT/30)
current = None
grid = []
visited = []
DISPLAY = pygame.display.set_mode((WIDTH, HEIGHT))
class Cell:
def __init__(self, r, c):
self.r = r
self.c = c
self.x = CellSize * c
self.y = CellSize * r
self.sides = [True, True, True, True] # Top, Bottom, Left, Right
self.visited = False
self.neighbours = []
self.NTop = None
self.NBottom = None
self.NRight = None
self.NLeft = None
self.NTopIndex = None
self.NBottomIndex = None
self.NRightIndex = None
self.NLeftIndex = None
self.nr = None
self.nc = None
self.random = None
self.neighbour = None
def index(self, nr, nc):
self.nr = nr
self.nc = nc
if self.nr < 0 or self.nc < 0 or self.nr > Rows-1 or self.nc > Columns-1:
return -1
return self.nr + self.nc * Columns
def neighbour_check(self):
# Get neighbour positions in Grid
self.NTopIndex = self.index(self.r, self.c - 1)
self.NBottomIndex = self.index(self.r, self.c + 1)
self.NRightIndex = self.index(self.r + 1, self.c)
self.NLeftIndex = self.index(self.r - 1, self.c)
# Look if they are truly neighbours and then append to neighbour list
if self.NTopIndex >= 0:
self.NTop = grid[self.NTopIndex]
if not self.NTop.visited:
self.neighbours.append(self.NTop)
if self.NBottomIndex >= 0:
self.NBottom = grid[self.NBottomIndex]
if not self.NBottom.visited:
self.neighbours.append(self.NBottom)
if self.NRightIndex >= 0:
self.NRight = grid[self.NRightIndex]
if not self.NRight.visited:
self.neighbours.append(self.NRight)
if self.NLeftIndex >= 0:
self.NLeft = grid[self.NLeftIndex]
if not self.NLeft.visited:
self.neighbours.append(self.NLeft)
# Choose random neighbour
if len(self.neighbours) > 0:
self.random = random.randint(0, len(self.neighbours) - 1)
self.neighbour = self.neighbours[self.random]
# Remove the wall between self and neighbour
if self.neighbour == self.NTop:
if self == grid[0]:
print('TOP')
self.sides[0] = False
self.NTop.sides[1] = False
elif self.neighbour == self.NBottom:
if self == grid[0]:
print('BOTTOM')
self.sides[1] = False
self.NBottom.sides[0] = False
elif self.neighbour == self.NLeft:
if self == grid[0]:
print('LEFT')
self.sides[2] = False
self.NLeft.sides[3] = False
elif self.neighbour == self.NRight:
if self == grid[0]:
print('RIGHT')
self.sides[3] = False
self.NRight.sides[2] = False
else:
print('SIDES ERROR')
return self.neighbours[self.random]
else:
return -1
def draw(self):
global DISPLAY, CellSize
# Top
if self.sides[0]:
pygame.draw.line(DISPLAY, (0, 0, 0), (self.x, self.y), (self.x + CellSize, self.y))
# Bottom
if self.sides[1]:
pygame.draw.line(DISPLAY, (0, 0, 0), (self.x, self.y + CellSize), (self.x + CellSize, self.y + CellSize))
# Left
if self.sides[2]:
pygame.draw.line(DISPLAY, (0, 0, 0), (self.x, self.y), (self.x, self.y + CellSize))
# Right
if self.sides[3]:
pygame.draw.line(DISPLAY, (0, 0, 0), (self.x + CellSize, self.y), (self.x + CellSize, self.y + CellSize))
class Maze:
def __init__(self):
global current
self.next = None
self.running = True
self.DISPLAY = None
self.display_running = True
def init_cells(self):
# Make grid and make cell 0 the begin of the algorithm
global current
for i in range(0, Columns):
for j in range(0, Rows):
cell = Cell(j, i)
grid.append(cell)
current = grid[0]
def init_maze(self):
global current, visited
print(grid[0].sides)
# Start Algorithm
while self.running:
# Check if the current cell is visited, if not make it visited and choose new neighbour
if not current.visited:
current.visited = True
visited.append(current)
self.next = current.neighbour_check()
if not self.next == -1:
# If it finds a neighbour then make it the new current cell
# self.next.visited = True
current = self.next
elif self.next == -1 and len(visited) > 0:
# If it doesn't then look trough the path and backtrack trough it to find a possible neighbour
if len(visited) > 1:
del visited[-1]
current = visited[-1]
# If the last cell of the visited list is Cell 0 then remove it
elif len(visited) <= 1:
del visited[-1]
elif len(visited) <= 0:
# Stop the Algorithm
self.running = False
print('Done')
def draw(self):
DISPLAY.fill((255, 255, 255))
# Get the maze made by the algorithm and draw it on the screen
for i in range(0, len(grid)):
grid[i].draw()
pygame.display.update()
while self.display_running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.display_running = False
maze = Maze()
maze.init_cells()
maze.init_maze()
maze.draw()
I put some print methods in it for debugging purposes.
And am still a beginner in programming, I know it could probably be way cleaner or that some naming of methods could be better.
What I want to happen is that in def init_maze the maze blueprints gets written out and that in def draw the blueprint gets drawn on the screen.

Display multiple images in PIL

-------------------------------Solved(Partially)----------------------------------------
My problem is that when I try to display multiple images on the canvas using PIL, I end up with only the last image.
All the images have slightly different characteristics(angle offset). Also the having a plethora of entries, I have to use a loop for sure. Also I'll need to use PIL(tkinter objects not possible) for the angle offset feature.
Here is the code;
#!/usr/bin/python
# Filename: weather_sim.py
import os
import tkinter as tk
import h5py as hp
import numpy as np
import ntpath as ntp
from PIL import Image, ImageTk
from tkinter.filedialog import askopenfilename
def path_leaf(path):
head, tail = ntp.split(path)
return tail or ntp.basename(head)
class CoordFind:
def __init__(self):
self.LatPx = 0
self.LonPx = 0
def find_px(self, Lat, Lon):
self.LatPx = (Lat - LatN)/LatLc
self.LonPx = (Lon - LonW)/LonLc
class PlottingGUI(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.coord = CoordFind()
self.root = parent
self.root.wm_title("-|-|-|-|||Wind Vector Plotter|||-|-|-|-")
self.root.resizable(False, False)
self.path = "None Selected"
self.HaM = 0
self.Lat = 0
self.Lon = 0
self.WiD = 0
self.WiS = 0
self.fr = tk.Frame(self.root, width = (width+20), height = (height+20), bd = 2)
self.fr.grid(row = 1, column = 0)
self.frBro = tk.Frame(self.root, width = (width+20), height = 50, bd = 2)
self.frBro.grid(row = 0, column = 0)
self.frHi = tk.Frame(self.root, width = (width+20), height = 50, bd = 2)
self.frHi.grid(row = 2, column = 0)
self.cv = tk.Canvas(self.fr, width = width, height = height, background = "white", bd = 0, relief = tk.SUNKEN)
self.cv.grid(row = 0, column = 0)
self.cv.create_image(1, 1, anchor = "nw", image = photo)
self.broButton = tk.Button(self.frBro, text = "Browse Dsets", command = self.analyseDset, height = 3, width = 16, bg = "yellow")
self.broButton.grid(row = 0, column = 0, padx = 20)
self.selFile = tk.Label(self.frBro, text = self.path)
self.selFile.grid(row = 0, column = 1)
self.caution = tk.Label(self.frHi, text = "Optional use. Warning!!, May lead to lags in program", fg = "red")
self.caution.grid(row = 0, column = 1)
self.shoRedBut = tk.Button(self.frHi, text = "Show H1", command = self.show_barbs1().__next__, height = 3, width = 16, bg = "#FF0000", fg = "white", activebackground="#E533B5")
self.shoRedBut.grid(row = 1, column = 0, padx = 7, pady = 2)
self.shoGrnBut = tk.Button(self.frHi, text = "Show H2", command = self.show_barbs2().__next__, height = 3, width = 16, bg = "#00B400", fg = "white", activebackground="#B5E533")
self.shoGrnBut.grid(row = 1, column = 1, padx = 7, pady = 2)
self.shoBluBut = tk.Button(self.frHi, text = "Show H3", command = self.show_barbs3().__next__, height = 3, width = 16, bg = "#0000FF", fg = "white", activebackground="#33B5E5")
self.shoBluBut.grid(row = 1, column = 2, padx = 7, pady = 2)
self.desc1 = tk.Label(self.frHi, text = "100-250 hPa", fg = "white", bg = "black")
self.desc1.grid(row = 2, column = 0)
self.desc2 = tk.Label(self.frHi, text = "250-350 hPa", fg = "white", bg = "black")
self.desc2.grid(row = 2, column = 1)
self.desc3 = tk.Label(self.frHi, text = "350-700 hPa", fg = "white", bg = "black")
self.desc3.grid(row = 2, column = 2)
def analyseDset(self):
self.path = askopenfilename(filetypes = (("Dataset files", "*.h5")
,("All files", "*.*") ))
self.jfname = path_leaf(self.path)
self.selFile = tk.Label(self.frBro, text = self.jfname)
self.selFile.grid(row = 0, column = 1)
self.extDset()
def extDset(self):
hf = hp.File(self.path, 'r')
HaM = hf.get('HEIGHT_ASSIGNMENT_METHOD')
Lat = hf.get('Latitude')
Lon = hf.get('Longitude')
WiD = hf.get('WIND_DIRECTION')
WiS = hf.get('WIND_SPEED')
self.HaM = np.array(HaM)
self.Lat = np.array(Lat)/100
self.Lon = np.array(Lon)/100
self.WiD = np.array(WiD)
self.WiS = np.array(WiS)
self.BrbImR = np.empty((self.HaM.shape[0],1))
self.BrbImB = np.empty((self.HaM.shape[0],1))
def show_barbs1(self):
self.coord = CoordFind()
script_dir = os.path.dirname(os.path.abspath(__file__))
im = Image.open(os.path.join(script_dir, 'Red_Barbs\icons8-wind-speed-43-47-50.png'))
w, h = im.size
im = im.resize((int(w/2), int(h/2)), Image.ANTIALIAS)
vec_im = ImageTk.PhotoImage(im.rotate(45))
for i in range(0, self.HaM.shape[0]):
if self.HaM[i] == 0:
self.coord.find_px(self.Lat[i], self.Lon[i])
x = self.coord.LonPx
y = self.coord.LatPx
self.BrbImR[i] = self.cv.create_image(x, y, image = vec_im)
while True:
for i in range(0, self.HaM.shape[0]):
self.cv.itemconfigure(self.BrbImR[i], state = tk.NORMAL)
self.shoRedBut.configure(text = "Showing H1")
yield
def show_barbs2(self):
self.coord = CoordFind()
BrbImG = np.empty((self.HaM.shape[0],1))
script_dir = os.path.dirname(os.path.abspath(__file__))
im = Image.open(os.path.join(script_dir, 'Green_Barbs\icons8-wind-speed-43-47-50.png'))
w, h = im.size
im = im.resize((int(w/2), int(h/2)), Image.ANTIALIAS)
for i in range(0, self.HaM.shape[0]):
if self.HaM[i] == 1:
vec_im = ImageTk.PhotoImage(im.rotate(self.WiD[i]))
self.coord.find_px(self.Lat[i], self.Lon[i])
x = self.coord.LonPx
y = self.coord.LatPx
BrbImG[i] = self.cv.create_image(x, y, image = vec_im)
while True:
for i in range(0, self.HaM.shape[0]):
self.cv.itemconfigure(BrbImG[i], state = tk.NORMAL)
self.shoGrnBut.configure(text = "Showing H2")
yield
def show_barbs3(self):
self.coord = CoordFind()
script_dir = os.path.dirname(os.path.abspath(__file__))
im = Image.open(os.path.join(script_dir, 'Blue_Barbs\icons8-wind-speed-43-47-50.png'))
w, h = im.size
im = im.resize((int(w/2), int(h/2)), Image.ANTIALIAS)
vec_im = ImageTk.PhotoImage(im.rotate(180))
for i in range(0, self.HaM.shape[0]):
if self.HaM[i] == 2:
self.coord.find_px(self.Lat[i], self.Lon[i])
x = self.coord.LonPx
y = self.coord.LatPx
self.BrbImB[i] = self.cv.create_image(x, y, image = vec_im)
while True:
for i in range(0, self.HaM.shape[0]):
self.cv.itemconfigure(self.BrbImB[i], state = tk.NORMAL)
self.shoBluBut.configure(text = "Showing H3")
yield
if __name__ == "__main__":
root = tk.Tk()
backmap = "Map.png"
photo = ImageTk.PhotoImage(file = backmap)
width = photo.width()
height = photo.height()
LatN = 69.5
LatS = -69.3
LonE = 148.9
LonW = 1.0
LatLc = (LatS - LatN)/height
LonLc = (LonE - LonW)/width
app = PlottingGUI(root)
root.mainloop()
The output currently is this;(For the green arrows as that is what I have tested on)
This is what I want;(But with different angles)
I am using Python 3.6 on Windows 10.
Thanks in advance!!
P.S.: Also there is another problem if someone can help me with that. I would like to be able to choose a particular image based on a range factor(Wind Speed) by doing like a switch-case(or if-elif-else) procedure if possible. But when I try to do that it says "No such File or Directory". I may put it in another Question though.
-------------------------------Solved(Till this point)---------------------------------
EDIT: Solved the problem of displaying multiple arrows according to
choice and at different angles.
Here's the code;
#!/usr/bin/python
# Filename: weather_sim.py
import os
import tkinter as tk
import h5py as hp
import numpy as np
import ntpath as ntp
from PIL import Image, ImageTk
from tkinter.filedialog import askopenfilename
def path_leaf(path):
head, tail = ntp.split(path)
return tail or ntp.basename(head)
class CoordFind:
def __init__(self):
self.LatPx = 0
self.LonPx = 0
def find_px(self, Lat, Lon):
self.LatPx = (Lat - LatN)/LatLc
self.LonPx = (Lon - LonW)/LonLc
class PlottingGUI(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.coord = CoordFind()
self.root = parent
self.root.wm_title("-|-|-|-|||Wind Vector Plotter|||-|-|-|-")
self.root.resizable(False, False)
self.path = "None Selected"
self.HaM = 0
self.Lat = 0
self.Lon = 0
self.WiD = 0
self.WiS = 0
self.ima = []
self.fr = tk.Frame(self.root, width = (width+20), height = (height+20), bd = 2)
self.fr.grid(row = 1, column = 0)
self.frBro = tk.Frame(self.root, width = (width+20), height = 50, bd = 2)
self.frBro.grid(row = 0, column = 0)
self.frHi = tk.Frame(self.root, width = (width+20), height = 50, bd = 2)
self.frHi.grid(row = 2, column = 0)
self.cv = tk.Canvas(self.fr, width = width, height = height, background = "white", bd = 0, relief = tk.SUNKEN)
self.cv.grid(row = 0, column = 0)
self.cv.create_image(1, 1, anchor = "nw", image = photo)
self.broButton = tk.Button(self.frBro, text = "Browse Dsets", command = self.analyseDset, height = 3, width = 16, bg = "yellow")
self.broButton.grid(row = 0, column = 0, padx = 20)
self.selFile = tk.Label(self.frBro, text = self.path)
self.selFile.grid(row = 0, column = 1)
self.caution = tk.Label(self.frHi, text = "Optional use. Warning!!, May lead to lags in program", fg = "red")
self.caution.grid(row = 0, column = 1)
self.shoRedBut = tk.Button(self.frHi, text = "Show H1", command = self.show_barbs1().__next__, height = 3, width = 16, bg = "#FF0000", fg = "white", activebackground="#E533B5")
self.shoRedBut.grid(row = 1, column = 0, padx = 7, pady = 2)
self.shoGrnBut = tk.Button(self.frHi, text = "Show H2", command = self.show_barbs2().__next__, height = 3, width = 16, bg = "#00B400", fg = "white", activebackground="#B5E533")
self.shoGrnBut.grid(row = 1, column = 1, padx = 7, pady = 2)
self.shoBluBut = tk.Button(self.frHi, text = "Show H3", command = self.show_barbs3().__next__, height = 3, width = 16, bg = "#0000FF", fg = "white", activebackground="#33B5E5")
self.shoBluBut.grid(row = 1, column = 2, padx = 7, pady = 2)
self.desc1 = tk.Label(self.frHi, text = "100-250 hPa", fg = "white", bg = "black")
self.desc1.grid(row = 2, column = 0)
self.desc2 = tk.Label(self.frHi, text = "250-350 hPa", fg = "white", bg = "black")
self.desc2.grid(row = 2, column = 1)
self.desc3 = tk.Label(self.frHi, text = "350-700 hPa", fg = "white", bg = "black")
self.desc3.grid(row = 2, column = 2)
def analyseDset(self):
self.path = askopenfilename(filetypes = (("Dataset files", "*.h5")
,("All files", "*.*") ))
self.jfname = path_leaf(self.path)
self.selFile = tk.Label(self.frBro, text = self.jfname)
self.selFile.grid(row = 0, column = 1)
self.extDset()
def extDset(self):
hf = hp.File(self.path, 'r')
HaM = hf.get('HEIGHT_ASSIGNMENT_METHOD')
Lat = hf.get('Latitude')
Lon = hf.get('Longitude')
WiD = hf.get('WIND_DIRECTION')
WiS = hf.get('WIND_SPEED')
self.HaM = np.array(HaM)
self.Lat = np.array(Lat)/100
self.Lon = np.array(Lon)/100
self.WiD = np.array(WiD)
self.WiS = np.array(WiS)
self.BrbImR = np.empty((self.HaM.shape[0],1))
self.BrbImG = np.empty((self.HaM.shape[0],1))
self.BrbImB = np.empty((self.HaM.shape[0],1))
def barb_def(self, WiS):
if WiS < 1:
self.ima = "1.png"
elif WiS < 3:
self.ima = "2.png"
elif WiS < 8:
self.ima = "3.png"
elif WiS < 13:
self.ima = "4.png"
elif WiS < 18:
self.ima = "5.png"
elif WiS < 23:
self.ima = "6.png"
elif WiS < 28:
self.ima = "7.png"
elif WiS < 33:
self.ima = "8.png"
elif WiS < 38:
self.ima = "9.png"
elif WiS < 43:
self.ima = "10.png"
elif WiS < 48:
self.ima = "11.png"
elif WiS < 53:
self.ima = "12.png"
elif WiS < 58:
self.ima = "13.png"
elif WiS < 63:
self.ima = "14.png"
elif WiS < 68:
self.ima = "15.png"
elif WiS < 73:
self.ima = "16.png"
elif WiS < 78:
self.ima = "17.png"
elif WiS < 83:
self.ima = "18.png"
elif WiS < 88:
self.ima = "19.png"
elif WiS < 93:
self.ima = "20.png"
elif WiS < 98:
self.ima = "21.png"
elif WiS < 103:
self.ima = "22.png"
else:
self.ima = "23.png"
def show_barbs1(self):
self.coord = CoordFind()
vec_im = []
im = []
p = []
script_dir = os.path.dirname(os.path.abspath(__file__))
for i in range(0, self.HaM.shape[0]):
self.barb_def(self.WiS[i])
p.append("{}{}".format('Red_Barbs\\', self.ima))
im.append(Image.open(os.path.join(script_dir, p[i])))
w, h = im[i].size
im[i] = im[i].resize((int(w/2), int(h/2)), Image.ANTIALIAS)
vec_im.append(ImageTk.PhotoImage(im[i].rotate(self.WiD[i])))
for i in range(0, self.HaM.shape[0]):
if self.HaM[i] == 0:
self.coord.find_px(self.Lat[i], self.Lon[i])
x = self.coord.LonPx
y = self.coord.LatPx
self.BrbImR[i] = self.cv.create_image(x, y, image = vec_im[i])
while True:
for i in range(0, self.HaM.shape[0]):
self.cv.itemconfigure(self.BrbImR[i], state = tk.NORMAL)
self.shoRedBut.configure(text = "Showing H1")
yield
def show_barbs2(self):
self.coord = CoordFind()
vec_im = []
im = []
p = []
script_dir = os.path.dirname(os.path.abspath(__file__))
for i in range(0, self.HaM.shape[0]):
self.barb_def(self.WiS[i])
p.append("{}{}".format('Green_Barbs\\', self.ima))
im.append(Image.open(os.path.join(script_dir, p[i])))
w, h = im[i].size
im[i] = im[i].resize((int(w/2), int(h/2)), Image.ANTIALIAS)
vec_im.append(ImageTk.PhotoImage(im[i].rotate(self.WiD[i])))
for i in range(0, self.HaM.shape[0]):
if self.HaM[i] == 1:
self.coord.find_px(self.Lat[i], self.Lon[i])
x = self.coord.LonPx
y = self.coord.LatPx
self.BrbImG[i] = self.cv.create_image(x, y, image = vec_im[i])
while True:
for i in range(0, self.HaM.shape[0]):
self.cv.itemconfigure(self.BrbImG[i], state = tk.NORMAL)
self.shoGrnBut.configure(text = "Showing H2")
yield
def show_barbs3(self):
self.coord = CoordFind()
vec_im = []
im = []
p = []
script_dir = os.path.dirname(os.path.abspath(__file__))
for i in range(0, self.HaM.shape[0]):
self.barb_def(self.WiS[i])
p.append("{}{}".format('Blue_Barbs\\', self.ima))
im.append(Image.open(os.path.join(script_dir, p[i])))
w, h = im[i].size
im[i] = im[i].resize((int(w/2), int(h/2)), Image.ANTIALIAS)
vec_im.append(ImageTk.PhotoImage(im[i].rotate(self.WiD[i])))
for i in range(0, self.HaM.shape[0]):
if self.HaM[i] == 2:
self.coord.find_px(self.Lat[i], self.Lon[i])
x = self.coord.LonPx
y = self.coord.LatPx
self.BrbImB[i] = self.cv.create_image(x, y, image = vec_im[i])
while True:
for i in range(0, self.HaM.shape[0]):
self.cv.itemconfigure(self.BrbImB[i], state = tk.NORMAL)
self.shoBluBut.configure(text = "Showing H3")
yield
if __name__ == "__main__":
root = tk.Tk()
backmap = "Map.png"
photo = ImageTk.PhotoImage(file = backmap)
width = photo.width()
height = photo.height()
LatN = 69.5
LatS = -69.3
LonE = 148.9
LonW = 1.0
LatLc = (LatS - LatN)/height
LonLc = (LonE - LonW)/width
app = PlottingGUI(root)
root.mainloop()
But this ended up having a new problem. One set of coloured arrows is showing at a time but when I click the button to display another set it goes "Python stopped working because of some error" and then the shell restarts. Don't know what's the prob though.

Resources