Python实现黑白棋人机对弈

Python实现黑白棋人机对弈


简书:Python实现黑白棋人机对弈https://www.jianshu.com/p/37191dffbe07

  • 规则
    黑白棋的每颗棋子由黑白两色组成,一面白,一面黑。每次落子,把本方颜色的棋子放在棋盘的空格上,若在横、竖、斜八个方向的任一方向上有本方棋子,则被夹在中间的对手棋子全部翻转为本方棋子颜色;并且,仅在可以翻转棋子的地方才能落子。如果一方至少有一步合法棋步可下,他就必须落子,不得弃权。棋盘已满或双方都没有棋子可下时棋局结束,以棋子数目来计算胜负,棋子多的一方获胜。在棋盘还没有下满时,如果一方的棋子已经被对方吃光,则棋局也结束,将对手棋子吃光的一方获胜。
    两位玩家轮流下棋,直到一方没有符合规则的落子位置,在这种情况下,剩下的一方继续下棋,直到对手有了可以落子的位置。此时,恢复两者轮流下棋的顺序。如果一方落子在非法位置,则视为放弃本次对弈,对方获胜。游戏结束的条件: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)

Python实现黑白棋人机对弈_第1张图片
[1]: https://www.jianshu.com/p/37191dffbe07

你可能感兴趣的:(Python实现黑白棋人机对弈)