1 """五子棋之人机对战"""  2   3 import random  4 import sys  5   6 import pygame  7 import pygame.gfxdraw  8 from pygame.locals import *  9  10 from checkerboard import Checkerboard, BLACK_CHESSMAN, WHITE_CHESSMAN, offset, Point 11  12 SIZE = 30  # 棋盘每个点时间的间隔 13 Line_Points = 19  # 棋盘每行/每列点数 14 Outer_Width = 20  # 棋盘外宽度 15 Border_Width = 4  # 边框宽度 16 Inside_Width = 4  # 边框跟实际的棋盘之间的间隔 17 Border_Length = SIZE * (Line_Points - 1) + Inside_Width * 2 + Border_Width  # 边框线的长度 18 Start_X = Start_Y = Outer_Width + int(Border_Width / 2) + Inside_Width  # 网格线起点(左上角)坐标 19 SCREEN_HEIGHT = SIZE * (Line_Points - 1) + Outer_Width * 2 + Border_Width + Inside_Width * 2  # 游戏屏幕的高 20 SCREEN_WIDTH = SCREEN_HEIGHT + 200  # 游戏屏幕的宽 21  22 Stone_Radius = SIZE // 2 - 3  # 棋子半径 23 Stone_Radius2 = SIZE // 2 + 3 24 Checkerboard_Color = (0xE3, 0x92, 0x65)  # 棋盘颜色 25 BLACK_COLOR = (0, 0, 0) 26 WHITE_COLOR = (255, 255, 255) 27 RED_COLOR = (200, 30, 30) 28 BLUE_COLOR = (30, 30, 200) 29  30 RIGHT_INFO_POS_X = SCREEN_HEIGHT + Stone_Radius2 * 2 + 10 31  32  33 def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): 34     imgText = font.render(text, True, fcolor) 35     screen.blit(imgText, (x, y)) 36  37  38 def main(): 39     pygame.init() 40     screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) 41     pygame.display.set_caption('五子棋') 42  43     font1 = pygame.font.SysFont('SimHei', 32) 44     font2 = pygame.font.SysFont('SimHei', 72) 45     fwidth, fheight = font2.size('黑方获胜') 46  47     checkerboard = Checkerboard(Line_Points) 48     cur_runner = BLACK_CHESSMAN 49     winner = None 50     computer = AI(Line_Points, WHITE_CHESSMAN) 51  52     black_win_count = 0 53     white_win_count = 0 54  55     while True: 56         for event in pygame.event.get(): 57             if event.type == QUIT: 58                 sys.exit() 59             elif event.type == KEYDOWN: 60                 if event.key == K_RETURN: 61                     if winner is not None: 62                         winner = None 63                         cur_runner = BLACK_CHESSMAN 64                         checkerboard = Checkerboard(Line_Points) 65                         computer = AI(Line_Points, WHITE_CHESSMAN) 66             elif event.type == MOUSEBUTTONDOWN: 67                 if winner is None: 68                     pressed_array = pygame.mouse.get_pressed() 69                     if pressed_array[0]: 70                         mouse_pos = pygame.mouse.get_pos() 71                         click_point = _get_clickpoint(mouse_pos) 72                         if click_point is not None: 73                             if checkerboard.can_drop(click_point): 74                                 winner = checkerboard.drop(cur_runner, click_point) 75                                 if winner is None: 76                                     cur_runner = _get_next(cur_runner) 77                                     computer.get_opponent_drop(click_point) 78                                     AI_point = computer.AI_drop() 79                                     winner = checkerboard.drop(cur_runner, AI_point) 80                                     if winner is not None: 81                                         white_win_count += 1 82                                     cur_runner = _get_next(cur_runner) 83                                 else: 84                                     black_win_count += 1 85                         else: 86                             print('超出棋盘区域') 87  88         # 画棋盘 89         _draw_checkerboard(screen) 90  91         # 画棋盘上已有的棋子 92         for i, row in enumerate(checkerboard.checkerboard): 93             for j, cell in enumerate(row): 94                 if cell == BLACK_CHESSMAN.Value: 95                     _draw_chessman(screen, Point(j, i), BLACK_CHESSMAN.Color) 96                 elif cell == WHITE_CHESSMAN.Value: 97                     _draw_chessman(screen, Point(j, i), WHITE_CHESSMAN.Color) 98  99         _draw_left_info(screen, font1, cur_runner, black_win_count, white_win_count)100 101         if winner:102             print_text(screen, font2, (SCREEN_WIDTH - fwidth) // 2, (SCREEN_HEIGHT - fheight) // 2, winner.Name + '获胜',103                        RED_COLOR)104 105         pygame.display.flip()106 107 108 def _get_next(cur_runner):109     if cur_runner == BLACK_CHESSMAN:110         return WHITE_CHESSMAN111     else:112         return BLACK_CHESSMAN113 114 115 # 画棋盘116 def _draw_checkerboard(screen):117     # 填充棋盘背景色118     screen.fill(Checkerboard_Color)119     # 画棋盘网格线外的边框120     pygame.draw.rect(screen, BLACK_COLOR, (Outer_Width, Outer_Width, Border_Length, Border_Length), Border_Width)121     # 画网格线122     for i in range(Line_Points):123         pygame.draw.line(screen, BLACK_COLOR,124                          (Start_Y, Start_Y + SIZE * i),125                          (Start_Y + SIZE * (Line_Points - 1), Start_Y + SIZE * i),126                          1)127     for j in range(Line_Points):128         pygame.draw.line(screen, BLACK_COLOR,129                          (Start_X + SIZE * j, Start_X),130                          (Start_X + SIZE * j, Start_X + SIZE * (Line_Points - 1)),131                          1)132     # 画星位和天元133     for i in (3, 9, 15):134         for j in (3, 9, 15):135             if i == j == 9:136                 radius = 5137             else:138                 radius = 3139             # pygame.draw.circle(screen, BLACK, (Start_X + SIZE * i, Start_Y + SIZE * j), radius)140             pygame.gfxdraw.aacircle(screen, Start_X + SIZE * i, Start_Y + SIZE * j, radius, BLACK_COLOR)141             pygame.gfxdraw.filled_circle(screen, Start_X + SIZE * i, Start_Y + SIZE * j, radius, BLACK_COLOR)142 143 144 # 画棋子145 def _draw_chessman(screen, point, stone_color):146     # pygame.draw.circle(screen, stone_color, (Start_X + SIZE * point.X, Start_Y + SIZE * point.Y), Stone_Radius)147     pygame.gfxdraw.aacircle(screen, Start_X + SIZE * point.X, Start_Y + SIZE * point.Y, Stone_Radius, stone_color)148     pygame.gfxdraw.filled_circle(screen, Start_X + SIZE * point.X, Start_Y + SIZE * point.Y, Stone_Radius, stone_color)149 150 151 # 画左侧信息显示152 def _draw_left_info(screen, font, cur_runner, black_win_count, white_win_count):153     _draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, Start_X + Stone_Radius2), BLACK_CHESSMAN.Color)154     _draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, Start_X + Stone_Radius2 * 4), WHITE_CHESSMAN.Color)155 156     print_text(screen, font, RIGHT_INFO_POS_X, Start_X + 3, '玩家', BLUE_COLOR)157     print_text(screen, font, RIGHT_INFO_POS_X, Start_X + Stone_Radius2 * 3 + 3, '电脑', BLUE_COLOR)158 159     print_text(screen, font, SCREEN_HEIGHT, SCREEN_HEIGHT - Stone_Radius2 * 8, '战况:', BLUE_COLOR)160     _draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, SCREEN_HEIGHT - int(Stone_Radius2 * 4.5)),161                        BLACK_CHESSMAN.Color)162     _draw_chessman_pos(screen, (SCREEN_HEIGHT + Stone_Radius2, SCREEN_HEIGHT - Stone_Radius2 * 2), WHITE_CHESSMAN.Color)163     print_text(screen, font, RIGHT_INFO_POS_X, SCREEN_HEIGHT - int(Stone_Radius2 * 5.5) + 3, f'{black_win_count} 胜',164                BLUE_COLOR)165     print_text(screen, font, RIGHT_INFO_POS_X, SCREEN_HEIGHT - Stone_Radius2 * 3 + 3, f'{white_win_count} 胜',166                BLUE_COLOR)167 168 169 def _draw_chessman_pos(screen, pos, stone_color):170     pygame.gfxdraw.aacircle(screen, pos[0], pos[1], Stone_Radius2, stone_color)171     pygame.gfxdraw.filled_circle(screen, pos[0], pos[1], Stone_Radius2, stone_color)172 173 174 # 根据鼠标点击位置,返回游戏区坐标175 def _get_clickpoint(click_pos):176     pos_x = click_pos[0] - Start_X177     pos_y = click_pos[1] - Start_Y178     if pos_x < -Inside_Width or pos_y < -Inside_Width:179         return None180     x = pos_x // SIZE181     y = pos_y // SIZE182     if pos_x % SIZE > Stone_Radius:183         x += 1184     if pos_y % SIZE > Stone_Radius:185         y += 1186     if x >= Line_Points or y >= Line_Points:187         return None188 189     return Point(x, y)190 191 192 class AI:193     def __init__(self, line_points, chessman):194         self._line_points = line_points195         self._my = chessman196         self._opponent = BLACK_CHESSMAN if chessman == WHITE_CHESSMAN else WHITE_CHESSMAN197         self._checkerboard = [[0] * line_points for _ in range(line_points)]198 199     def get_opponent_drop(self, point):200         self._checkerboard[point.Y][point.X] = self._opponent.Value201 202     def AI_drop(self):203         point = None204         score = 0205         for i in range(self._line_points):206             for j in range(self._line_points):207                 if self._checkerboard[j][i] == 0:208                     _score = self._get_point_score(Point(i, j))209                     if _score > score:210                         score = _score211                         point = Point(i, j)212                     elif _score == score and _score > 0:213                         r = random.randint(0, 100)214                         if r % 2 == 0:215                             point = Point(i, j)216         self._checkerboard[point.Y][point.X] = self._my.Value217         return point218 219     def _get_point_score(self, point):220         score = 0221         for os in offset:222             score += self._get_direction_score(point, os[0], os[1])223         return score224 225     def _get_direction_score(self, point, x_offset, y_offset):226         count = 0  # 落子处我方连续子数227         _count = 0  # 落子处对方连续子数228         space = None  # 我方连续子中有无空格229         _space = None  # 对方连续子中有无空格230         both = 0  # 我方连续子两端有无阻挡231         _both = 0  # 对方连续子两端有无阻挡232 233         # 如果是 1 表示是边上是我方子,2 表示敌方子234         flag = self._get_stone_color(point, x_offset, y_offset, True)235         if flag != 0:236             for step in range(1, 6):237                 x = point.X + step * x_offset238                 y = point.Y + step * y_offset239                 if 0 <= x < self._line_points and 0 <= y < self._line_points:240                     if flag == 1:241                         if self._checkerboard[y][x] == self._my.Value:242                             count += 1243                             if space is False:244                                 space = True245                         elif self._checkerboard[y][x] == self._opponent.Value:246                             _both += 1247                             break248                         else:249                             if space is None:250                                 space = False251                             else:252                                 break  # 遇到第二个空格退出253                     elif flag == 2:254                         if self._checkerboard[y][x] == self._my.Value:255                             _both += 1256                             break257                         elif self._checkerboard[y][x] == self._opponent.Value:258                             _count += 1259                             if _space is False:260                                 _space = True261                         else:262                             if _space is None:263                                 _space = False264                             else:265                                 break266                 else:267                     # 遇到边也就是阻挡268                     if flag == 1:269                         both += 1270                     elif flag == 2:271                         _both += 1272 273         if space is False:274             space = None275         if _space is False:276             _space = None277 278         _flag = self._get_stone_color(point, -x_offset, -y_offset, True)279         if _flag != 0:280             for step in range(1, 6):281                 x = point.X - step * x_offset282                 y = point.Y - step * y_offset283                 if 0 <= x < self._line_points and 0 <= y < self._line_points:284                     if _flag == 1:285                         if self._checkerboard[y][x] == self._my.Value:286                             count += 1287                             if space is False:288                                 space = True289                         elif self._checkerboard[y][x] == self._opponent.Value:290                             _both += 1291                             break292                         else:293                             if space is None:294                                 space = False295                             else:296                                 break  # 遇到第二个空格退出297                     elif _flag == 2:298                         if self._checkerboard[y][x] == self._my.Value:299                             _both += 1300                             break301                         elif self._checkerboard[y][x] == self._opponent.Value:302                             _count += 1303                             if _space is False:304                                 _space = True305                         else:306                             if _space is None:307                                 _space = False308                             else:309                                 break310                 else:311                     # 遇到边也就是阻挡312                     if _flag == 1:313                         both += 1314                     elif _flag == 2:315                         _both += 1316 317         score = 0318         if count == 4:319             score = 10000320         elif _count == 4:321             score = 9000322         elif count == 3:323             if both == 0:324                 score = 1000325             elif both == 1:326                 score = 100327             else:328                 score = 0329         elif _count == 3:330             if _both == 0:331                 score = 900332             elif _both == 1:333                 score = 90334             else:335                 score = 0336         elif count == 2:337             if both == 0:338                 score = 100339             elif both == 1:340                 score = 10341             else:342                 score = 0343         elif _count == 2:344             if _both == 0:345                 score = 90346             elif _both == 1:347                 score = 9348             else:349                 score = 0350         elif count == 1:351             score = 10352         elif _count == 1:353             score = 9354         else:355             score = 0356 357         if space or _space:358             score /= 2359 360         return score361 362     # 判断指定位置处在指定方向上是我方子、对方子、空363     def _get_stone_color(self, point, x_offset, y_offset, next):364         x = point.X + x_offset365         y = point.Y + y_offset366         if 0 <= x < self._line_points and 0 <= y < self._line_points:367             if self._checkerboard[y][x] == self._my.Value:368                 return 1369             elif self._checkerboard[y][x] == self._opponent.Value:370                 return 2371             else:372                 if next:373                     return self._get_stone_color(Point(x, y), x_offset, y_offset, False)374                 else:375                     return 0376         else:377             return 0378 379 380 if __name__ == '__main__':381     main()