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
- 其他棋型
我們給它分配分數20
再次說明,我們的方法並不是最好,但請你先實現這種方法,之后再嘗試你的想法。
我們將計算每一個當前還是空着的位置的得分。
按照第六步的方法獲得棋盤,此時需要根據當前落子是黑方還是白方,將黑棋和白棋表示為M
或O
找到所有還空着的位置
對每一個空位子
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/