您好,登錄后才能下訂單哦!
本文實例為大家分享了python實現五子棋游戲的具體代碼,供大家參考,具體內容如下
一、運行截圖:
二、代碼
# 用數組定義一個棋盤,棋盤大小為 15×15 # 數組索引代表位置, # 元素值代表該位置的狀態:0代表沒有棋子,1代表有黑棋,-1代表有白棋。 from tkinter import * from tkinter.messagebox import * class Chess(object): def __init__(self): ############# # param # ####################################### self.row, self.column = 15, 15 self.mesh = 25 self.ratio = 0.9 self.board_color = "#CDBA96" self.header_bg = "#CDC0B0" self.btn_font = ("黑體", 12, "bold") self.step = self.mesh / 2 self.chess_r = self.step * self.ratio self.point_r = self.step * 0.2 self.matrix = [[0 for y in range(self.column)] for x in range(self.row)] self.is_start = False self.is_black = True self.last_p = None ########### # GUI # ####################################### self.root = Tk() self.root.title("Gobang By Young") self.root.resizable(width=False, height=False) self.f_header = Frame(self.root, highlightthickness=0, bg=self.header_bg) self.f_header.pack(fill=BOTH, ipadx=10) self.b_start = Button(self.f_header, text="開始", command=self.bf_start, font=self.btn_font) self.b_restart = Button(self.f_header, text="重來", command=self.bf_restart, state=DISABLED, font=self.btn_font) self.l_info = Label(self.f_header, text="未開始", bg=self.header_bg, font=("楷體", 18, "bold"), fg="white") self.b_regret = Button(self.f_header, text="悔棋", command=self.bf_regret, state=DISABLED, font=self.btn_font) self.b_lose = Button(self.f_header, text="認輸", command=self.bf_lose, state=DISABLED, font=self.btn_font) self.b_start.pack(side=LEFT, padx=20) self.b_restart.pack(side=LEFT) self.l_info.pack(side=LEFT, expand=YES, fill=BOTH, pady=10) self.b_lose.pack(side=RIGHT, padx=20) self.b_regret.pack(side=RIGHT) self.c_chess = Canvas(self.root, bg=self.board_color, width=(self.column + 1) * self.mesh, height=(self.row + 1) * self.mesh, highlightthickness=0) self.draw_board() self.c_chess.bind("<Button-1>", self.cf_board) self.c_chess.pack() self.root.mainloop() # 畫x行y列處的網格 def draw_mesh(self, x, y): # 一個倍率,由于tkinter操蛋的GUI,如果不加倍率,悔棋的時候會有一點痕跡,可以試試把這個改為1,就可以看到 ratio = (1 - self.ratio) * 0.99 + 1 center_x, center_y = self.mesh * (x + 1), self.mesh * (y + 1) # 先畫背景色 self.c_chess.create_rectangle(center_y - self.step, center_x - self.step, center_y + self.step, center_x + self.step, fill=self.board_color, outline=self.board_color) # 再畫網格線,這里面a b c d是不同的系數,根據x,y不同位置確定,需要一定推導。 a, b = [0, ratio] if y == 0 else [-ratio, 0] if y == self.row - 1 else [-ratio, ratio] c, d = [0, ratio] if x == 0 else [-ratio, 0] if x == self.column - 1 else [-ratio, ratio] self.c_chess.create_line(center_y + a * self.step, center_x, center_y + b * self.step, center_x) self.c_chess.create_line(center_y, center_x + c * self.step, center_y, center_x + d * self.step) # 有一些特殊的點要畫小黑點 if ((x == 3 or x == 11) and (y == 3 or y == 11)) or (x == 7 and y == 7): self.c_chess.create_oval(center_y - self.point_r, center_x - self.point_r, center_y + self.point_r, center_x + self.point_r, fill="black") # 畫x行y列處的棋子,color指定棋子顏色 def draw_chess(self, x, y, color): center_x, center_y = self.mesh * (x + 1), self.mesh * (y + 1) # 就是畫個圓 self.c_chess.create_oval(center_y - self.chess_r, center_x - self.chess_r, center_y + self.chess_r, center_x + self.chess_r, fill=color) # 畫整個棋盤 def draw_board(self): [self.draw_mesh(x, y) for y in range(self.column) for x in range(self.row)] # 在正中間顯示文字 def center_show(self, text): width, height = int(self.c_chess['width']), int(self.c_chess['height']) self.c_chess.create_text(int(width / 2), int(height / 2), text=text, font=("黑體", 30, "bold"), fill="red") # 開始的時候設置各個組件,變量的狀態,初始化matrix矩陣,初始化棋盤,初始化信息 def bf_start(self): self.set_btn_state("start") self.is_start = True self.is_black = True self.matrix = [[0 for y in range(self.column)] for x in range(self.row)] self.draw_board() self.l_info.config(text="黑方下棋") # 重來跟開始的效果一樣 def bf_restart(self): self.bf_start() # 用last_p來標識上一步的位置。先用網格覆蓋掉棋子,操作相應的變量,matrix[x][y]要置空,只能悔一次棋 def bf_regret(self): if not self.last_p: showinfo("提示", "現在不能悔棋") return x, y = self.last_p self.draw_mesh(x, y) self.matrix[x][y] = 0 self.last_p = None self.trans_identify() # 幾個狀態改變,還有顯示文字,沒什么說的 def bf_lose(self): self.set_btn_state("init") self.is_start = False text = self.ternary_operator("黑方認輸", "白方認輸") self.l_info.config(text=text) self.center_show("蔡") # Canvas的click事件 def cf_board(self, e): # 找到離點擊點最近的坐標 x, y = int((e.y - self.step) / self.mesh), int((e.x - self.step) / self.mesh) # 找到該坐標的中心點位置 center_x, center_y = self.mesh * (x + 1), self.mesh * (y + 1) # 計算點擊點到中心的距離 distance = ((center_x - e.y) ** 2 + (center_y - e.x) ** 2) ** 0.5 # 如果距離不在規定的圓內,退出//如果這個位置已經有棋子,退出//如果游戲還沒開始,退出 if distance > self.step * 0.95 or self.matrix[x][y] != 0 or not self.is_start: return # 此時棋子的顏色,和matrix中該棋子的標識。 color = self.ternary_operator("black", "white") tag = self.ternary_operator(1, -1) # 先畫棋子,在修改matrix相應點的值,用last_p記錄本次操作點 self.draw_chess(x, y, color) self.matrix[x][y] = tag self.last_p = [x, y] # 如果贏了,則游戲結束,修改狀態,中心顯示某方獲勝 if self.is_win(x, y, tag): self.is_start = False self.set_btn_state("init") text = self.ternary_operator("黑方獲勝", "白方獲勝") self.center_show(text) return # 如果游戲繼續,則交換棋手 self.trans_identify() def is_win(self, x, y, tag): # 獲取斜方向的列表 def direction(i, j, di, dj, row, column, matrix): temp = [] while 0 <= i < row and 0 <= j < column: i, j = i + di, j + dj i, j = i - di, j - dj while 0 <= i < row and 0 <= j < column: temp.append(matrix[i][j]) i, j = i - di, j - dj return temp four_direction = [] # 獲取水平和豎直方向的列表 four_direction.append([self.matrix[i][y] for i in range(self.row)]) four_direction.append([self.matrix[x][j] for j in range(self.column)]) # 獲取斜方向的列表 four_direction.append(direction(x, y, 1, 1, self.row, self.column, self.matrix)) four_direction.append(direction(x, y, 1, -1, self.row, self.column, self.matrix)) # 一一查看這四個方向,有沒有滿足五子連珠 for v_list in four_direction: count = 0 for v in v_list: if v == tag: count += 1 if count == 5: return True else: count = 0 return False # 設置四個按鈕是否可以點擊 def set_btn_state(self, state): state_list = [NORMAL, DISABLED, DISABLED, DISABLED] if state == "init" else [DISABLED, NORMAL, NORMAL, NORMAL] self.b_start.config(state=state_list[0]) self.b_restart.config(state=state_list[1]) self.b_regret.config(state=state_list[2]) self.b_lose.config(state=state_list[3]) # 因為有很多和self.black相關的三元操作,所以就提取出來 def ternary_operator(self, true, false): return true if self.is_black else false # 交換棋手 def trans_identify(self): self.is_black = not self.is_black text = self.ternary_operator("黑方下棋", "白方下棋") self.l_info.config(text=text) if __name__ == '__main__': Chess()
三、增加復盤和保存棋譜功能
直接貼可以運行的源碼,添加了兩個按鍵和一個頁面。
# 用數組定義一個棋盤,棋盤大小為 15×15 # 數組索引代表位置, # 元素值代表該位置的狀態:0代表沒有棋子,1代表有黑棋,-1代表有白棋。 from tkinter import * from tkinter.messagebox import * import os TAG_BLACK = "1" TAG_EMPTY = "." TAG_WHITE = "0" ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + ".") class Chess(object): def bf_save(self): path = os.path.join(ROOT_DIR, "record.txt") file = open(path, "w") for i in range(len(self.record)): x, y = self.record[i] file.write("{}: [{}, {}]\n".format("黑方" if i % 2 == 0 else "白方", x, y)) file.close() def init_matrix(self): return [[TAG_EMPTY for y in range(self.column)] for x in range(self.row)] def __init__(self): ############# # param # ####################################### self.row, self.column = 15, 15 self.mesh = 25 self.ratio = 0.9 self.board_color = "#CDBA96" self.header_bg = "#CDC0B0" self.btn_font = ("黑體", 12, "bold") self.step = self.mesh / 2 self.chess_r = self.step * self.ratio self.point_r = self.step * 0.2 self.matrix = self.init_matrix() self.is_start = False self.is_black = True self.record = [] ########### # GUI # ####################################### self.root = Tk() self.root.title("Gobang By Young") self.root.resizable(width=False, height=False) self.f_header = Frame(self.root, highlightthickness=0, bg=self.header_bg) self.b_start = Button(self.f_header, text="開始", command=self.bf_start, font=self.btn_font) self.b_restart = Button(self.f_header, text="重來", command=self.bf_restart, state=DISABLED, font=self.btn_font) self.l_info = Label(self.f_header, text="未開始", bg=self.header_bg, font=("楷體", 18, "bold"), fg="white") self.b_regret = Button(self.f_header, text="悔棋", command=self.bf_regret, state=DISABLED, font=self.btn_font) self.b_lose = Button(self.f_header, text="認輸", command=self.bf_lose, state=DISABLED, font=self.btn_font) self.c_chess = Canvas(self.root, bg=self.board_color, width=(self.column + 1) * self.mesh, height=(self.row + 1) * self.mesh, highlightthickness=0) self.draw_board() self.c_chess.bind("<Button-1>", self.cf_board) self.b_record = Button(self.root, text="復 盤", command=self.bf_record, font=self.btn_font, bg="lightblue") self.b_save = Button(self.root, text="保 存", command=self.bf_save, font=self.btn_font, bg="lightblue") self.f_header.pack(side=TOP, fill=BOTH, ipadx=10) self.b_start.pack(side=LEFT, padx=20) self.b_restart.pack(side=LEFT) self.l_info.pack(side=LEFT, expand=YES, fill=BOTH, pady=10) self.b_lose.pack(side=RIGHT, padx=20) self.b_regret.pack(side=RIGHT) self.c_chess.pack(side=TOP) self.b_record.pack(side=TOP, expand=YES, fill=X) self.b_save.pack(side=TOP, expand=YES, fill=X) self.root.mainloop() # 畫x行y列處的網格 def draw_mesh(self, x, y): # 一個倍率,由于tkinter操蛋的GUI,如果不加倍率,悔棋的時候會有一點痕跡,可以試試把這個改為1,就可以看到 ratio = (1 - self.ratio) * 0.99 + 1 center_x, center_y = self.mesh * (x + 1), self.mesh * (y + 1) # 先畫背景色 self.c_chess.create_rectangle(center_y - self.step, center_x - self.step, center_y + self.step, center_x + self.step, fill=self.board_color, outline=self.board_color) # 再畫網格線,這里面a b c d是不同的系數,根據x,y不同位置確定,需要一定推導。 a, b = [0, ratio] if y == 0 else [-ratio, 0] if y == self.row - 1 else [-ratio, ratio] c, d = [0, ratio] if x == 0 else [-ratio, 0] if x == self.column - 1 else [-ratio, ratio] self.c_chess.create_line(center_y + a * self.step, center_x, center_y + b * self.step, center_x) self.c_chess.create_line(center_y, center_x + c * self.step, center_y, center_x + d * self.step) # 有一些特殊的點要畫小黑點 if ((x == 3 or x == 11) and (y == 3 or y == 11)) or (x == 7 and y == 7): self.c_chess.create_oval(center_y - self.point_r, center_x - self.point_r, center_y + self.point_r, center_x + self.point_r, fill="black") # 畫x行y列處的棋子,color指定棋子顏色 def draw_chess(self, x, y, color): center_x, center_y = self.mesh * (x + 1), self.mesh * (y + 1) # 就是畫個圓 self.c_chess.create_oval(center_y - self.chess_r, center_x - self.chess_r, center_y + self.chess_r, center_x + self.chess_r, fill=color) # 畫整個棋盤 def draw_board(self): [self.draw_mesh(x, y) for y in range(self.column) for x in range(self.row)] # 在正中間顯示文字 def center_show(self, text): width, height = int(self.c_chess['width']), int(self.c_chess['height']) self.c_chess.create_text(int(width / 2), int(height / 2), text=text, font=("黑體", 30, "bold"), fill="red") def bf_record(self): Record(self.record) pass # 開始的時候設置各個組件,變量的狀態,初始化matrix矩陣,初始化棋盤,初始化信息 def bf_start(self): self.set_btn_state("start") self.is_start = True self.is_black = True self.matrix = self.init_matrix() self.draw_board() self.record = [] self.l_info.config(text="黑方下棋") # 重來跟開始的效果一樣 def bf_restart(self): self.record = [] self.bf_start() # 用last_p來標識上一步的位置。先用網格覆蓋掉棋子,操作相應的變量,matrix[x][y]要置空,只能悔一次棋 def bf_regret(self): if len(self.record) == 0: showinfo("提示", "現在不能悔棋") return x, y = self.record[-1] self.draw_mesh(x, y) self.matrix[x][y] = TAG_EMPTY self.record = self.record[:-1] self.trans_identify() # 幾個狀態改變,還有顯示文字,沒什么說的 def bf_lose(self): self.set_btn_state("init") self.is_start = False text = self.ternary_operator("黑方認輸", "白方認輸") self.l_info.config(text=text) self.center_show("蔡") def go_chess(self, x, y): # 此時棋子的顏色,和matrix中該棋子的標識。 color = self.ternary_operator("black", "white") tag = self.ternary_operator(TAG_BLACK, TAG_WHITE) # 先畫棋子,在修改matrix相應點的值,用last_p記錄本次操作點 self.draw_chess(x, y, color) self.matrix[x][y] = tag self.record.append([x, y]) # 如果贏了,則游戲結束,修改狀態,中心顯示某方獲勝 if self.is_win(x, y, tag): self.is_start = False self.set_btn_state("init") text = self.ternary_operator("黑方獲勝", "白方獲勝") self.center_show(text) return # 如果游戲繼續,則交換棋手 self.trans_identify() # Canvas的click事件 def cf_board(self, e): # 找到離點擊點最近的坐標 x, y = int((e.y - self.step) / self.mesh), int((e.x - self.step) / self.mesh) # 找到該坐標的中心點位置 center_x, center_y = self.mesh * (x + 1), self.mesh * (y + 1) # 計算點擊點到中心的距離 distance = ((center_x - e.y) ** 2 + (center_y - e.x) ** 2) ** 0.5 # 如果距離不在規定的圓內,退出//如果這個位置已經有棋子,退出//如果游戲還沒開始,退出 if distance > self.step * 0.95 or self.matrix[x][y] != TAG_EMPTY or not self.is_start: return self.go_chess(x, y) def is_win(self, x, y, tag): # 獲取斜方向的列表 def direction(i, j, di, dj, row, column, matrix): temp = [] while 0 <= i < row and 0 <= j < column: i, j = i + di, j + dj i, j = i - di, j - dj while 0 <= i < row and 0 <= j < column: temp.append(matrix[i][j]) i, j = i - di, j - dj return temp four_direction = [] # 獲取水平和豎直方向的列表 four_direction.append([self.matrix[i][y] for i in range(self.row)]) four_direction.append([self.matrix[x][j] for j in range(self.column)]) # 獲取斜方向的列表 four_direction.append(direction(x, y, 1, 1, self.row, self.column, self.matrix)) four_direction.append(direction(x, y, 1, -1, self.row, self.column, self.matrix)) # 一一查看這四個方向,有沒有滿足五子連珠 for v_list in four_direction: if tag * 5 in "".join(v_list): return True return False # 設置四個按鈕是否可以點擊 def set_btn_state(self, state): state_list = [NORMAL, DISABLED, DISABLED, DISABLED] if state == "init" else [DISABLED, NORMAL, NORMAL, NORMAL] self.b_start.config(state=state_list[0]) self.b_restart.config(state=state_list[1]) self.b_regret.config(state=state_list[2]) self.b_lose.config(state=state_list[3]) # 因為有很多和self.black相關的三元操作,所以就提取出來 def ternary_operator(self, true, false): return true if self.is_black else false # 交換棋手 def trans_identify(self): self.is_black = not self.is_black text = self.ternary_operator("黑方下棋", "白方下棋") self.l_info.config(text=text) def print_process(self): pass class Record(object): def __init__(self, record): ############# # param # ####################################### self.row, self.column = 15, 15 self.mesh = 25 self.ratio = 0.9 self.board_color = "#CDBA96" self.header_bg = "#CDC0B0" self.btn_font = ("黑體", 12, "bold") self.step = self.mesh / 2 self.chess_r = self.step * self.ratio self.point_r = self.step * 0.2 ########### self.is_black = True self.index = -1 self.record = record ########### # GUI # ####################################### self.root = Tk() self.root.title("復盤") self.root.resizable(width=False, height=False) self.root.bind("<Key>", self.kf_step) self.f_header = Frame(self.root, highlightthickness=0, bg=self.header_bg) self.l_info = Label(self.f_header, text="未開始", bg=self.header_bg, font=("楷體", 18, "bold"), fg="white") self.c_chess = Canvas(self.root, bg=self.board_color, width=(self.column + 1) * self.mesh, height=(self.row + 1) * self.mesh, highlightthickness=0) self.draw_board() self.f_header.pack(fill=BOTH, ipadx=10) self.l_info.pack(side=LEFT, expand=YES, fill=BOTH, pady=10) self.c_chess.pack() self.root.mainloop() def kf_step(self, e): if e.keycode not in [37, 39]: return if e.keycode == 37: if self.index == -1: self.l_info.config(text="已經走到最開始了") return x, y = self.record[self.index] self.draw_mesh(x, y) if self.index == 0: self.l_info.config(text="未開始") else: self.l_info.config(text="黑方走棋" if self.is_black else "白方走棋") self.is_black = not self.is_black self.index -= 1 if self.index > 0: x, y = self.record[self.index] color = "white" if self.is_black else "black" self.draw_chess(x, y, color, "red") elif e.keycode == 39: if self.index == len(self.record) - 1: self.l_info.config(text="已經走到最末尾了") return self.index += 1 x, y = self.record[self.index] color = "black" if self.is_black else "white" self.draw_chess(x, y, color, "red") if self.index > 0: x, y = self.record[self.index - 1] color = "white" if self.is_black else "black" self.draw_chess(x, y, color) self.l_info.config(text="黑方走棋" if self.is_black else "白方走棋") self.is_black = not self.is_black else: pass # 畫x行y列處的網格 def draw_mesh(self, x, y): # 一個倍率,由于tkinter操蛋的GUI,如果不加倍率,悔棋的時候會有一點痕跡,可以試試把這個改為1,就可以看到 ratio = (1 - self.ratio) * 0.99 + 1 center_x, center_y = self.mesh * (x + 1), self.mesh * (y + 1) # 先畫背景色 self.c_chess.create_rectangle(center_y - self.step, center_x - self.step, center_y + self.step, center_x + self.step, fill=self.board_color, outline=self.board_color) # 再畫網格線,這里面a b c d是不同的系數,根據x,y不同位置確定,需要一定推導。 a, b = [0, ratio] if y == 0 else [-ratio, 0] if y == self.row - 1 else [-ratio, ratio] c, d = [0, ratio] if x == 0 else [-ratio, 0] if x == self.column - 1 else [-ratio, ratio] self.c_chess.create_line(center_y + a * self.step, center_x, center_y + b * self.step, center_x) self.c_chess.create_line(center_y, center_x + c * self.step, center_y, center_x + d * self.step) # 有一些特殊的點要畫小黑點 if ((x == 3 or x == 11) and (y == 3 or y == 11)) or (x == 7 and y == 7): self.c_chess.create_oval(center_y - self.point_r, center_x - self.point_r, center_y + self.point_r, center_x + self.point_r, fill="black") # 畫x行y列處的棋子,color指定棋子顏色 def draw_chess(self, x, y, color, outline="black"): center_x, center_y = self.mesh * (x + 1), self.mesh * (y + 1) # 就是畫個圓 self.c_chess.create_oval(center_y - self.chess_r, center_x - self.chess_r, center_y + self.chess_r, center_x + self.chess_r, fill=color, outline=outline) # 畫整個棋盤 def draw_board(self): [self.draw_mesh(x, y) for y in range(self.column) for x in range(self.row)] # 在正中間顯示文字 def center_show(self, text): width, height = int(self.c_chess['width']), int(self.c_chess['height']) self.c_chess.create_text(int(width / 2), int(height / 2), text=text, font=("黑體", 30, "bold"), fill="red") # 開始的時候設置各個組件,變量的狀態,初始化matrix矩陣,初始化棋盤,初始化信息 if __name__ == '__main__': Chess()
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。