python五子棋
2026-06-08 13:34:35
发布于:广东
AI生成
import tkinter as tk
import random
# 棋盘参数
BOARD_SIZE = 15
CELL_SIZE = 40
MARGIN = 30
PIECE_RADIUS = 18
DOT_RADIUS = 5
# 棋手常量
EMPTY = 0
BLACK = 1
WHITE = 2
# AI 评分模式分值
FIVE = 100000
FOUR = 10000
FOUR_RUSH = 1000
THREE = 1000
THREE_SLEEP = 100
TWO = 100
TWO_SLEEP = 10
ONE = 1
class GomokuGame:
def __init__(self):
self.root = tk.Tk()
self.root.title("五子棋人机对战")
self.root.resizable(False, False)
# 棋盘数据
self.board = None
self.game_over = False
self.latest_piece = None
self.piece_ids = {}
self.player_color = None
self.ai_color = None
self.canvas = None
self.game_frame = None
# 先弹出颜色选择窗口
self.show_color_choice()
def show_color_choice(self):
"""显示颜色选择小窗口,左边执黑,右边执白"""
# 清除之前的游戏界面
if self.game_frame is not None:
self.game_frame.destroy()
self.game_frame = None
self.choice_win = tk.Toplevel(self.root)
self.choice_win.title("选择颜色")
self.choice_win.resizable(False, False)
self.choice_win.transient(self.root)
self.choice_win.grab_set()
# 窗口居中
win_width = 280
win_height = 120
screen_w = self.root.winfo_screenwidth()
screen_h = self.root.winfo_screenheight()
x = (screen_w - win_width) // 2
y = (screen_h - win_height) // 2
self.choice_win.geometry(f"{win_width}x{win_height}+{x}+{y}")
# 提示文字
label = tk.Label(
self.choice_win,
text="请选择你要执的颜色",
font=("微软雅黑", 13)
)
label.pack(pady=(15, 10))
# 按钮框架
btn_frame = tk.Frame(self.choice_win)
btn_frame.pack()
black_btn = tk.Button(
btn_frame,
text="执黑(先手)",
font=("微软雅黑", 10), # 字体从 12 缩小到 10
width=10, # 宽度从 12 调整为 10
bg="#333333",
fg="white",
activebackground="#555555",
command=lambda: self.start_game(BLACK)
)
black_btn.pack(side=tk.LEFT, padx=10)
white_btn = tk.Button(
btn_frame,
text="执白(后手)",
font=("微软雅黑", 10), # 同上
width=10,
bg="#e0e0e0",
fg="black",
activebackground="#cccccc",
command=lambda: self.start_game(WHITE)
)
white_btn.pack(side=tk.LEFT, padx=10)
# 等选择窗口关闭时,如果还没开始游戏则退出主程序
self.choice_win.protocol("WM_DELETE_WINDOW", self.root.destroy)
def start_game(self, player_color):
"""关闭选择窗口,初始化游戏界面"""
self.player_color = player_color
self.ai_color = WHITE if player_color == BLACK else BLACK
self.choice_win.destroy()
# 创建游戏界面
self.game_frame = tk.Frame(self.root)
self.game_frame.pack()
canvas_width = MARGIN * 2 + CELL_SIZE * (BOARD_SIZE - 1)
canvas_height = MARGIN * 2 + CELL_SIZE * (BOARD_SIZE - 1)
self.canvas = tk.Canvas(
self.game_frame,
width=canvas_width,
height=canvas_height,
bg="#deb887"
)
self.canvas.pack()
self.canvas.bind("<Button-1>", self.on_click)
self.draw_board()
self.restart_game()
def draw_board(self):
"""绘制棋盘网格和星位"""
for i in range(BOARD_SIZE):
self.canvas.create_line(
MARGIN, MARGIN + i * CELL_SIZE,
MARGIN + (BOARD_SIZE - 1) * CELL_SIZE, MARGIN + i * CELL_SIZE
)
self.canvas.create_line(
MARGIN + i * CELL_SIZE, MARGIN,
MARGIN + i * CELL_SIZE, MARGIN + (BOARD_SIZE - 1) * CELL_SIZE
)
star_points = [(3, 3), (7, 7), (11, 11), (3, 11), (11, 3),
(7, 3), (7, 11), (3, 7), (11, 7)]
for r, c in star_points:
x = MARGIN + c * CELL_SIZE
y = MARGIN + r * CELL_SIZE
self.canvas.create_oval(x - 2, y - 2, x + 2, y + 2, fill="black")
def restart_game(self):
"""初始化棋盘状态"""
self.board = [[EMPTY for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
self.game_over = False
self.latest_piece = None
self.clear_pieces()
if self.ai_color == BLACK:
self.ai_move()
def clear_pieces(self):
"""清除棋子与红点"""
for obj_id in list(self.piece_ids.values()):
self.canvas.delete(obj_id)
self.piece_ids.clear()
def on_click(self, event):
"""玩家点击落子"""
if self.game_over:
return
if self.whose_turn() != self.player_color:
return
col = round((event.x - MARGIN) / CELL_SIZE)
row = round((event.y - MARGIN) / CELL_SIZE)
if 0 <= row < BOARD_SIZE and 0 <= col < BOARD_SIZE:
if self.board[row][col] == EMPTY:
self.place_piece(row, col, self.player_color)
if not self.game_over:
self.ai_move()
def place_piece(self, row, col, color):
"""落子并更新画面"""
self.board[row][col] = color
x = MARGIN + col * CELL_SIZE
y = MARGIN + row * CELL_SIZE
fill_color = "black" if color == BLACK else "white"
piece_id = self.canvas.create_oval(
x - PIECE_RADIUS, y - PIECE_RADIUS,
x + PIECE_RADIUS, y + PIECE_RADIUS,
fill=fill_color, outline="gray", width=2
)
self.piece_ids[(row, col)] = piece_id
# 移除旧红点
if self.latest_piece:
prev_r, prev_c = self.latest_piece
dot_id = self.piece_ids.pop(("dot", prev_r, prev_c), None)
if dot_id:
self.canvas.delete(dot_id)
# 添加新红点
dot_id = self.canvas.create_oval(
x - DOT_RADIUS, y - DOT_RADIUS,
x + DOT_RADIUS, y + DOT_RADIUS,
fill="red", outline=""
)
self.piece_ids[("dot", row, col)] = dot_id
self.latest_piece = (row, col)
# 判定胜负
if self.check_win(row, col, color):
self.game_over = True
winner = "你" if color == self.player_color else "AI"
self.canvas.create_text(
MARGIN + CELL_SIZE * (BOARD_SIZE - 1) // 2,
MARGIN + CELL_SIZE * (BOARD_SIZE - 1) // 2,
text=f"{winner} 赢了!", fill="red", font=("Arial", 20), tags="win_text"
)
self.root.after(2000, self.end_game)
elif self.is_board_full():
self.game_over = True
self.canvas.create_text(
MARGIN + CELL_SIZE * (BOARD_SIZE - 1) // 2,
MARGIN + CELL_SIZE * (BOARD_SIZE - 1) // 2,
text="平局!", fill="blue", font=("Arial", 20), tags="win_text"
)
self.root.after(2000, self.end_game)
def check_win(self, row, col, color):
"""五连判定"""
directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
for dr, dc in directions:
count = 1
r, c = row + dr, col + dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == color:
count += 1
r += dr
c += dc
r, c = row - dr, col - dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == color:
count += 1
r -= dr
c -= dc
if count >= 5:
return True
return False
def is_board_full(self):
"""满盘判定"""
for row in self.board:
if EMPTY in row:
return False
return True
def whose_turn(self):
"""当前轮到谁"""
black_cnt = sum(row.count(BLACK) for row in self.board)
white_cnt = sum(row.count(WHITE) for row in self.board)
return BLACK if black_cnt == white_cnt else WHITE
def end_game(self):
"""游戏结束,销毁游戏界面,返回颜色选择窗口"""
if self.game_frame is not None:
self.game_frame.destroy()
self.game_frame = None
self.canvas = None
self.piece_ids.clear()
self.show_color_choice()
# ==================== AI 逻辑 ====================
def ai_move(self):
if self.game_over:
return
empty_positions = [(r, c) for r in range(BOARD_SIZE)
for c in range(BOARD_SIZE) if self.board[r][c] == EMPTY]
if not empty_positions:
return
best_score = -1
best_moves = []
for r, c in empty_positions:
score = self.evaluate_position(r, c)
if score > best_score:
best_score = score
best_moves = [(r, c)]
elif score == best_score:
best_moves.append((r, c))
move = random.choice(best_moves)
self.place_piece(move[0], move[1], self.ai_color)
def evaluate_position(self, row, col):
"""综合进攻与防守评分"""
self.board[row][col] = self.ai_color
ai_score = self.calculate_point_score(row, col, self.ai_color)
self.board[row][col] = EMPTY
self.board[row][col] = self.player_color
player_score = self.calculate_point_score(row, col, self.player_color)
self.board[row][col] = EMPTY
return ai_score + int(player_score * 1.1)
def calculate_point_score(self, row, col, color):
"""单点评分"""
total = 0
directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
for dr, dc in directions:
cnt = 1
r, c = row + dr, col + dc
open_plus = 0
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == color:
cnt += 1
r += dr
c += dc
if 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == EMPTY:
open_plus = 1
r, c = row - dr, col - dc
open_minus = 0
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == color:
cnt += 1
r -= dr
c -= dc
if 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == EMPTY:
open_minus = 1
total += self.get_pattern_score(cnt, open_plus + open_minus)
return total
def get_pattern_score(self, count, open_ends):
"""模式分值"""
if count >= 5:
return FIVE
if count == 4:
return FOUR if open_ends == 2 else (FOUR_RUSH if open_ends == 1 else 0)
if count == 3:
return THREE if open_ends == 2 else (THREE_SLEEP if open_ends == 1 else 0)
if count == 2:
return TWO if open_ends == 2 else (TWO_SLEEP if open_ends == 1 else 0)
if count == 1 and open_ends == 2:
return ONE
return 0
def run(self):
self.root.mainloop()
if __name__ == "__main__":
game = GomokuGame()
game.run()
全部评论 2
那还敢发,建议紫衫
1周前 来自 江西
0d d d
1周前 来自 广东
0























有帮助,赞一个