Related
I need to improve the speed of this program, because at the moment it is pretty slow. I know that representing game states in binary can be very effective, however, I don't know how to do that. I have also tried using numba, however that seems to make it slower. I have attached the code below. Thank you to anyone who can help!
import pygame, sys, time, hashlib
from copy import deepcopy
pygame.init()
red = pygame.Color(255,0,0)
white = pygame.Color(255,255,255)
black = pygame.Color(0,0,0)
pygame.display.set_caption('Hexapawn AI')
width, height = 700,700
game_window = pygame.display.set_mode((width, height))
def set_pawns():
global game_window, board
for y in range(5):
for x in range(5):
if board[y][x] == 1:
game_window.blit( blue_pawn, ( (width/5)*x, (height/5)*(4-y) ))
if board[y][x] == -1:
game_window.blit( red_pawn, ( (width/5)*x , (height/5)*(4-y) ))
def build_lines():
global game_window
for x in range(1,5):
pygame.draw.line(game_window, black, (width/5 * x, 0), (width/5 * x, height), 7)
pygame.draw.line(game_window, black, (0, height/5 * x), (width, height/5 * x), 7)
def get_possible_moves(board, player):
possible_moves = []
forward = 1 if player == 1 else -1
opponent = -1 if player == 1 else 1
for y in range(5):
for x in range(5):
if board[y][x] != player:
continue
if x-1 >= 0 and y+forward < 5 and board[y+forward][x-1] == opponent:
possible_moves.append([x,y,x-1,y+forward])
if x+1 < 5 and y+forward < 5 and board[y+forward][x+1] == opponent:
possible_moves.append([x,y,x+1,y+forward])
if (y+1 < 5 and player == 1) or (y+1 > -1 and player == -1):
if board[y+forward][x] == " ":
possible_moves.append([x,y,x,y+forward])
return possible_moves
def make_move(board,move,player):
global game_window, width, height
game_window.fill(white)
build_lines()
board[move[1]][move[0]] = " "
board[move[3]][move[2]] = player
set_pawns()
def neg_make_move(board, move, player):
x1, y1, x2, y2 = move
board = deepcopy(board)
board[y1][x1] = " "
board[y2][x2] = player
return board
def check_for_win(board,player):
if player == -1:
if -1 in board[0]:
return True
if get_possible_moves(board,1) == []:
return True
elif player == 1:
if 1 in board[4]:
return True
if get_possible_moves(board,-1) == []:
return True
return False
TRANSPOSITION_TABLE = {}
def state_hash(board):
serialized = str(board).encode()
return hashlib.sha256(serialized).hexdigest()
def store(table, board, alpha, beta, best, depth):
state = state_hash(board)
if best[1] <= alpha:
flag = 'UPPERCASE'
elif best[1] >= beta:
flag = 'LOWERCASE'
else:
flag = 'EXACT'
table[state] = [best, flag, depth]
def negamax(board, depth, turn, alpha, beta):
alpha_org = alpha
state = state_hash(board)
if state in TRANSPOSITION_TABLE:
tt_entry = TRANSPOSITION_TABLE[state]
if tt_entry[2] >= depth:
if tt_entry[1] == 'EXACT':
return tt_entry[0]
elif tt_entry[1] == 'LOWERCASE':
alpha = max(alpha, tt_entry[0][1])
elif tt_entry[1] == 'UPPERCASE':
beta = min(beta, tt_entry[0][1])
if alpha >= beta:
return tt_entry[0]
if check_for_win(board, -turn):
return None, -(25+depth)
if depth == 0:
return get_possible_moves(board,turn)[0], (depth)
best_score = -200
for move in get_possible_moves(board,turn):
new_board = neg_make_move(board, move, turn)
score = -negamax(new_board, depth - 1, -turn, -beta, -alpha)[1]
alpha = max(alpha,score)
if score > best_score:
best_score, best_move = score, move
if alpha >= beta:
break
store(TRANSPOSITION_TABLE, board, alpha_org, beta, [best_move,best_score], depth)
return best_move, best_score
# Build board
board = [[1 for x in range(5)]]
for x in range(3):
board.append([" " for x in range(5)])
board.append([-1 for x in range(5)])
game_window.fill(white)
# Draw game board lines
build_lines()
# Load sprites with correct sizes
tile_size = (width/5,height/5)
blue_pawn = pygame.transform.scale(pygame.image.load("blue_pawn.png"), tile_size)
red_pawn = pygame.transform.scale(pygame.image.load("red_pawn.png"), tile_size)
# Draw the pawns to the board
set_pawns()
pygame.display.update()
while True:
for event in pygame.event.get():
# if user clicks the X or they type esc then the screen will close
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
start = time.time()
move = negamax(board,12,1,-10000,10000)[0]
print(f"Blue move took {time.time()-start} seconds to calculate.")
make_move(board,move,1)
pygame.display.update()
if check_for_win(board,1):
print("Blue Wins!")
pygame.quit()
sys.exit()
time.sleep(1)
start = time.time()
move = negamax(board,12,-1,-10000,10000)[0]
print(f"Red move took {time.time()-start} seconds to calculate.")
make_move(board,move,-1)
pygame.display.update()
if check_for_win(board,-1):
print("Red Wins!")
pygame.quit()
sys.exit()
pygame.display.update()
time.sleep(1)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
So I have been trying to figure out why I keep getting this error, even though everything is run from my game_view.py module. Everytime I press the 1 key to start a game and test to see if the players health bar and hit points works, I get this error message. TypeError: start_new_game() missing 1 required positional argument: 'max_health'
The sad part is, is that it reffers me to the start_view which doesn't have anything to do with anything else but running the start screen so players can choose to play solo or with another player. Below is the game_view and start_view so you guys can see where I'm going wrong. I wanted to test this out so this way I can add other enemies, bosses and power-ups later, but running into this error for the past several days is hindering progress. Anyway, code for both will be below. Thanks in advance for any and all help.
start_view:
import arcade
from game_view import GameView
class StartView(arcade.View):
def on_show(self):
# This is run once when we switch to this view
arcade.set_background_color(arcade.csscolor.BLACK)
# Reset the viewport, necessary if we have a scrolling game
arcade.set_viewport(0, self.window.width, 0, self.window.height)
def on_draw(self):
# Draw this view
arcade.start_render()
line_height = 70
line_location = self.window.height - line_height * 2
arcade.draw_text("Space Defense Force",
self.window.width / 2,
line_location,
arcade.color.WHITE,
font_size=50,
anchor_x="center",
font_name="SF Atarian System")
line_location -= line_height
line_location -= line_height
arcade.draw_text("1 - Start One Player Game",
self.window.width / 2,
line_location,
arcade.color.WHITE,
font_size=20,
anchor_x="center",
font_name="SF Atarian System")
# if len(self.window.joysticks) > 1:
# color = arcade.color.WHITE
# else:
# color = arcade.color.GRAY
color = arcade.color.GRAY
line_location -= line_height
arcade.draw_text("2 - Start Two Player Game",
self.window.width / 2,
line_location,
color,
font_size=20,
anchor_x="center",
font_name="SF Atarian System")
line_location -= line_height
line_location -= line_height
color = arcade.color.WHITE
arcade.draw_text("Use joysticks to play, or arrow keys to move and number keys to fire.",
self.window.width / 2,
line_location,
color,
font_size=20,
anchor_x="center",
font_name="SF Atarian System")
def on_key_press(self, symbol: int, modifiers: int):
if symbol == arcade.key.KEY_1:
game_view = GameView()
game_view.start_new_game(1)
self.window.show_view(game_view)
elif symbol == arcade.key.KEY_2:
game_view = GameView()
game_view.start_new_game(2)
self.window.show_view(game_view)
game_view:
import random
import math
import arcade
from health import Health
from game_over_view import GameOverView
from typing import cast
from arcade.experimental.shadertoy import Shadertoy
from constants import *
from asteroid_sprite import AsteroidSprite
from ship_sprite import ShipSprite
from bullet import Bullet
from glow_line import GlowLine
from glow_ball import GlowBall
from explosion import ExplosionMaker
from glow_image_sprite import GlowImageSprite
from window import Window as window
class GameView(arcade.View):
# Main application class
def __init__(self):
super().__init__()
# Sprite lists
self.player_sprite_list = arcade.SpriteList()
self.asteroid_list = arcade.SpriteList()
self.bullet_list = arcade.SpriteList()
self.ship_life_list = arcade.SpriteList()
self.health_list = arcade.SpriteList()
# Sounds
self.laser_sound = arcade.load_sound(":resources:sounds/hurt5.wav")
self.hit_sound1 = arcade.load_sound(":resources:sounds/explosion1.wav")
self.hit_sound2 = arcade.load_sound(":resources:sounds/explosion2.wav")
self.hit_sound3 = arcade.load_sound(":resources:sounds/hit1.wav")
self.hit_sound4 = arcade.load_sound(":resources:sounds/hit2.wav")
self.dead_sound = arcade.load_sound(":resources:sounds/gameover2.wav")
self.glowball_shadertoy = Shadertoy.create_from_file(self.window.get_size(), "glow_ball.glsl")
self.glowline_shadertoy = Shadertoy.create_from_file(self.window.get_size(), "glow_line.glsl")
self.explosion_list = []
# for joystick in self.window.joysticks:
# joystick.push_handlers(self)
def start_new_game(self, player_count, max_health):
#Set up the game and initialize the variables
self.game_over = False
arcade.set_background_color(arcade.csscolor.BLACK)
# Sprite lists
self.player_sprite_list = arcade.SpriteList()
self.asteroid_list = arcade.SpriteList()
self.bullet_list = arcade.SpriteList()
self.ship_life_list = arcade.SpriteList()
self.health_list = arcade.SpriteList()
# if len(self.window.joysticks) > 0:
# joystick = self.window.joysticks[0]
# else:
# joystick = None
joystick = None
player_sprite = ShipSprite(":resources:images/space_shooter/playerShip1_orange.png",
SCALE,
joystick,
player_no=1,
player_count=player_count,
max_health=5)
self.player_sprite_list.append(player_sprite)
self.health_list.append(max_health)
if player_count > 1:
joystick = None
# if len(self.window.joysticks) > 1:
# joystick = self.window.joysticks[1]
# else:
# joystick = None
player_sprite = ShipSprite(":resources:images/space_shooter/playerShip1_green.png",
SCALE,
joystick,
player_no=2,
player_count=player_count,
max_health=5
)
self.player_sprite_list.append(player_sprite)
self.health_list.append(max_health)
# Set up the player
for player in self.player_sprite_list:
player.score = 0
player.lives = 3
# Set up the little icons that represent the player lives.
cur_pos = 10
for i in range(self.player_sprite_list[0].lives):
life = arcade.Sprite(":resources:images/space_shooter/playerLife1_orange.png", SCALE)
life.center_x = cur_pos + life.width
life.center_y = life.height
cur_pos += life.width
self.ship_life_list.append(life)
if len(self.player_sprite_list) > 1:
cur_pos = 100
for i in range(self.player_sprite_list[1].lives):
life = arcade.Sprite(":resources:images/space_shooter/playerLife1_green.png", SCALE)
life.center_x = cur_pos + life.width
life.center_y = life.height
cur_pos += life.width
self.ship_life_list.append(life)
# Make the asteroids
image_list = (":resources:images/space_shooter/meteorGrey_big1.png",
":resources:images/space_shooter/meteorGrey_big2.png",
":resources:images/space_shooter/meteorGrey_big3.png",
":resources:images/space_shooter/meteorGrey_big4.png")
for i in range(STARTING_ASTEROID_COUNT):
image_no = random.randrange(4)
enemy_sprite = AsteroidSprite(image_list[image_no], SCALE)
enemy_sprite.guid = "Asteroid"
enemy_sprite.center_y = random.randrange(BOTTOM_LIMIT, TOP_LIMIT)
enemy_sprite.center_x = random.randrange(LEFT_LIMIT, RIGHT_LIMIT)
enemy_sprite.change_x = random.random() * 2 - 1
enemy_sprite.change_y = random.random() * 2 - 1
enemy_sprite.change_angle = (random.random() - 0.5) * 2
enemy_sprite.size = 4
self.asteroid_list.append(enemy_sprite)
def on_draw(self):
# Render the screen.
# This command has to happen before we start drawing
arcade.start_render()
# Draw all the sprites.
self.asteroid_list.draw()
self.ship_life_list.draw()
for bullet in self.bullet_list:
bullet.draw()
self.bullet_list.draw()
for explosion in self.explosion_list:
explosion.render()
self.player_sprite_list.draw()
self.health_list.draw()
# Put the text on the screen.
output = f"Player 1 Score: {self.player_sprite_list[0].score}"
arcade.draw_text(output, 10, 40, arcade.color.AMBER,
font_size=15,
font_name="Arcade")
if len(self.player_sprite_list) > 1:
output = f"Player 2 Score: {self.player_sprite_list[1].score}"
arcade.draw_text(output, 500, 40, arcade.color.AMBER,
font_size=15,
font_name="Arcade")
output = f"Asteroid Count: {len(self.asteroid_list)}"
arcade.draw_text(output, 10, 80, arcade.color.AMBER,
font_size=15,
font_name="Arcade")
for player in health_list:
player.draw_health_number()
player.draw_health_bar()
# def on_joybutton_press(self, joystick, button):
# # What player is this?
# if joystick == self.window.joysticks[0]:
# player_sprite = self.player_sprite_list[0]
# else:
# player_sprite = self.player_sprite_list[1]
# if player_sprite.player_no == 1:
# color = 255, 128, 128
# else:
# color = 128, 255, 128
# if button == 0:
# self.fire_circle(color, player_sprite, player_no=player_sprite.player_no)
# elif button == 1:
# self.fire_line(color, player_sprite, player_no=player_sprite.player_no)
# elif button == 2:
# bullet_sprite = GlowImageSprite(":resources:images/space_shooter/laserBlue01.png",
# SCALE,
# glowcolor=arcade.color.WHITE,
# shadertoy=self.glowball_shadertoy,
# player_no=player_sprite.player_no)
# self.set_bullet_vector(bullet_sprite, 10, player_sprite)
# arcade.play_sound(self.laser_sound)
def on_key_press(self, symbol, modifiers):
# Shoot if the player hit the space bar and we aren't respawning.
if symbol == arcade.key.LEFT:
self.player_sprite_list[0].change_angle = 3
elif symbol == arcade.key.RIGHT:
self.player_sprite_list[0].change_angle = -3
elif symbol == arcade.key.UP:
self.player_sprite_list[0].thrust = 0.15
elif symbol == arcade.key.DOWN:
self.player_sprite_list[0].thrust = -.2
elif symbol == arcade.key.KEY_1:
color = (255, 128, 128)
self.fire_circle(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_2:
color = (128, 255, 128)
self.fire_circle(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_3:
color = (128, 128, 255)
self.fire_circle(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_4:
color = (255, 128, 255)
self.fire_circle(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_5:
color = (255, 255, 255)
self.fire_line(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_6:
color = (64, 255, 64)
self.fire_line(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_7:
bullet_sprite = GlowImageSprite(":resources:images/space_shooter/laserBlue01.png",
SCALE,
glowcolor=arcade.color.WHITE,
shadertoy=self.glowball_shadertoy,
player_no=0)
self.set_bullet_vector(bullet_sprite, 13, self.player_sprite_list[0])
arcade.play_sound(self.laser_sound)
def fire_circle(self, bullet_color, player_sprite, player_no):
bullet_sprite = GlowBall(glowcolor=bullet_color,
radius=5,
shadertoy=self.glowball_shadertoy,
player_no=player_no)
self.set_bullet_vector(bullet_sprite, 5, player_sprite)
arcade.play_sound(self.laser_sound)
def fire_line(self, bullet_color, player_sprite, player_no):
bullet_sprite = GlowLine(glowcolor=bullet_color,
shadertoy=self.glowline_shadertoy,
player=player_sprite,
player_no=player_no)
self.set_bullet_vector(bullet_sprite, 13, player_sprite)
arcade.play_sound(self.laser_sound)
def set_bullet_vector(self, bullet_sprite, bullet_speed, player_sprite):
bullet_sprite.change_y = \
math.cos(math.radians(player_sprite.angle)) * bullet_speed
bullet_sprite.change_x = \
-math.sin(math.radians(player_sprite.angle)) \
* bullet_speed
bullet_sprite.center_x = player_sprite.center_x
bullet_sprite.center_y = player_sprite.center_y
self.bullet_list.append(bullet_sprite)
def on_key_release(self, symbol, modifiers):
# Called whenever a key is released
if symbol == arcade.key.LEFT:
self.player_sprite_list[0].change_angle = 0
elif symbol == arcade.key.RIGHT:
self.player_sprite_list[0].change_angle = 0
elif symbol == arcade.key.UP:
self.player_sprite_list[0].thrust = 0
elif symbol == arcade.key.DOWN:
self.player_sprite_list[0].thrust = 0
def split_asteroid(self, asteroid: AsteroidSprite):
# Split an asteroid into chunks
x = asteroid.center_x
y = asteroid.center_y
if asteroid.size == 4:
for i in range(3):
image_no = random.randrange(2)
image_list = [":resources:images/space_shooter/meteorGrey_med1.png",
":resources:images/space_shooter/meteorGrey_med2.png"]
enemy_sprite = AsteroidSprite(image_list[image_no],
SCALE * 1.5)
enemy_sprite.center_y = y
enemy_sprite.center_x = x
enemy_sprite.change_x = random.random() * 2.5 - 1.25
enemy_sprite.change_y = random.random() * 2.5 - 1.25
enemy_sprite.change_angle = (random.random() - 0.5) * 2
enemy_sprite.size = 3
self.asteroid_list.append(enemy_sprite)
self.hit_sound1.play()
elif asteroid.size == 3:
for i in range(3):
image_no = random.randrange(2)
image_list = [":resources:images/space_shooter/meteorGrey_small1.png",
":resources:images/space_shooter/meteorGrey_small2.png"]
enemy_sprite = AsteroidSprite(image_list[image_no],
SCALE * 1.5)
enemy_sprite.center_y = y
enemy_sprite.center_x = x
enemy_sprite.change_x = random.random() * 3 - 1.5
enemy_sprite.change_y = random.random() * 3 - 1.5
enemy_sprite.change_angle = (random.random() - 0.5) * 2
enemy_sprite.size = 2
self.asteroid_list.append(enemy_sprite)
self.hit_sound2.play()
elif asteroid.size == 2:
for i in range(3):
image_no = random.randrange(2)
image_list = [":resources:images/space_shooter/meteorGrey_tiny1.png",
":resources:images/space_shooter/meteorGrey_tiny2.png"]
enemy_sprite = AsteroidSprite(image_list[image_no],
SCALE * 1.5)
enemy_sprite.center_y = y
enemy_sprite.center_x = x
enemy_sprite.change_x = random.random() * 3.5 - 1.75
enemy_sprite.change_y = random.random() * 3.5 - 1.75
enemy_sprite.change_angle = (random.random() - 0.5) * 2
enemy_sprite.size = 1
self.asteroid_list.append(enemy_sprite)
self.hit_sound3.play()
elif asteroid.size == 1:
self.hit_sound4.play()
def on_update(self, x, delta_time):
# Move everything
self.asteroid_list.update()
self.bullet_list.update()
self.player_sprite_list.update()
self.health_list.update()
explosion_list_copy = self.explosion_list.copy()
for explosion in explosion_list_copy:
explosion.update(x)
if explosion.time > .9:
self.explosion_list.remove(explosion)
for bullet in self.bullet_list:
hit_list = arcade.check_for_collision_with_list(bullet, self.player_sprite_list)
# If it did hit, get rid of sprite
if len(hit_list) > 0:
bullet.remove_from_lists()
for player in hit_list:
if not isinstance(player, ShipSprite):
raise TypeError("List contents must be all ints")
# Remove one health point
player.cur_health -= 1
# Check Health
if player.cur_health <= 0:
arcade.play_sound(self.dead_sound)
view=GameOverView
self.window.show_view(view)
else:
# Not Dead
arcade.play_sound(self.hit_sound1)
assert isinstance(bullet, Bullet)
asteroids = arcade.check_for_collision_with_list(bullet, self.asteroid_list)
if len(asteroids) > 0:
explosion = ExplosionMaker(self.window.get_size(), bullet.position)
self.explosion_list.append(explosion)
for asteroid in asteroids:
assert isinstance(asteroid, AsteroidSprite)
self.player_sprite_list[bullet.player_no - 1].score += 1
self.split_asteroid(cast(AsteroidSprite, asteroid)) # expected AsteroidSprite, got Sprite instead
asteroid.remove_from_sprite_lists()
bullet.remove_from_sprite_lists()
# Remove bullet if it goes off-screen
size = max(bullet.width, bullet.height)
if bullet.center_x < 0 - size:
bullet.remove_from_sprite_lists()
if bullet.center_x > SCREEN_WIDTH + size:
bullet.remove_from_sprite_lists()
if bullet.center_y < 0 - size:
bullet.remove_from_sprite_lists()
if bullet.center_y > SCREEN_HEIGHT + size:
bullet.remove_from_sprite_lists()
for player in self.player_sprite_list:
assert isinstance(player, ShipSprite, max_health)
if not player.respawning:
asteroids = arcade.check_for_collision_with_list(player, self.asteroid_list)
if len(asteroids) > 0:
if player.lives > 0:
player.lives -= 1
player.respawn()
self.split_asteroid(cast(AsteroidSprite, asteroids[0]))
asteroids[0].remove_from_sprite_lists()
self.ship_life_list.pop().remove_from_sprite_lists()
elif len(asteroids) > 0:
if player.health > 0:
player.health -=1
player.respawn()
self.split_asteroid(cast(AsteroidSprite, asteroids[0]))
asteroids[0].remove_from_sprite_lists()
self.ship_list_list.pop().remove_from_sprite_lists()
else:
arcade.play_sound(self.dead_sound)
view = GameOverView()
self.window.show_view(view)
Sorry in advance if I have tons of code to go through. But like I said I am adding some features that wasn't in the Arcade Repository from github. I even set a separte module for the health bar and hit points so this way I can see what conflicts. But the error above has been a royal pain.Thanks again.
P.S. Remarked out joysticks because it was conflicting with another module I built.
As your title says, your start game function requires 2 arguments: player_count and max_healh. And in your code, when using start_new_game, you aren't supplying the max_health argument, thus raising an error.
(function) start_new_game(self, player_count, max_health)
With a Tic Tac Toe project almost finished, I am having a few issues regarding binding and adding a tie condition. I'm able to bind functions to and and they work normally, but I want them to be bound to R and escape key (reset_game to R and close to escape). I have also tried adding a variable k for the tie condition, but it says that is has not been defined. Here's the code:
from tkinter import *
import tkinter.messagebox
ttt = Tk()
ttt.title("Tic Tac Toe")
w = Canvas(ttt, width = 902, height = 902)
w.configure (bg = "white")
w.pack()
m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
size = 300
player = 1
w.create_line(0, 300, 902, 300, fill = "black")
w.create_line(0, 601, 902, 601, fill = "black")
w.create_line(300, 0, 300, 902, fill = "black")
w.create_line(601, 0, 601, 902, fill = "black")
def on_click(event):
global m
global player
global k
row = event.y // size
col = event.x // size
if m[row][col] == 0:
cx = col * size + size // 2
cy = row * size + size // 2
if player == 1:
draw_X(cx, cy)
print ("Player 1, X")
else:
draw_O(cx, cy)
print ("Player 2, O")
m[row][col] = player
Win()
player = 2 if player == 1 else 1
k = k + 1
def draw_O(x, y):
radius = size // 3
w.create_oval(x-radius, y-radius, x+radius, y+radius, width=5, tag='cell')
def draw_X(x, y):
radius = size // 3
w.create_line(x-radius, y-radius, x+radius, y+radius, width=5, tag='cell')
w.create_line(x+radius, y-radius, x-radius, y+radius, width=5, tag='cell')
def reset_game(event):
global m
global player
w.delete('cell')
m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
player = 1
k = 0
def tie():
if (k==8):
tkinter.messagebox.showinfo("Tic Tac Toe", "Tie")
def Win():
if (m[0][0] == m[0][1] and m[0][0] == m[0][2] and m[0][0]!=0):
tkinter.messagebox.showinfo("Tic Tac Toe", "Winner is player " + str(m[0][0]))
ttt.destroy()
print ("Player", str(m[0][0]), "wins")
elif (m[0][0] == m[1][0] and m[0][0] == m[2][0] and m[0][0]!=0):
tkinter.messagebox.showinfo("Tic Tac Toe", "Winner is player " + str(m[0][0]))
ttt.destroy()
print ("Player", str(m[0][0]), "wins")
elif (m[1][0] == m[1][1] and m[1][0] == m[1][2] and m[1][0]!=0):
tkinter.messagebox.showinfo("Tic Tac Toe", "Winner is player " + str(m[1][0]))
ttt.destroy()
print ("Player", str(m[1][0]), "wins")
elif (m[0][1] == m[1][1] and m[0][1] == m[2][1] and m[0][1]!=0):
tkinter.messagebox.showinfo("Tic Tac Toe", "Winner is player " + str(m[0][1]))
ttt.destroy()
print ("Player", str(m[0][1]), "wins")
elif (m[0][2] == m[1][2] and m[0][2] == m[2][2] and m[0][2]!=0):
tkinter.messagebox.showinfo("Tic Tac Toe", "Winner is player " + str(m[0][2]))
ttt.destroy()
print ("Player", str(m[0][2]), "wins")
elif (m[2][0] == m[2][1] and m[2][0] == m[2][2] and m[2][0]!=0):
tkinter.messagebox.showinfo("Tic Tac Toe", "Winner is player " + str(m[2][0]))
ttt.destroy()
print ("Player", str(m[2][0]), "wins")
elif (m[0][0] == m[1][1] and m[0][0] == m[2][2] and m[0][0]!=0):
tkinter.messagebox.showinfo("Tic Tac Toe", "Winner is player " + str(m[0][0]))
ttt.destroy()
print ("Player", str(m[0][0]), "wins")
elif (m[0][2] == m[1][1] and m[0][2] == m[2][0] and m[0][2]):
tkinter.messagebox.showinfo("Tic Tac Toe", "Winner is player " + str(m[0][2]))
ttt.destroy()
print ("Player", str(m[0][2]), "wins")
w.bind('<Button-1>', on_click)
def close(event):
ttt.destroy()
w.bind('<Button-2>',close)
w.bind('<Button-3>', reset_game)
ttt.mainloop()
I also want to stop the game after somebody wins or there's a tie without closing the canvas so I could reset. Any ideas on how to do that?
Since you have added global variable k as the number of turns played, player can be determined by value of k so it can be removed from the global variables.
You need to declare global variable k:
m = [[0,0,0], [0,0,0], [0,0,0]]
size = 300
k = 0
Also you can simplify/modify the function Win to accept the row and col as arguments and return whether there is winner:
def Win(row, col):
# check horizontal
if m[row][0] == m[row][1] == m[row][2]:
return m[row][col]
# check vertical
if m[0][col] == m[1][col] == m[2][col]:
return m[row][col]
# check diagonals
cell = (row, col)
if cell in ((0,0), (1,1), (2,2)) and m[0][0] == m[1][1] == m[2][2]:
return m[row][col]
if cell in ((2,0), (1,1), (0,2)) and m[2][0] == m[1][1] == m[0][2]:
return m[row][col]
# no winner, returns None
return None
Then modify on_click function:
def on_click(event):
global m
global k
row = event.y // size
col = event.x // size
if m[row][col] == 0:
cx = col * size + size // 2
cy = row * size + size // 2
# determine current player
player = 1 + k % 2
if player == 1:
draw_X(cx, cy)
print("Player 1, X")
else:
draw_O(cx, cy)
print("Player 2, O")
m[row][col] = player
k += 1
# only need to check winner after 5 turns
if k >= 5:
winner = Win(row, col)
msg = None
if winner:
msg = "Winner is player {}: {}".format(player, 'X' if player == 1 else 'O')
elif k == 9:
msg = "Tie game"
if msg:
tkinter.messagebox.showinfo("Tic Tac Toe", msg)
reset_game()
For the keys binding:
w.bind('<Escape>', lambda e: ttt.destroy())
w.bind('R', reset_game)
w.bind('r', reset_game)
w.focus_set() # Canvas need to get the focus in order to get the keyboard events
from tkinter import *
import random
tk = Tk()
tk.wm_title("Battleship")
switch = True
game_over = False
labels = []
class player:
def __init__(self):
self.switchuser = False
self.placedships = []
self.bombed = []
self.sunk = []
self.ship_sizes = [5, 4, 3, 3, 2]
self.direction = 'v'
self.player_ocean = []
temp = []
for i in range(10):
for y in range(10):
temp += [0]
self.player_ocean += [temp]
temp = []
self.selectedCoord = [0, 0] # [0] = x coord, [1] = y coord
self.attack_selection = [0, 0]
self.hits = []
self.misses = []
def selectPlacement(self, event, key):
'''
initialise column and row index
condition for different directions
check if ship placed is off grid or clashes with another ship
place ship
add to self.placedships
remove ship from availiable ships to cycle to next ship
'''
clear = True
col = self.selectedCoord[0]
row = self.selectedCoord[1]
print(self.selectedCoord)
if self.direction == 'v':
v_range_start = row - self.ship_sizes[0] + 1
if v_range_start >= 0: # check if ship will be off the grid
for cell in range(v_range_start, row + 1): # check if the ship clashes with existing ships
if [cell, col] in self.placedships:
clear = False
break
if clear == True:
for y in range(v_range_start, row + 1):
self.player_ocean[y][col] = 1
self.placedships.append([y, col])
self.ship_sizes.remove(self.ship_sizes[0])
refresh_ocean('place')
elif self.direction == 'h':
h_range_end = col + self.ship_sizes[0]
if 10 > h_range_end:
for cell in range(col, h_range_end):
if [row, cell] in self.placedships:
clear = False
break
if clear == True:
for x in range(col, h_range_end):
self.player_ocean[row][x] = 1
self.placedships.append([row, x])
self.ship_sizes.remove(self.ship_sizes[0])
refresh_ocean('place')
def selectAttack(self, event):
col = self.attack_selection[0]
row = self.attack_selection[1]
if [row, col] in ai.ai_placedships:
if [row, col] not in self.hits:
self.hits.append([row, col])
print('hit')
else:
if [row, col] not in self.misses:
self.misses.append([row, col])
# if str(type(event)) == 'tkinter.Event':
# return True
refresh_ocean('attackselection')
ai.ai_attack()
# forming tkinter window
def baseGrid():
gridLabel_player = Label(tk,
text="Your grid \nA B C D E F G H I J ")
gridLabel_player.grid(row=0, column=0)
gridLabel_ai = Label(tk,
text="AI's grid \nA B C D E F G H I J ")
gridLabel_ai.grid(row=0, column=1)
tk.player_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
tk.ai_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
tk.player_canvas.grid(row=1, column=0, padx=50)
tk.ai_canvas.grid(row=1, column=1, padx=50)
for x in range(10):
for y in range(10):
tk.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
tk.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
def moveShip(event, key):
print(player1.selectedCoord)
if event.keysym == 'Down':
if key == 'place':
if player1.selectedCoord[1] != 9:
player1.selectedCoord[1] += 1
elif key == 'attackselection':
if player1.attack_selection[1] != 9:
player1.attack_selection[1] += 1
elif event.keysym == 'Up':
if key == 'place':
if player1.selectedCoord[1] != 0:
player1.selectedCoord[1] -= 1
elif key == 'attackselection':
if player1.attack_selection[1] != 0:
player1.attack_selection[1] -= 1
elif event.keysym == 'Left':
if key == 'place':
if player1.selectedCoord[0] != 0:
player1.selectedCoord[0] -= 1
elif key == 'attackselection':
if player1.attack_selection[0] != 0:
player1.attack_selection[0] -= 1
elif event.keysym == 'Right':
if key == 'place':
if player1.selectedCoord[0] != 9:
player1.selectedCoord[0] += 1
elif key == 'attackselection':
if player1.attack_selection[0] != 9:
player1.attack_selection[0] += 1
for y in range(10):
for x in range(10):
if key == 'place':
if [y, x] == player1.selectedCoord or [x, y] in player1.placedships:
player1.player_ocean[x][y] = 1
else:
player1.player_ocean[x][y] = 0
# elif key == 'attackselection':
# if [y,x] == player1.attack_selection or [x,y] in player1.hits:
# ai.ai_ocean[x][y] = 1
# else:
# ai.ai_ocean[x][y] = 0
refresh_ocean(key)
def changedir(event):
if player1.direction == 'v':
player1.direction = 'h'
elif player1.direction == 'h':
player1.direction = 'v'
def refresh_ocean(key):
print('function call')
for y in range(10):
for x in range(10):
colour = 'white'
if key == 'place':
if [y, x] in player1.placedships:
colour = 'green'
if [x, y] == player1.selectedCoord:
colour = 'yellow'
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30, fill=colour))
elif key == 'attackselection':
# print('miss',ai.AI_miss,'\nhits',ai.destroyed_cords,'\nships',player1.placedships)
if [y, x] in player1.placedships:
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='green')
if [y, x] in ai.AI_miss:
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='gray')
if [y, x] in ai.destroyed_cords:
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='red')
if [y, x] in player1.hits:
colour = 'red'
if [y, x] in player1.misses:
colour = 'gray'
if [x, y] == player1.attack_selection:
colour = 'yellow'
tk.ai_canvas.itemconfig(
tk.ai_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill=colour)
# else:
# tk.player_canvas.itemconfig(
# tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30, fill='white'))
def attackGui():
tk.bind("<Key>", lambda event: moveShip(event, 'attackselection'))
tk.bind("<Return>", lambda event: player1.selectAttack(event))
class Ai(player):
def __init__(self):
# = [[[9,0], [9, 1], [9, 2], [9, 3], [9, 4]], [[9, 5], [9, 6]]]
# player1.placedships = [[[9, 0], [8, 0], [7, 0], [6, 0], [5, 0]], [[4, 0], [3, 0]]]
self.destroyed_ships = []
self.destroyed_cords = []
self.AI_miss = []
self.fmove_check = True
self.mdirection = 1
self.ai_placedships = []
self.directions = ['v', 'h']
self.ship_sizes = [5, 4, 3, 3, 2]
self.currentcoord = [0,0]
def ai_attack(self):
def first_move(self):
self.missed = 0
self.AIx = random.randint(0, 9)
self.AIy = random.randint(0, 9)
self.AIsel_cords = [self.AIy, self.AIx]
while self.AIsel_cords in self.AI_miss or self.AIsel_cords in self.destroyed_cords:
self.AIx = random.randint(0, 9)
self.AIy = random.randint(0, 9)
self.AIsel_cords = [self.AIy, self.AIx]
self.currentcoord = self.AIsel_cords
if self.AIsel_cords in player1.placedships:
# self.ship_check = ship
self.destroyed_cords.append(player1.placedships.pop(player1.placedships.index(self.AIsel_cords)))
self.fmove_check = False
else:
self.AI_miss.append(self.AIsel_cords)
def fol_move(self):
checked = False
self.entered = False
# direction check
if self.mdirection > 4:
self.mdirection = 1
# up
elif self.mdirection == 1 and self.AIy - 1 >= 0:
self.entered = True
self.AIy -= 1
self.currentcoord[0] -= 1
# to find whether the cords are part of a ship
if [self.AIy, self.AIx] in player1.placedships:
# if [self.AIx, self.AIy] in self.ship_check:
# self.destroyed_cords.append(ship.pop(ship.index([self.AIx, self.AIy])))
# else:
# self.destroyed_cords +=
self.destroyed_cords.append(
player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
checked = True
# add the cords that are not part of a ship into AI_miss
else:
self.AI_miss.append([self.AIy, self.AIx])
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
self.missed += 1
# left
elif self.mdirection == 2 and self.AIx - 1 >= 0:
self.entered = True
self.AIx -= 1
self.currentcoord[1] -= 1
# to find whether the cords are part of a ship
if [self.AIy, self.AIx] in player1.placedships:
self.destroyed_cords.append(
player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
checked = True
# add the cords that are not part of a ship into AI_miss
else:
self.AI_miss.append([self.AIy, self.AIx])
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
self.missed += 1
# down
elif self.mdirection == 3 and self.AIy + 1 <= 9:
self.entered = True
self.AIy += 1
self.currentcoord[0] += 1
# to find whether the cords are part of a ship
if [self.AIy, self.AIx] in player1.placedships:
self.destroyed_cords.append(
player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
checked = True
# add the cords that are not part of a ship into AI_miss
else:
self.AI_miss.append([self.AIy, self.AIx])
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
self.missed += 1
# right
elif self.mdirection == 4 and self.AIx + 1 <= 9:
self.entered = True
self.AIx += 1
self.currentcoord[1] += 1
# to find whether the cords are part of a ship
if [self.AIy, self.AIx] in player1.placedships:
self.destroyed_cords.append(
player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
checked = True
# add the cords that are not part of a ship into AI_miss
else:
self.AI_miss.append([self.AIy, self.AIx])
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
self.missed += 1
elif not self.entered:
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
if self.missed == 2:
self.missed = 0
self.fmove_check = True
if self.fmove_check:
first_move(self)
elif not self.fmove_check:
fol_move(self)
if not self.entered:
fol_move(self)
# print('\n', self.destroyed_cords)
# print(player1.placedships)
# print(self.AI_miss)
def ai_place(self):
print(len(ai.ship_sizes))
ai_dir = random.choice(self.directions)
col = random.randint(0, 9)
row = random.randint(0, 9)
clear = True
if ai_dir == 'v':
v_range_start = row - self.ship_sizes[0] + 1
if v_range_start >= 0: # check if ship will be off the grid
for cell in range(v_range_start, row + 1): # check if the ship clashes with existing ships
if [cell, col] in self.ai_placedships:
clear = False
break
if clear == True:
for y in range(v_range_start, row + 1):
self.ai_placedships.append([y, col])
self.ship_sizes.remove(self.ship_sizes[0])
elif ai_dir == 'h':
h_range_end = col + self.ship_sizes[0]
if 10 > h_range_end:
for cell in range(col, h_range_end):
if [row, cell] in self.ai_placedships:
clear = False
break
if clear == True:
for x in range(col, h_range_end):
self.ai_placedships.append([row, x])
self.ship_sizes.remove(self.ship_sizes[0])
attackinstructionLabel = Label(tk, text="Arrow keys to move selection"
"\nEnter to shoot at selected cell"
"\nGrey cells are missed ships"
"\nRed cells are hit ships")
attackinstructionLabel.grid(row=2)
instructionLabel = Label(tk, text="Arrow keys to move selection"
"\nRight shift to change ship orientation"
"\nEnter to place ship"
"\nYellow cells means that you are selecting a cell to place the next ship in"
"\nGreen cells show placed ships")
instructionLabel.grid(row=2)
tk.bind("<Key>", lambda event: moveShip(event, 'place'))
tk.bind("<Shift_R>", changedir)
tk.bind("<Return>", lambda event: player1.selectPlacement(event, 'place'))
base = baseGrid()
player1 = player()
ai = Ai()
while True:
tk.update()
tk.update_idletasks()
if len(player1.ship_sizes) != 0:
if len(ai.ship_sizes) != 0:
ai_place = ai.ai_place()
refresh_ocean('place')
else:
if (sorted(player1.hits) != sorted(ai.ai_placedships)) and len(player1.placedships) != 0:
attack = attackGui()
instructionLabel.destroy()
refresh_ocean('attackselection')
else:
popup = Tk()
p_label = Label(popup,text='GAME OVER')
popup.after(5000,p_label.destroy())
tk.destroy()
i tried taking out all the code run during the while loop that creates additional things in the program but it still gets noticeably laggy. the only thing i can identify right now which may be the problem is the refresh_ocean function which is the only thing that deals with the gui in the while loop but it uses the itemconfig method which shouldnt add on anything to the gui
I think you are using:
tk.player_canvas.itemconfig in bad way.
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='green')
You are creating more and more rectangles.
This is my usual way of handling an a grid on tkinter canvas
grid = [[0 for x in range(10)] for y in range(10)]
for x in range(10):
for y in range(10):
grid[x][y] = tk.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
tk.player_canvas.itemconfig( grid[x][y], fill="blue")
So first here is my code:
import pygame, sys, random
from pygame.locals import *
# Create the constants (go ahead and experiment with different values)
BOARDWIDTH = 4 # number of columns in the board
BOARDHEIGHT = 4 # number of rows in the board
TILESIZE = 80
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
FPS = 30
BLANK = None
# R G B
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
BRIGHTBLUE = ( 0, 50, 255)
DARKTURQUOISE = ( 3, 54, 73)
GREEN = ( 0, 204, 0)
BGCOLOR = DARKTURQUOISE
TILECOLOR = GREEN
TEXTCOLOR = WHITE
BORDERCOLOR = BRIGHTBLUE
BASICFONTSIZE = 20
BUTTONCOLOR = WHITE
BUTTONTEXTCOLOR = BLACK
MESSAGECOLOR = WHITE
XMARGIN = int((WINDOWWIDTH - (TILESIZE * BOARDWIDTH + (BOARDWIDTH - 1))) / 2)
YMARGIN = int((WINDOWHEIGHT - (TILESIZE * BOARDHEIGHT + (BOARDHEIGHT - 1))) / 2)
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, RESET_SURF, RESET_RECT, NEW_SURF, NEW_RECT, SOLVE_SURF, SOLVE_RECT
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Slide Puzzle')
BASICFONT = pygame.font.Font('freesansbold.ttf', BASICFONTSIZE)
# Store the option buttons and their rectangles in OPTIONS.
RESET_SURF, RESET_RECT = makeText('Reset', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 90)
NEW_SURF, NEW_RECT = makeText('New Game', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 60)
SOLVE_SURF, SOLVE_RECT = makeText('Solve', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 30)
mainBoard, solutionSeq = generateNewPuzzle(80)
SOLVEDBOARD = getStartingBoard() # a solved board is the same as the board in a start state.
allMoves = [] # list of moves made from the solved configuration
while True: # main game loop
slideTo = None # the direction, if any, a tile should slide
msg = 'Click tile or press arrow keys to slide.' # contains the message to show in the upper left corner.
if mainBoard == SOLVEDBOARD:
msg = 'Solved!'
drawBoard(mainBoard, msg)
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
spotx, spoty = getSpotClicked(mainBoard, event.pos[0], event.pos[1])
if (spotx, spoty) == (None, None):
# check if the user clicked on an option button
if RESET_RECT.collidepoint(event.pos):
resetAnimation(mainBoard, allMoves) # clicked on Reset button
allMoves = []
elif NEW_RECT.collidepoint(event.pos):
mainBoard, solutionSeq = generateNewPuzzle(80) # clicked on New Game button
allMoves = []
elif SOLVE_RECT.collidepoint(event.pos):
resetAnimation(mainBoard, solutionSeq + allMoves) # clicked on Solve button
allMoves = []
else:
# check if the clicked tile was next to the blank spot
blankx, blanky = getBlankPosition(mainBoard)
if spotx == blankx + 1 and spoty == blanky:
slideTo = LEFT
elif spotx == blankx - 1 and spoty == blanky:
slideTo = RIGHT
elif spotx == blankx and spoty == blanky + 1:
slideTo = UP
elif spotx == blankx and spoty == blanky - 1:
slideTo = DOWN
elif event.type == KEYUP:
# check if the user pressed a key to slide a tile
if event.key in (K_LEFT, K_a) and isValidMove(mainBoard, LEFT):
slideTo = LEFT
elif event.key in (K_RIGHT, K_d) and isValidMove(mainBoard, RIGHT):
slideTo = RIGHT
elif event.key in (K_UP, K_w) and isValidMove(mainBoard, UP):
slideTo = UP
elif event.key in (K_DOWN, K_s) and isValidMove(mainBoard, DOWN):
slideTo = DOWN
if slideTo:
slideAnimation(mainBoard, slideTo, 'Click tile or press arrow keys to slide.', 8) # show slide on screen
makeMove(mainBoard, slideTo)
allMoves.append(slideTo) # record the slide
pygame.display.update()
FPSCLOCK.tick(FPS)
def terminate():
pygame.quit()
sys.exit()
def checkForQuit():
for event in pygame.event.get(QUIT): # get all the QUIT events
terminate() # terminate if any QUIT events are present
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
terminate() # terminate if the KEYUP event was for the Esc key
pygame.event.post(event) # put the other KEYUP event objects back
def getStartingBoard():
# Return a board data structure with tiles in the solved state.
# For example, if BOARDWIDTH and BOARDHEIGHT are both 3, this function
# returns [[1, 4, 7], [2, 5, 8], [3, 6, BLANK]]
counter = 1
board = []
for x in range(BOARDWIDTH):
column = []
for y in range(BOARDHEIGHT):
column.append(counter)
counter += BOARDWIDTH
board.append(column)
counter -= BOARDWIDTH * (BOARDHEIGHT - 1) + BOARDWIDTH - 1
board[BOARDWIDTH-1][BOARDHEIGHT-1] = BLANK
return board
def getBlankPosition(board):
# Return the x and y of board coordinates of the blank space.
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if board[x][y] == BLANK:
return (x, y)
def makeMove(board, move):
# This function does not check if the move is valid.
blankx, blanky = getBlankPosition(board)
if move == UP:
board[blankx][blanky], board[blankx][blanky + 1] = board[blankx][blanky + 1], board[blankx][blanky]
elif move == DOWN:
board[blankx][blanky], board[blankx][blanky - 1] = board[blankx][blanky - 1], board[blankx][blanky]
elif move == LEFT:
board[blankx][blanky], board[blankx + 1][blanky] = board[blankx + 1][blanky], board[blankx][blanky]
elif move == RIGHT:
board[blankx][blanky], board[blankx - 1][blanky] = board[blankx - 1][blanky], board[blankx][blanky]
def isValidMove(board, move):
blankx, blanky = getBlankPosition(board)
return (move == UP and blanky != len(board[0]) - 1) or \
(move == DOWN and blanky != 0) or \
(move == LEFT and blankx != len(board) - 1) or \
(move == RIGHT and blankx != 0)
def getRandomMove(board, lastMove=None):
# start with a full list of all four moves
validMoves = [UP, DOWN, LEFT, RIGHT]
# remove moves from the list as they are disqualified
if lastMove == UP or not isValidMove(board, DOWN):
validMoves.remove(DOWN)
if lastMove == DOWN or not isValidMove(board, UP):
validMoves.remove(UP)
if lastMove == LEFT or not isValidMove(board, RIGHT):
validMoves.remove(RIGHT)
if lastMove == RIGHT or not isValidMove(board, LEFT):
validMoves.remove(LEFT)
# return a random move from the list of remaining moves
return random.choice(validMoves)
def getLeftTopOfTile(tileX, tileY):
left = XMARGIN + (tileX * TILESIZE) + (tileX - 1)
top = YMARGIN + (tileY * TILESIZE) + (tileY - 1)
return (left, top)
def getSpotClicked(board, x, y):
# from the x & y pixel coordinates, get the x & y board coordinates
for tileX in range(len(board)):
for tileY in range(len(board[0])):
left, top = getLeftTopOfTile(tileX, tileY)
tileRect = pygame.Rect(left, top, TILESIZE, TILESIZE)
if tileRect.collidepoint(x, y):
return (tileX, tileY)
return (None, None)
def drawTile(tilex, tiley, number, adjx=0, adjy=0):
# draw a tile at board coordinates tilex and tiley, optionally a few
# pixels over (determined by adjx and adjy)
left, top = getLeftTopOfTile(tilex, tiley)
pygame.draw.rect(DISPLAYSURF, TILECOLOR, (left + adjx, top + adjy, TILESIZE, TILESIZE))
textSurf = BASICFONT.render(str(number), True, TEXTCOLOR)
textRect = textSurf.get_rect()
textRect.center = left + int(TILESIZE / 2) + adjx, top + int(TILESIZE / 2) + adjy
DISPLAYSURF.blit(textSurf, textRect)
def makeText(text, color, bgcolor, top, left):
# create the Surface and Rect objects for some text.
textSurf = BASICFONT.render(text, True, color, bgcolor)
textRect = textSurf.get_rect()
textRect.topleft = (top, left)
return (textSurf, textRect)
def drawBoard(board, message):
DISPLAYSURF.fill(BGCOLOR)
if message:
textSurf, textRect = makeText(message, MESSAGECOLOR, BGCOLOR, 5, 5)
DISPLAYSURF.blit(textSurf, textRect)
for tilex in range(len(board)):
for tiley in range(len(board[0])):
if board[tilex][tiley]:
drawTile(tilex, tiley, board[tilex][tiley])
left, top = getLeftTopOfTile(0, 0)
width = BOARDWIDTH * TILESIZE
height = BOARDHEIGHT * TILESIZE
pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (left - 5, top - 5, width + 11, height + 11), 4)
DISPLAYSURF.blit(RESET_SURF, RESET_RECT)
DISPLAYSURF.blit(NEW_SURF, NEW_RECT)
DISPLAYSURF.blit(SOLVE_SURF, SOLVE_RECT)
def slideAnimation(board, direction, message, animationSpeed):
#This function does not check if the move is valid.
blankx, blanky = getBlankPosition(board)
if direction == UP:
movex = blankx
movey = blanky + 1
elif direction == DOWN:
movex = blankx
movey = blanky - 1
elif direction == LEFT:
movex = blankx + 1
movey = blanky
elif direction == RIGHT:
movex = blankx - 1
movey = blanky
# prepare the base surface
drawBoard(board, message)
baseSurf = DISPLAYSURF.copy()
# draw a blank space over the moving tile on the baseSurf Surface.
moveLeft, moveTop = getLeftTopOfTile(movex, movey)
pygame.draw.rect(baseSurf, BGCOLOR, (moveLeft, moveTop, TILESIZE, TILESIZE))
for i in range(0, TILESIZE, animationSpeed):
# animate the tile sliding over
checkForQuit()
DISPLAYSURF.blit(baseSurf, (0, 0))
if direction == UP:
drawTile(movex, movey, board[movex][movey], 0, -i)
if direction == DOWN:
drawTile(movex, movey, board[movex][movey], 0, i)
if direction == LEFT:
drawTile(movex, movey, board[movex][movey], -i, 0)
if direction == RIGHT:
drawTile(movex, movey, board[movex][movey], i, 0)
pygame.display.update()
FPSCLOCK.tick(FPS)
def generateNewPuzzle(numSlides):
# From a starting configuration, make numSlides number of moves (and
# animate these moves).
sequence = []
board = getStartingBoard()
drawBoard(board, '')
pygame.display.update()
pygame.time.wait(500) # pause 500 milliseconds for effect
lastMove = None
for i in range(numSlides):
move = getRandomMove(board, lastMove)
slideAnimation(board, move, 'Generating new puzzle...', animationSpeed=int(TILESIZE / 3))
makeMove(board, move)
sequence.append(move)
lastMove = move
return (board, sequence)
def resetAnimation(board, allMoves):
# make all of the moves in allMoves in reverse.
revAllMoves = allMoves[:] # gets a copy of the list
revAllMoves.reverse()
for move in revAllMoves:
if move == UP:
oppositeMove = DOWN
elif move == DOWN:
oppositeMove = UP
elif move == RIGHT:
oppositeMove = LEFT
elif move == LEFT:
oppositeMove = RIGHT
slideAnimation(board, oppositeMove, '', animationSpeed=int(TILESIZE / 2))
makeMove(board, oppositeMove)
if __name__ == '__main__':
main()
Here is the bubble sort code:
def shortBubbleSort(alist):
exchanges = True
passnum = len(alist)-1
while passnum > 0 and exchanges:
exchanges = False
for i in range(passnum):
if alist[i]>alist[i+1]:
exchanges = True
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
passnum = passnum-1
alist=[20,30,40,90,50,60,70,80,100,110]
shortBubbleSort(alist)
print(alist)
I am not sure how to select the numbers I have and arrange them using bubble sort method.
Oh - I found your code very complex for python and bubble-sort.
Here is the my view:
def bubbleSort(alist):
for passnum in range(len(alist)-1, 0, -1):
for i in range(passnum):
if alist[i] > alist[i+1]:
alist[i] , alist[i+1] = alist[i+1] , alist[i]
alist = [54,26,93,17,77,31,44,55,20]
bubbleSort(alist)
print(alist)
You do not need any flags or temp variables - this is the python, the language of magic! :) :) :) abracadabra!!!