You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

匹配函数优化:同权重玩家优先同等级匹配后,如何跨等级配对?

玩家匹配函数优化方案

问题背景

原本的玩家匹配函数可实现相同weight的两名玩家配对,逻辑运行正常。现在新增level优先级规则:优先匹配同weight且同level的玩家,但当前函数仅能完成同level玩家配对,无同level的同weight玩家无法被配对。需要优化为:优先同level配对,无同level时允许同weight(或等级相近)的玩家配对。

现有代码(待优化)

const source = [
  {
    entryID: 1,
    entryName: "player1",
    weight: 1900,
    noFight: [],
    level: 1,
  },
  {
    entryID: 2,
    entryName: "player2",
    weight: 1900,
    noFight: [],
    level: 2,
  },
  {
    entryID: 3,
    entryName: "player3",
    weight: 1900,
    noFight: [],
    level: 1,
  },
  {
    entryID: 4,
    entryName: "player4",
    weight: 1900,
    noFight: [],
    level: 2,
  },
  { 
    entryID: 5,
    entryName: "player5",
    weight: 1900,
    noFight: [],
    level: 4,
  },
  { 
    entryID: 6,
    entryName: "player6",
    weight: 1900,
    noFight: [],
    level: 5,
  },
];

console.log(combine(source))

function combine(data = [], different = 0, maxGroupSize = 2) 
{
const 
groups        = []
, related       = []
, sortedData    = [...data].sort((a, b) => a.weight - b.weight)
, alreadyInRela = (setX,eName) => {
    let list = [...setX, eName] 
    return related.some(rela=>list.every(l=>rela.has(l)))
};
sortedData.forEach((el,indx)=>{
let place = groups.findIndex(
    g => g.names.size < maxGroupSize          
        && !g.names.has(el.entryName)         
        && (el.weight - g.weight) <= different 
        && el.level == g.level  
        && !alreadyInRela(g.names, el.entryName ) 
        && !el.noFight.some(noFightEl => g.indxs.map(gi => sortedData[gi].entryID).includes(noFightEl))
    )
if (place < 0) {
  let names = new Set().add(el.entryName)                      
  groups.push( { names, indxs: [indx], weight: el.weight, level: el.level } )  
  related.push( names )                                      
} else {
  groups[place].names.add(el.entryName)  
  groups[place].indxs.push(indx)        
}
})
return groups.reduce((r,g,i)=>{
  if (g.indxs.length > 1) {
    let key = `${i}_` + g.indxs.map(x=>sortedData[x].weight).join('_')
    r[key] = []
    g.indxs.forEach(x=> r[key].push( sortedData[x]) )
  }
  return r
}, {} )
}

当前输出

{
  "0_1900_1900": [
    {
      "entryID": 1,
      "entryName": "player1",
      "level": 1,
      "noFight": [],
      "weight": 1900
    },
    {
      "entryID": 3,
      "entryName": "player3",
      "level": 1,
      "noFight": [],
      "weight": 1900
    }
  ],
  "1_1900_1900": [
    {
      "entryID": 2,
      "entryName": "player2",
      "level": 2,
      "noFight": [],
      "weight": 1900
    },
    {
      "entryID": 4,
      "entryName": "player4",
      "level": 2,
      "noFight": [],
      "weight": 1900
    }
  ]
}

目标输出

{
  "0_1900_1900": [
    {
      "entryID": 1,
      "entryName": "player1",
      "level": 1,
      "noFight": [],
      "weight": 1900
    },
    {
      "entryID": 3,
      "entryName": "player3",
      "level": 1,
      "noFight": [],
      "weight": 1900
    }
  ],
  "1_1900_1900": [
    {
      "entryID": 2,
      "entryName": "player2",
      "level": 2,
      "noFight": [],
      "weight": 1900
    },
    {
      "entryID": 4,
      "entryName": "player4",
      "level": 2,
      "noFight": [],
      "weight": 1900
    }
  ],
  "2_1900_1900": [
    {
      "entryID": 5,
      "entryName": "player5",
      "level": 4,
      "noFight": [],
      "weight": 1900
    },
    {
      "entryID": 6,
      "entryName": "player6",
      "level": 5,
      "noFight": [],
      "weight": 1900
    }
  ]
}

优化后代码

const source = [
  {
    entryID: 1,
    entryName: "player1",
    weight: 1900,
    noFight: [],
    level: 1,
  },
  {
    entryID: 2,
    entryName: "player2",
    weight: 1900,
    noFight: [],
    level: 2,
  },
  {
    entryID: 3,
    entryName: "player3",
    weight: 1900,
    noFight: [],
    level: 1,
  },
  {
    entryID: 4,
    entryName: "player4",
    weight: 1900,
    noFight: [],
    level: 2,
  },
  { 
    entryID: 5,
    entryName: "player5",
    weight: 1900,
    noFight: [],
    level: 4,
  },
  { 
    entryID: 6,
    entryName: "player6",
    weight: 1900,
    noFight: [],
    level: 5,
  },
];

console.log(combine(source))

function combine(data = [], different = 0, maxGroupSize = 2, levelTolerance = 1) 
{
const 
groups        = []
, related       = []
, sortedData    = [...data].sort((a, b) => a.weight - b.weight)
, alreadyInRela = (setX,eName) => {
    let list = [...setX, eName] 
    return related.some(rela=>list.every(l=>rela.has(l)))
};

// 第一步:优先匹配同level的玩家
sortedData.forEach((el,indx)=>{
  let place = groups.findIndex(
    g => g.names.size < maxGroupSize          
        && !g.names.has(el.entryName)         
        && (el.weight - g.weight) <= different 
        && el.level === g.level  
        && !alreadyInRela(g.names, el.entryName ) 
        && !el.noFight.some(noFightEl => g.indxs.map(gi => sortedData[gi].entryID).includes(noFightEl))
    )
  if (place < 0) {
    let names = new Set().add(el.entryName)                      
    groups.push( { names, indxs: [indx], weight: el.weight, level: el.level } )  
    related.push( names )                                      
  } else {
    groups[place].names.add(el.entryName)  
    groups[place].indxs.push(indx)        
  }
})

// 第二步:提取未配对的玩家,进行等级相近匹配
const unpairedIndices = [];
// 先筛选出未完成的组,记录玩家索引并移除这些组
for (let i = groups.length - 1; i >= 0; i--) {
  if (groups[i].indxs.length < maxGroupSize) {
    unpairedIndices.push(...groups[i].indxs);
    groups.splice(i, 1);
  }
}

// 处理未配对玩家
const unpairedPlayers = unpairedIndices.map(idx => ({...sortedData[idx], originalIdx: idx}));
unpairedPlayers.forEach((el)=>{
  let place = groups.findIndex(
    g => g.names.size < maxGroupSize          
        && !g.names.has(el.entryName)         
        && (el.weight - g.weight) <= different 
        && Math.abs(el.level - g.level) <= levelTolerance // 等级相近判断,可通过参数调整
        && !alreadyInRela(g.names, el.entryName ) 
        && !el.noFight.some(noFightEl => g.indxs.map(gi => sortedData[gi].entryID).includes(noFightEl))
    )
  if (place < 0) {
    let names = new Set().add(el.entryName)                      
    groups.push( { names, indxs: [el.originalIdx], weight: el.weight, level: el.level } )  
    related.push( names )                                      
  } else {
    groups[place].names.add(el.entryName)  
    groups[place].indxs.push(el.originalIdx)        
  }
})

// 生成最终结果
return groups.reduce((r,g,i)=>{
  if (g.indxs.length > 1) {
    let key = `${i}_` + g.indxs.map(x=>sortedData[x].weight).join('_')
    r[key] = []
    g.indxs.forEach(x=> r[key].push( sortedData[x]) )
  }
  return r
}, {} )
}

优化说明

  1. 拆分匹配流程:先完成同level优先匹配,再处理未配对玩家,保证优先级逻辑
  2. 新增levelTolerance参数,可自定义等级相近的范围(默认允许1级差距),灵活适配需求
  3. 保留原有的weight匹配、noFight黑名单、重复配对校验逻辑,不破坏原有规则
  4. 提取未完成组的玩家重新匹配,确保无同level的玩家也能找到配对对象

内容的提问来源于stack exchange,提问作者Ulquiorra Schiffer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 12:15:47