突然奇想,什么时候可以自己实现一个机器对战的小游戏,但一直不敢去尝试,直到偶尔发现了重力四子棋的规则,有限的空间棋盘正好可以拿来练手。
有关下棋AI的算法,说来说去也就那么几种,随机蒙特卡罗方法、UCT信心上限树、博弈论(Alpha−Beta剪枝)...
这个小游戏我时间更多的花在ui界面和游戏逻辑的实现,可以切换先后手顺序,添加了重置游戏和暂停游戏的规则,可落子节点辅助提示,以及对应的文字提示信息。
算法采用了无忧化的蒙特卡罗方法,模拟当前棋盘状态可落子节点扩展的胜利可能性,模拟的次数越多,时间自然也就越久,但智能度相应着也会提高。
源代码:https://download.csdn.net/download/qq_40204582/11212878
代码开源了,如果有复制过去的朋友,可以顺手点个赞吗^_^
import pygame, sys
from pygame.locals import *
import time
import random
import copy# game parameters
pygame.init()
win_width, win_height = 930, 700
displaysurf = pygame.display.set_mode((win_width, win_height), 0, 32)
pygame.display.set_caption('Connect_4')# color parameters
backgroundcolor_chess = (244, 171, 102)
color_white = (255, 255, 255)
color_black = (0, 0, 0)
color_tip_white = (225, 225, 225)
color_tip_black = (25, 25, 25)
color_green = (0, 255, 0)# chess parameters
chess_grid_row, chess_grid_col = 6, 8
chess_list = []
for i in range(chess_grid_row):new_line = [0 for j in range(chess_grid_col)]chess_list.append(new_line)
player = True
play_flag = False# draw chessboard
def draw_chessboard():displaysurf.fill(color_white)fontobj = pygame.font.SysFont('SimHei',70)text = fontobj.render("重力四子棋", True, color_black, color_white)textrect = text.get_rect()textrect.center = (430, 70)displaysurf.blit(text, textrect)pygame.draw.rect(displaysurf, backgroundcolor_chess, (50, 170, 640, 480))for pix_row in range(7):pygame.draw.line(displaysurf, color_black, (50, 170 + pix_row * 80), (690, 170 + pix_row * 80))for pix_col in range(9):pygame.draw.line(displaysurf, color_black, (50 + pix_col * 80, 170), (50 + pix_col * 80, 650))def draw_tip_chess(mousex, mousey, type):for row in range(chess_grid_row):for col in range(chess_grid_col):if chess_list[row][col] in [3, 4]:chess_list[row][col] = 0col = int((mousex - 50) / 80)row = int((mousey - 170) / 80)if row == chess_grid_row:row -= 1if col == chess_grid_col:col -= 1if row < chess_grid_row - 1:if chess_list[row + 1][col] == 0:returnif chess_list[row][col] == 0:chess_list[row][col] = typedef clear_tip_chess():for row in range(chess_grid_row):for col in range(chess_grid_col):if chess_list[row][col] in [3, 4]:chess_list[row][col] = 0def draw_check_chess(mousex, mousey, type):for row in range(chess_grid_row):for col in range(chess_grid_col):if chess_list[row][col] in [3, 4]:chess_list[row][col] = 0col = int((mousex - 50) / 80)row = int((mousey - 170) / 80)if row == chess_grid_row:row -= 1if col == chess_grid_col:col -= 1if row < chess_grid_row - 1:if chess_list[row + 1][col] == 0:returnif chess_list[row][col] in [1, 2]:return Falseelse:chess_list[row][col] = typereturn Truedef draw_chess():for row in range(chess_grid_row):for col in range(chess_grid_col):if chess_list[row][col] == 0:pygame.draw.circle(displaysurf, backgroundcolor_chess, (90 + col * 80, 210 + row * 80), 38)elif chess_list[row][col] == 1:pygame.draw.circle(displaysurf, color_black, (90 + col * 80, 210 + row * 80), 38)elif chess_list[row][col] == 2:pygame.draw.circle(displaysurf, color_white, (90 + col * 80, 210 + row * 80), 38)elif chess_list[row][col] == 3:pygame.draw.circle(displaysurf, color_tip_black, (90 + col * 80, 210 + row * 80), 38)elif chess_list[row][col] == 4:pygame.draw.circle(displaysurf, color_tip_white, (90 + col * 80, 210 + row * 80), 38)def is_win(temp_chess_list):not_null_sum = 0for row in range(chess_grid_row):for col in range(chess_grid_col):if temp_chess_list[row][col] in [3, 4]:temp_chess_list[row][col] = 0if temp_chess_list[row][col] != 0:not_null_sum += 1# horizontalif col < chess_grid_col - 3:if temp_chess_list[row][col] == temp_chess_list[row][col + 1] == temp_chess_list[row][col + 2] == \temp_chess_list[row][col + 3] and temp_chess_list[row][col] != 0:return temp_chess_list[row][col]# verticalif row < chess_grid_row - 3:if temp_chess_list[row][col] == temp_chess_list[row + 1][col] == temp_chess_list[row + 2][col] == \temp_chess_list[row + 3][col] and temp_chess_list[row][col] != 0:return temp_chess_list[row][col]# right slantif col < chess_grid_col - 3 and row < chess_grid_row - 3:if temp_chess_list[row][col] == temp_chess_list[row + 1][col + 1] == temp_chess_list[row + 2][col + 2] == \temp_chess_list[row + 3][col + 3] and temp_chess_list[row][col] != 0:return temp_chess_list[row][col]# left slantif col >= 3 and row < chess_grid_row - 3:if temp_chess_list[row][col] == temp_chess_list[row + 1][col - 1] == temp_chess_list[row + 2][col - 2] == \temp_chess_list[row + 3][col - 3] and temp_chess_list[row][col] != 0:return temp_chess_list[row][col]if not_null_sum == chess_grid_row*chess_grid_col:return 3return 0def AI(chess_list, type):node_list = []chess_null_sum = 0for col in range(chess_grid_col):for row in range(chess_grid_row):if chess_list[row][col] == 0:chess_null_sum += 1if row == chess_grid_row -1:temp_chess_list = copy.deepcopy(chess_list)temp_chess_list[row][col] = typenode_list.append([row, col])flag = is_win(temp_chess_list)if flag != 0:chess_list[row][col] = typereturn row, colelif chess_list[row+1][col] != 0:temp_chess_list = copy.deepcopy(chess_list)temp_chess_list[row][col] = typenode_list.append([row, col])flag = is_win(temp_chess_list)if flag != 0:chess_list[row][col] = typereturn row, colprint(node_list)range_sum = 500 + int((chess_grid_row*chess_grid_col-chess_null_sum)/(chess_grid_row*chess_grid_col)*100)print(range_sum)win_list = [0 for j in range(chess_grid_col)]tip_list = [0 for j in range(chess_grid_col)]start = time.clock()for i in range(len(node_list)):for j in range(100):temp_type = typetemp_chess_list = copy.deepcopy(chess_list)temp_node_list = copy.deepcopy(node_list)temp_chess_list[temp_node_list[i][0]][temp_node_list[i][1]] = temp_typeflag_win = is_win(temp_chess_list)if flag_win != 0:if flag_win == type:win_list[i] += 1continueelif flag_win == 3:tip_list[i] += 1if temp_node_list[i][0] == 0:del temp_node_list[i]else:temp_node_list[i][0] -= 1while True:if temp_type == 1:temp_type = 2else:temp_type = 1try:temp_index = random.randint(0, len(temp_node_list)-1)except:breaktemp_chess_list[temp_node_list[temp_index][0]][temp_node_list[temp_index][1]] = temp_typeflag_win = is_win(temp_chess_list)if flag_win != 0:if flag_win == type:win_list[i] += 1elif flag_win == 3:tip_list[i] += 1breakif temp_node_list[temp_index][0] == 0:del temp_node_list[temp_index]else:temp_node_list[temp_index][0] -= 1end = time.clock()print(end - start)if max(win_list) > range_sum*0.1:print(win_list)check = win_list.index(max(win_list))print(node_list)print(check)else:check = tip_list.index(max(tip_list))print("选择平局")chess_list[node_list[check][0]][node_list[check][1]] = typedef draw_player(player):fontobj = pygame.font.SysFont('SimHei', 25)if player:text = fontobj.render("先手: 电脑 棋色: 黑色", True, color_black, color_white)else:text = fontobj.render("先手: 玩家 棋色: 黑色", True, color_black, color_white)textrect = text.get_rect()textrect.center = (260, 140)displaysurf.blit(text, textrect)def button():pygame.draw.rect(displaysurf, color_green, (730, 200, 160, 80))fontobj1 = pygame.font.SysFont('SimHei', 30)text1 = fontobj1.render("切换先手", True, color_white, color_green)textrect1 = text1.get_rect()textrect1.center = (810, 240)displaysurf.blit(text1, textrect1)pygame.draw.rect(displaysurf, color_green, (730, 360, 160, 80))fontobj2 = pygame.font.SysFont('SimHei', 30)if play_flag == False:text2 = fontobj2.render("开始游戏", True, color_white, color_green)else:text2 = fontobj2.render("暂停游戏", True, color_white, color_green)textrect2 = text2.get_rect()textrect2.center = (810, 400)displaysurf.blit(text2, textrect2)pygame.draw.rect(displaysurf, color_green, (730, 520, 160, 80))fontobj3 = pygame.font.SysFont('SimHei', 30)text3 = fontobj3.render("重置游戏", True, color_white, color_green)textrect3 = text3.get_rect()textrect3.center = (810, 560)displaysurf.blit(text3, textrect3)def play_type():fontobj = pygame.font.SysFont('SimHei', 25)if play_flag == False:win_flag = is_win(chess_list)pygame.draw.rect(displaysurf, color_white, (400, 120, 300, 45))if win_flag == 0:text = fontobj.render("状态: 未开始游戏", True, color_black, color_white)elif win_flag == 1:if player:text = fontobj.render("状态: 电脑胜利", True, color_black, color_white)else:text = fontobj.render("状态: 玩家胜利", True, color_black, color_white)elif win_flag == 2:if player:text = fontobj.render("状态: 玩家胜利", True, color_black, color_white)else:text = fontobj.render("状态: 电脑胜利", True, color_black, color_white)elif win_flag == 3:text = fontobj.render("状态: 平局", True, color_black, color_white)else:null_sum = 0for row in range(chess_grid_row):for col in range(chess_grid_col):if chess_list[row][col] in [0, 3, 4]:null_sum += 1if player:if (chess_grid_row*chess_grid_col-null_sum) % 2 == 0:text = fontobj.render("状态: 请电脑落子", True, color_black, color_white)else:text = fontobj.render("状态: 请玩家落子", True, color_black, color_white)else:if (chess_grid_row*chess_grid_col-null_sum) % 2 == 1:text = fontobj.render("状态: 请电脑落子", True, color_black, color_white)else:text = fontobj.render("状态: 请玩家落子", True, color_black, color_white)textrect = text.get_rect()textrect.center = (570, 140)displaysurf.blit(text, textrect)def new_play():global player, play_flagdraw_chessboard()# AI(chess_list, 1)# main game loopwhile True:for event in pygame.event.get():# close gameif event.type == QUIT:pygame.quit()sys.exit()elif event.type == MOUSEMOTION:mousex, mousey = event.posif play_flag:if mousex > 50 and mousex < 690 and mousey > 170 and mousey < 730:if player:draw_tip_chess(mousex, mousey, 4)else:draw_tip_chess(mousex, mousey, 3)else:clear_tip_chess()elif event.type == MOUSEBUTTONUP:mousex, mousey = event.posif play_flag:if mousex > 50 and mousex < 690 and mousey > 170 and mousey < 730:if player:flag = draw_check_chess(mousex, mousey, 2)draw_chess()pygame.display.update()if flag:if is_win(chess_list) != 0:play_flag = Falseplay_type()pygame.display.update()if play_flag:AI(chess_list, 1)if is_win(chess_list) != 0:play_flag = Falseelse:flag = draw_check_chess(mousex, mousey, 1)draw_chess()pygame.display.update()if flag:if is_win(chess_list) != 0:play_flag = Falseplay_type()pygame.display.update()if play_flag:AI(chess_list, 2)if is_win(chess_list) != 0:play_flag = Falseelse:if mousex > 730 and mousex < 890 and mousey > 200 and mousey < 280:if is_win(chess_list) == 0:if player:player = Falseelse:player = Truedraw_player(player)if mousex > 730 and mousex < 890 and mousey > 360 and mousey < 440:if play_flag:play_flag = Falseelse:if is_win(chess_list) == 0:play_flag = Trueplay_type()button()pygame.display.update()if player and sum(chess_list[-1]) == 0:AI(chess_list, 1)elif mousex > 730 and mousex < 890 and mousey > 520 and mousey < 600:play_flag = Falsefor row in range(chess_grid_row):for col in range(chess_grid_col):chess_list[row][col] = 0draw_player(player)button()draw_chess()play_type()pygame.display.update()def main():new_play()main()