Python實(shí)現(xiàn)黑白棋人機(jī)對(duì)弈
-
規(guī)則
黑白棋的每顆棋子由黑白兩色組成待错,一面白褐澎,一面黑会钝。每次落子,把本方顏色的棋子放在棋盤(pán)的空格上工三,若在橫迁酸、豎、斜八個(gè)方向的任一方向上有本方棋子俭正,則被夾在中間的對(duì)手棋子全部翻轉(zhuǎn)為本方棋子顏色奸鬓;并且,僅在可以翻轉(zhuǎn)棋子的地方才能落子掸读。如果一方至少有一步合法棋步可下全蝶,他就必須落子,不得棄權(quán)寺枉。棋盤(pán)已滿(mǎn)或雙方都沒(méi)有棋子可下時(shí)棋局結(jié)束抑淫,以棋子數(shù)目來(lái)計(jì)算勝負(fù),棋子多的一方獲勝姥闪。在棋盤(pán)還沒(méi)有下滿(mǎn)時(shí)始苇,如果一方的棋子已經(jīng)被對(duì)方吃光,則棋局也結(jié)束筐喳,將對(duì)手棋子吃光的一方獲勝催式。
兩位玩家輪流下棋,直到一方?jīng)]有符合規(guī)則的落子位置避归,在這種情況下荣月,剩下的一方繼續(xù)下棋,直到對(duì)手有了可以落子的位置梳毙。此時(shí)哺窄,恢復(fù)兩者輪流下棋的順序。如果一方落子在非法位置,則視為放棄本次對(duì)弈萌业,對(duì)方獲勝坷襟。游戲結(jié)束的條件:1)整個(gè)棋盤(pán)滿(mǎn)了;2)一方的棋子已經(jīng)被對(duì)方吃光生年;3)兩名玩家都沒(méi)有可以落子的棋盤(pán)格婴程;4)一方落子在非法位置。前3 種情況以棋子數(shù)目來(lái)計(jì)算勝負(fù)抱婉,棋子多的一方獲勝档叔;第4 種情況判定對(duì)方獲勝。
-
計(jì)算機(jī)選擇落子位置的策略
選擇落子位置的策略 選擇落子位置的策略對(duì)每個(gè)可能 的落子 位置,計(jì)算 該位置的 該位置的 “分值 ”(可以翻轉(zhuǎn)的對(duì)手棋子數(shù)量 可以翻轉(zhuǎn)的對(duì)手棋子數(shù)量 可以翻轉(zhuǎn)的對(duì)手棋子數(shù)量.同分?jǐn)?shù)選擇行數(shù)小的蒸绩。
-
實(shí)現(xiàn)思路
黑白棋玩家的子的坐標(biāo)放在集合中衙四,改變集合元素實(shí)現(xiàn)下棋。根據(jù)集合中元素打印棋盤(pán)侵贵。
-
亟待完善的地方
- 機(jī)器下棋策略可以改善届搁,設(shè)計(jì)遞推方法
- 不同的持棋方式寫(xiě)了重復(fù)的代碼缘薛,可以進(jìn)一步包裝
- 無(wú)效代碼可以刪除窍育,如cont,
- 命名
import time
import csv
class HeiBaiPlayer(object):
status = True # 是否有位置可以下
defeat = False # 是否贏了
R_LIST = [(i, j) for i in range(-1, 2) for j in range(-1, 2)]
R_LIST.remove((0, 0))
count = 0
def __init__(self, dim, players, _color): # _color只能是hei or bai 宴胧,players只能是com or peop
self.hei = {(dim//2+1, dim//2), (dim//2, dim//2+1)}
self.players = players
self.bai = {(dim//2, dim//2), (dim//2+1, dim//2+1)}
self.dim = dim
self._color = _color # dic
def qp_print(self):
'''
根據(jù)場(chǎng)中的hei和bai打印棋盤(pán)
:return:
'''
for i in range(self.dim + 1):
if i == 0:
print(" ", end='')
print(''.join([str(chr(97 + x)) for x in range(self.dim)]))
else:
for j in range(self.dim + 1):
if j == 0:
print(chr(96 + i), end='')
else:
if (i, j) in self.hei:
print('X', end='')
elif (i, j) in self.bai:
print('O', end='')
else:
# print((i,j))
print('.', end='')
print()
def legal_position(self,players):
'''
:param players:bai或者h(yuǎn)ei的集合
:return: 字典 {bai玩家或者h(yuǎn)ei玩家可以落子位置:反轉(zhuǎn)對(duì)手子的位置}
'''
if players == self.hei:
_players = self.bai
else:
_players = self.hei
kong = [(i, j) for i in range(1, self.dim + 1) for j in range(1, self.dim + 1)]
kong = set(kong) - self.hei - self.bai
# print(kong)
p_players_list_in = {} # 如果落在p漱抓,會(huì)有的夾在中間的反色子集合
for p in kong:
all_r_players_list_in = [] # 所有方向的反色夾在中間子的集合
for r in self.R_LIST:
_players_list_in = [] # 某一方向夾在中間反色子的集合
i = 1
lst = []
while 1:
if (p[0] + i * r[0], p[1] + i * r[1]) in _players:
lst.append(tuple([p[0] + i * r[0], p[1] + i * r[1]]))
i += 1
if (p[0] + i * r[0], p[1] + i * r[1]) in players:
_players_list_in += lst
break
if i > self.dim + 1:
break
else:
break
if _players_list_in: # 如果這個(gè)方向有jiazai中間的反色子
all_r_players_list_in += _players_list_in
if all_r_players_list_in: # 如果落在p,會(huì)夾在中間的反色子集合【】
p_players_list_in[p] = all_r_players_list_in
# print(p_players_list_in,'這是測(cè)試')
return p_players_list_in
def callback(self):
'''
根據(jù)對(duì)象不同選擇不同的下棋方式
:return: 機(jī)器下棋還是人工下棋
'''
if self.players == 'com':
return self.computer_xia
if self.players == 'peop':
return self.players_xia
def color(self):
if self._color == 'hei':
return self.hei
return self.bai
def hefa(self,players, p):
'''
測(cè)試某一位置是否合法恕齐,如果合法乞娄,返回相應(yīng)反轉(zhuǎn)的子的位置,不合法返回False
:param p: 位置元組
:return:列表
'''
if p in self.legal_position(players).keys():
return self.legal_position(players)[p]
return False
def defen(self, players, p):
'''
某一位置的得分
:param players:set
:param p:(,)
:return:
'''
return len(self.hefa(players, p))
def computer_xia(self,players): # 要么是黑显歧,要么是白仪或,players類(lèi)型是集合
if not self.legal_position(players).keys():
print('com no Invalid move\n========')
self.status = False
else:
self.status = True
p_score = {}
for p in self.legal_position(players).keys():
p_score[p] = self.defen(players, p)
score = max(p_score.values())
for p in [(i, j) for i in range(1, self.dim + 1) for j in range(1, self.dim + 1)]:
if self.hefa(players, p):
if p_score[p] == score:
return {p: self.legal_position(players)[p]}
def players_xia(self, players): # 要么是黑,要么是白士骤,players類(lèi)型是集合
'''
人工下棋范删,先判斷有無(wú)位置可以下,在讓用戶(hù)選擇落子位置拷肌,如果位置出錯(cuò) self.defeat = True
:param players: 人player擁有子位置的集合
:return: {落子位置:反轉(zhuǎn)對(duì)面位置}
'''
if not self.legal_position(players).keys():
print('poeple no Invalid move\n========')
self.status = False
else:
self.status = True
try:
s = input("你的落子位置(例如ab:a行b列):?")
posintion = tuple([ord(s[0]) - 96, ord(s[1]) - 96])
if posintion in self.legal_position(players).keys():
return {posintion:self.legal_position(players=players)[posintion]}
else:
self.defeat = True
except Exception as e:
print('Sth Wrong, Try again',e)
s = input("你的落子位置:?")
posintion = tuple([ord(s[0]) - 96, ord(s[1]) - 96])
if posintion in self.legal_position(players).keys():
return {posintion: self.legal_position(players=players)[posintion]}
else:
self.defeat = True
def change(self, dic):
'''
下棋之后改變hei和bai中的元素
:param dic: {落子位置:反轉(zhuǎn)對(duì)面位置}
:return: 新的hei和bai集合
'''
if self._color == 'hei':
self.hei = self.hei | set(list(dic.keys())) | set(list(dic.values())[0])
self.bai = self.bai - set(list(dic.values())[0])
else:
self.bai = self.bai | set(list(dic.keys())) | set(list(dic.values())[0])
self.hei = self.hei - set(list(dic.values())[0])
def com_turn():
'''
電腦下棋
:return:
'''
com.bai = peop.bai
com.hei = peop.hei
color_set = com.color() # 顏色集合
HeiBaiPlayer_function = com.callback() # 下棋方法傳入集合
dic = HeiBaiPlayer_function(color_set) # 得到下棋位置和反轉(zhuǎn)位置
if not com.status:
peop.qp_print()
else:
if peop.status == False:
peop.status = True
com.count = 0
print('==' * 5)
print('機(jī)器下棋位置:反轉(zhuǎn)對(duì)方位置', dic)
com.change(dic)
# print(com.hei, com.bai)
com.qp_print()
if not peop.status:
peop.status = True
def peop_turn():
'''
人下棋
:return:
'''
peop.bai = com.bai
peop.hei = com.hei
color_set = peop.color()
HeiBaiPlayer_function = peop.callback() # 下棋的函數(shù)
dic = HeiBaiPlayer_function(color_set)
if not peop.status:
peop.qp_print()
elif not peop.defeat:
if com.status == False:
com.status = True
peop.count = 0
print('=='*5)
# print('人的下棋位置:反轉(zhuǎn)對(duì)方位置', dic)
peop.change(dic)
# print('黑,白', peop.hei, peop.bai)
peop.qp_print()
else:
peop.qp_print()
peop.defeat = True
# print("人輸了")
t1 = time.time()
begin_time = time.strftime('%Y%m%d %H:%M:%S')
Dimension = eval(input('Dimension:')) # 用戶(hù)輸入開(kāi)始
OX = input('Computer plays (X/O):')
if OX == 'O':
com = HeiBaiPlayer(dim=Dimension, players='com', _color='bai')
peop = HeiBaiPlayer(dim=Dimension, players='peop', _color='hei')
hei_player = 'computer'
if OX == 'X':
com = HeiBaiPlayer(dim=Dimension, players='com', _color='hei')
peop = HeiBaiPlayer(dim=Dimension, players='peop', _color='bai')
hei_player = 'players'
if com._color == 'hei':
count = 0
peop.qp_print()
while 1:
com_turn()
if peop.status == False and com.status == False:
print("Both players have no valid move.")
print("Game Over")
print('com:{}**peop:{}'.format(com.color(), peop.color()))
if len(com.color()) > len(peop.color()):
print('com win!!')
elif len(com.color()) < len(peop.color()):
print('players win!!')
else:
print('0比0')
score = str(len(com.color())) +':'+ str(len(peop.color()))
break
peop_turn()
if peop.defeat:
print('Invalid move.\nGame over.')
print('com win')
score = 'Human give up'
break
if peop.status == False and com.status == False:
print("Both players have no valid move.")
print("Game Over")
print('com:{}**peop:{}'.format(com.color(), peop.color()))
if len(com.color()) > len(peop.color()):
print('com win!!')
elif len(com.color()) < len(peop.color()):
print('players win!!')
else:
print('0比0')
score = str(len(com.color())) +':'+ str(len(peop.color()))
break
peop.qp_print()
if peop._color == 'hei':
count = 0
peop.qp_print()
while 1:
peop_turn()
if peop.defeat:
print('Invalid move.\nGame over.')
print('com win')
score = 'Human give up'
break
if peop.status == False and com.status == False:
print("Both players have no valid move.")
print("Game Over")
print('com:{}**peop:{}'.format(com.color(), peop.color()))
if len(com.color()) > len(peop.color()):
print('com win!!')
elif len(com.color()) < len(peop.color()):
print('players win!!')
else:
print('0比0')
score = str(len(peop.color())) +':'+ str(len(com.color()))
break
com_turn()
if peop.status == False and com.status == False:
print("Both players have no valid move.")
print("Game Over")
print('com:{}**peop:{}'.format(com.color(), peop.color()))
if len(com.color()) > len(peop.color()):
print('com win!!')
elif len(com.color()) < len(peop.color()):
print('players win!!')
else:
print('0比0')
score = str(len(peop.color())) +':'+ str(len(com.color()))
break
peop.qp_print()
t2 = time.time()
time_sep = int(t2 - t1)
if hei_player == 'computer':
bai_player = 'players'
else:
bai_player = 'computer'
def save_info(begin_time, time_sep, dim, hei_player, bai_player, score):
with open('reversi.csv', 'a', newline='') as f:
writer = csv.writer(f)
writer.writerow([begin_time, time_sep, str(dim)+'*'+str(dim), hei_player, bai_player, score])
save_info(begin_time, time_sep, Dimension, hei_player, bai_player, score)