高效查表判断胡牌算法的lua版本

来源:互联网 发布:mac u盘复制文件 编辑:程序博客网 时间:2024/05/21 09:40

来源于日本论坛的一套用于麻将的判断胡牌算法,运用查表方式实现。原文链接(http://hp.vector.co.jp/authors/VA046927/mjscore/mjalgorism.html)

原算法是java实现,这里移植为lua版本。

移植为lua版本的代码如下

local M = {}local MAN1 = 0local MAN2 = 1local MAN3 = 2local MAN4 = 3local MAN5 = 4local MAN6 = 5local MAN7 = 6local MAN8 = 7local MAN9 = 8local PIN1 = 9local PIN2 = 10local PIN3 = 11local PIN4 = 12local PIN5 = 13local PIN6 = 14local PIN7 = 15local PIN8 = 16local PIN9 = 17local SOU1 = 18local SOU2 = 19local SOU3 = 20local SOU4 = 21local SOU5 = 22local SOU6 = 23local SOU7 = 24local SOU8 = 25local SOU9 = 26local TON = 27local NAN = 28local SHA = 29local PEI = 30local HAK = 31local HAT = 32local CHU = 33local PRINT_MAP = {    [0] = "一万",    [1] = "二万",    [2] = "三万",    [3] = "四万",    [4] = "五万",    [5] = "六万",    [6] = "七万",    [7] = "八万",    [8] = "九万",    [9] = "一条",    [10] = "二条",    [11] = "三条",    [12] = "四条",    [13] = "五条",    [14] = "六条",    [15] = "七条",    [16] = "八条",    [17] = "九条",    [18] = "一筒",    [19] = "二筒",    [20] = "三筒",    [21] = "四筒",    [22] = "五筒",    [23] = "六筒",    [24] = "七筒",    [25] = "八筒",    [26] = "九筒",    [27] = "东风",    [28] = "南风",    [29] = "西风",    [30] = "北风",    [31] = "红中",    [32] = "发财",    [33] = "白板",}function M:init()    self.tbl = require "hupai_table"end--==============================----desc: 计算每一种牌的个数,1-9万、1-9索、1-9筒、东南西北中发白共34种牌--@hai: 玩家的手牌--return  返回每种牌个数的数组--==============================--function M:analyse(hai)    local n = {}    for i = 0, 33 do        n[i] = 0    end    for _, v in ipairs(hai) do        n[v] = n[v] + 1    end    return nend-- key对应的值定义-- 3bit  0: 刻子の数(0~4)-- 3bit  3: 順子の数(0~4)-- 4bit  6: 頭の位置(1~13)-- 4bit 10: 面子の位置1(0~13)-- 4bit 14: 面子の位置2(0~13)-- 4bit 18: 面子の位置3(0~13)-- 4bit 22: 面子の位置4(0~13)-- 计算牌型对应的key值function M:calc_key(n, pos)    local p = -1    local x = 0    local pos_p = 0    local b = false    local tmp = 0    -- 数牌(万、索、筒)    for i = 0, 2 do        for j = 0, 8 do            if n[i * 9 + j] == 0 then                if b then                    b = false                    x = x | (0x1 << p)                    p = p + 1                end            else                p = p + 1                b = true                pos[pos_p] = i * 9 + j                pos_p = pos_p + 1                tmp = n[i * 9 + j]                if tmp == 2 then                    x = x | (0x3 << p)                    p = p + 2                elseif tmp == 3 then                    x = x | (0xf << p)                    p = p + 4                elseif tmp == 4 then                    x = x | (0x3f << p)                    p = p + 6                end            end        end        if b then            b = false            x = x | (0x1 << p)            p = p + 1        end    end    -- 字牌    for i = TON, CHU do        if n[i] > 0 then            p = p + 1            pos[pos_p] = i            pos_p = pos_p + 1            tmp = n[i]            if tmp == 2 then                x = x | (0x3 << p)                p = p + 2            elseif tmp == 3 then                x = x | (0xf << p)                p = p + 4            elseif tmp == 4 then                x = x | (0x3f << p)                p = p + 6            end            x = x | (0x1 << p)            p = p + 1        end    end    return xend-- 获取key值对应的胡牌值(包括:刻子个数、顺子个数、雀头、刻子值、顺子值(顺子第一张牌值)、其他特殊胡牌类型)function M:agari(key)    return self.tbl[key]end-- 计算是否胡牌-- 牌值定义:0-26: 万条筒,27-33:字牌(东南西北中发白)-- 传入参数是非亮牌外的正常手牌,加上自摸(或吃、碰)到的牌,可能是14、11、8、5、2张牌-- 返回胡牌类型function M:check_hupai(hai)    local pos = {}    local n = self:analyse(hai)    local key = self:calc_key(n, pos)    local ret = self:agari(key)    if not ret then        return false    end        local hu = false    local tbl = {} -- 保存胡牌结果    for _, r in ipairs(ret) do        hu = true        tbl.duizi = pos[(r >> 6) & 0xf]        print("雀头=", tbl.duizi, PRINT_MAP[tbl.duizi])        local num_kotsu = r & 0x7        local num_shuntsu = (r >> 3) & 0x7        tbl.kezi = {}        for i = 0, num_kotsu - 1 do            table.insert(tbl.kezi, pos[(r >> (10 + i * 4)) & 0xf])            print("刻子=", tbl.kezi[i + 1], PRINT_MAP[tbl.kezi[i + 1]])        end        tbl.shunzi = {}        for i = 0, num_shuntsu - 1 do            table.insert(tbl.shunzi, pos[(r >> (10 + num_kotsu * 4 + i * 4)) & 0xf])            print("顺子=", tbl.shunzi[i + 1], PRINT_MAP[tbl.shunzi[i + 1]])        end    end    return hu, tblendfunction M:test()    local hai = {        MAN1, MAN1, MAN1,        MAN2, MAN3, MAN4,        MAN6, MAN7, MAN8,        TON, TON, TON,        SHA, SHA    }    local n    local pos = {}    local ret    local t = os.time()    for i = 1, 1000000 do        n = self:analyse(hai)        local key = self:calc_key(n, pos)        ret = self:agari(key)    end    print(string.format("cost time: %ds", os.time()-t))        for _, r in ipairs(ret) do        print("雀头=", pos[(r >> 6) & 0xf])        local num_kotsu = r & 0x7        local num_shuntsu = (r >> 3) & 0x7        for i = 0, num_kotsu - 1 do            print("刻子=", pos[(r >> (10 + i * 4)) & 0xf])        end        for i = 0, num_shuntsu - 1 do            print("顺子=", pos[(r >> (10 + num_kotsu * 4 + i * 4)) & 0xf])        end    endendreturn M


胡牌表定义hupai_table.lua

return {    [0x74444] = {0x258c320},    [0x47444] = {0x298c260},    [0x44744] = {0x29cc1a0},    [0x44474] = {0x29d00e0},    [0x44447] = {0x29d0420},    [0x3a220] = {0x258c320},    -- 由于表较大,此处省略中间部分    [0x23a20] = {0x298c260},    [0x223a0] = {0x29cc1a0},    [0x3a204] = {0x258c320},    [0x23a04] = {0x298c260},    [0x3a044] = {0x258c320},    [0x20744] = {0x29cc1a0},}


测试代码

local logic_hupai = require "logic_hupai"logic_hupai:init()logic_hupai:test()

测试数据显示判断胡牌100万次耗时7秒。测试环境为Linux系统,单核CPU,2G内存。


原创粉丝点击