《连环夺宝》算法浅析

Posted ecofast

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《连环夺宝》算法浅析相关的知识,希望对你有一定的参考价值。

  孤陋寡闻如我,也只是去年才知道有“连环夺宝”这么个游戏,而且似乎各福彩大厅都有数十台游戏机供人“娱乐”。去年和几个朋友路过福彩看了下,大厅里在玩《连环夺宝》的人似乎挺多的,几十台的游戏机都基本不够用。玩众也百色,无论是西装革履的中年同志,抑或打扮普通的普通民众,都玩得不亦乐乎...老实说,我是无法理解为何他们对此沉迷如斯的,当然我对此类游戏确实也不感冒。
  可能,通过游戏赚(大)钱、打发时间是比较合理的解释吧。譬如每台游戏机都会不定时的滚屏播报某地谁又中了多少奖励之类信息,对不少玩众还是有些或较有诱惑力的。
  当然,《连环夺宝》由福彩运营(?),在某些方面,可能玩众也会放心一些吧。

  作为技术人员,我其实对《连环夺宝》里的宝石连线算法以及宝石矩阵填充处理等技术点比较感兴趣。较之游戏开发里的常规业务逻辑编写,可能它们在实现上更有“技术含量”吧。
  言归正传。第一个问题,宝石连线算法,一开始我没看清连线规则,以为是“一笔画”之类,后发现不是,只要相邻的宝石同类即可连线。细想了会算法实现,很明显,广度优先搜索即非常适合这种应用场景(连连看之类游戏差不多应也是类似算法处理)。
  于是来到第二个问题,当每次符合连线规则的宝石消除后,应如何填充这个宝石矩阵呢?毕竟,这是个联网游戏,假定关键性的游戏逻辑都在服务器端计算,那么服务器应如何将宝石矩阵(可能较大)以及消除信息(可能较多)等告知客户端呢?我想出的做法粗略如下:
    0) 宝石矩阵(GemMatrix)生成这个没啥说的,一般都是通过各类宝石概率配置来生成每一个元素
    1) 消除经 BFS 标记出的宝石(可能有多组)
    2) 对 GemMatrix 按列逐行由低往高,移动宝石至低行空位,最后计算出需填补的行数(NeedRows)
    3) 对额外的宝石填充矩阵(GemMatrixEx)作类似上一步的处理
    4) 若 GemMatrixEx 的完整行数(AvailRows)少于 NeedRows,则将 GemMatrixEx 扩充 NeedRows - AvailRows 行并按步骤 0 的规则填充,再以步骤 2 的规则作宝石移动处理
    5) 按列逐行由低往高将 GemMatrixEx 中的非空元素置入 GemMatrix 中的空位
    6) 对填充后的 GemMatrix 作 BFS 处理,再转到步骤 1,循环往复直至 GemMatrix 消无可消
  而综合以上思路,由服务器告知客户端的最终的宝石大矩阵及消除历史等信息已不难生成。

  简化的处理代码如下。

-- 每关中宝石矩阵尺寸
local MatrixSizeArr = {4, 5, 6}
-- 宝石矩阵
local Gems = {}
-- 宝石填补矩阵
local GemsStandby = {}

local function GetValidStandbyRowNum(lv)    
    local ret = 0
    local sz = MatrixSizeArr[lv]
    local r = #GemsStandby
    for row = 1, r do
        for col = 1, sz do
            if GemsStandby[row][col] == 0 then
                return ret
            end
        end
        ret = ret + 1
    end
    return ret
end

local function ExtendStandbyGems(row, lv)
    local sz = MatrixSizeArr[lv]
    for i = 1, row do
        table.insert(GemsStandby, {})
        for j = 1, sz do
            table.insert(GemsStandby[#GemsStandby], GenGemIndex(j))
        end
    end
end

local function ShiftStandbyGems(lv)
    local r = #GemsStandby
    if r < 2 then
        return true
    end
    local sz = MatrixSizeArr[lv]    
    for col = 1, sz do        
        for row = 1, r do
            if GemsStandby[row][col] == 0 then
                for k = row + 1, r do
                    if GemsStandby[k][col] >= 1 and GemsStandby[k][col] <= 5 then
                        GemsStandby[row][col] = GemsStandby[k][col]                        
                        GemsStandby[k][col] = 0
                        break
                    end
                end
            end
        end
    end

    return true
end

local function ShiftGems(lv)
    local sz = MatrixSizeArr[lv]
    for col = 1, sz do        
        for row = 1, sz do
            if Gems[row][col].Selected or Gems[row][col].GemIndex == 0 then
                local bFlag = false
                for k = row + 1, sz do
                    if (not Gems[k][col].Selected) and (Gems[k][col].GemIndex >= 1) and (Gems[k][col].GemIndex <= 5) then
                        Gems[row][col].GemIndex = Gems[k][col].GemIndex
                        Gems[row][col].Selected = false
                        Gems[k][col].GemIndex = 0
                        Gems[k][col].Selected = false
                        bFlag = true
                        break
                    else
                        Gems[k][col].Selected = false
                        Gems[k][col].GemIndex = 0
                    end
                end
                if not bFlag then
                    Gems[row][col].GemIndex = 0
                    Gems[row][col].Selected = false
                end
            end
        end
    end

    return true
end

local function FillGems(lv)
    local needRows = 0
    local sz = MatrixSizeArr[lv]
    for col = 1, sz do
        local tmp = 0        
        for row = sz, 1, -1 do
            if Gems[row][col].GemIndex == 0 then
                tmp = tmp + 1
            else
              break
            end
        end
        if tmp > needRows then
            needRows = tmp
        end
    end

    ShiftStandbyGems(lv)
    local num = GetValidStandbyRowNum(lv)
    if num < needRows then
        ExtendStandbyGems(needRows - num, lv)
        ShiftStandbyGems(lv)
    end
    
    for col = 1, sz do
        for row = 1, sz do
            if Gems[row][col].GemIndex == 0 then
                for row2 = 1, needRows do
                    if GemsStandby[row2][col] ~= 0 then
                        Gems[row][col].GemIndex = GemsStandby[row2][col]
                        GemsStandby[row2][col] = 0
                        break
                    end
                end
            end
        end
    end

    return true
end

以上是关于《连环夺宝》算法浅析的主要内容,如果未能解决你的问题,请参考以下文章

连环夺宝押注技巧分享,值得一看,

传奇夺宝脚本问题

专业定制开发一元夺宝(一元购)网站系统源码建设

一元夺宝系统平台开发

专业定制开发一元夺宝(一元购)网站系统建设,带源码

redis连环夺命问