腾讯欢乐斗地主辅助程序V1.0,PYTHON实现

来源:互联网 发布:mssql2005数据库 编辑:程序博客网 时间:2024/04/29 01:22

闲来无事写了这个玩意.深感PYTHON好用.蛋疼的是,实践效果和想象的有些差距.因为每手牌都要敲一次命令.加上还要分析,时间比较紧.

目测只有那种紧张刺激的炸弹局才有必要如此蛋疼地用吧.

# ===斗地主出牌记录及查询程序V1.0===# 作者:项楠(280145668@qq.com)# 版权所有,翻录不得究:-)# =====记录命令=====# 1表示下家,0表示上家,i表示本人(i可省略).例如:133表示下家出对3,i4447或4447表示本人出三带一.# 各种出牌的表示规则:# 单:d(大王),x(小王),2,a,k,Q,8,7,6,s(10),S(10)# 对:kk,99# 王炸:DX,dx,xd,# 三个:222,999# 炸弹:9999,3333,# 四带二:999945,333344,# 四带两对:99994455,33334477,# =====以下类型支持简写形式=====# 三带一:4449,49,3336,36, 重复数必须写在最前面# 三带一对:44499,499,33366,366# 飞机:66677789,6789,6667778899,6789-, "-"表示带对# 顺子:76543,3-7,7-3,AKQJS98,A-8,8-A, 可用"-"替代中间的数字# 连对:776655,7--5,5--7,AAKKQQJJSS,a--s,S--a, 可用"--"替代中间的数字# =====其他命令(均以"="开头)=====# 显示当前所有牌的剩余数量表:=# 显示某牌X的剩余数量(包括本人):=X# 显示上家(屏幕左方玩家)出牌历史:=0# 显示下家(屏幕下方玩家)出牌历史:=1# 显示本人出牌历史:=i# 撤销上次的出牌记录:==# =====完整对应表=====# D  ->  大王# X  ->  小王# 2  ->  2# A  ->  A# K  ->  K# Q  ->  Q# J  ->  J# S  ->  10# 9  ->  9# 8  ->  8# 7  ->  7# 6  ->  6# 5  ->  5# 4  ->  4# 3  ->  3import reimport datetimeQUERY = '='LEFT_PLAYER = '0'RIGHT_PLAYER = '1'MYSELF = 'i'PLAYER_DICT = {LEFT_PLAYER: '上家', RIGHT_PLAYER: '下家', MYSELF: '本人', }PLAYER = ''.join(PLAYER_DICT)JOKERS = 'DX'  # 大小王SPECIAL = '2'SEQUENCE = 'AKQJS9876543'  # 顺子,连对,飞机3位重复数ALL = JOKERS + SPECIAL + SEQUENCE  # 所有数字BOMB = SPECIAL + SEQUENCE  # 炸弹,对子,三REG_DICT = {'jk1': JOKERS[0], 'jk2': JOKERS[1],            'sq': SEQUENCE, 'al': ALL, 'bb': BOMB, }CARD_DICT = {}for i, k in enumerate(ALL):    if i < 2:        CARD_DICT[k] = 1  # 大小王各一张    else:        CARD_DICT[k] = 4  # 其他四张_RAW_REGEX = (    #(正则表达式,出牌类型)    (r'^[%(al)s]$' % REG_DICT, '单'),    (r'^([%(bb)s])\1$' % REG_DICT, '对'),    (r'^%(jk1)s%(jk2)s$|^%(jk2)s%(jk1)s$' % REG_DICT, '王炸'),    (r'^([%(bb)s])\1\1$' % REG_DICT, '三个'),    (r'^([%(bb)s])\1\1\1$' % REG_DICT, '炸弹'),    (r'^([%(bb)s])\1\1\1[%(al)s]{2}$' % REG_DICT, '四带二'),    (r'^([%(bb)s])\1\1\1([%(al)s])\2([%(al)s])\3$' % REG_DICT, '四带两对'),    (r'^([%(bb)s])\1\1[%(al)s]$' % REG_DICT, '三带一'),    (r'^([%(bb)s])\1\1([%(al)s])\2$' % REG_DICT, '三带一对'),    (r'^([%(sq)s])\1\1([%(sq)s])\2\2[%(al)s]{2}$' % REG_DICT, '飞机带单'),    (r'^([%(sq)s])\1\1([%(sq)s])\2\2(?:([%(al)s])\3){2}$' % REG_DICT, '飞机带对'),    (r'^(?:([%(sq)s])\1){3,10}$' % REG_DICT, '连对'),    (r'^[%(sq)s]{5,12}$' % REG_DICT, '顺子'),    #(r'^$'%REG_DICT,''),)RAW_REGEX = [re.compile(pat) for pat, name in _RAW_REGEX]def _sequence(cards, num):    a = SEQUENCE.index(cards[0])    b = SEQUENCE.index(cards[-1])    s = min(a, b)    t = max(a, b)    raw_cards = ''    for i, card in enumerate(SEQUENCE):        if s <= i <= t:            raw_cards += card * num    return raw_cardsdef double_sequence(cards):    return _sequence(cards, 2)def single_sequence(cards):    return _sequence(cards, 1)_ALIAS_REGEX = (    #(正则表达式,出牌类型,解释函数)    (r'^[%(bb)s][%(al)s]$' % REG_DICT, '三带一', lambda c: c[0] * 3 + c[1:]),    (r'^[%(bb)s]([%(al)s])\1$' % REG_DICT, '三带一对', lambda c: c[0] * 3 + c[1:]),    (r'^[%(bb)s]{2}[%(al)s]{2}$' %     REG_DICT, '飞机带单', lambda c: c[0] * 3 + c[1] * 3 + c[2:]),    (r'^[%(bb)s]{2}[%(al)s]{2}-$' % REG_DICT, '飞机带对',     lambda c: c[0] * 3 + c[1] * 3 + c[2] * 2 + c[3] * 2),    (r'^[%(sq)s]--[%(sq)s]$' % REG_DICT, '连对', double_sequence),    (r'^[%(sq)s]-[%(sq)s]$' % REG_DICT, '顺子', single_sequence),    #(r'^$'%REG_DICT,''),)ALIAS_REGEX = [re.compile(pat) for pat, name, f in _ALIAS_REGEX]class Cards(dict):    def __init__(self):        super(Cards, self).__init__(CARD_DICT)        self._all = ALL    def status(self):        print("    各张牌剩余情况:")        for k in self._all:            print('    %s : %s' % (k, self[k]))    def sub(self, cards):        for k in cards:            self[k] -= 1    def add(self, cards):        for k in cards:            self[k] += 1class Game(object):    def __init__(self):        self.logs = list()  # 用于存放出牌记录        self.cards = Cards()  # 初始化扑克牌对象        self.insert_trys = (self.is_raw, self.is_alias)  # 解析出牌命令的函数序列    def over(self):        "判断当前游戏是否结束"        logs = self.logs        if not logs:  # 没有出牌记录的游戏是不可能结束的            return False        count_left = 0        count_right = 0        count_myself = 0        for log in logs:            player_type, card_type, cards = log.split()            if player_type == PLAYER_DICT[LEFT_PLAYER]:                count_left += len(cards)            elif player_type == PLAYER_DICT[RIGHT_PLAYER]:                count_right += len(cards)            else:                count_myself += len(cards)        first_player = logs[0].split()[0]        if first_player == PLAYER_DICT[LEFT_PLAYER]:  # 如果地主是上家            if count_left == 20 or count_right == 17 or count_myself == 17:                return True        elif first_player == PLAYER_DICT[RIGHT_PLAYER]:  # 如果地主是下家            if count_left == 17 or count_right == 20 or count_myself == 17:                return True        else:  # 如果地主是自己            if count_left == 17 or count_right == 17 or count_myself == 20:                return True        return False    def log(self, line):        self.logs.append(line)        print('    ' + line)    def format_cmd(self, cmd):        return re.sub(r'\s', '', cmd).upper()    def dispatch(self, cmd):        "根据首字符对命令进行一个初次分配"        cmd = self.format_cmd(cmd)        if not cmd:            return False        flag = cmd[0]        if flag in QUERY:            return self.is_query(cmd)        if flag in PLAYER:            return self.is_insert(cmd)        if flag in ALL:  # 本人出的牌            return self.is_insert(MYSELF + cmd)        return False    def is_insert(self, cmd):        "先尝试原始形式,再尝试简写形式"        return any(f(cmd[0], cmd[1:]) for f in self.insert_trys)    def is_raw(self, player, cards):        for i, reg in enumerate(RAW_REGEX):            if reg.search(cards):                self.log('%s\t%s\t%s' % (                    PLAYER_DICT[player],  # 玩家位置                    _RAW_REGEX[i][1],  # 出牌类型                    cards,  # 牌内容                ))                self.cards.sub(cards)                return True        return False    def is_alias(self, player, cards):        for i, reg in enumerate(ALIAS_REGEX):            if reg.search(cards):                f = _ALIAS_REGEX[i][2]                raw_cards = f(cards)  # 把简写出牌形式转换为原始形式.例如3-7转化为76543.                self.log('%s\t%s\t%s' % (                    PLAYER_DICT[player],  # 玩家位置                    _ALIAS_REGEX[i][1],  # 出牌类型                    raw_cards,                ))                self.cards.sub(raw_cards)                return True        return False    def is_query(self, cmd):        if cmd == '=':            self.cards.status()            return True        if cmd == '==':  # 撤销最近一次插入操作(如果有的话)            if self.logs:                _, _, cards = self.logs.pop().split()                self.cards.add(cards)            return True        if re.search(r'^=[%s]$' % PLAYER, cmd):            player = PLAYER_DICT[cmd[1]]            print('    %s出牌记录:' % player)            for log in self.logs:                player_type, card_type, cards = log.split()                if player == player_type:                    print('    %s\t%s\t%s' % (player_type, card_type, cards))            return True        if re.search(r'^=[%(al)s]$' % REG_DICT, cmd):            k = cmd[1]            print('    还有%s张%s' % (self.cards[k], k))            return True        return False    def log_to_file(self):        if self.logs:            with open(datetime.datetime.now().strftime('%Y%m%d%H%M%S') + '.txt', 'w') as f:                f.write('\n'.join(self.logs))def tour():    while 1:        print('=========新局开始===========')        game = Game()        while 1:            cmd = input('enter:')            if cmd == '':                break            if game.dispatch(cmd) is False:                print('    无法识别的命令,请再试')                continue            # 每次合法的命令执行后,判断当前局是否结束            if game.over():                print('=========本局结束=========')                break        game.log_to_file()if __name__ == '__main__':    tour()


一个简单的运行示例:

>>> 
=========新局开始===========
enter:9-3
    本人 顺子 9876543
enter:9-3
    本人 顺子 9876543
enter:3-8
    本人 顺子 876543
=========本局结束=========
=========新局开始===========
enter:



0 0
原创粉丝点击