Python实现黑白棋人机对弈

Python实现黑白棋人机对弈

  • 规则

黑白棋的每颗棋子由黑白两色组成,一面白,一面黑。每次落子,把本方颜色的棋子放在棋盘的空格上,若在横、竖、斜八个方向的任一方向上有本方棋子,则被夹在中间的对手棋子全部翻转为本方棋子颜色;并且,仅在可以翻转棋子的地方才能落子。如果一方至少有一步合法棋步可下,他就必须落子,不得弃权。棋盘已满或双方都没有棋子可下时棋局结束,以棋子数目来计算胜负,棋子多的一方获胜。在棋盘还没有下满时,如果一方的棋子已经被对方吃光,则棋局也结束,将对手棋子吃光的一方获胜。

两位玩家轮流下棋,直到一方没有符合规则的落子位置,在这种情况下,剩下的一方继续下棋,直到对手有了可以落子的位置。此时,恢复两者轮流下棋的顺序。如果一方落子在非法位置,则视为放弃本次对弈,对方获胜。游戏结束的条件:1)整个棋盘满了;2)一方的棋子已经被对方吃光;3)两名玩家都没有可以落子的棋盘格;4)一方落子在非法位置。前3 种情况以棋子数目来计算胜负,棋子多的一方获胜;第4 种情况判定对方获胜。

  • 计算机选择落子位置的策略

选择落子位置的策略 选择落子位置的策略对每个可能 的落子 位置,计算 该位置的 该位置的 “分值 ”(可以翻转的对手棋子数量 可以翻转的对手棋子数量 可以翻转的对手棋子数量.同分数选择行数小的。

  • 实现思路

黑白棋玩家的子的坐标放在集合中,改变集合元素实现下棋。根据集合中元素打印棋盘。

  • 亟待完善的地方

  • 机器下棋策略可以改善,设计递推方法
  • 不同的持棋方式写了重复的代码,可以进一步包装
  • 无效代码可以删除,如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):

        '''

        根据场中的hei和bai打印棋盘

        :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或者hei的集合

        :return: 字典 {bai玩家或者hei玩家可以落子位置:反转对手子的位置}

        '''

        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,会有的夹在中间的反色子集合

        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:  # 如果这个方向有jiazai中间的反色子

                    all_r_players_list_in += _players_list_in

            if all_r_players_list_in:  # 如果落在p,会夹在中间的反色子集合【】

                p_players_list_in[p] = all_r_players_list_in

        # print(p_players_list_in,'这是测试')

        return p_players_list_in

    def callback(self):

        '''

        根据对象不同选择不同的下棋方式

        :return: 机器下棋还是人工下棋

        '''

        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):

        '''

        测试某一位置是否合法,如果合法,返回相应反转的子的位置,不合法返回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类型是集合

        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类型是集合

        '''

        人工下棋,先判断有无位置可以下,在让用户选择落子位置,如果位置出错 self.defeat = True

        :param players: 人player拥有子位置的集合

        :return: {落子位置:反转对面位置}

        '''

        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: {落子位置:反转对面位置}

        :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)  # 得到下棋位置和反转位置

    if not com.status:

        peop.qp_print()

    else:

        if peop.status == False:

            peop.status = True

        com.count = 0

        print('==' * 5)

        print('机器下棋位置:反转对方位置', 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()  # 下棋的函数

    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('人的下棋位置:反转对方位置', 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:'))  # 用户输入开始

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)

1544455193(1).jpg
1544455180(1).jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容

  • 磨剑记(8) 8,飘海 袅袅要真武在她生日正日去她家。真武对她有一种说不出的喜爱,高高纤细的身段,如花的面容,天真...
    火若一筆阅读 217评论 0 0
  • 转眼间,牛雪莉的年龄已进入了而立之年,皮气、个性、思想都有了质的变化。确切的说,处事为人,看问题比以前大有长...
    闫忠录阅读 563评论 0 1
  • 在我们成长的过程中,一直被教育,不能辜负别人的期望。 不辜负父母、不辜负朋友、不辜负老师、不辜负另一半。甚至不去在...
    耳边漫时光阅读 1,290评论 0 0
  • 1. “小苏老师。 还是习惯这样称呼你,当年大家都这样叫你,用以区分你和另一个苏老师。 你还好吗? 我回了学校,即...
    许清和阅读 1,578评论 10 20
  • 一、string字符串 1.常用功能 1.1获取长度和次数 代码演示:#1.计算字符串长度 len#类似于lis...
    hollow_02f9阅读 574评论 0 1