AI五子棋_09 消息循环实现自动对局
2021-08-26 23:13
1526 查看
第九步 恭喜你到达第九步!
上一步我们已经完成了一个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检查游戏状态
如果游戏完成就退出
如果不轮你下,就等一会,否则使用AI确定要落子的位置,并用
play_game
告知服务器你落子的位置返回到第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_step 上一步落子的坐标
win_step如果一方获胜,这个字段给出连成五子的一条线的棋子坐标
注意不要过于频繁的检查游戏的状态,使用sleep函数等待服务器更新状态,两次检查以5到10秒的间隔为宜。
任务 9
实现消息循环,开始作战吧!
Python实现
import requests as re import time as t def fastModular(x): """x[0] = base """ """x[1] = power""" """x[2] = modulus""" result = 1 while(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 result def str_to_num(strings): sum = 0 lens = len(strings) for i in range(0,lens): sum += ord(strings[i])*256**(lens-i-1) return sum def encodeLogin(password): # 公钥 power = 65537 modulus = 135261828916791946705313569652794581721330948863485438876915508683244111694485850733278569559191167660149469895899348939039437830613284874764820878002628686548956779897196112828969255650312573935871059275664474562666268163936821302832645284397530568872432109324825205567091066297960733513602409443790146687029 return 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 getHtml def check_game(game_id): url = 'http://2**.207.12.156:9012/check_game/'+ str(game_id) getState = re.get(url) #print(getState.text) # 测试显示数据用 return getState def 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 spot def 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 += 1 return line def 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 RWP def 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 8 index = 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 += 1 print(board) # 测试显示数据用 maxCoord = '' maxPoints = 0 for 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 = 0 for 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 = points maxCoord = coord print(f"{maxCoord} {maxPoints}",end=' ') return maxCoord user = '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/
相关文章推荐
- TMsgThread, TCommThread -- 在delphi线程中实现消息循环
- 循环实现自动售货机的学习笔记
- 深度揭秘android摄像头的autoFocus-----循环自动聚焦的实现(Android Camera AutoFocus on Demand)
- DS09-实现循环双链表
- 五子棋AI循序渐进【1】实现界面和位棋盘
- 自动消失的消息提示(Js+Div实现)
- android自定义Gallery实现手动和自动循环滚动切换图片
- Python_猜数字游戏_初次尝试(遗留问题:猜错后程序自动循环执行未实现)---加入循环搞定
- jQuery实现列表自动循环滚动鼠标悬停时停止滚动
- 深度揭秘android摄像头的autoFocus-----循环自动聚焦的实现(Android Camera AutoFocus on Demand)
- 基因组实现自动AI建模,华为云助力科研人员探索生命奥秘
- 未公开函数MessageBoxTimeOut 实现定时消息(ZT) MFC实现MessageBox自动消失
- QT中|Qt::Tool类型窗口自动退出消息循环问题解决
- Python实现微信自动回复和指定发送群聊消息
- 五子棋AI算法简易实现(六)
- android 实现类似qq未读消息点击循环显示
- JS实现div内部的文字或图片自动循环滚动
- UIScrollView自动滚动 循环滚动视图实现
- java实现AI五子棋
- JAVA实现 springMVC方式的微信接入、实现消息自动回复