本文使用python中的pygame库设计制作了一个围棋游戏。
参考项目资料: https://github.com/HapHac/weiqi
1、初始化棋盘
# 绘制棋盘
def draw_chessboard(self):
# 画棋盘,填充颜色
pygame.draw.rect(self.screen, (204, 85, 17), [0 * self.size, 0 * self.size, 400 * self.size, 400 * self.size])
pygame.draw.rect(self.screen, (51, 102, 153),
[400 * self.size, 0 * self.size, 200 * self.size, 400 * self.size])
# 画外框
outer_frame_color = (60, 20, 0)
pygame.draw.rect(self.screen, outer_frame_color,
[20 * self.size, 20 * self.size, 360 * self.size, 360 * self.size],
5)
# 棋盘上的九个定位点,以中点为模型,移动位置,以作出其余八个点
for m in [-1, 0, 1]:
for n in [-1, 0, 1]:
rect = pygame.Rect([200 * self.size - self.size * 2,
200 * self.size - self.size * 2,
self.size * 4, self.size * 4])
pygame.draw.ellipse(self.screen, (0, 0, 0), rect, width=0)
rect = rect.move(m * self.interval * (2 if self.mode_num == 9 else (3 if self.mode_num == 13 else 6)),
n * self.interval * (2 if self.mode_num == 9 else (3 if self.mode_num == 13 else 6)))
pygame.draw.ellipse(self.screen, (0, 0, 0), rect, width=0)
# 画中间的线条
for i in range(1, self.mode_num - 1):
pygame.draw.line(self.screen, (0, 0, 0), (20 * self.size, 20 * self.size + i * self.interval),
(380 * self.size, 20 * self.size + i * self.interval), width=2)
pygame.draw.line(self.screen, (0, 0, 0), (20 * self.size + i * self.interval, 20 * self.size),
(20 * self.size + i * self.interval, 380 * self.size), width=2)
# 放置右侧初始图片
if self.stop:
self.screen.blit(self.photoW, (480 * self.size, 65 * self.size))
self.screen.blit(self.photoB, (480 * self.size - 45, 65 * self.size))
elif self.present == 1:
self.screen.blit(self.photoB, (480 * self.size - 45, 65 * self.size))
else:
self.screen.blit(self.photoW, (480 * self.size, 65 * self.size))
# # 几个功能按钮
button_color = (255, 255, 255)
self.start_button = Button('开始游戏', button_color, 'msyh.ttc', 23)
self.start_button.draw(self.screen, 480 * self.size, 200 * self.size)
self.pass_me_button = Button('弃一子', button_color, 'msyh.ttc', 23)
self.pass_me_button.draw(self.screen, 480 * self.size, 225 * self.size)
self.regert_button = Button('悔棋', button_color, 'msyh.ttc', 23)
self.regert_button.draw(self.screen, 480 * self.size, 250 * self.size)
self.restsrt_button = Button('重新开始', button_color, 'msyh.ttc', 23)
self.restsrt_button.draw(self.screen, 480 * self.size, 275 * self.size)
self.thirteen_way_button = Button('十三路棋', button_color, 'msyh.ttc', 23)
self.thirteen_way_button.draw(self.screen, 480 * self.size, 300 * self.size)
self.nineteenth_way_button = Button('十九路棋', button_color, 'msyh.ttc', 23)
self.nineteenth_way_button.draw(self.screen, 480 * self.size, 325 * self.size)
self.exit_button = Button('退出游戏', button_color, 'msyh.ttc', 23)
self.exit_button.draw(self.screen, 480 * self.size, 350 * self.size)
在上述代码中,首先绘制棋盘的框架,使用pygame中的pygame.draw.rect,然后通过pygame.draw.line绘制线条,形成完整的棋盘。除此之外,在棋盘的一旁,添加了一个太极图用以表示当前的棋手,以及一些按钮用于控制游戏的进程(按钮使用自定义类完成)。
class Text:
def __init__(self, text: str, text_color, font_type: str, font_size: int):
"""
text: 文本内容,注意是字符串形式
text_color: 字体颜色
font_type: 字体文件
font_size: 字体大小
"""
self.text = text
self.text_color = text_color
self.font_type = font_type
self.font_size = font_size
font = pygame.font.Font(os.path.join('font', (self.font_type)), self.font_size)
self.text_image = font.render(self.text, True, self.text_color).convert_alpha()
self.text_width = self.text_image.get_width()
self.text_height = self.text_image.get_height()
def draw(self, surface: pygame.Surface, center_x, center_y):
"""
surface: 文本放置的表面
center_x, center_y: 文本放置在表面的<中心坐标>
"""
upperleft_x = center_x - self.text_width / 2
upperleft_y = center_y - self.text_height / 2
surface.blit(self.text_image, (upperleft_x, upperleft_y))
class Button(Text):
def __init__(self, text: str, text_color, font_type: str, font_size: int):
super().__init__(text, text_color, font_type, font_size)
self.rect = self.text_image.get_rect()
self.enable = True
def draw(self, surface: pygame.Surface, center_x, center_y):
super().draw(surface, center_x, center_y)
self.rect.center = center_x, center_y
def handle_event(self, command):
self.hovered = self.rect.collidepoint(pygame.mouse.get_pos())
if self.hovered:
if self.enable:
command()
else:
pass
2、初始化棋子
# 绘制棋子
def draw_chess(self):
# 遍历棋盘二维数组,绘制出棋盘中所有已下子
for i in range(self.mode_num):
for j in range(self.mode_num):
pos = i * self.interval + 20 * self.size - 30 * self.p, j * self.interval + 20 * self.size - 30 * self.p
if self.positions[i][j] == 0:
continue
elif self.positions[i][j] == 1:
self.screen.blit(self.photoBD, pos)
elif self.positions[i][j] == -1:
self.screen.blit(self.photoWD, pos)
定义一个数组:self.positions用以存储棋盘中棋子的状态。
3、开始游戏
点击开始游戏按钮,正式开始游戏,删除白色太极图,表示黑棋先行。
# 开始游戏函数,点击“开始游戏”时调用
def start(self):
# 删除右侧太极图
self.screen.blit(self.bg_rect, (400 * self.size, 65 * self.size))
# 利用右侧图案提示开始时谁先落子
if self.present == 1:
self.screen.blit(self.photoB, (480 * self.size - 45, 65 * self.size))
else:
self.screen.blit(self.photoW, (480 * self.size, 65 * self.size))
# 开始标志,解除stop
self.stop = None
4、落子设置
首先定义一个函数,用以获取当前鼠标的位置。
# 获取鼠标当前位置
def get_mouse_current_position(self, x, y):
self.mouse_x = x
self.mouse_y = y
然后设置棋子跟随鼠标移动。
# 棋子跟随鼠标移动
def chess_follow(self):
if 20 * self.size < self.mouse_x < 380 * self.size and 20 * self.size < self.mouse_y < 380 * self.size:
pos = self.mouse_x - 30 * self.p, self.mouse_y - 35 * self.p
if self.present == 1:
self.screen.blit(self.photoBD, pos)
else:
self.screen.blit(self.photoWD, pos)
最后定义一个函数,在鼠标左键点击时,落下棋子。
# 落子,并驱动玩家的轮流下棋行为
def getDown(self):
# 拷贝三份棋盘“快照”,悔棋和判断“打劫”时需要作参考
self.last_3_positions = copy.deepcopy(self.last_2_positions)
self.last_2_positions = copy.deepcopy(self.last_1_positions)
self.last_1_positions = copy.deepcopy(self.positions)
dx = (self.mouse_x - 20 * self.size) % self.interval
dy = (self.mouse_y - 20 * self.size) % self.interval
if not self.stop:
row = int((self.mouse_x - 20 * self.size) / self.interval) + round(dx / self.interval)
col = int((self.mouse_y - 20 * self.size) / self.interval) + round(dy / self.interval)
if self.positions[row][col] == 0:
self.positions[row][col] = self.present
deadlist = self.get_deadlist()
self.kill(deadlist)
# 自杀判定
# 对方无“气”棋子全部提走后,对己方棋子进行有无“气”的判断,若己方仍存在无“气”棋子,则判定为自杀行为,自杀标志置1(因只需检测到一个无“气”子即说明是自杀,故无需继续检测,跳出循环)
for i in range(9):
for j in range(9):
if self.positions[i][j] == self.present:
if self.if_dead(i, j) == True:
win32api.MessageBox(0, "禁止自杀", "警告", win32con.MB_ICONWARNING)
self.positions[i][j] = 0
self.present = - self.present
else:
# 警告信息框
win32api.MessageBox(0, "此处以存在棋子", "警告", win32con.MB_ICONWARNING)
5、吃子判断
在每次落子之后,遍历整个棋盘,并返回死棋列表位置
# 落子后,依次判断四周是否有棋子被杀死,并返回死棋位置列表
def get_deadlist(self):
deadlist = []
for i in range(self.mode_num):
for j in range(self.mode_num):
if self.positions[i][j] == 0:
continue
elif self.positions[i][j] == -self.present and self.if_dead(i, j) == True:
# continue
self.visit_positions = [[0 for k in range(self.mode_num + 2)] for k in range(self.mode_num + 2)]
deadlist.append([i, j])
# print(deadlist)
return deadlist
判断棋子是否有气函数if_dead
# 判断棋子是否无气(死亡),有气则返回False,无气则返回无气棋子的列表
def if_dead(self, x, y):
# 为避免重复搜索,走过的位置记为1
self.visit_positions[x][y] = 1
directions = [[x - 1, y], [x + 1, y], [x, y - 1], [x, y + 1]]
# 左,右,上,下四个方向
for dx, dy in directions:
# 左边是墙 或 右边是墙 或 上边是墙 或 下边是墙,即死路,则跳过此方向
if dx < 0 or dx > 8 or dy < 0 or dy > 8:
continue
# 若此方向没有搜索过,则开始搜索
elif self.visit_positions[dx][dy] == 0:
# 此方向没有棋子,可看做迷宫的出口,于是该棋子有“气”,停止搜索
if self.positions[dx][dy] == 0:
return False
# 此方向是对方棋子,是死路,跳过此方向
elif self.positions[dx][dy] == - self.positions[x][y]:
continue
# 此方向是己方棋子,即通路,继续递归执行DFS
elif self.positions[dx][dy] == self.positions[x][y]:
self.if_dead(dx, dy)
# 以上条件都不满足,即所有路径都为死路,该棋子无“气”,停止搜索
return True
杀死死棋文章来源:https://www.toymoban.com/news/detail-594489.html
# 杀死位置列表killList中的棋子,即删除图片,位置值置0
def kill(self, killList):
if len(killList) > 0:
for i, j in killList:
self.positions[i][j] = 0
6 悔棋和弃一子
# 放弃一子
def passme(self):
self.present = -self.present
# 悔棋函数
def regret(self):
self.positions = self.last_2_positions
7 重新开始、推出与切换棋盘
# 重新开始游戏
def reload(self):
self.present = 1
self.draw_chessboard()
# 定义棋盘阵列,无子:0,黑棋:1,白棋:-1
self.positions = [[0 for i in range(self.mode_num + 2)] for i in range(self.mode_num + 2)]
self.visit_positions = [[0 for i in range(self.mode_num + 2)] for i in range(self.mode_num + 2)]
self.draw_chess()
# 退出游戏
def exit(self):
pygame.quit()
sys.exit()
# 更改游戏棋盘
def newgame1(self):
self.mode_num = 13
# 棋盘每格的边长
self.interval = 360 * self.size / (self.mode_num - 1)
# 相对九路棋盘的矫正比例
self.p = 1 if self.mode_num == 9 else (2 / 3 if self.mode_num == 13 else 4 / 9)
# 定义棋盘阵列,无子:0,黑棋:1,白棋:-1
self.positions = [[0 for i in range(self.mode_num + 2)] for i in range(self.mode_num + 2)]
self.visit_positions = [[0 for i in range(self.mode_num + 2)] for i in range(self.mode_num + 2)]
self.photoBD = pygame.image.load("./Pictures/" + "BD" + "-" + str(self.mode_num) + ".png") # .convert()
self.photoWD = pygame.image.load("./Pictures/" + "WD" + "-" + str(self.mode_num) + ".png") # .convert()
# 更改游戏棋盘
def newgame2(self):
self.mode_num = 19
# 棋盘每格的边长
self.interval = 360 * self.size / (self.mode_num - 1)
# 相对九路棋盘的矫正比例
self.p = 1 if self.mode_num == 9 else (2 / 3 if self.mode_num == 13 else 4 / 9)
# 定义棋盘阵列,无子:0,黑棋:1,白棋:-1
self.positions = [[0 for i in range(self.mode_num + 2)] for i in range(self.mode_num + 2)]
self.visit_positions = [[0 for i in range(self.mode_num + 2)] for i in range(self.mode_num + 2)]
self.photoBD = pygame.image.load("./Pictures/" + "BD" + "-" + str(self.mode_num) + ".png") # .convert()
self.photoWD = pygame.image.load("./Pictures/" + "WD" + "-" + str(self.mode_num) + ".png") # .convert()
8 显示
def show(self):
while True:
pygame.display.flip()
self.clock = pygame.time.Clock()
# 绘制棋盘
self.draw_chessboard()
# 绘制棋子
self.draw_chess()
if not self.stop:
# 棋子跟随鼠标移动
self.chess_follow()
# 监听所有事件
for event in pygame.event.get():
# 点击x则关闭窗口
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# 点击窗口里面类容则完成相应指令
elif event.type == MOUSEMOTION:
x, y = event.pos
self.get_mouse_current_position(x, y)
elif event.type == MOUSEBUTTONDOWN:
# 鼠标点击按钮函数
self.start_button.handle_event(self.start)
self.pass_me_button.handle_event(self.passme)
self.regert_button.handle_event(self.regret)
self.restsrt_button.handle_event(self.reload)
self.thirteen_way_button.handle_event(self.newgame1)
self.nineteenth_way_button.handle_event(self.newgame2)
self.exit_button.handle_event(self.exit)
# 如果鼠标左键在棋盘内按下
if 20 * self.size < self.mouse_x < 380 * self.size and 20 * self.size < self.mouse_y < 380 * self.size:
self.getDown()
self.present = - self.present
9 初始化
class weiqi():
def __init__(self):
# 模式,九路棋:9,十三路棋:13,十九路棋:19
self.mode_num = 9
# 窗口尺寸设置,默认:1.8
self.size = 1.8
# 棋盘每格的边长
self.interval = 360 * self.size / (self.mode_num - 1)
# 相对九路棋盘的矫正比例
self.p = 1 if self.mode_num == 9 else (2 / 3 if self.mode_num == 13 else 4 / 9)
# 定义棋盘阵列,无子:0,黑棋:1,白棋:-1
self.positions = [[0 for i in range(self.mode_num + 2)] for i in range(self.mode_num + 2)]
self.visit_positions = [[0 for i in range(self.mode_num + 2)] for i in range(self.mode_num + 2)]
# 当前轮到的玩家,黑:1,白:-1,执黑先行
self.present = 1
# 初始停止运行,点击“开始游戏”运行游戏
self.stop = True
# 悔棋次数,次数大于0才可悔棋,初始置0(初始不能悔棋),悔棋后置0,下棋或弃手时恢复为1,以禁止连续悔棋
self.regretchance = 0
self.mouse_x = -100
self.mouse_y = -100
self.last_1_positions = copy.deepcopy(self.positions)
self.last_2_positions = copy.deepcopy(self.positions)
self.last_3_positions = copy.deepcopy(self.positions)
pygame.init()
# 创建一个窗口
self.screen = pygame.display.set_mode([600 * self.size, 400 * self.size])
# 设置窗口标题
pygame.display.set_caption("围棋")
self.photoW = pygame.image.load("./Pictures/W.png") # .convert()
self.photoB = pygame.image.load("./Pictures/B.png") # .convert()
self.photoBD = pygame.image.load("./Pictures/" + "BD" + "-" + str(self.mode_num) + ".png") # .convert()
self.photoWD = pygame.image.load("./Pictures/" + "WD" + "-" + str(self.mode_num) + ".png") # .convert()
self.bg_rect = pygame.Surface((200 * self.size, 100 * self.size), flags=pygame.HWSURFACE)
self.bg_rect.fill((51, 102, 153))
完整代码
https://download.csdn.net/download/m0_55818687/87698112文章来源地址https://www.toymoban.com/news/detail-594489.html
到了这里,关于基于python pyqt的围棋游戏制作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!