|
|
|
|
@ -0,0 +1,201 @@
|
|
|
|
|
import pygame
|
|
|
|
|
import sys
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
# 初始化pygame
|
|
|
|
|
pygame.init()
|
|
|
|
|
|
|
|
|
|
# 游戏常量
|
|
|
|
|
BOARD_SIZE = 15 # 15x15的棋盘
|
|
|
|
|
GRID_SIZE = 40 # 每个格子的像素大小
|
|
|
|
|
MARGIN = 50 # 边距
|
|
|
|
|
PIECE_RADIUS = 18 # 棋子半径
|
|
|
|
|
LINE_WIDTH = 2 # 线宽
|
|
|
|
|
|
|
|
|
|
# 计算窗口大小
|
|
|
|
|
WINDOW_SIZE = 2 * MARGIN + GRID_SIZE * (BOARD_SIZE - 1)
|
|
|
|
|
|
|
|
|
|
# 颜色定义
|
|
|
|
|
BLACK = (0, 0, 0)
|
|
|
|
|
WHITE = (255, 255, 255)
|
|
|
|
|
BROWN = (210, 180, 140)
|
|
|
|
|
RED = (255, 0, 0)
|
|
|
|
|
|
|
|
|
|
# 创建窗口
|
|
|
|
|
screen = pygame.display.set_mode((WINDOW_SIZE, WINDOW_SIZE))
|
|
|
|
|
pygame.display.set_caption("五子棋")
|
|
|
|
|
|
|
|
|
|
class GomokuGame:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
|
|
|
|
|
self.current_player = 1 # 1为黑棋,2为白棋
|
|
|
|
|
self.game_over = False
|
|
|
|
|
self.winner = None
|
|
|
|
|
|
|
|
|
|
def reset_game(self):
|
|
|
|
|
"""重置游戏"""
|
|
|
|
|
self.board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
|
|
|
|
|
self.current_player = 1
|
|
|
|
|
self.game_over = False
|
|
|
|
|
self.winner = None
|
|
|
|
|
|
|
|
|
|
def make_move(self, row, col):
|
|
|
|
|
"""落子"""
|
|
|
|
|
if self.game_over or self.board[row][col] != 0:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
self.board[row][col] = self.current_player
|
|
|
|
|
|
|
|
|
|
# 检查是否获胜
|
|
|
|
|
if self.check_win(row, col):
|
|
|
|
|
self.game_over = True
|
|
|
|
|
self.winner = self.current_player
|
|
|
|
|
# 检查是否平局
|
|
|
|
|
elif np.all(self.board != 0):
|
|
|
|
|
self.game_over = True
|
|
|
|
|
self.winner = 0 # 0表示平局
|
|
|
|
|
else:
|
|
|
|
|
# 切换玩家
|
|
|
|
|
self.current_player = 3 - self.current_player # 1->2, 2->1
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def check_win(self, row, col):
|
|
|
|
|
"""检查是否获胜"""
|
|
|
|
|
player = self.board[row][col]
|
|
|
|
|
directions = [
|
|
|
|
|
[(0, 1), (0, -1)], # 水平
|
|
|
|
|
[(1, 0), (-1, 0)], # 垂直
|
|
|
|
|
[(1, 1), (-1, -1)], # 主对角线
|
|
|
|
|
[(1, -1), (-1, 1)] # 副对角线
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
for direction_pair in directions:
|
|
|
|
|
count = 1 # 当前位置已经有一个棋子
|
|
|
|
|
|
|
|
|
|
# 检查每个方向的两个相反方向
|
|
|
|
|
for dx, dy in direction_pair:
|
|
|
|
|
temp_row, temp_col = row, col
|
|
|
|
|
|
|
|
|
|
# 沿着方向检查连续的棋子
|
|
|
|
|
for _ in range(4): # 最多再检查4个位置
|
|
|
|
|
temp_row += dx
|
|
|
|
|
temp_col += dy
|
|
|
|
|
|
|
|
|
|
if (0 <= temp_row < BOARD_SIZE and
|
|
|
|
|
0 <= temp_col < BOARD_SIZE and
|
|
|
|
|
self.board[temp_row][temp_col] == player):
|
|
|
|
|
count += 1
|
|
|
|
|
else:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if count >= 5:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def draw_board(self):
|
|
|
|
|
"""绘制棋盘"""
|
|
|
|
|
# 绘制背景
|
|
|
|
|
screen.fill(BROWN)
|
|
|
|
|
|
|
|
|
|
# 绘制网格线
|
|
|
|
|
for i in range(BOARD_SIZE):
|
|
|
|
|
# 横线
|
|
|
|
|
pygame.draw.line(screen, BLACK,
|
|
|
|
|
(MARGIN, MARGIN + i * GRID_SIZE),
|
|
|
|
|
(WINDOW_SIZE - MARGIN, MARGIN + i * GRID_SIZE),
|
|
|
|
|
LINE_WIDTH)
|
|
|
|
|
# 竖线
|
|
|
|
|
pygame.draw.line(screen, BLACK,
|
|
|
|
|
(MARGIN + i * GRID_SIZE, MARGIN),
|
|
|
|
|
(MARGIN + i * GRID_SIZE, WINDOW_SIZE - MARGIN),
|
|
|
|
|
LINE_WIDTH)
|
|
|
|
|
|
|
|
|
|
# 绘制天元和星位
|
|
|
|
|
star_points = [3, 7, 11] # 15x15棋盘的星位位置
|
|
|
|
|
for i in star_points:
|
|
|
|
|
for j in star_points:
|
|
|
|
|
pygame.draw.circle(screen, BLACK,
|
|
|
|
|
(MARGIN + i * GRID_SIZE, MARGIN + j * GRID_SIZE),
|
|
|
|
|
4)
|
|
|
|
|
|
|
|
|
|
def draw_pieces(self):
|
|
|
|
|
"""绘制棋子"""
|
|
|
|
|
for i in range(BOARD_SIZE):
|
|
|
|
|
for j in range(BOARD_SIZE):
|
|
|
|
|
if self.board[i][j] == 1: # 黑棋
|
|
|
|
|
pygame.draw.circle(screen, BLACK,
|
|
|
|
|
(MARGIN + j * GRID_SIZE, MARGIN + i * GRID_SIZE),
|
|
|
|
|
PIECE_RADIUS)
|
|
|
|
|
elif self.board[i][j] == 2: # 白棋
|
|
|
|
|
pygame.draw.circle(screen, WHITE,
|
|
|
|
|
(MARGIN + j * GRID_SIZE, MARGIN + i * GRID_SIZE),
|
|
|
|
|
PIECE_RADIUS)
|
|
|
|
|
# 白棋加黑色边框
|
|
|
|
|
pygame.draw.circle(screen, BLACK,
|
|
|
|
|
(MARGIN + j * GRID_SIZE, MARGIN + i * GRID_SIZE),
|
|
|
|
|
PIECE_RADIUS, 1)
|
|
|
|
|
|
|
|
|
|
def draw_game_info(self):
|
|
|
|
|
"""绘制游戏信息"""
|
|
|
|
|
font = pygame.font.SysFont('Arial', 20)
|
|
|
|
|
|
|
|
|
|
if self.game_over:
|
|
|
|
|
if self.winner == 1:
|
|
|
|
|
text = "黑棋获胜!按R重新开始"
|
|
|
|
|
elif self.winner == 2:
|
|
|
|
|
text = "白棋获胜!按R重新开始"
|
|
|
|
|
else:
|
|
|
|
|
text = "平局!按R重新开始"
|
|
|
|
|
else:
|
|
|
|
|
if self.current_player == 1:
|
|
|
|
|
text = "当前: 黑棋回合"
|
|
|
|
|
else:
|
|
|
|
|
text = "当前: 白棋回合"
|
|
|
|
|
|
|
|
|
|
text_surface = font.render(text, True, BLACK)
|
|
|
|
|
screen.blit(text_surface, (10, 10))
|
|
|
|
|
|
|
|
|
|
def get_board_position(self, mouse_pos):
|
|
|
|
|
"""将鼠标位置转换为棋盘坐标"""
|
|
|
|
|
x, y = mouse_pos
|
|
|
|
|
col = round((x - MARGIN) / GRID_SIZE)
|
|
|
|
|
row = round((y - MARGIN) / GRID_SIZE)
|
|
|
|
|
|
|
|
|
|
if 0 <= row < BOARD_SIZE and 0 <= col < BOARD_SIZE:
|
|
|
|
|
return row, col
|
|
|
|
|
return None, None
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
game = GomokuGame()
|
|
|
|
|
clock = pygame.time.Clock()
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
for event in pygame.event.get():
|
|
|
|
|
if event.type == pygame.QUIT:
|
|
|
|
|
pygame.quit()
|
|
|
|
|
sys.exit()
|
|
|
|
|
|
|
|
|
|
elif event.type == pygame.KEYDOWN:
|
|
|
|
|
if event.key == pygame.K_r: # 按R重新开始游戏
|
|
|
|
|
game.reset_game()
|
|
|
|
|
|
|
|
|
|
elif event.type == pygame.MOUSEBUTTONDOWN:
|
|
|
|
|
if event.button == 1 and not game.game_over: # 左键点击且游戏未结束
|
|
|
|
|
row, col = game.get_board_position(event.pos)
|
|
|
|
|
if row is not None and col is not None:
|
|
|
|
|
game.make_move(row, col)
|
|
|
|
|
|
|
|
|
|
# 绘制游戏
|
|
|
|
|
game.draw_board()
|
|
|
|
|
game.draw_pieces()
|
|
|
|
|
game.draw_game_info()
|
|
|
|
|
|
|
|
|
|
pygame.display.flip()
|
|
|
|
|
clock.tick(60)
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|
|
|
|
|
print("what happend?")
|
|
|
|
|
|