程序麻将机裁判系统

下面是一个完整的程序麻将机裁判系统的实现,包含洗牌、发牌、游戏流程管理和胡牌判断等功能。

import random
from collections import defaultdict
from enum import Enum
import sys
class Suit(Enum):
    """麻将花色枚举"""
    CHARACTERS = '万'  # 万
    BAMBOO = '条'     # 条
    DOTS = '筒'       # 筒
    HONOR = '字'      # 字牌
class HonorType(Enum):
    """字牌类型枚举"""
    EAST = '东'
    SOUTH = '南'
    WEST = '西'
    NORTH = '北'
    RED = '中'
    GREEN = '发'
    WHITE = '白'
class Tile:
    """麻将牌类"""
    def __init__(self, suit, value=None, honor=None):
        self.suit = suit
        self.value = value  # 数值牌的值(1-9)
        self.honor = honor  # 字牌类型
    def __str__(self):
        if self.suit == Suit.HONOR:
            return f"{self.honor.value}"
        return f"{self.value}{self.suit.value}"
    def __repr__(self):
        return str(self)
    def __eq__(self, other):
        return (self.suit == other.suit and 
                self.value == other.value and 
                self.honor == other.honor)
    def __hash__(self):
        return hash((self.suit, self.value, self.honor))
class Player:
    """玩家类"""
    def __init__(self, name, position):
        self.name = name
        self.position = position  # 玩家位置(东、南、西、北)
        self.hand = []            # 手牌
        self.melds = []           # 碰杠牌组
        self.discards = []        # 弃牌
        self.ready_hand = False   # 是否听牌
    def draw_tile(self, tile):
        """摸牌"""
        self.hand.append(tile)
        self.hand.sort(key=lambda t: (t.suit.value, t.value or 0, t.honor.value if t.honor else ''))
    def discard_tile(self, tile):
        """打牌"""
        if tile in self.hand:
            self.hand.remove(tile)
            self.discards.append(tile)
            return tile
        return None
    def can_pung(self, tile):
        """是否可以碰牌"""
        return sum(1 for t in self.hand if t == tile) >= 2
    def pung(self, tile):
        """碰牌"""
        if self.can_pung(tile):
            # 移除两张相同的牌
            removed = []
            for _ in range(2):
                for t in self.hand:
                    if t == tile:
                        self.hand.remove(t)
                        removed.append(t)
                        break
            # 添加到碰牌组
            self.melds.append(('碰', [removed[0], removed[1], tile]))
            return True
        return False
    def can_kong(self, tile, from_self=False):
        """是否可以杠牌"""
        count = sum(1 for t in self.hand if t == tile)
        if from_self:
            # 暗杠或加杠
            return count == 4 or any(meld[0] == '碰' and meld[1][0] == tile for meld in self.melds)
        else:
            # 明杠
            return count == 3
    def kong(self, tile, from_self=False, from_meld=False):
        """杠牌"""
        if from_self:
            # 暗杠或加杠
            if sum(1 for t in self.hand if t == tile) == 4:
                # 暗杠
                removed = [t for t in self.hand if t == tile][:4]
                self.hand = [t for t in self.hand if t not in removed]
                self.melds.append(('杠', removed))
                return True, '暗杠'
            elif from_meld:
                # 加杠
                for i, meld in enumerate(self.melds):
                    if meld[0] == '碰' and meld[1][0] == tile:
                        # 找到对应的碰牌组
                        self.melds[i] = ('杠', meld[1] + [tile])
                        self.hand.remove(tile)
                        return True, '加杠'
        else:
            # 明杠
            if sum(1 for t in self.hand if t == tile) == 3:
                # 移除三张相同的牌
                removed = [t for t in self.hand if t == tile][:3]
                self.hand = [t for t in self.hand if t not in removed]
                # 添加到杠牌组
                self.melds.append(('杠', removed + [tile]))
                return True, '明杠'
        return False, None
    def can_win(self, tile=None):
        """检查是否可以胡牌"""
        hand_to_check = self.hand.copy()
        if tile:
            hand_to_check.append(tile)
        return is_winning_hand(hand_to_check)
    def __str__(self):
        return f"{self.name} ({self.position.value}): 手牌: {self.hand} 碰杠: {self.melds} 弃牌: {self.discards}"
class MahjongReferee:
    """麻将裁判系统"""
    def __init__(self, players):
        self.players = players
        self.wall = []              # 牌墙
        self.dead_wall = []         # 杠牌区
        self.current_player = 0     # 当前玩家索引
        self.last_discard = None    # 最后一张打出的牌
        self.game_over = False      # 游戏是否结束
        self.winner = None          # 获胜者
        self.dora_indicators = []   # 宝牌指示牌
        self.round = 1              # 当前轮次
        self.dealer = 0             # 庄家索引
    def initialize_tiles(self):
        """初始化麻将牌"""
        tiles = []
        # 万、条、筒各36张 (1-9各4张)
        for suit in [Suit.CHARACTERS, Suit.BAMBOO, Suit.DOTS]:
            for value in range(1, 10):
                for _ in range(4):
                    tiles.append(Tile(suit, value))
        # 字牌各4张 (东南西北中发白)
        for honor in HonorType:
            for _ in range(4):
                tiles.append(Tile(Suit.HONOR, honor=honor))
        return tiles
    def shuffle_tiles(self):
        """洗牌"""
        self.wall = self.initialize_tiles()
        random.shuffle(self.wall

相关资讯