AI五子棋_08 五子棋落子规则对应的价值

AI五子棋 第八步

恭喜你到达第八步!

利用前一步得到的棋型分析结果,考察每一个可能落子的位置,给每一个可能的位置打分,将棋子落在分数最高的位置上。根据经验,我们可以总结出下面的落子规则:

1. 致胜棋型

若在某处落子后我方获胜,采取这一落子位置。

我们将空位子记作.,本方棋子记作M(me),对方棋子记作O(opponent),考察点记作C(current),能够致胜的棋型必然包含:

"CMMMM"
"MCMMM"
"MMCMM"
"MMMCM"
"MMMMC"

为了保证其优先级,我们给这条规则分配一个大的分数10000

2. 必须防守棋型

若我方棋子不落在某处,对方将出现致胜棋型,采取这一落子位置,不过优先级小于前者。

按照上面的记号,此时棋型应包含:

"OOOOC"
"COOOO"

我们给它分配一个较大的分数6000

3. 两步致胜棋型

若在某处落子后,出现致胜棋型,采取这一落子位置,不过优先级小于前者。

按照上面的记号,此时棋型应包含:

".CMMM."
".MCMM."
".MMCM."
".MMMC."

我们给它分配一个较大的分数5000

4. 两步防守棋型

若我方棋子不落在某处,对方将出现两步致胜棋型,采取这一落子位置,不过优先级小于前者。

"COOO."
".OOOC"
".OOCO."
".OCOO."

我们给它分配分数2500

5. 进攻棋型

若在某处落子后,出现一端被挡住的四个连续棋子,此时对方必需挡住另一端,采取这一落子位置,不过优先级小于前者。

按照上面的记号,此时棋型应包含:

"OCMMM."
"OMCMM."
"OMMCM."
"OMMMC."
".CMMMO"
".MCMMO"
".MMCMO"
".MMMCO"

我们给它分配分数2000

6. 两步进攻棋型

若在某处落子后,出现两端都不被挡住的三个连续棋子,此时对方必需挡住其中一端,采取这一落子位置,不过优先级小于前者。

".MMC."
".MCM."
".CMM."

我们给它分配分数400

7. 预防棋型

若我方棋子不落在某处,对方将出现两步进攻棋型或进攻棋型,采取这一落子位置。

".OOC"
"COO."
"MOOOC"
"COOOM"

我们给它分配分数400

8. 无效进攻防守棋型

若在某处落子后,出现一端被挡住的三个连续棋子,或者若我方棋子不落在某处,对方将出现一端被挡住的三个连续棋子,这一步进攻或者防守不会引起对方的立即反应。

".MMCO"
".MCMO"
".CMMO"
"OMMC."
"OMCM."
"OCMM."
"MOOC"
"COOM"

我们给它分配分数200

9. 布局棋型

若在某处落子后,出现两端都不被挡住的两个连续棋子。

".MC."
".CM."

我们给它分配分数50

  1. 其他棋型
    我们给它分配分数20

再次说明,我们的方法并不是最好,但请你先实现这种方法,之后再尝试你的想法。

我们将计算每一个当前还是空着的位置的得分。

按照第六步的方法获得棋盘,此时需要根据当前落子是黑方还是白方,将黑棋和白棋表示为MO

找到所有还空着的位置

对每一个空位子

a. 将这个位置设为C

b. 按照第七步的方法获得该位置的棋型字符串

c. 在所有的棋型字符串上按顺序寻找上述所有模式,每得到一个匹配,将对应的分数加上,最终所得即为该位置的分数

d. 将这个位置设为.

找出分数最大的位置,若分数最大的位置有多个,随意选择一个

任务 8

实现按照评分规则选择落子位置的算法,通过服务器的检验。

访问http://2**.207.12.156:9012/step_08服务器会给你几个棋局的坐标表示,保存到questions字段,以JSON数组表示。请给出分数最大的一个落子位置,写入到ans字段,按顺序给出坐标,坐标之间用逗号隔开。服务器不会告诉你,你是白棋还是黑棋,你需要根据规则自己确定

待处理信息

{"is_success": true, "questions": ["hhifhjigkhjghghiihjhkjjijjij", "hhigjhihjgiiifhgjijfkhkeli", "hhjhiijjkijijkjgjfkhijiflihegdlh", "hhkhlhihkgjimijfnjoklgjhjgigmgnglfli", "hhjhihjiijjjjgjkjliihigjkgigkflehf", "edfefdgdeeefhcdffccfffdddegbgcecicjchb", "gheifhiihhihhiijighg", "hhjhiijgghjjjkjijfkjig", "ggffhggfhffgiefhfeheidehdidhgheg", "hhjhiijgghjjjkjijfkjiggiijih", "hhjhiijgghjjjkjijfkjiggi", "ghhihhhggiggihfhigfjiiifjh", "hhggfhghifgigfgjgkhfhkhiijfgjikh", "hhihgihijgiiigjffjekgghggjghijhjgkiffijekdkfgl", "hhjhihjiijjjjgjkjlii", "hhjhihjiijjjjgjkjliihigjkgigkflehfhgifjf", "ghhihhhggiggihfhigfjiiifjhkhjgjfhfgekfijkg"]}

Python实现

import requests as re

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[0]='aa' spot[1]='ab' ...."""
        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):
        """ 服务器并没有给我们我们是 M 还是 O"""
        """ 根据棋局的命令序列判断"""
        if (len(testOrder)//2) % 2 == 0:     # 我是黑方
                return 'MO'
        else:                           # 我是白方
                return 'OM'
        
def RuleWithPoints():
        """ 返回一个 规则字典 对应规则和分值"""
        RWP = {
                ("CMMMM","MCMMM","MMCMM","MMMCM","MMMMC") : 10000,
                ("COOOO","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)

        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 coord in ['kh','ke']:
                                print(f"{coord} {points}")
                                print(lines4)
                        if points > maxPoints :
                                maxPoints = points
                                maxCoord = coord
                                 
        print(f"{maxCoord} {maxPoints}")
        return maxCoord

def getNextStep(url,answer):
        """提交答案 获取下一题链接"""
        param = {
                'ans' : answer[:-1]
                }

        getHtml = re.get(url, params=param)
        print(getHtml.text)



url = "http://2**.207.12.156:9012/step_08/"
getHtml = re.get(url)

stepOrders = getHtml.json()['questions']

RWP = RuleWithPoints()
indexSrc = allIndexStr()

#answer = 'ki,he,ih,le,hg,ia,eh,gi,ci,hi,ke,kh,gl,gm,hi,kh,hj,'

answer = ''
for order in stepOrders:
        answer += getMaxCoords(order, RWP, indexSrc) + ','
     
getNextStep(url, answer)

运行即可获得答案

解题tips

注意规则的匹配次数!

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

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

上一篇:AI五子棋_07 落子点四周棋形获取


下一篇:高光遮罩MaskTexture