
本教程详细讲解如何使用javascript实现一个智能赛事调度算法,确保选手在连续参赛之间保持设定的休息间隔。通过引入“疲劳选手”机制和迭代查找可用赛事的方法,该算法能有效避免选手连续出战,并允许灵活配置休息场次。文章将深入解析代码实现,并探讨其应用场景及潜在局限。
在许多竞技或娱乐赛事中,为了保证公平性、选手健康或观赏性,通常需要为选手设定一定的休息间隔,避免其连续出战。例如,在拳击比赛中,一位选手在完成一场比赛后,可能需要休息3-4场比赛才能再次登场。
传统的顺序分配 fightNumber 的方法,如简单地按照原始数据顺序或分组后顺序分配,往往无法满足这种间隔约束。这可能导致同一选手在极短的 fightNumber 间隔内多次出战,或者由于复杂的分配逻辑导致间隔过大,使得调度效率低下。
我们的目标是设计一个算法,能够根据预设的“休息场次间隔” (gapNumber),为一系列潜在的比赛分配 fightNumber,确保任何选手在两次出战之间至少有 gapNumber 场比赛的休息时间。
考虑以下原始比赛数据结构,其中 fightNumber 初始时可以视为待分配:
立即学习“Java免费学习笔记(深入)”;
const data = [
{ id: "1", fighter1: "paul", fighter2: "anna", fightNumber: null },
{ id: "2", fighter1: "jack", fighter2: "paul", fightNumber: null },
{ id: "3", fighter1: "roger", fighter2: "law", fightNumber: null },
{ id: "4", fighter1: "lee", fighter2: "law", fightNumber: null },
{ id: "5", fighter1: "law", fighter2: "paul", fightNumber: null },
{ id: "6", fighter1: "roger", fighter2: "anna", fightNumber: null },
{ id: "7", fighter1: "lee", fighter2: "jack", fightNumber: null },
{ id: "8", fighter1: "roger", fighter2: "anna", fightNumber: null },
{ id: "9", fighter1: "lee", fighter2: "jack", fightNumber: null },
];期望的输出结果是 fightNumber 重新排序,并满足间隔约束,例如:
const new_result= [
{"id":"1","fighter1":"paul","fighter2":"anna","fightNumber":0}, // 示例中从0开始,与目标输出的1对应
{"id":"3","fighter1":"roger","fighter2":"law","fightNumber":1},
{"id":"7","fighter1":"lee","fighter2":"jack","fightNumber":2},
{"id":"2","fighter1":"jack","fighter2":"paul","fightNumber":3}, // paul在此处再次出战,与fightNumber 0之间有2场比赛的间隔
// ... 其他比赛
];为了实现间隔约束,我们引入“疲劳选手”的概念。当一名选手参加完一场比赛后,他会在接下来的 gapNumber 场比赛中被视为“疲劳”状态,不能再次出战。算法的核心思想是迭代地为每一场比赛 (fightNumber 从0开始递增) 寻找一个合适的未使用的比赛,该比赛的两位选手当前都不是疲劳状态。
具体步骤如下:
下面是实现上述算法的JavaScript代码,并结合HTML界面进行交互:
HTML 结构:
<label>选择选手休息的场次间隔: </label> <select name="gap" id="gapNumberInput"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> </select> <br> <button onclick="calculatreFight()">计算调度</button> <br><br><br> <p>请注意,休息间隔越大,可能找到的解决方案越少,从而导致某些场次无法安排选手。</p> <pre id="output"></pre> <!-- 用于显示结果 -->
JavaScript 代码:
const data = [
{ id: "1", fighter1: "paul", fighter2: "anna", fightNumber: null },
{ id: "2", fighter1: "jack", fighter2: "paul", fightNumber: null },
{ id: "3", fighter1: "roger", fighter2: "law", fightNumber: null },
{ id: "4", fighter1: "lee", fighter2: "law", fightNumber: null },
{ id: "5", fighter1: "law", fighter2: "paul", fightNumber: null },
{ id: "6", fighter1: "roger", fighter2: "anna", fightNumber: null },
{ id: "7", fighter1: "lee", fighter2: "jack", fightNumber: null },
{ id: "8", fighter1: "roger", fighter2: "anna", fightNumber: null },
{ id: "9", fighter1: "lee", fighter2: "jack", fightNumber: null },
];
function calculatreFight() {
// 获取用户选择的休息间隔
const gapNumber = parseInt(document.getElementById("gapNumberInput").value);
// tiredFightersList: 存储每场比赛的选手,用于判断哪些选手当前是疲劳的
// 结构如:[[fighter1_0, fighter2_0], [fighter1_1, fighter2_1], ...]
const tiredFightersList = [];
// compiledIndexes: 存储原始data数组中已被使用的比赛的索引
const compiledIndexes = [];
// 使用 map 方法迭代,为每一场比赛 (fightNumber 从 0 到 data.length - 1) 进行调度
const scheduledFights = data.map((_, index) => {
// 计算当前“疲劳”的选手列表
// slice(-gapNumber) 获取最近的 gapNumber 场比赛的选手数据
// reduce 扁平化数组并去重,得到所有疲劳选手
const tiredFighters = tiredFightersList.slice(-gapNumber).reduce((prev, curr) => {
// 确保 curr 存在且是数组,处理可能为空的情况
if (curr) {
curr.forEach(fighter => {
if (fighter && !prev.includes(fighter)) {
prev.push(fighter);
}
});
}
return prev;
}, []);
let searchIndex = 0; // 用于在原始 data 数组中查找可用比赛的索引
// 循环查找符合条件的比赛:
// 1. 比赛的 fighter1 或 fighter2 不能是疲劳选手
// 2. 该比赛不能已经被调度过 (compiledIndexes.includes(searchIndex))
while (searchIndex < data.length && (
tiredFighters.includes(data[searchIndex]?.fighter1) ||
tiredFighters.includes(data[searchIndex]?.fighter2) ||
compiledIndexes.includes(searchIndex)
)) {
searchIndex += 1;
}
let currentFight = null;
if (searchIndex < data.length) {
// 找到可用比赛,记录其选手和索引
currentFight = data[searchIndex];
tiredFightersList[index] = [currentFight.fighter1, currentFight.fighter2];
compiledIndexes.push(searchIndex);
} else {
// 未找到可用比赛,当前场次为空,但仍需在 tiredFightersList 中占位,防止后续计算出错
tiredFightersList[index] = [null, null];
}
// 返回调度后的比赛对象
return {
...currentFight, // 如果 currentFight 为 null,这里会是空对象
fightNumber: index // 赋予当前的 fightNumber
};
});
// 将结果输出到页面
document.getElementById("output").textContent = JSON.stringify(scheduledFights, null, 2);
}代码解析:
本教程介绍了一种基于“疲劳选手”机制的JavaScript赛事调度算法,能够有效地在分配比赛 fightNumber 时强制执行选手休息间隔。通过维护 tiredFightersList 和 compiledIndexes,算法能够迭代地为每场比赛找到符合条件的选手组合,从而避免选手连续出战。尽管该算法在数据不足时可能产生空比赛场次,但它提供了一个灵活且可配置的解决方案,适用于需要考虑选手休息期的赛事管理场景。开发者可以根据实际需求,在此基础上进行扩展,例如增加更复杂的优化策略或选手优先级规则。
以上就是JavaScript实现带有间隔约束的赛事调度算法教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号