编辑代码

-- 玩家组
local a = {
    [1] = {1, 2},
    [2] = {3, 4},
    [3] = {5, 6},
    [4] = {7, 8},
    [5] = {9, 10}
}

-- 所有组号
local b = {1, 2, 3, 4, 5}

-- 记录当前所有组里元素最多的组的元素数量(当前需求下为2)
local maxSize = 0 

-- 剩余元素为index的组的数量
local c = {}

-- 设置随机种子
math.randomseed(os.time())


-- 辅助函数:从组的键中随机取出一个玩家并移除
local function getRandomPlayerAndRemove(groupKey)
    
    if #a[groupKey] == 0 then
        error(string.format("错误:组 %d 为空", groupKey))
    end
    local index = math.random(#a[groupKey])
    local player = a[groupKey][index]

    c[#a[groupKey]] = c[#a[groupKey]] -1
    if #a[groupKey] > 1 then 
        c[#a[groupKey]-1] = c[#a[groupKey]-1] + 1
    end
    while c[maxSize] == 0 do -- 更新maxsize
        maxSize = maxSize - 1
    end

    table.remove(a[groupKey], index)
    return player
end

-- 辅助函数:从列表 b 中随机取出一个组号并移除(优先取组内元素大于1的组)
local function getGroupIndex()
    if #b == 0 then
        return nil
    end
    local index = math.random(#b)
    local element = b[index]
    table.remove(b, index)
    return element
end

-- 主匹配函数
local function matchPlayers()
    local matches = {}
    local totalPlayers = 10 -- 总人数
    local numOnematch = 2 -- 每次匹配的人数
    maxSize = 2 
    
    local numMatches = totalPlayers / numOnematch -- 循环次数

    -- 动态确定循环次数
    for matchid = 1, numMatches do
        local i 
        -- 当剩余的匹配数和剩余人数最大的那个组的人数相等时,干预,使得每次匹配都必须带上这一组
        if (numMatches - matchid + 1 == maxSize) and (maxSize > 1) then 
            for index = 1, #b do
                if #a[b[index]] == maxSize then
                    i = b[index]
                    table.remove(b,index)
                    break
                end
            end
        else
            i = getGroupIndex()
        end

        if not i then
            print("没有找到合适的组 i")
            break
        end


        -- 随机取出一个组号 j,确保 i 和 j 不同,并优先取组内元素大于 1 的组
        local j = getGroupIndex()
        if not j then
            print("没有找到合适的组 j")
            break
        end
        

        -- 从组 i 和组 j 中各随机取出一个玩家进行匹配
        local player_i = getRandomPlayerAndRemove(i)
        local player_j = getRandomPlayerAndRemove(j)
        if player_i and player_j then
            print(string.format("对战: 玩家 %d vs 玩家 %d", player_i, player_j))
            table.insert(matches, {i, j}) -- 记录匹配的玩家的组号,用于后续判断
        else
            error("匹配失败:无法从组中移除玩家")
        end

        -- 如果组 i 和组 j 还有剩余玩家,则将它们的组号放回 availableGroups 中
        if #a[i] > 0 then
            table.insert(b, i)
        end
        if #a[j] > 0 then
            table.insert(b, j)
        end
    end

    print("一局完成了!")
    return matches
end

-- 自检脚本
local function selfCheck()
    for _ = 1, 100000 do
        -- 重置玩家组和组号列表
        a = {
            [1] = {1, 2},
            [2] = {3, 4},
            [3] = {5, 6},
            [4] = {7, 8},
            [5] = {9, 10}
        }
        b = {1, 2, 3, 4, 5}
        c = {0, 5}

        -- 运行匹配函数
        local matches = matchPlayers()

        -- 检查所有玩家是否匹配完成
        local allMatched = true
        for _, group in pairs(a) do
            if #group > 0 then
                allMatched = false
                break
            end
        end

        -- 检查匹配是否正确
        if not allMatched then
            error("检测失败:有玩家轮空")
        end

        for _, match in ipairs(matches) do
            local i, j = match[1], match[2]
            -- 检查玩家是否来自不同组
            if i == j then
                error(string.format("检测失败:匹配中有同组玩家"))
            end
        end
    end
    print("检测通过:所有玩家匹配完成且无轮空无同组")
end

-- 运行自检脚本
selfCheck()