I am trying to create a networked python chess game using tkinter, pygame and sockets.
My implementation is as follows:
Server class: no problems on this side
Player class:
-
when initialised, it creates the tkinter input window.
-
When the player has typed their alias, pressing the Return key triggers self.clear(), which gets rid of the input box, establishes a connection to the server, and send the player’s alias to the server in the form (‘alias’: self.alias}.
-
When the server has both player’s aliases, it broadcasts each other’s alias to each player, and also their (randomised) colour for the game, either white or black.
-
Once each player receives their colour, it kills the tkinter root window, and starts the game.
When the program triggers self.start_game(), that’s where I’m getting the ‘zsh: trace trap’ error.
from CTkMessagebox import CTkMessagebox
from chessboard import ChessBoard
from boardfunctions import *
from tkinter import *
import customtkinter
from sys import exit
from move import *
import threading
import itertools
import socket
import pygame
import math
import copy
import time
import json
import sys
FORMAT = 'utf-8'
BUFFSIZE = 1024
DISCONNECT_MESSAGE = '!DISCONNECT'
class Player:
def __init__(self, host='localhost', port=6679):
self.host = host
self.port = port
self.gameConfig = [['br', 'bn', 'bb', 'bq', 'bk', 'bb', 'bn', 'br'],
['bp', 'bp', 'bp', 'bp', 'bp', 'bp', 'bp', 'bp'],
['--', '--', '--', '--', '--', '--', '--', '--'],
['--', '--', '--', '--', '--', '--', '--', '--'],
['--', '--', '--', '--', '--', '--', '--', '--'],
['--', '--', '--', '--', '--', '--', '--', '--'],
['wp', 'wp', 'wp', 'wp', 'wp', 'wp', 'wp', 'wp'],
['wr', 'wn', 'wb', 'wq', 'wk', 'wb', 'wn', 'wr']]
self.alias = ''
self.opponent = ''
self.colour = ''
self.opponent_colour = ''
self.turn = None
self.game_active = True
customtkinter.set_appearance_mode('dark')
customtkinter.set_default_color_theme('dark-blue')
self.root = customtkinter.CTk()
self.root.title('Chess')
self.root.geometry('600x100+400+400')
self.entry = customtkinter.CTkEntry(self.root,
placeholder_text='Enter an alias',
height=100,
width=500,
font=('Georgia',25),
corner_radius=50,
text_color='#333634',
placeholder_text_color='#888a89',
fg_color=('black', '#b3daf2'),
state='normal'
)
self.entry.bind('<Return>', self.clear)
self.entry.pack(pady=20)
self.root.protocol('WM_DELETE_WINDOW', self.terminate)
self.root.mainloop()
def terminate(self):
self.json_convert_send({'protocol': DISCONNECT_MESSAGE})
self.clientsocket.close()
exit()
def clear(self, *args):
if self.entry.get():
self.alias = self.entry.get()
self.entry.destroy()
time.sleep(0.5)
self.wait = customtkinter.CTkLabel(self.root, text='Waiting for opponent...', font=('Georgia',30))
self.wait.pack(pady=30)
self.establish_connection()
def establish_connection(self):
self.clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.clientsocket.connect((self.host, self.port))
self.client_thread = threading.Thread(target=self.client_receive, daemon=True).start()
self.json_convert_send({'alias':self.alias})
def json_convert_send(self, message):
message = json.dumps(message)
try:
self.clientsocket.send(message.encode(FORMAT))
except Exception as e:
print('ERROR: ' + e)
def json_convert_recv(self):
message = self.clientsocket.recv(BUFFSIZE).decode(FORMAT)
message = json.loads(message)
tag = next(iter(message.keys()))
item = next(iter(message.values()))
return tag, item
def client_receive(self):
while True:
try:
tag, item = self.json_convert_recv()
if tag == 'gameConfig':
newConfig = item
for i in range(2):
newConfig = list(zip(*newConfig[::-1]))
self.gameConfig = newConfig
self.turn = True
elif tag == 'aliases':
for alias in item:
if alias != self.alias:
self.opponent = alias
elif tag == 'colour':
self.colour = item
self.turn = True if self.colour == 'w' else False
self.opponent_colour = 'b' if self.colour == 'w' else 'w'
self.root.withdraw()
self.start_game()
elif item == DISCONNECT_MESSAGE:
msg = CTkMessagebox(title='Connection Lost', message='Your opponent has disconnected!', option_1='OK')
if msg.get() == 'OK':
self.json_convert_send({'protocol':'shutdown'})
self.root.destroy()
exit()
except Exception as e:
print(e)
self.clientsocket.close()
exit()
def start_game(self):
print('game started!')
WIDTH, HEIGHT = 1300, 800
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Chess')
clock = pygame.time.Clock()
if self.colour == 'b':
for i in range(2):
self.gameConfig = list(zip(*self.gameConfig[::-1]))
print(self.gameConfig)
players = ['w', 'b']
idx = 0
source = 0
dest = 0
moveStack = []
moveStack.append(copy.deepcopy(gameConfig))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
mouseLoc = pygame.mouse.get_pos()
if self.turn:
if game.topleft[0] <= mouseLoc[0] <= game.bottomright[0] and game.topleft[1] <= mouseLoc[1] <= game.bottomright[1]:
if source == 0:
sourceSQ = calculateSquare(game, mouseLoc)
if gameConfig[sourceSQ[0]][sourceSQ[1]][0] == self.colour:
source = mouseLoc
else:
dest = mouseLoc
destSQ = calculateSquare(game, dest)
if gameConfig[destSQ[0]][destSQ[1]][0] != self.colour and checkLegalMoves(sourceSQ, destSQ, self.colour, self.opponent_colour):
Move(sourceSQ, destSQ).updateBoard(game, gameConfig, sourceSQ, destSQ)
moveStack.append(copy.deepcopy(gameConfig))
source, dest = 0, 0
idx = (idx + 1) % 2
self.turn = False
else:
source = 0
dest = 0
else:
if source != 0:
source = 0
if game.undo_rect.collidepoint(mouseLoc):
if len(moveStack) > 1:
moveStack = moveStack[:-1]
gameConfig = moveStack[-1]
idx = (idx + 1) % 2
if game_active:
game = ChessBoard(screen, moveStack[-1])
pygame.display.update()
clock.tick(60)
Player()
Sorry for the lengthy code, but I have no idea what’s wrong. Is it because the self.start_game function is called from inside the player’s socket thread? Or smth wrong with how my program is structured? I also read that tkinter and pygame are not threadsafe, but I’m not sure how else to implement it. Any help would be greatly appreciated!
user24889088 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.