欢迎访问宙启技术站
智能推送

Python中的MjViewer()函数:可视化麻将游戏回放

发布时间:2024-01-04 14:10:18

MjViewer()函数是Python中一个可视化麻将游戏回放的函数,它可以将麻将游戏的历史记录转化为一个可视化的动画。这个函数是基于Python的matplotlib库实现的,可以用来展示麻将游戏的每一步操作,包括玩家的出牌、吃碰杠等操作,以及显示当前的手牌情况和计分情况。

下面是一个使用MjViewer()函数的例子:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.animation import FuncAnimation
from matplotlib.offsetbox import OffsetImage, AnnotationBbox

def MjViewer(playback):
    # 创建游戏画面
    fig, ax = plt.subplots(figsize=(8, 8), dpi=80)
    ax.set_xlim(0, 10)
    ax.set_ylim(0, 10)
    ax.axis('off')

    # 定义牌的图片路径和大小
    mahjong_images = {
        # 万
        '1m': ('mahjong_images/1m.png', [0.06, 0.035]),
        '2m': ('mahjong_images/2m.png', [0.06, 0.035]),
        # 条
        '1s': ('mahjong_images/1s.png', [0.06, 0.035]),
        '2s': ('mahjong_images/2s.png', [0.06, 0.035]),
        # 饼
        '1p': ('mahjong_images/1p.png', [0.06, 0.035]),
        '2p': ('mahjong_images/2p.png', [0.06, 0.035]),
        # 字牌
        'dong': ('mahjong_images/dong.png', [0.08, 0.05]),
        'xi': ('mahjong_images/xi.png', [0.08, 0.05]),
        'nan': ('mahjong_images/nan.png', [0.08, 0.05]),
        'bei': ('mahjong_images/bei.png', [0.08, 0.05]),
    }

    def update(frame):
        ax.clear()

        # 绘制玩家手牌
        player_hand = playback[frame]['player_hand']
        draw_hand(player_hand, 1, 1.5, 5, 1)

        # 绘制其他玩家的手牌
        for i, other_hand in enumerate(playback[frame]['other_hands']):
            draw_hand(other_hand, 1, 8.5 - i * 1.5, 13, 1)

        # 绘制牌堆
        draw_tiles(playback[frame]['tiles'], 2.5, 1, 1)

        # 绘制弃牌堆
        draw_tiles(playback[frame]['discard_pile'], 6.5, 1, 1)

        # 绘制当前操作
        current_action = playback[frame]['current_action']
        if current_action:
            action_string = f"玩家{current_action['player']} "
            if current_action['type'] == 'discard':
                action_string += f"出牌 {current_action['tile']}"
            elif current_action['type'] == 'draw':
                action_string += "摸牌"
            elif current_action['type'] == 'pong':
                action_string += f"碰 {current_action['tile']}"
            elif current_action['type'] == 'chow':
                action_string += f"吃 {current_action['chow_tiles']}"
            elif current_action['type'] == 'kong':
                action_string += f"杠 {current_action['kong_tiles']}"
            ax.text(4, 9, action_string, fontsize=10)

    def draw_hand(hand, x, y, width, height):
        for i, tile in enumerate(hand):
            mahjong_image = mahjong_images[tile]
            mahjong_path = mahjong_image[0]
            mahjong_size = mahjong_image[1]
            x_offset = mahjong_size[0] * i
            y_offset = mahjong_size[1] * i
            x_pos = x + x_offset
            y_pos = y - y_offset
            image = OffsetImage(plt.imread(mahjong_path), zoom=1)
            ab = AnnotationBbox(image, (x_pos, y_pos), frameon=False)
            ax.add_artist(ab)

    def draw_tiles(tiles, x, y, rows):
        nrows = len(tiles) // rows
        for i, tile in enumerate(tiles):
            tile_image = mahjong_images[tile]
            tile_path = tile_image[0]
            tile_size = tile_image[1]
            row = i % rows
            col = i // rows
            x_pos = x + tile_size[0] * row
            y_pos = y - tile_size[1] * col
            image = OffsetImage(plt.imread(tile_path), zoom=1)
            ab = AnnotationBbox(image, (x_pos, y_pos), frameon=False)
            ax.add_artist(ab)

    # 创建动画
    anim = FuncAnimation(fig, update, frames=len(playback), interval=1000, repeat=False)
    plt.show()

使用上述的MjViewer()函数,我们可以播放一个麻将游戏的回放。下面是一个示例的游戏回放数据:

playback = [
    {
        'player_hand': ['1m', '2m', '1s', '2s', '1p', '2p', 'dong', 'xi', 'nan', 'bei'],
        'other_hands': [['1m', '2m', '1s', '2s', '1p', '2p', 'dong', 'nan', 'bei'], 
                        ['1m', '2m', '1s', '2s', '1p', '2p', 'xi', 'dong', 'nan'],
                        ['1m', '2m', '1s', '2s', '1p', '2p', 'bei', 'xi', 'dong']],
        'tiles': ['1m', '2m', '1s', '2s', '1p', '2p', 'dong', 'xi', 'nan', 'bei'],
        'discard_pile': [],
        'current_action': {'player': 1, 'type': 'draw'},
    },
    {
        'player_hand': ['1m', '2m', '1s', '2s', '1p', '2p', 'dong', 'xi', 'bei'],
        'other_hands': [['1m', '2m', '1s', '2s', '1p', '2p', 'dong', 'nan', 'bei'], 
                        ['1m', '2m', '1s', '2s', '1p', '2p', 'xi', 'dong', 'nan'],
                        ['1m', '2m', '1s', '2s', '1p', '2p', 'bei', 'xi', 'dong']],
        'tiles': ['1m', '2m', '1s', '2s', '1p', '2p', 'dong', 'xi', 'nan'],
        'discard_pile': ['bei'],
        'current_action': {'player': 1, 'type': 'discard', 'tile': 'nan'},
    },
    ...
]

以上代码中的playback列表记录了游戏的每一步操作。每个元素表示一个回合的数据,包括玩家手牌(player_hand)、其他玩家手牌(other_hands)、牌堆(tiles)、弃牌堆(discard_pile)和当前操作(current_action)。

使用MjViewer()函数,我们可以将上述的回放数据进行可视化展示。运行下面的代码即可播放麻将游戏的回放动画:

MjViewer(playback)

在动画中,我们可以观察到玩家的手牌、其他玩家的手牌、牌堆、弃牌堆以及当前操作的变化。