Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

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

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Income Tax Fundamentals 2013

Authors: Gerald E. Whittenburg, Martha Altus Buller, Steven L Gill

31st Edition

1111972516, 978-1285586618, 1285586611, 978-1285613109, 978-1111972516

More Books

Students also viewed these Programming questions