Pyhton实践项目之(一)五子棋人机对战
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_CHESSMAN 111 else: 112 return BLACK_CHESSMAN 113 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 = 5 137 else: 138 radius = 3 139 # 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_X 177 pos_y = click_pos[1] - Start_Y 178 if pos_x < -Inside_Width or pos_y < -Inside_Width: 179 return None 180 x = pos_x // SIZE 181 y = pos_y // SIZE 182 if pos_x % SIZE > Stone_Radius: 183 x += 1 184 if pos_y % SIZE > Stone_Radius: 185 y += 1 186 if x >= Line_Points or y >= Line_Points: 187 return None 188 189 return Point(x, y) 190 191 192 class AI: 193 def __init__(self, line_points, chessman): 194 self._line_points = line_points 195 self._my = chessman 196 self._opponent = BLACK_CHESSMAN if chessman == WHITE_CHESSMAN else WHITE_CHESSMAN 197 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.Value 201 202 def AI_drop(self): 203 point = None 204 score = 0 205 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 = _score 211 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.Value 217 return point 218 219 def _get_point_score(self, point): 220 score = 0 221 for os in offset: 222 score += self._get_direction_score(point, os[0], os[1]) 223 return score 224 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_offset 238 y = point.Y + step * y_offset 239 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 += 1 243 if space is False: 244 space = True 245 elif self._checkerboard[y][x] == self._opponent.Value: 246 _both += 1 247 break 248 else: 249 if space is None: 250 space = False 251 else: 252 break # 遇到第二个空格退出 253 elif flag == 2: 254 if self._checkerboard[y][x] == self._my.Value: 255 _both += 1 256 break 257 elif self._checkerboard[y][x] == self._opponent.Value: 258 _count += 1 259 if _space is False: 260 _space = True 261 else: 262 if _space is None: 263 _space = False 264 else: 265 break 266 else: 267 # 遇到边也就是阻挡 268 if flag == 1: 269 both += 1 270 elif flag == 2: 271 _both += 1 272 273 if space is False: 274 space = None 275 if _space is False: 276 _space = None 277 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_offset 282 y = point.Y - step * y_offset 283 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 += 1 287 if space is False: 288 space = True 289 elif self._checkerboard[y][x] == self._opponent.Value: 290 _both += 1 291 break 292 else: 293 if space is None: 294 space = False 295 else: 296 break # 遇到第二个空格退出 297 elif _flag == 2: 298 if self._checkerboard[y][x] == self._my.Value: 299 _both += 1 300 break 301 elif self._checkerboard[y][x] == self._opponent.Value: 302 _count += 1 303 if _space is False: 304 _space = True 305 else: 306 if _space is None: 307 _space = False 308 else: 309 break 310 else: 311 # 遇到边也就是阻挡 312 if _flag == 1: 313 both += 1 314 elif _flag == 2: 315 _both += 1 316 317 score = 0 318 if count == 4: 319 score = 320 elif _count == 4: 321 score = 9000 322 elif count == 3: 323 if both == 0: 324 score = 1000 325 elif both == 1: 326 score = 100 327 else: 328 score = 0 329 elif _count == 3: 330 if _both == 0: 331 score = 900 332 elif _both == 1: 333 score = 90 334 else: 335 score = 0 336 elif count == 2: 337 if both == 0: 338 score = 100 339 elif both == 1: 340 score = 10 341 else: 342 score = 0 343 elif _count == 2: 344 if _both == 0: 345 score = 90 346 elif _both == 1: 347 score = 9 348 else: 349 score = 0 350 elif count == 1: 351 score = 10 352 elif _count == 1: 353 score = 9 354 else: 355 score = 0 356 357 if space or _space: 358 score /= 2 359 360 return score 361 362 # 判断指定位置处在指定方向上是我方子、对方子、空 363 def _get_stone_color(self, point, x_offset, y_offset, next): 364 x = point.X + x_offset 365 y = point.Y + y_offset 366 if 0 <= x < self._line_points and 0 <= y < self._line_points: 367 if self._checkerboard[y][x] == self._my.Value: 368 return 1 369 elif self._checkerboard[y][x] == self._opponent.Value: 370 return 2 371 else: 372 if next: 373 return self._get_stone_color(Point(x, y), x_offset, y_offset, False) 374 else: 375 return 0 376 else: 377 return 0 378 379 380 if __name__ == '__main__': 381 main()
当前标题:Pyhton实践项目之(一)五子棋人机对战
文章源于:http://scyanting.com/article/dsogsod.html