倒计时井字游戏Python

问题描述 投票:0回答:1

所以,我尝试在 python 中的井字棋游戏上应用倒计时器,因为这个游戏在终端上运行,如果这个实现我会遇到几个问题,因为当前的实现显示计时器在假设的同一行运行让用户输入他想要在网格的哪个象限中玩。我想做的是显示正在运行的计时器,而不妨碍用户输入其游戏的行。这可以在终端上实现吗?如果是的话,我该如何申请?

tic_tac_toe.py

from bot import Bot
import time
import threading

class TicTacToe:
    def __init__(self):
        self.board = [" "] * 9
        self.x = "x"
        self.o = "o"

    def display_grid(self):
        print(f"""
            1    |2    |3
              {self.board[0]}  |  {self.board[1]}  |  {self.board[2]} 
            _____|_____|_____
            4    |5    |6
              {self.board[3]}  |  {self.board[4]}  |  {self.board[5]} 
            _____|_____|_____
            7    |8    |9
              {self.board[6]}  |  {self.board[7]}  |  {self.board[8]}
                 |     |
            """)

    def highlight_win(self, a, b, c):
        if b == a + 1:
            self.board[a], self.board[b], self.board[c] = "-", "-", "-"
        elif b == a + 3:
            self.board[a], self.board[b], self.board[c] = "|", "|", "|"
        elif a == 0 and c == 8:
            self.board[a], self.board[b], self.board[c] = "\\", "\\", "\\"
        elif a == 2 and c == 6:
            self.board[a], self.board[b], self.board[c] = "/", "/", "/"



    def check_win_row(self, player):
        for i in range(0, 9, 3):
            if self.board[i] == self.board[i+1] == self.board[i+2] == player:
                self.highlight_win(i, i+1, i+2)
                return True
                
        return False  


    def check_win_column(self, player):
        columns = [[0, 3, 6], [1, 4, 7], [2, 5, 8]]
        for col in columns:
            if self.board[col[0]] == self.board[col[1]] == self.board[col[2]] == player:
                self.highlight_win(col[0], col[1], col[2])
                return True 
        return False    


    def check_win_diagonals(self, player):
        diagonals = [[0, 4, 8], [2, 4, 6]]
        for dialgonal in diagonals:
            if self.board[dialgonal[0]] == self.board[dialgonal[1]] == self.board[dialgonal[2]] == player:
                self.highlight_win(dialgonal[0], dialgonal[1], dialgonal[2])
                return True
        return False



    def check_win(self, player):
        if self.check_win_row(player) or self.check_win_column(player) or self.check_win_diagonals(player):
            print(f"{player} wins!!!")
            return True
        return False

        
class GameController:
    def __init__(self):
        self.game = TicTacToe()
        self.adversary = Bot()
        self.timer_active = True

    def get_play(self, player):
        while True:
            try:
                play = input(f"{player}'s turn: ")
                if play.isdigit() and 1 <= int(play) <= 9:
                    return play
                else:
                    raise ValueError("Type a number between 1 to 9")
            except ValueError as e:
                print(e)


    def countdown_timer(self, duration):
        """Countdown timer that stops the game when time runs out."""
        while duration > 0 and self.timer_active:
            print(f"Time remaining: {duration} seconds", end="\r")
            time.sleep(1)
            duration -= 1
        if duration == 0:
            self.timer_active = False
            print("\nTime's up! Game over.")

    def game_loop(self, game_style, difficulty):
        for j in range(9):
            if game_style == "bot":
                if j % 2 == 0:
                    player = self.game.x
                    move = self.get_play(player)
                    quadrant = int(move) - 1 
                    if self.game.board[quadrant] == " ":
                        self.game.board[quadrant] = player
                        self.game.display_grid()
                        if self.game.check_win(player):
                            self.game.display_grid()
                            break        
                    else:
                        print("Invalid Quadrant")
                    if j == 8:
                        print("Draw!!!")
                else:
                    print("o's turn...")
                    match difficulty:
                        case "1":
                            self.adversary.easy_bot(self.game.display_grid, self.game.board)
                        case "2":
                            self.adversary.medium_bot(self.game.display_grid, self.game.board, j)
                        case "3":
                            self.adversary.hard_bot(self.game.display_grid, self.game.board)
                    player = self.game.o
                    if self.game.check_win(player):
                        self.game.display_grid()
                        break
                    if j == 8:
                        print("Draw!!!")
            elif game_style == "player2":
                player = self.game.x if j % 2 == 0 else self.game.o
                move = self.get_play(player)
                quadrant = int(move) - 1
                if self.game.board[quadrant] == " ":
                    self.game.board[quadrant] = player
                    self.game.display_grid()
                    if self.game.check_win(player):
                        self.game.display_grid()
                        break     
                else:
                    print("Invalid Quadrant")
                if j == 8:
                    print("Draw!!!")
            else:
                raise ValueError("Invalid command, type bot or player2")
            

            
    def game_timed_loop(self, game_style, difficulty):
        timer_thread = threading.Thread(target= self.countdown_timer, args=(20,))
        timer_thread.start()
        for j in range(9):
            if game_style == "bot":
                if j % 2 == 0:
                    player = self.game.x
                    move = self.get_play(player)
                    quadrant = int(move) - 1 
                    if self.game.board[quadrant] == " ":
                        self.game.board[quadrant] = player
                        self.game.display_grid()
                        if self.game.check_win(player):
                            self.game.display_grid()
                            break        
                    else:
                        print("Invalid Quadrant")
                    if j == 8:
                        print("Draw!!!")
                else:
                    print("o's turn...")
                    match difficulty:
                        case "1":
                            self.adversary.easy_bot(self.game.display_grid, self.game.board)
                        case "2":
                            self.adversary.medium_bot(self.game.display_grid, self.game.board, j)
                        case "3":
                            self.adversary.hard_bot(self.game.display_grid, self.game.board)
                    player = self.game.o
                    if self.game.check_win(player):
                        self.game.display_grid()
                        break
                    if j == 8:
                        print("Draw!!!")
            elif game_style == "player2":
                player = self.game.x if j % 2 == 0 else self.game.o
                move = self.get_play(player)
                quadrant = int(move) - 1
                if self.game.board[quadrant] == " ":
                    self.game.board[quadrant] = player
                    self.game.display_grid()
                    if self.game.check_win(player):
                        self.game.display_grid()
                        break     
                else:
                    print("Invalid Quadrant")
                if j == 8:
                    print("Draw!!!")
            else:
                raise ValueError("Invalid command, type bot or player2")
        else:
            print("Time is over")
        self.timer_active = False  # Ensure timer stops after the game ends
        timer_thread.join() 
            


def main():
    controller = GameController()

    game_mode = input("""Choose game mode: 
    1. With countdown timer
    2. Without countdown timer\n""")
    while game_mode != "1" and game_mode != "2":
        game_mode = input("""Choose game mode: 
    1. With countdown timer
    2. Without countdown timer\n""")
        
    if game_mode == "2":

        game_style = input("Choose game style (bot or player2): ")
        while game_style != "bot" and game_style != "player2":
            game_style = input("Choose game style (bot or player2): ")

        if game_style == "bot":
            valid_difficulties = ["1", "2", "3", "4"]
            difficulty = None
            while difficulty not in valid_difficulties:
                difficulty =  input("""Choose difficulty:
            1. Easy
            2. Medium
            3. Hard
            4. Hardcore\n""")
                
        controller.game.display_grid()
        controller.game_loop(game_style, difficulty)

    else:
        game_style = input("Choose game style (bot or player2): ")
        while game_style != "bot" and game_style != "player2":
            game_style = input("Choose game style (bot or player2): ")

        if game_style == "bot":
            valid_difficulties = ["1", "2", "3", "4"]
            difficulty = None
            while difficulty not in valid_difficulties:
                difficulty =  input("""Choose difficulty:
            1. Easy
            2. Medium
            3. Hard
            4. Hardcore\n""")
                
        controller.game.display_grid()
        controller.game_timed_loop(game_style, difficulty)

main()

bot.py

import random

class Bot:
    def __init__(self):
        self.o = "o"
        self.x = "x"

    def easy_bot(self, display_grid, board):
            choice = random.randrange(9)
            quadrant = int(choice) - 1
            while board[quadrant] != " ":
                choice = random.randrange(9)
                quadrant = int(choice) - 1
            board[quadrant] = self.o
            display_grid()
    
    def medium_bot(self, display_grid,board, j):
        if j == 1:
            choice = random.randrange(9)
            quadrant = int(choice) - 1
            while board[quadrant] != " ":
                choice = random.randrange(9)
                quadrant = int(choice) - 1
            board[quadrant] = self.o
            display_grid()
        else:
        # Winning Moves
            for i in range(0, 9, 3):  # Check rows
                if board[i] == board[i + 1] == self.o and board[i + 2] == " ":
                    board[i + 2] = self.o
                    display_grid()
                    return
                elif board[i + 1] == board[i + 2] == self.o and board[i] == " ":
                    board[i] = self.o
                    display_grid()
                    return
                elif board[i] == board[i + 2] == self.o and board[i + 1] == " ":
                    board[i + 1] = self.o
                    display_grid()
                    return

            for i in range(3):  # Check columns
                if board[i] == board[i + 3] == self.o and board[i + 6] == " ":
                    board[i + 6] = self.o
                    display_grid()
                    return
                elif board[i + 3] == board[i + 6] == self.o and board[i] == " ":
                    board[i] = self.o
                    display_grid()
                    return
                elif board[i] == board[i + 6] == self.o and board[i + 3] == " ":
                    board[i + 3] = self.o
                    display_grid()
                    return

            # Check diagonals
            diagonals = [(0, 4, 8), (2, 4, 6)]
            for d in diagonals:
                if board[d[0]] == board[d[1]] == self.o and board[d[2]] == " ":
                    board[d[2]] = self.o
                    display_grid()
                    return
                elif board[d[1]] == board[d[2]] == self.o and board[d[0]] == " ":
                    board[d[0]] = self.o
                    display_grid()
                    return
                elif board[d[0]] == board[d[2]] == self.o and board[d[1]] == " ":
                    board[d[1]] = self.o
                    display_grid()
                    return

            # Blocking Moves
            for i in range(0, 9, 3):  # Check rows
                if board[i] == board[i + 1] == self.x and board[i + 2] == " ":
                    board[i + 2] = self.o
                    display_grid()
                    return
                elif board[i + 1] == board[i + 2] == self.x and board[i] == " ":
                    board[i] = self.o
                    display_grid()
                    return
                elif board[i] == board[i + 2] == self.x and board[i + 1] == " ":
                    board[i + 1] = self.o
                    display_grid()
                    return

            for i in range(3):  # Check columns
                if board[i] == board[i + 3] == self.x and board[i + 6] == " ":
                    board[i + 6] = self.o
                    display_grid()
                    return
                elif board[i + 3] == board[i + 6] == self.x and board[i] == " ":
                    board[i] = self.o
                    display_grid()
                    return
                elif board[i] == board[i + 6] == self.x and board[i + 3] == " ":
                    board[i + 3] = self.o
                    display_grid()
                    return

            # Check diagonals
            for d in diagonals:
                if board[d[0]] == board[d[1]] == self.x and board[d[2]] == " ":
                    board[d[2]] = self.o
                    display_grid()
                    return
                elif board[d[1]] == board[d[2]] == self.x and board[d[0]] == " ":
                    board[d[0]] = self.o
                    display_grid()
                    return
                elif board[d[0]] == board[d[2]] == self.x and board[d[1]] == " ":
                    board[d[1]] = self.o
                    display_grid()
                    return

            # Strategic Moves 
            if board[4] == " ":  # Center
                board[4] = self.o
                display_grid()
                return

            for corner in [0, 2, 6, 8]:  # Corners
                if board[corner] == " ":
                    board[corner] = self.o
                    display_grid()
                    return

            for edge in [1, 3, 5, 7]:  # Edges
                if board[edge] == " ":
                    board[edge] = self.o
                    display_grid()
                    return
    
    def hard_bot(self, display_grid, board):
        for i in range(0, 9, 3):  # Check rows
                if board[i] == board[i + 1] == self.o and board[i + 2] == " ":
                    board[i + 2] = self.o
                    display_grid()
                    return
                elif board[i + 1] == board[i + 2] == self.o and board[i] == " ":
                    board[i] = self.o
                    display_grid()
                    return
                elif board[i] == board[i + 2] == self.o and board[i + 1] == " ":
                    board[i + 1] = self.o
                    display_grid()
                    return

        for i in range(3):  # Check columns
                if board[i] == board[i + 3] == self.o and board[i + 6] == " ":
                    board[i + 6] = self.o
                    display_grid()
                    return
                elif board[i + 3] == board[i + 6] == self.o and board[i] == " ":
                    board[i] = self.o
                    display_grid()
                    return
                elif board[i] == board[i + 6] == self.o and board[i + 3] == " ":
                    board[i + 3] = self.o
                    display_grid()
                    return

            # Check diagonals
        diagonals = [(0, 4, 8), (2, 4, 6)]
        for d in diagonals:
                if board[d[0]] == board[d[1]] == self.o and board[d[2]] == " ":
                    board[d[2]] = self.o
                    display_grid()
                    return
                elif board[d[1]] == board[d[2]] == self.o and board[d[0]] == " ":
                    board[d[0]] = self.o
                    display_grid()
                    return
                elif board[d[0]] == board[d[2]] == self.o and board[d[1]] == " ":
                    board[d[1]] = self.o
                    display_grid()
                    return

            # Blocking Moves
        for i in range(0, 9, 3):  # Check rows
                if board[i] == board[i + 1] == self.x and board[i + 2] == " ":
                    board[i + 2] = self.o
                    display_grid()
                    return
                elif board[i + 1] == board[i + 2] == self.x and board[i] == " ":
                    board[i] = self.o
                    display_grid()
                    return
                elif board[i] == board[i + 2] == self.x and board[i + 1] == " ":
                    board[i + 1] = self.o
                    display_grid()
                    return

        for i in range(3):  # Check columns
                if board[i] == board[i + 3] == self.x and board[i + 6] == " ":
                    board[i + 6] = self.o
                    display_grid()
                    return
                elif board[i + 3] == board[i + 6] == self.x and board[i] == " ":
                    board[i] = self.o
                    display_grid()
                    return
                elif board[i] == board[i + 6] == self.x and board[i + 3] == " ":
                    board[i + 3] = self.o
                    display_grid()
                    return

            # Check diagonals
        for d in diagonals:
                if board[d[0]] == board[d[1]] == self.x and board[d[2]] == " ":
                    board[d[2]] = self.o
                    display_grid()
                    return
                elif board[d[1]] == board[d[2]] == self.x and board[d[0]] == " ":
                    board[d[0]] = self.o
                    display_grid()
                    return
                elif board[d[0]] == board[d[2]] == self.x and board[d[1]] == " ":
                    board[d[1]] = self.o
                    display_grid()
                    return

            # Strategic Moves 
        if board[4] == " ":  # Center
                board[4] = self.o
                display_grid()
                return

        for corner in [0, 2, 6, 8]:  # Corners
                if board[corner] == " ":
                    board[corner] = self.o
                    display_grid()
                    return

        for edge in [1, 3, 5, 7]:  # Edges
                if board[edge] == " ":
                    board[edge] = self.o
                    display_grid()
                    return
python python-3.x tic-tac-toe
1个回答
0
投票

找到答案,显然您可以使用 ANSI Escape Sequences 来控制终端光标。 def countdown_timer 现在看起来像这样

def countdown_timer(self, duration):
    """Countdown timer that updates on a separate line."""
    sys.stdout.write("\033[s")  # Save the current cursor position
    while duration > 0 and self.timer_active:
        sys.stdout.write("\033[u")  # Restore the saved cursor position
        sys.stdout.write(f"\033[KTime remaining: {duration} seconds\n")  # Clear line and print timer
        sys.stdout.flush()
        time.sleep(1)
        duration -= 1
    if duration == 0:
        self.timer_active = False
        sys.stdout.write("\033[u\033[KTime's up! Game over.\n")  # Notify when time is up
        sys.stdout.flush()
© www.soinside.com 2019 - 2024. All rights reserved.