Question
I have create 3 modules but the code are not fully correct, can you help me fix it? these are the requirements Purpose of this
I have create 3 modules but the code are not fully correct, can you help me fix it?
these are the requirements
Purpose of this Lab:
The purpose of this lab is to get you used to networking by using sockets. (In our case, both the client and the server will be running on our local machine) and creating a user interface. The main libraries to be used are the sockets library (socket) and tkinter (or PyGames).
As for all labs this quarter, you will need to ensure your code works using IDLE with the version being used this quarter (Python 3.10), and refer to my lecture on sockets and tkinter for a refresher on how to use sockets and write a user interface.
Introduction to the Lab :
In this lab, we will be creating a Tic Tac Toe game. For those not familiar with Tic Tac Toe, refer to this Wikipedia page (Links to an external site.)Links to an external site. for it. In short, Tic Tac Toe is a 2-player game where one player's game piece is X and the second player's game piece is O (letter). The players take turns putting 1 of their game pieces in 1 of the empty slots in the 3 by 3 board. The first player to get 3 of their game pieces to align (vertically, horizontally or diagonally) wins. If the board has no empty slots and neither of the players has already won, no one wins and the game ends in a tie.
For this lab, I would like you to use sockets to pass the player moves between the players, one of whom is acting as the server and the other as the client. Our tic tac toe game will use a standard 3 x 3 board, and we will also use the standard x/X and o/O for the values that we will be passing back and forth.
Program Details:
You will create 3 new modules with the following details:
class BoardClass (gameboard.py)
The board game will consist of the following public interface. (Note this module can be imported and used by both player1 and player2 modules
The class should have a minimum of the following (you can add more if you need to):
Attributes:
User name of player 1
User name of player 2
User name of the last player to have a turn
Number of wins
Number of ties
Number of losses
Functions:
updateGamesPlayed()
Keeps track how many games have started
resetGameBoard()
Clear all the moves from game board
updateGameBoard()
Updates the game board with the player's move
isWinner()
Checks if the latest move resulted in a win
Updates the wins and losses count
boardIsFull()
Checks if the board is full (I.e. no more moves to make - tie)
Updates the ties count
computeStats()
Computes and returns the following stats:
The username of both players
The number of games
The number of wins
The number of losses
The number of ties
Player 1 Module(Module Name: player1.py) - The joining player
As the client, Player 1 will ask the user for the host information of Player 2 to join the game:
Prompt the user for the host name/IP address of Player 2 they want to play with
Prompt the user for the port to use in order to play with Player 2
Using that information they will attempt to connect to Player 2
Upon successful connection they will send Player 2 their username (just alphanumeric username with no special characters)
If the connection cannot be made then the user will be asked if they want to try again:
If the user enters 'Y/y' (or clicks a button) then you will request the host information from the user again
If the user enters 'N/n' (or clicks a button) then you will end the program
Once Player 1 receives Player 2's username or if the users decides to play again
Player 1 will ask the user for their move using the current player display area.
Send the move to player 2.
Player 1 will always be x/X
Player 1 will always send the first move to Player 2
Each move will correspond to the area on the board they user clicks on.
Once player 1 sends their move they will wait for Player 2's move.
Repeat steps 3.1 - 3.2.3 until the game is over (A game is over when a winner is found or the board is full)
Once a game has finished (win, lose, or tie) the user will indicate if they want to play again using the user interface.
If the user enters 'Y/y' (or clicks a button) then player 2 will send "Play Again" to player 2
If the user enters 'N/n' (or clicks a button) then player 2 will send "Fun Times" to player 2 and end the program
Once the user is done, the module will print all the statistics.
Player 2 Module (Module Name: player2.py) - The host of the game, or the server
The user will be asked to provide the host information so that it can establish a socket connection as the server
Player 2 will accept incoming requests to start a new game
When a connection request is received and accepted, Player 2 will wait for Player 1 to send their username
Once Player 2 receives Player 1's user name, then Player 2 will ask the user to enter their username and send it to Player 1 and wait for Player 1 to send their move.
Once Player 2 receives Player 1's move they will ask the user for their move and send it to Player 1 using the current player display area.
Each move will correspond to the area on the board they user clicks on.
Once player 2 sends their move they will wait for Player 1's move.
Repeat steps 4.1 - 4.2 until the game is over (A game is over when a winner is found or the board is full)
Once a game has finished (win or tie) player 2 will wait for player 1 to indicate if they want to play again using the user interface.
If Player 1 wants to play again then Player 2 will wait for player 1's first move.
If Player 1 does not wants to play again then Player 2 will print the statistics
User Interface:
You will create a user interface using either the Tkinter library or the PyGames library. At no point should the user be required to interact with the python shell with the input() or print() functions. The user interface should include the following components:
A text entry for the host information
A text entry for the username
A Tic Tac Toe board that allows the user to select their move by clicking on that
A dialog that asks the user if they want to play again (only on player 1)
A display area where you display the BoardClass's computed statistics when they are done and any other printed information specified in the lab.
An area indicating who's turn it is currently
An area where the final results will be displayed
and these are the 3 modules
gameboard.py
import tkinter as tk
from tkinter import messagebox
from tkinter.scrolledtext import ScrolledText
class BoardClass:
def __init__(self, player_name):
"""
Initialize the game board.
Args:
player_name (str): Name of the player
"""
self.player_name = player_name
self.last_player = None
self.move = 'X'
self.opponent = 'O'
self.wins = {player_name: 0}
self.ties = 0
self.losses = {player_name: 0}
self.games_played = 0
self.game_board = [[' ' for _ in range(3)] for _ in range(3)]
def updateGamesPlayed(self):
"""
Update the number of games played.
"""
self.games_played += 1
def resetGameBoard(self):
"""
Reset the game board.
"""
self.game_board = [[' ' for _ in range(3)] for _ in range(3)]
self.last_player = None
def updateGameBoard(self, player, row, col):
"""
Update the game board with the player's move.
Args:
player (str): Player's move ('X' or 'O')
row (int): Row index
col (int): Column index
"""
self.game_board[row][col] = self.move
self.last_player = player
if self.move == 'X':
self.move = 'O'
elif self.move == 'O':
self.move = 'X'
def isWinner(self, move):
"""
Check if there is a winner on the game board.
Args:
move (str): Current move ('X' or 'O')
Returns:
winner (bool): True if the current player wins, False if the opponent wins, None if no winner yet
"""
winning_moves = [
[[0, 0], [0, 1], [0, 2]],
[[1, 0], [1, 1], [1, 2]],
[[2, 0], [2, 1], [2, 2]],
[[0, 0], [1, 0], [2, 0]],
[[0, 1], [1, 1], [2, 1]],
[[0, 2], [1, 2], [2, 2]],
[[0, 0], [1, 1], [2, 2]],
[[0, 2], [1, 1], [2, 0]],
]
opponent = 'O' if move == 'X' else 'X'
for move_combination in winning_moves:
marks = [self.game_board[row][col] for row, col in move_combination]
if marks == [move, move, move]:
return True
elif marks == [opponent, opponent, opponent]:
return False
return None
def boardIsFull(self):
"""
Check if the game board is full.
Returns:
full (bool): True if the game board is full, False otherwise
"""
for row in self.game_board:
if ' ' in row:
return False
# Indicate that the game board is full
return True
def computeStats(self):
"""
Compute and return the game statistics.
Returns:
stats (dict): Dictionary containing the following stats:
- player_name (str): Name of the player
- games_played (int): Number of games played
- wins (dict): Number of wins for the player {player_name: wins}
- losses (dict): Number of losses for the player {player_name: losses}
- ties (int): Number of ties
"""
stats = {
'player_name': self.player_name,
'games_played': self.games_played,
'wins': self.wins,
'losses': self.losses,
'ties': self.ties
}
return stats
class TicTacToeGUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.board = BoardClass("Player1")
self.buttons = [[None, None, None] for _ in range(3)]
self.build_board()
def build_board(self):
"""Builds the tic-tac-toe board GUI."""
# Host information entry
self.host_entry = tk.Entry(self)
self.host_entry.grid(row=0, column=0, columnspan=3)
self.host_entry.insert(0, "Enter host information")
# Username entry
self.username_entry = tk.Entry(self)
self.username_entry.grid(row=1, column=0, columnspan=3)
self.username_entry.insert(0, "Enter username")
# Game board buttons
for i in range(3):
for j in range(3):
self.buttons[i][j] = tk.Button(
self, text=' ', command=lambda row=i, col=j: self.button_click(row, col), height=2, width=5
)
self.buttons[i][j].grid(row=i + 3, column=j) # Start the game board at the 3rd row
# Current turn label
self.current_turn_label = tk.Label(self, text=f"{self.board.player_name}'s turn")
self.current_turn_label.grid(row=6, column=0, columnspan=3)
# Final result label
self.final_result_label = tk.Label(self, text="")
self.final_result_label.grid(row=7, column=0, columnspan=3)
# Statistics display area
self.stats_text = ScrolledText(self)
self.stats_text.grid(row=8, column=0, columnspan=3)
def button_click(self, row, col):
"""Event handler for button clicks."""
if self.board.game_board[row][col] == ' ':
self.board.updateGameBoard(self.board.player_name, row, col)
self.buttons[row][col]['text'] = self.board.game_board[row][col]
if self.board.isWinner('X'):
self.display_winner('X')
self.board.updateStats('win')
elif self.board.isWinner('O'):
self.display_winner('O')
self.board.updateStats('loss')
elif self.board.boardIsFull():
self.display_draw()
self.board.updateStats('tie')
self.update_stats_display()
def display_winner(self, player):
"""Displays the winner of the game."""
messagebox.showinfo('Game Over', f'Player {player} wins!')
self.board.resetGameBoard()
self.reset_buttons()
def display_draw(self):
"""Displays a message if the game is a draw."""
messagebox.showinfo('Game Over', 'Draw!')
self.board.resetGameBoard()
self.reset_buttons()
def reset_buttons(self):
"""Resets the text of all buttons."""
for i in range(3):
for j in range(3):
self.buttons[i][j]['text'] = ' '
def update_stats_display(self):
"""Updates the statistics display area."""
stats = self.board.computeStats()
self.stats_text.delete('1.0', tk.END)
self.stats_text.insert(tk.END, "Player's username: {}\n".format(stats['player_name']))
self.stats_text.insert(tk.END, "Number of games played: {}\n".format(stats['games_played']))
self.stats_text.insert(tk.END, "Number of games won: {}\n".format(stats['wins'][stats['player_name']]))
self.stats_text.insert(tk.END, "Number of games tied: {}\n".format(stats['ties']))
self.stats_text.insert(tk.END, "Number of games lost: {}\n".format(stats['losses'][stats['player_name']]))
self.stats_text.insert(tk.END, "Total number of games played: {}\n".format(stats['games_played']))
self.stats_text.config(state=tk.DISABLED)
if __name__ == '__main__':
game_gui = TicTacToeGUI()
game_gui.mainloop()
player1.py
import socket
import tkinter as tk
from tkinter import messagebox
from gameboard import BoardClass
class Player1GUI(tk.Tk):
"""Class for the Player 1 GUI."""
def __init__(self):
tk.Tk.__init__(self)
self.title("Player 1")
self.geometry('200x150')
self.configure(background='white')
self.resizable(0, 0)
self.host = None
self.port = None
self.username = None
self.server_socket = None
self.game_board = BoardClass("Player1")
self.create_widgets()
def create_widgets(self):
"""Create the GUI widgets."""
host_label = tk.Label(self, text="Host/IP Address:")
host_label.pack()
self.host_entry = tk.Entry(self)
self.host_entry.pack()
port_label = tk.Label(self, text="Port:")
port_label.pack()
self.port_entry = tk.Entry(self)
self.port_entry.pack()
connect_button = tk.Button(self, text="Connect", command=self.start_server)
connect_button.pack()
def start_server(self):
"""Start the server and wait for Player 2 to connect."""
self.host = self.host_entry.get()
self.port = int(self.port_entry.get())
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.host, self.port))
self.server_socket.listen(1)
print("Waiting for Player 2 to connect...")
self.client_socket, addr = self.server_socket.accept()
print("Player 2 connected.")
self.username = self.get_username()
self.client_socket.send(self.username.encode())
self.play_game()
except socket.error as e:
print(f"Error occurred: {e}")
self.quit()
def get_username(self):
"""Prompt the user for their username."""
username = None
while not username:
username = input("Enter your username: ")
if not username.isalnum():
print("Invalid username. Please use only alphanumeric characters.")
username = None
return username
def play_game(self):
"""Start playing the game with Player 2."""
print("Game started.")
while True:
self.game_board.print_board()
self.get_player1_move()
if self.username == "QUIT":
print("You have quit the game.")
self.client_socket.send("QUIT".encode())
break
self.client_socket.send(self.username.encode())
if self.username == "Play Again":
continue
player2_move = self.client_socket.recv(1024).decode()
if player2_move == "Play Again":
continue
if player2_move == "Fun Times":
break
self.server_socket.close()
print("Closing the game.")
def get_player1_move(self):
"""Prompt Player 1 for a move."""
self.username = input("Your move: ")
if self.username.lower() == "quit":
self.quit()
def quit(self):
"""Quit the game."""
self.username = "QUIT"
if __name__ == "__main__":
player1 = Player1GUI()
player1.mainloop()
player2.py
import socket
import tkinter as tk
from tkinter import messagebox
from gameboard import BoardClass
class Player2GUI(tk.Tk):
"""Class for the Player 2 GUI."""
def __init__(self):
tk.Tk.__init__(self)
self.title("Player 2")
self.geometry('200x150')
self.configure(background='white')
self.resizable(0, 0)
self.host = None
self.port = None
self.username = None
self.client_socket = None
self.game_board = BoardClass("Player2")
self.create_widgets()
def create_widgets(self):
"""Create the GUI widgets."""
host_label = tk.Label(self, text="Host/IP Address:")
host_label.pack()
self.host_entry = tk.Entry(self)
self.host_entry.pack()
port_label = tk.Label(self, text="Port:")
port_label.pack()
self.port_entry = tk.Entry(self)
self.port_entry.pack()
connect_button = tk.Button(self, text="Connect", command=self.connect_to_server)
connect_button.pack()
def connect_to_server(self):
"""Connect to the server hosted by Player 1."""
self.host = self.host_entry.get()
self.port = int(self.port_entry.get())
try:
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.connect((self.host, self.port))
self.username = self.get_username()
self.client_socket.send(self.username.encode())
self.play_game()
except socket.error as e:
print(f"Error occurred: {e}")
self.quit()
def get_username(self):
"""Prompt the user for their username."""
username = None
while not username:
username = input("Enter your username: ")
if not username.isalnum():
print("Invalid username. Please use only alphanumeric characters.")
username = None
return username
def play_game(self):
"""Start playing the game with Player 1."""
print("Game started.")
while True:
self.game_board.print_board()
player1_move = self.client_socket.recv(1024).decode()
if player1_move == "QUIT":
print("Player 1 has quit the game.")
break
if player1_move == "Play Again":
continue
self.get_player2_move()
self.client_socket.send(self.username.encode())
if self.username == "Play Again":
continue
if self.username == "Fun Times":
break
self.client_socket.close()
print("Closing the game.")
def get_player2_move(self):
"""Prompt Player 2 for a move."""
self.username = input("Your move: ")
if self.username.lower() == "quit":
self.quit()
def quit(self):
"""Quit the game."""
self.username = "QUIT"
if __name__ == "__main__":
player2 = Player2GUI()
player2.mainloop()
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started