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**.2**.**.1**: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 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**.2**.**.1**: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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM