+1 (315) 557-6473 

Python Program to Create A Tic-Tac-Toe Game Assignment Solution.


Instructions

Objective
Write a python assignment program to create a tic-tac-toe game.

Requirements and Specifications

Source Code
GAMEBOARD
import tkinter as tk
from tkinter import simpledialog
from tkinter.messagebox import askyesno
from turtle import update
from numpy import true_divide
class BoardClass:
def __init__(self, player):
self.players = [] # players that will be playing. This list will contains 'X' and 'O'
self.player = player # Owner of the board
self.turn_player = "X" # Variable to switch turns
self.window = None # Tkinter window
self.boardButtons = list()
self.infoLabel = None
self.hasPlayed = False
# Counters to record the number of games played, wins, losses and ties
self.games_played = 0
self.number_of_wins = 0
self.number_of_ties = 0
self.number_of_losses = 0
# Board
self.board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']
]
def startGUI(self):
# Create window
self.window = tk.Tk()
self.window.title('Tic Tac Toe - Player ' + self.player)
self.window.geometry('400x300')
self.infoLabel = tk.Label(self.window, text = "Waiting for the other player to connect...")
self.infoLabel.pack()
# Grid for buttons
for i in range(3):
row = list()
for j in range(3):
btn = tk.Button(self.window, text = " ", height = 3, width = 6)
row.append(btn)
self.boardButtons.append(row)
x = 100
y = 50
for i in range(3):
for j in range(3):
#self.boardButtons[i][j].grid(row = i+1, column = j)
self.boardButtons[i][j].place(x=x, y=y)
x += 55
y += 60
x = 100
#self.askForConnectionInfo()
#self.window.mainloop()
self.window.update()
def displayInfo(self, message):
self.infoLabel.config(text = message)
print(self.player, message)
self.window.update()
def askYesNo(self, title, message):
answer = askyesno(title = title, message = message)
self.window.update()
return answer
def askForConnectionInfo(self):
serverHost = simpledialog.askstring("Host", "Enter server host", parent = self.window)
serverPort = simpledialog.askstring("Port", "Enter server port", parent = self.window)
return serverHost, int(serverPort)
def askForMove(self):
row = simpledialog.askstring("Move", "Enter row", parent = self.window)
col = simpledialog.askstring("Move", "Enter column", parent = self.window)
return int(row), int(col)
def addPlayer(self, player):
# Add a player to the game
self.players.append(player)
def updateGamesPlayed(self):
# Increment counter for number of games played
self.games_played += 1
def resetGameBoard(self):
# Reset the board
self.board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']
]
for i in range(3):
for j in range(3):
self.boardButtons[i][j].config(text = ' ')
def printBoard(self):
# print board
print('+---+---+---+')
for i in range(3):
for j in range(3):
print('| ' + self.board[i][j] + ' ', end='')
print('|')
print('+---+---+---+')
def isValid(self, row, column):
# Check that the movement is valid
if row < 1 or row > 3 or column < 1 or column > 3:
return False
return True
def updateGameBoard(self, row, column, token):
# Check that the given position is in the bounds
if not self.isValid(row, column):
return f"Invalid move. Given row or column is outside the bounds!"
# First, check it the cell at the given position is empty
if not self.board[row-1][column-1] == ' ':
return f"Invalid move. Position ({row},{column}) is not empty."
# Update board
self.board[row-1][column-1] = token
self.boardButtons[row-1][column-1].config(text = token)
# Switch turns
if self.turn_player == 'X':
elf.turn_player = 'O'
else:
self.turn_player = 'X'
self.window.update()
return None
def isWinner(self, token):
# Check if the given token is a winner
# First check columns
for j in range(3):
if self.__column(j) == [token, token, token]:
return True
# Now check rows
for i in range(3):
if self.__row(i) == [token, token, token]:
return True
# Check diagonals
diag = [self.board[0][0], self.board[1][1], self.board[2][2]]
if diag == [token, token, token]:
return True
diag = [self.board[2][0], self.board[1][1], self.board[0][2]]
if diag == [token, token, token]:
return True
return False
def boardIsFull(self):
for i in range(3):
for j in range(3):
if self.board[i][j] == ' ':
return False
return True
def printStats(self):
print('='*10)
print("SUMMARY")
print('='*10)
print("Player: " + self.player)
print("Last turn: " + self.turn_player)
print("Number of games: " + str(self.games_played))
print("Number of wins: " + str(self.number_of_wins))
print("Number of losses: " + str(self.number_of_losses))
print("Number of ties: " + str(self.number_of_ties))
print('='*10)
def __column(self, column):
# Returns a list containing the elements in the requested column from board
return [self.board[i][column] for i in range(3)]
def __row(self, row):
# Returns a list containing the elements in the requested row from board
return self.board[row]
PLAYER 1
import socket
from gameboard import *
import time
'''
PLAYER 1 IS THE CLIENT
'''
# First, open connection to receive connections
# Now receive connections
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#DESKTOP-HETA5H7
PLAYER_NAME = "X"
# Create board
board = BoardClass(PLAYER_NAME)
# Ask for host and port
board.startGUI()
IP, Port = board.askForConnectionInfo()
# Now connect
# Ask for host and port
connected = False
while not connected:
#IP = input("Enter hostname of Player 2 (Server): ")
#Port = int(input("Enter Port of Player 2 (Server): "))
try:
s.connect((IP, Port))
connected = True
board.displayInfo("Connected!")
except:
board.displayInfo("Unable to connect to " + IP + ":" + str(Port))
answer = board.askYesNo("Connected", "Try again? (y/n): ")
if not answer:
break
if not connected:
board.displayInfo("Connection not made. Exiting program")
exit(0)
# Receive name from player 2 (Server)
player1_name = s.recv(1024).decode()
board.displayInfo("Player " + player1_name + " has joined the game!")
board.addPlayer(player1_name)
# Send username
s.send(PLAYER_NAME.encode())
# Now, begin with program
running = True
while running:
# Start round
round_running = True
board.resetGameBoard()
board.updateGamesPlayed()
board.turn_player = 'X'
while round_running:
# Ask for move
if board.turn_player == PLAYER_NAME:
board.displayInfo("It is your turn, please make a move!")
board.hasPlayed = False
while not board.hasPlayed:
# Wait for move
row, col = board.askForMove()
result = board.updateGameBoard(row, col, board.turn_player)
if result is None:
board.hasPlayed = True
board.displayInfo("Waiting for Player 2 move...")
message = f"{row},{col},{PLAYER_NAME}".encode()
s.send(message)
if board.isWinner(PLAYER_NAME):
board.displayInfo("Player " + PLAYER_NAME + " won!")
board.number_of_wins += 1
round_running = False
elif board.boardIsFull(): # If the board is full and no winner, then it is a tie
board.displayInfo("It is a tie, nobody wins!")
round_running = False
board.number_of_ties += 1
else:
board.displayInfo(result)
else:
board.displayInfo("Waiting for Player 2 to move...")
# Now receive
message = s.recv(1024).decode()
data = message.split(',')
row = int(data[0])
col = int(data[1])
player2_name = data[2]
board.displayInfo(f"Player {player2_name} played on ({row},{col})")
board.updateGameBoard(row, col, player2_name)
board.printBoard()
if board.isWinner(player2_name):
board.displayInfo("Player " + player2_name + " won!")
round_running = False
board.number_of_losses += 1
# Receive answer from player 2
print("Waiting for Player 2 to see if another round is played...")
answer = s.recv(1024).decode()
if answer == 'n': # Player 2 said no
print("Player 2 declined to play a new round.")
board.printStats()
running = False
elif answer == 'y':
print("Player 2 accepted to play a new round.")
PLAYER 2
from cgitb import enable
import socket
from gameboard import *
import tkinter as tk
import time
'''
PLAYER 2 IS THE SERVER
'''
PLAYER_NAME = "O"
# Create board
board = BoardClass(PLAYER_NAME)
board.startGUI()
# Create socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Now receive connections
hostport = 8080
hostname = socket.gethostname()
s.bind((hostname, hostport))
s.listen(1)
print("Server started at " + hostname + " on port " + str(hostport))
print("Waiting for Player 1 to connect...")
board.displayInfo("Server started at " + hostname + " on port " + str(hostport))
board.displayInfo("Waiting for Player 1 to connect...")
(clientsocket, address) = s.accept()
# Now send to player 1 the name of player 1
clientsocket.send(PLAYER_NAME.encode())
# Receive player2 name
player2_name = clientsocket.recv(1024)
board.displayInfo("Player " + player2_name.decode() + " has joined the game!")
board.addPlayer(player2_name)
# Now, begin with the round
running = True
while running:
# Start a new round
round_running = True
board.resetGameBoard()
board.updateGamesPlayed()
board.turn_player = 'X'
while round_running:
if board.turn_player == PLAYER_NAME:
board.displayInfo("It is your turn, please make a move!")
board.hasPlayed = False
while not board.hasPlayed:
# Wait for move
row, col = board.askForMove()
result = board.updateGameBoard(row, col, board.turn_player)
if result is None:
board.hasPlayed = True
message = f"{row},{col},{PLAYER_NAME}".encode()
clientsocket.send(message)
if board.isWinner(PLAYER_NAME):
board.displayInfo("Player " + PLAYER_NAME + " won!")
board.number_of_wins += 1
round_running = False
elif board.boardIsFull(): # If the board is full and no winner, then it is a tie
board.displayInfo("It is a tie, nobody wins!")
round_running = False
board.number_of_ties += 1
else:
board.displayInfo(result)
else:
board.displayInfo("Waiting for Player 1 to move...")
# Now receive
message = clientsocket.recv(1024).decode()
data = message.split(',')
row = int(data[0])
col = int(data[1])
player1_name = data[2]
board.displayInfo(f"Player {player1_name} played on ({row},{col})")
board.updateGameBoard(row, col, player1_name)
#board.printBoard()
if board.isWinner(player1_name):
board.displayInfo("Player " + player1_name + " won!")
board.number_of_losses += 1
round_running = False
# Ask Player 1 if s/he wants to play again
answer = board.askYesNo("Play again?", "Do you want to play another round?")
# Send answer to player 1
if not answer:
running = False
# Print statistics
board.printStats()
# Send choice to player 1
answerStr = "y"
if not answer:
answerStr = "n"
clientsocket.send(answerStr.encode())