七月二日 python完成简单围棋游戏

第二天

最近,数据结构的小学期,这两天主要是完成我自己的课题设计完成围棋游戏。

【题目43】围棋游戏

设计一个简易的围棋游戏。盘面有纵横各十九条等距离、垂直交叉的平行线,共构成361个交叉点(以下简称为"点")。棋子分黑白两色。对局双方各执一色棋子,黑先白后,交替下子,每次只能下一子。 棋子下在棋盘的点上。棋子下定后,不得向其它点移动。轮流下子是双方的权利,但允许任何一方放弃下子权。谁占据的点位越多谁获胜。

设计要求:

(1) 要求实现图形化界面;

(2) 要求实现棋谱的记录;

(3) 要求实现人人对弈和人机对弈;

 

今天的代码:

import tkinter as tk
from tkinter import messagebox


class MainPage(tk.Frame):
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

        tk.Label(self, text="欢迎来到围棋天地", font=("Arial", 15)).pack(pady=20)

        tk.Button(self, text="人机对局", command=lambda: controller.show_page(Page1)).pack(pady=10)
        tk.Button(self, text="双人对局", command=lambda: controller.show_page(Page2)).pack(pady=10)
        tk.Button(self, text="退出游戏", command=self.quit_game, width=10, height=2).pack(side='bottom', pady=10)

    def quit_game(self):
        quit_window = tk.Toplevel(self)
        # quit_window.title("退出")

        # 弹窗大小
        window_width = 300
        window_height = 150

        #获取主窗口大小和位置
        main_x = self.controller.winfo_x()
        main_y = self.controller.winfo_y()
        main_width = self.controller.winfo_width()
        main_height = self.controller.winfo_height()

        # 计算弹窗的位置
        position_x = main_x + int(main_width/2 - window_width/2)
        position_y = main_y + int(main_height/2 - window_height/2)

        quit_window.geometry(f"{window_width}x{window_height}+{position_x}+{position_y}")


        quit_window.transient(self.controller)
        quit_window.grab_set()

        tk.Label(quit_window, text="确定要退出游戏吗?").pack(pady=20)
        tk.Button(quit_window, text="确定", command=lambda: self.controller.quit_game()).pack(side='left', padx=30, pady=20)
        tk.Button(quit_window, text="取消", command=quit_window.destroy).pack(side='right', padx=30, pady=20)

# 人机对战
class Page1(tk.Frame):
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

        tk.Label(self, text="人机对局", font=("Arial", 10)).pack(pady=20)
        tk.Button(self, text="返回", command=lambda: controller.show_page(MainPage)).pack(side='left', anchor='nw', pady=10)

 # 创建并添加棋盘
        self.board = Board(self)
        self.board.pack(pady=20)
# 双人对战
class Page2(tk.Frame):
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

        tk.Label(self, text="双人对局", font=("Arial", 15)).pack(pady=20)
        tk.Button(self, text="返回", command=lambda: controller.show_page(MainPage)).pack(side='left', anchor='nw', pady=10)

        # 创建并添加棋盘
        self.board = Board(self)
        self.board.pack(pady=20)

# 窗口位置以及初始化的页面
class GameApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("围棋游戏")

        # 设置窗口大小
        window_width = 700
        window_height = 700

        # 计算屏幕大小
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()

        # 计算窗口居中位置
        position_x = int((screen_width/2) - (window_width/2))
        position_y = int((screen_height/2) - (window_height/2))

        self.geometry(f"{window_width}x{window_height}+{position_x}+{position_y}")

        # self.geometry('500x500')
        # 全屏
        # self.attributes("-fullscreen", True)

        container = tk.Frame(self)
        container.pack(fill='both', expand=True)

        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.pages = {}
        for Page in (MainPage, Page1, Page2):
            page_instance = Page(container, self)
            self.pages[Page] = page_instance
            page_instance.grid(row=0, column=0, sticky='nsew')

        self.show_page(MainPage)

    def show_page(self, page):
        self.pages[page].tkraise()

    def quit_game(self):
        self.destroy()

# 棋盘
class Board(tk.Frame):
    def __init__(self, parent, size=19):
        super().__init__(parent)
        self.size = size
        self.board =[['.' for _ in range(size)] for _ in range(size)]
        self.current_player = "B"

        self.canvas = tk.Canvas(self, width=600, height=600, bg='saddlebrown')
        self.canvas.pack()
        self.cell_size = 600//(self.size+1)
        self.canvas.bind("<Button-1>", self.handle_click)
        self.draw_board()

    # 画棋盘,先画竖线,i表示第条线
    def draw_board(self):
        for i in range(1, self.size + 1):
            self.canvas.create_line(self.cell_size * i, self.cell_size, self.cell_size * i, 600 - self.cell_size)
            self.canvas.create_line(self.cell_size, self.cell_size * i, 600 - self.cell_size, self.cell_size * i)
        self.draw_stones()

    def draw_stones(self):
        self.canvas.delete("stone")
        for x in range(self.size):
            for y in range(self.size):
                if self.board[x][y] == 'B':
                    self.draw_stone(x, y, 'black')
                elif self.board[x][y] == 'W':
                    self.draw_stone(x, y, 'white')


    def draw_stone(self, x, y, color):
        self.canvas.create_oval(
            (x + 1) * self.cell_size - self.cell_size // 2,
            (y + 1) * self.cell_size - self.cell_size // 2,
            (x + 1) * self.cell_size + self.cell_size // 2,
            (y + 1) * self.cell_size + self.cell_size // 2,
            fill=color,
            tags="stone"
        )


    # 因为有边框,占了一个格子的宽度
    def handle_click(self, event):
        x = round((event.x - self.cell_size) / self.cell_size)
        y = round((event.y - self.cell_size) / self.cell_size)

        if self.is_on_board(x, y) and self.is_empty(x, y):
            self.board[x][y] = self.current_player
            # 如果 self.current_player 的值等于 'B',则将 self.current_player 的值设为 'W'。
            # 如果 self.current_player 的值不等于 'B'(即为 'W'),则将 self.current_player 的值设为 'B'。
            self.current_player = 'W' if self.current_player == 'B' else 'B'
            self.draw_board()



    # 棋子在棋盘上,判断是否点击在棋盘上
    def is_on_board(self, x, y):
        return 0 <= x < self.size and 0 <= y < self.size
    # 判断是否点击的是空的位置
    def is_empty(self, x, y):
        return self.board[x][y] == '.'


if __name__ == '__main__':
    app = GameApp()
    app.mainloop()

 

代码主要实现棋盘和两种棋子可以点击到棋盘,还没有实现玩法的控制。还有实现点击退出游戏按钮的防误触功能,弹窗提醒玩家是否退出。

 

 

 

 

posted @ 2024-07-03 00:05  *太¥^白%  阅读(9)  评论(0编辑  收藏  举报