AI智能
改变未来

AI五子棋_09 消息循环实现自动对局

第九步恭喜你到达第九步!

上一步我们已经完成了一个AI大脑的最核心功能。我们可以用它来对战了。

访问服务器

http://202.207.12.156:9012/join_game

,会返回一个游戏编号

game_id

。之后你可以使用这个游戏编号,进行游戏

http://2**.207.12.156:9012/play_game/{game_id}

并查询游戏状态

http://2**.207.12.156:9012/check_game/{game_id}

利用这三个功能我们就可以让我们的AI参战了。这个过程应该是这样的,这是一个典型的消息循环。

join_game

加入游戏

check_game

检查游戏状态

  1. 如果游戏完成就退出

  2. 如果不轮你下,就等一会,否则使用AI确定要落子的位置,并用

    play_game

    告知服务器你落子的位置

  3. 返回到第2步用

    check_game

    检查游戏状态

其中

join_game

需要登录,需要提交用户名和密码,需要使用第五步使用的加密方法对密码加密,用户名写入

user

字段,加密后的密码写入

password

字段。另外需要传入字段

data_type

,将其设为json,返回字段

game_id

是加入的游戏编号。

play_game

也需要登录,落子的坐标写入

coord

字段。

check_game

不需要登录,返回当前的游戏状态, 会返回以下状态:

is_success,error

查询是否成功及错误原因

step

当前是第几步

creator

游戏一方的用户名

creator_name

游戏一方的名字(昵称)

creator_stone

游戏一方使用的棋子(x表示黑棋,o表示白棋)

opponent

游戏另一方的用户名

opponent_name

游戏另一方的名字(昵称)

opponent_stone

游戏另一方使用的棋子(x表示黑棋,o表示白棋)

ready

游戏是否就绪,两个玩家都在线时,游戏进入就绪状态

current_turn

当前应当落子的玩家的用户名

current_stone

当前应当落子的玩家的使用的棋子(x表示黑棋,o表示白棋)

left_time

剩余时间,为避免玩家过长思考,限制玩家必须在60秒内落子,否则游戏结束

winner

获胜的玩家的用户名,当游戏没有产生赢家时,该值为None

board

棋盘的坐标表示

last_ste

p 上一步落子的坐标

win_step

如果一方获胜,这个字段给出连成五子的一条线的棋子坐标

注意不要过于频繁的检查游戏的状态,使用sleep函数等待服务器更新状态,两次检查以5到10秒的间隔为宜。

任务 9

实现消息循环,开始作战吧!

Python实现

import requests as reimport time as tdef fastModular(x):"""x[0] = base """"""x[1] = power""""""x[2] = modulus"""result = 1while(x[1] > 0):if(x[1] & 1):result = result * x[0] % x[2]x[1] = int(x[1]/2)x[0] = x[0] * x[0] % x[2]return resultdef str_to_num(strings):sum = 0lens = len(strings)for i in range(0,lens):sum += ord(strings[i])*256**(lens-i-1)return sumdef encodeLogin(password):# 公钥power = 65537modulus = 135261828916791946705313569652794581721330948863485438876915508683244111694485850733278569559191167660149469895899348939039437830613284874764820878002628686548956779897196112828969255650312573935871059275664474562666268163936821302832645284397530568872432109324825205567091066297960733513602409443790146687029return hex(fastModular([str_to_num(password),power,modulus]))def join_game(user, myHexPass):"""加入游戏并返回一个 get回复包对象"""url = \'http://2**.207.12.156:9012/join_game/\'param = {\'user\' : user,\'password\': myHexPass,\'data_type\':\'json\'}getHtml = re.get(url, params = param)print(f"Open a new game{getHtml.text}")return getHtmldef check_game(game_id):url = \'http://2**.207.12.156:9012/check_game/\'+ str(game_id)getState = re.get(url)#print(getState.text)    # 测试显示数据用return getStatedef play_game(user, myHexPass, game_id, coord ):url = \'http://2**.207.12.156:9012/play_game/\' + str(game_id)param = {\'user\' : user,\'password\': myHexPass,\'data_type\':\'json\',\'coord\' : coord}re.get(url, params=param)def getIndexNum(coords):"""coords y x"""# 0行 [0]=\'.\'--- [14]=\'.\'[15]=\'\\n\'# 1行 [16]=\'.\'--- [30]=\'.\'[31]=\'\\n\'# 2行 [32]=\'.\'--- [46]=\'.\'[47]=\'\\n\'# 15行 [240]=\'.\'--- [254]=\'.\'[255]=\'\\n\'return (ord(coords[0]) - ord(\'a\'))*16 + ord(coords[1]) - ord(\'a\')def allIndexStr():spot = []for i in range(0,15):for j in range(0,16):spot.append(chr(i+97) + chr(j+97))return spotdef getLine(coord,board):"""获得中心点的四周点情况 返回一个字符串列表coord[0] y 纵坐标 coord[1] x 控制横坐标board  棋局"""line = [\'\', \'\' , \'\' , \'\']i =0""" 核心思想就是 将周围点两个坐标x,y的限制 转化为一个位置index的限制 """while(i != 9):if ord(coord[1])-ord(\'a\')- 4 + i in range(0, 15) :      # line[0]是横线 只需保证 横坐标在棋盘里就好line[0] +=board[(ord(coord[0])-ord(\'a\'))*16 + ord(coord[1])-ord(\'a\')- 4 + i]else:line[0] += \' \'if ord(coord[0])-ord(\'a\') -4 + i in range(0, 15) :      # line[2]是竖线 只需保证 纵坐标在棋盘里就好line[2] +=board[(ord(coord[0])-ord(\'a\')- 4 + i)*16 + ord(coord[1])-ord(\'a\')]else:line[2] += \' \'# - 4 + i 是从最小值上升判断  + 4 - i 是从最大值下降判断 两者没有什么不同 根据index的求法而定if ord(coord[1])-ord(\'a\')- 4 + i in range(0, 15) and ord(coord[0])-ord(\'a\') -4 + i in range(0, 15) :    # line[1]是\\线 保证 横纵坐标都在棋盘里就好line[1] +=board[(ord(coord[0])-ord(\'a\')- 4 + i)*16 + ord(coord[1])-ord(\'a\')- 4 + i]else:line[1] += \' \'if ord(coord[1])-ord(\'a\') + 4 - i in range(0, 15) and ord(coord[0])-ord(\'a\') -4 + i in range(0, 15) :   # line[3]是/线 保证 横纵坐标都在棋盘里就好line[3] +=board[(ord(coord[0])-ord(\'a\')- 4 + i)*16 + ord(coord[1])-ord(\'a\')+ 4 - i]else:line[3] += \' \'i += 1return linedef judge(testOrder):if (len(testOrder)//2) % 2 == 0:     # 我是黑方return \'MO\'else:                           # 我是白方return \'OM\'def RuleWithPoints():RWP = {("CMMMM","MCMMM","MMCMM","MMMCM","MMMMC") : 10000,("COOOO","OCOOO","OOCOO","OOOCO","OOOOC") : 6000,(".CMMM.",".MCMM.",".MMCM.",".MMMC.") : 5000,("COOO.",".OOOC",".OOCO.",".OCOO.") :2500,("OCMMM.","OMCMM.","OMMCM.","OMMMC.",".CMMMO",".MCMMO",".MMCMO",".MMMCO"):2000,(".MMC.",".MCM.",".CMM.") : 400,(".OOC","COO.","MOOOC","COOOM") : 400,(".MMCO",".MCMO",".CMMO","OMMC.","OMCM.","OCMM.","MOOC","COOM") : 200,(".MC.",".CM.") : 50,(\'.\') : 20}return RWPdef getMaxCoords(Order,RWP, indexSrc):"""对于每一个当下的棋局 返回一个最成功的下点"""board = \'\'              # 棋板for i in range(0,15):board += \'...............\' + \'\\n\'step = 0 # 步数 用于判断黑白 黑方先走BW = judge(Order)if len(order) == 0:     # 黑子走最中间 算法实现比较复杂return \'hh\'for i in range(0, len(Order), 2): # i = 0 2 4 6 8index = getIndexNum(Order[i:i+2])# Python不允许直接修改字符串 只能用拼接的方法if (step % 2) == 0:board = board[0: index] + BW[0] + board[index + 1:]else:board = board[0: index] + BW[1] + board[index + 1:]step += 1print(board) # 测试显示数据用maxCoord = \'\'maxPoints = 0for i in range(0,len(board)):if board[i] == \'.\':tempBoard = board[0: i] + \'C\' + board[i + 1:]coord = indexSrc[i]lines4 = \',\'.join(getLine(coord,tempBoard))points = 0for rules,value in RWP.items():for rul in range(0, len(rules)) :if rules[rul] in lines4:points += value * lines4.count(rules[rul])if points > maxPoints :maxPoints = pointsmaxCoord = coordprint(f"{maxCoord} {maxPoints}",end=\' \')return maxCoorduser = \'yyds\'password = \'xxxxxx\'myHexPass = encodeLogin(password)RWP = RuleWithPoints()indexSrc = allIndexStr()game_id = join_game(user, myHexPass ).json()["game_id"]state = check_game(game_id).json()print("Looking forgame partners ...")while state[\'ready\'] == "False":state = check_game(game_id).json()print(state[\'ready\'],end=" ")t.sleep(5)if state[\'creator\'] != user:opponent = state[\'creator\']else:opponent = state[\'opponent_name\']while state[\'ready\'] == "True":if state[\'current_turn\'] == user :order = state[\'board\']coord = getMaxCoords(order, RWP, indexSrc)play = play_game(user, myHexPass, game_id, coord)print(f"Playing {coord}")else:print(f"Waiting for {opponent} to play")t.sleep(5)state = check_game(game_id).json()if state[\'winner\'] != "None":print(f"The winner is {state[\'winner\']}")break

直接运行 即可开始一场对局

程序运行解释

首先开启一场对局,等待其他人加入。

如果有人加入则开始对局,每次对局轮到自己下棋时会出现当前的棋局。程序算出最佳点后返回给服务器。

等待对手下棋。

下一次轮到我们的时候,我们之前下了一颗,对手下了一颗,所以比上一盘多两颗棋子。

加油吧少年,根据这个博客你也可以写出一个相对智能的五子棋程序,甚至更强的AI算法!

文章会随时改动,注意到博客里去看。一些网站会爬取本文章,但是可能会有出入。https://www.cnblogs.com/asmurmur/

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » AI五子棋_09 消息循环实现自动对局