Ejemplo n.º 1
0
        },
        'box_6_2': {
            'box_key': 'black_xiang1',
            'state': False
        },
        'box_6_3': {
            'box_key': 'red_pao2',
            'state': False
        },
        'box_7_0': {
            'box_key': 'red_ma1',
            'state': False
        },
        'box_7_1': {
            'box_key': 'red_ju1',
            'state': False
        },
        'box_7_2': {
            'box_key': 'black_pao2',
            'state': False
        },
        'box_7_3': {
            'box_key': 'red_ju2',
            'state': False
        }
    }
    move = MinMax.search_next_move(all_pieces, 'red', depth=1)
    logg.info(
        f"best_move:{move.box_name_from}===>>>{move.box_from}===>>>{move.box_action}===>>>{move.box_name_to}===>>>{move.box_to}===>>>{move.box_res}===>>>{move.score}"
    )
Ejemplo n.º 2
0
class SeachMove():
    def __init__(self, setting):
        self.setting = setting
        self.logg = LoggerPrint(self.setting).printLogToSystem(False)

    # 寻找AI的下一步走棋
    @clock
    def search_next_move(self, all_pieces, player1Color, depth=1):
        # 取得当前player2的所有走棋步骤内容
        all_moves = Moves(all_pieces, player1Color).generate_all_moves()
        #
        best_move = None
        # allmoves为空,表明要么无棋子可走(输了),要么打开的棋子上没有合适的棋子可走
        if len(all_moves) == 0:
            self.logg.info('当前的allmoves为None!!')
            # 获得双方剩余棋子的数量
            dp = DataPercent(all_pieces)
            red_count, black_count = dp.pieces_perc()
            # 根据剩余棋子数量判断是否为0
            if red_count == 0 or black_count == 0:
                self.logg.info(f"一方棋子数量为0,best_move为None!!")
            else:
                # 不为0还需判断是否有未打开棋子,如果当前还有棋子未打开,则打开循环到的第一个未打开的棋子
                box_to = None
                for key, value in all_pieces.items():
                    if value['state'] is False:
                        box_to = key
                        break
                # box_to不为空,将box_to传递给best_move
                if box_to is not None:
                    best_move = MoveNodes(None, box_to, '打开', None, box_to,
                                          None)
                    self.logg.info(f"打开循环到的第一个未打开的棋子best_move: {box_to}")
                # box_to为空,表示所有棋子都已打开而且没有合适棋子可走,玩家2自动认输
                else:
                    pass
        # allmoves不为空
        else:
            self.logg.info(f"当player1color为 [{player1Color}] 时, allmove的值:")
            for move in all_moves:
                # 基于当前的move计算下一步的走棋,并返回最高得分
                self.logg.info(
                    f"{move.box_name_from}===>>>{move.box_from}===>>>{move.box_action}===>>>{move.box_name_to}===>>>{move.box_to}===>>>{move.box_res}===>>>{move.score}"
                )
                move.score = self._seach_other_moves(all_pieces, player1Color,
                                                     depth, move)
                self.logg.info(f"最终的score:{move.score}")
                # 把得分最高的走棋给best_move
                if best_move is None or move.score >= best_move.score:
                    best_move = move
        return best_move

    # 为下一个玩家寻找行棋内容
    def _seach_other_moves(self, all_pieces, player1Color, depth, move):
        # 设置一个all_pieces的替身,好还原all_pieces的值
        all_pieces_1 = deepcopy(all_pieces)
        # 根据行棋状态修改all_pieces_1的值
        if move.box_action == '吃棋':
            if move.box_res == 'box1=box2':
                all_pieces_1[move.box_from]['box_key'] = None
                all_pieces_1[move.box_from]['state'] = None
                all_pieces_1[move.box_to]['box_key'] = None
                all_pieces_1[move.box_to]['state'] = None
            elif move.box_res == 'success':
                all_pieces_1[move.box_to]['box_key'] = all_pieces_1[
                    move.box_from]['box_key']
                all_pieces_1[move.box_to]['state'] = True
                all_pieces_1[move.box_from]['box_key'] = None
                all_pieces_1[move.box_from]['state'] = None
        elif move.box_action == '移动':
            all_pieces_1[move.box_to]['box_key'] = all_pieces_1[
                move.box_from]['box_key']
            all_pieces_1[move.box_to]['state'] = True
            all_pieces_1[move.box_from]['box_key'] = None
            all_pieces_1[move.box_from]['state'] = None
        elif move.box_action == '打开':
            # box_action == '打开' 时,不能给出打开这个棋子的信息,只能给出打开当前棋子的价值,同时将depth=0,给出得分
            depth = 0
        #
        if depth == 0:
            return move.score
        # depth不为0,更换player1Color的颜色方阵,反过来计算如果player1是player2的话,走棋都有哪些内容
        player1Color = 'black' if player1Color == 'red' else 'red'
        #
        score = 10
        moves = Moves(all_pieces_1, player1Color)
        all_moves = moves.generate_all_moves()
        self.logg.info(
            f"player2反置:当player1color为 [{player1Color}] 时, allmove的值:")
        for move_1 in all_moves:
            # 回调该函数自己,同时depth-1
            self.logg.info(
                f"player2反置:{move_1.box_name_from}===>>>{move_1.box_from}===>>>{move_1.box_action}===>>>"
                f"{move_1.box_name_to}===>>>{move_1.box_to}===>>>{move_1.box_res}===>>>{move_1.score}"
            )
            score = max(
                score,
                self._seach_other_moves(all_pieces_1, player1Color, depth - 1,
                                        move_1))
        if score >= 1000:
            score = 0
        move.score += score
        # 还原all_pieces的值,保证下一个循环用到的值还是原来的all_pieces
        all_pieces_1 = deepcopy(all_pieces)
        #
        return move.score
Ejemplo n.º 3
0
class GameFunction():
    """
    游戏逻辑的所有方法,不涉及到界面显示内容
    """
    def __init__(self, setting):
        self.setting = setting
        self.logger = LoggerPrint(self.setting).printLogToSystem()

    # 将红黑棋子对应的图片,关联起来,存放在字典中
    def _get_all_pieces(self, piece_flag):
        pieces = []
        for piece in self.setting.pieces_list:
            # value = f"{self.setting.pieces_front}{piece_flag}_{piece}{self.setting.pieces_noun}"
            if piece in ['shi', 'xiang', 'ma', 'ju', 'pao']:
                for i in range(1, 3):
                    pieces.append(f"{piece_flag}_{piece}{str(i)}")
            elif piece == 'zu':
                for i in range(1, 6):
                    pieces.append(f"{piece_flag}_{piece}{str(i)}")
            else:
                pieces.append(f"{piece_flag}_{piece}1")
        return pieces

    # 初始化棋子配置
    def box_pieces(self):
        # 获得所有的红黑棋子的dict
        pieces = self._get_all_pieces('red')
        pieces_black = self._get_all_pieces('black')
        pieces += pieces_black
        all_pieces = {}
        for i in range(8):
            for j in range(4):
                # 随机抽取key放入boxid中,并初始化box的状态为False
                random_key = random.choice(pieces)
                all_pieces[f"box_{i}_{j}"] = {
                    'box_key': random_key,
                    'state': False
                }
                pieces.remove(random_key)
        return all_pieces

    # 获取鼠标位置所对应的方格id
    def get_box_xy(self, event_x, event_y):
        # 确定鼠标的有效矩形位置
        min_area_x = self.setting.piece_first_x
        min_area_y = self.setting.piece_first_y
        max_area_x = min_area_x + 8 * self.setting.piece_size
        max_area_y = min_area_y + 4 * self.setting.piece_size
        # 确认鼠标是在棋盘上有效的矩形范围之内
        if (min_area_x < event_x < max_area_x) and (min_area_y < event_y <
                                                    max_area_y):
            mouse_x_not = (i * 100 + min_area_x for i in range(1, 9))
            mouse_y_not = (i * 100 + min_area_y for i in range(1, 5))
            # 鼠标不能在棋盘线上
            if (event_x not in mouse_x_not) and (event_y not in mouse_y_not):
                # 计算当前鼠标坐标所在的方格坐标
                box_x = int((event_x - min_area_x) / 100)
                box_y = int((event_y - min_area_y) / 100)
                return (box_x, box_y)

    # 获取棋子所在方格左上角的坐标
    def get_box_local_xy(self, box_x, box_y):
        box_local_x = box_x * self.setting.piece_size + self.setting.piece_first_x
        box_local_y = box_y * self.setting.piece_size + self.setting.piece_first_y

    # 加载棋子对应的图片
    def get_piece_image(self):
        pieces_dict = {}
        for piece_name in self.setting.pieces_list:
            pieces_dict[
                f"red_{piece_name}"] = f"{self.setting.pieces_front}red_{piece_name}{self.setting.pieces_noun}"
            pieces_dict[
                f"black_{piece_name}"] = f"{self.setting.pieces_front}black_{piece_name}{self.setting.pieces_noun}"
        return pieces_dict

    # 两个棋子之间的比较
    def piece_VS_piece(self, box1_xy, box2_xy, all_pieces):
        '''
        :param box1_xy:
        :param box2_xy:
        :param all_pieces:
        :return: [True|False|None, '原因', True|False]
                True|False|None:表示box1和box2的比较结果
                '原因':表示原因,便于提示失败的原因,也可指示成功的提示
                True|False:表示对于该原因,对后续AI走棋获取该走棋步骤时,是否为需要添加的走棋步骤
        '''
        value_list = self.setting.pieces_list
        box1_x = int(box1_xy.split('_')[1])
        box1_y = int(box1_xy.split('_')[2])
        box2_x = int(box2_xy.split('_')[1])
        box2_y = int(box2_xy.split('_')[2])
        box1_name = all_pieces[box1_xy]['box_key']
        box2_name = all_pieces[box2_xy]['box_key']
        box1_color = box1_name.split('_')[0]
        box1_value = box1_name.split('_')[1]
        box1_value = box1_value[:-1]
        box1_value_index = value_list.index(box1_value)
        # 如果box1的位置比box2的位置大,则交换他们的值
        if box1_y > box2_y:
            box1_y, box2_y = box2_y, box1_y
        if box1_x > box2_x:
            box1_x, box2_x = box2_x, box1_x
        # box2如果为空,则认为第二次选择了棋盘空格,不为空则需要取box2的值与box1比较
        if box2_name is not None:
            box2_color = box2_name.split('_')[0]
            if box2_color == box1_color:
                # self.logger.info("false原因:两个棋子在同一个方阵")
                return [False, 'color', False]
            box2_value = box2_name.split('_')[1]
            box2_value = box2_value[:-1]
            box2_value_index = value_list.index(box2_value)
        else:
            return self._other_vs_piece(box1_x,
                                        box1_y,
                                        box2_x,
                                        box2_y,
                                        piece_equal=False)
        # 如果两个棋子相同
        if box1_value_index == box2_value_index:
            if box1_value == 'pao':
                # '炮'相同时的吃法:
                # 中间有且只有一个棋子,中间棋子不论打没打开都可以,没有距离限制
                return self._pao_vs_piece(box1_x,
                                          box1_y,
                                          box2_x,
                                          box2_y,
                                          all_pieces,
                                          piece_equal=False)
            else:
                # 其他相同棋子的吃法:
                # 只能相邻位置两个棋子,最后也是两个棋子同时失去
                return self._other_vs_piece(box1_x,
                                            box1_y,
                                            box2_x,
                                            box2_y,
                                            piece_equal=True)
        # 如果两个棋子不相同
        else:
            if box1_value == 'pao':
                # '炮'的吃法:
                # 1、中间必须有且只有一个棋子,才能吃到对方棋子,没有距离限制;
                # 2、炮没有大小吃法限制,上到将,下到卒都可以吃;
                # 3、炮移动只能相邻的格子移动,不能跳着移动;
                return self._pao_vs_piece(box1_x,
                                          box1_y,
                                          box2_x,
                                          box2_y,
                                          all_pieces,
                                          piece_equal=False)
            else:
                # 其他的棋子的吃法:
                # 1、大吃小(将(帅)>士>(象)相>马>车>炮和卒(兵)),两两相同则一起吃掉;
                # 2、炮和卒(兵)、炮和将(帅)相互不能吃,任何棋子都可以吃炮,除了卒(兵)、将(帅)外;
                # 3、任何棋子都可以吃卒(兵),而卒(兵)只吃对方的帅(将);
                # 4、棋子只能相邻的吃,而且一次只能走一步,吃一个棋子,炮除外
                if box1_value_index < box2_value_index:
                    # 大吃小,除非jiang和zu或pao同时出现
                    if box1_value == 'jiang' and box2_value == 'zu':
                        # self.logger.info("false原因:jiang在和zu比较")
                        return [False, 'jiang_zu', True]
                    elif box1_value == 'jiang' and box2_value == 'pao':
                        # self.logger.info("false原因:jiang在和pao比较")
                        return [False, 'jiang_pao', False]
                    else:
                        return self._other_vs_piece(box1_x,
                                                    box1_y,
                                                    box2_x,
                                                    box2_y,
                                                    piece_equal=False)
                elif box1_value_index > box2_value_index:
                    # 最后一种情况:zu只能吃jiang
                    if box1_value == 'zu' and box2_value == 'jiang':
                        return self._other_vs_piece(box1_x,
                                                    box1_y,
                                                    box2_x,
                                                    box2_y,
                                                    piece_equal=False)
                    elif box1_value == 'zu' and box2_value == 'pao':
                        # self.logger.info("false原因:zu在和pao比较")
                        return [False, 'zu_pao', False]
                    else:
                        # self.logger.info("false原因:box1比box2还小")
                        return [False, 'box1<box2', True]

    # pao的比较
    def _pao_vs_piece(self,
                      box1_x,
                      box1_y,
                      box2_x,
                      box2_y,
                      all_pieces,
                      piece_equal=True):
        if box1_x == box2_x and box2_y - box1_y > 1:
            between_state_have = 0
            for i in range(box1_y + 1, box2_y):
                if all_pieces[f"box_{box1_x}_{i}"]['state'] is not None:
                    between_state_have += 1
                if between_state_have > 1:
                    break
            if between_state_have == 1:
                if piece_equal is True:
                    # self.logger.info("None:box1和box2相同,都是pao")
                    return [None, 'box1=box2', True]
                else:
                    return [True, 'success', True]
            else:
                # self.logger.info("false原因:box1和box2之间,在y轴上没有棋子,或者有大于2个的棋子")
                return [False, 'pao_between', False]
        elif box1_y == box2_y and box2_x - box1_x > 1:
            between_state_have = 0
            for i in range(box1_x + 1, box2_x):
                if all_pieces[f"box_{i}_{box1_y}"]['state'] is not None:
                    between_state_have += 1
                if between_state_have > 1:
                    break
            if between_state_have == 1:
                if piece_equal is True:
                    # self.logger.info("None:box1和box2相同,都是pao")
                    return [None, 'box1=box2', True]
                else:
                    return [True, 'success', True]
            else:
                # self.logger.info("false原因:box1和box2之间,在x轴上没有棋子,或者有大于2个的棋子")
                return [False, 'pao_between', False]
        else:
            # self.logger.info("false原因:box1和box2不在同一条x轴或y轴上")
            return [False, 'box1_noline_box2', False]

    # 其他棋子的比较
    def _other_vs_piece(self,
                        box1_x,
                        box1_y,
                        box2_x,
                        box2_y,
                        piece_equal=True):
        if (box1_x == box2_x
                and box2_y - box1_y == 1) or (box1_y == box2_y
                                              and box2_x - box1_x == 1):
            if piece_equal is True:
                # self.logger.info("None:box1和box2相同")
                return [None, 'box1=box2', True]
            else:
                return [True, 'success', True]
        else:
            # self.logger.info("false原因:box1和box2不在同一条x轴或y轴上")
            return [False, 'box1_noline_box2', False]

    # 游戏结束判断
    def is_game_over(self, all_pieces, nowPlayer, player1Color):
        # 循环all_pieces中的state得到棋子状态
        true_count = 0
        none_count = 0
        new_pieces = {}
        for key, value in all_pieces.items():
            for key1, value1 in value.items():
                if key1 == 'state':
                    if value1 is True:
                        true_count += 1
                        new_pieces[all_pieces[key]['box_key']] = key
                    elif value1 is False:
                        # 如果查到state的状态为false,立即return
                        return 'none'
                    elif value1 is None:
                        none_count += 1
        self.logger.info(f"true_count: {true_count}")
        self.logger.info(f"none_count: {none_count}")
        self.logger.info(f"new_pieces: {new_pieces}")
        # 如果allpieces全部为none,则为平局
        if none_count == 32:
            return 'tie'
        else:
            # 只有一个棋子,则取棋子的颜色return
            if true_count == 1:
                key_list = list(new_pieces.keys())
                box_color = key_list[0].split('_')[0]
                return box_color
            # 有多个棋子,则要分开判断
            else:
                # 取红黑棋子分别占有多少
                value_list = self.setting.pieces_list
                red_count, black_count = 0, 0
                box_count = len(new_pieces)
                for key, value in new_pieces.items():
                    box_color = key.split('_')[0]
                    if box_color == 'red':
                        red_count += 1
                    else:
                        black_count += 1
                self.logger.info(f"red_count: {red_count}")
                self.logger.info(f"black_count: {black_count}")
                self.logger.info(f"box_count: {box_count}")
                # 如果全部为红色或者黑色,则return
                if red_count == box_count:
                    return 'red'
                elif black_count == box_count:
                    return 'black'
                # 总数为2,红黑棋子各占1个
                elif box_count == 2 and red_count == 1:
                    red_x = 0
                    red_y = 0
                    red_value = ''
                    black_x = 0
                    black_y = 0
                    black_value = ''
                    for key, value in new_pieces.items():
                        box_color = key.split('_')[0]
                        box_value = key.split('_')[1]
                        if box_color == 'red':
                            red_x = int(value.split('_')[1])
                            red_y = int(value.split('_')[2])
                            red_value = box_value[:-1]
                        else:
                            black_x = int(value.split('_')[1])
                            black_y = int(value.split('_')[2])
                            black_value = box_value[:-1]
                    red_value_index = value_list.index(red_value)
                    black_value_index = value_list.index(black_value)
                    # 如果红黑双方棋子相同或者是不能相互吃掉的棋子,则为平局
                    if red_value == black_value or \
                            (red_value in ['jiang', 'pao'] and black_value  in ['jiang', 'pao']) or \
                            (red_value in ['pao', 'zu'] and black_value in ['pao', 'zu']):
                        return 'tie'
                    # 当前玩家和玩家方阵为红方,且红方的棋子比黑方的棋子大,则他们相邻比较的时候就会是平局,红方无法吃掉黑方
                    if (nowPlayer == self.setting.player1_name and player1Color == 'red') or \
                            (nowPlayer == self.setting.player2_name and player1Color == 'black'):
                        if red_value_index > black_value_index:
                            if (red_x == black_x and fabs(red_y - black_y)
                                    == 1) or (red_y == black_y
                                              and fabs(red_x - black_x) == 1):
                                return 'tie'
                    # 黑方也是一样
                    elif (nowPlayer == self.setting.player1_name and player1Color == 'black') or \
                            (nowPlayer == self.setting.player2_name and player1Color == 'red'):
                        if red_value_index < black_value_index:
                            if (red_x == black_x and fabs(red_y - black_y)
                                    == 1) or (red_y == black_y
                                              and fabs(red_x - black_x) == 1):
                                return 'tie'
                # 总数>2,只判断一方只为1个的情况
                elif box_count > 2:
                    # 红方只有一个棋子,如果这个棋子在棋盘上黑方有其他棋子能吃掉它,则红方就一定会输
                    # 相反如果红方的这个棋子在棋盘上黑方没有棋子能吃掉它,那么就只能是平局了
                    if red_count == 1:
                        return self._one_vs_more(new_pieces, 'red', value_list)
                    elif black_count == 1:
                        return self._one_vs_more(new_pieces, 'black',
                                                 value_list)
                    else:
                        return 'none'
        # return 'none'

    # 判断某一方只有一个棋子时
    def _one_vs_more(self, new_pieces, one_color, value_list):
        index_list = []
        for key, value in new_pieces.items():
            box_color = key.split('_')[0]
            box_value = key.split('_')[1]
            if box_color == one_color:
                one_value = box_value[:-1]
                one_index = value_list.index(one_value)
            else:
                more_value = box_value[:-1]
                index_list.append(value_list.index(more_value))
        # 红方只有一个pao,黑方也只有pao和zu,则为平局
        if one_index == 5 and [0, 1, 2, 3, 4
                               ] not in index_list and len(index_list) < 4:
            return 'tie'
        count = 0
        for index in index_list:
            if one_index < index:
                # 要排除jiang和zu同时存在的情况
                if one_index == 0 and index == 6:
                    return 'none'
                count += 1
            else:
                return 'none'
        # 如果对方所有的棋子都比这一个棋子小,则为平局
        if count == len(index_list):
            return 'tie'