Add utility function for calculating group sizes

This commit is contained in:
2026-01-29 01:58:23 +00:00
parent 43bc719292
commit beff7cd832

View File

@@ -0,0 +1,149 @@
/**
* groupSizeUtils.js
* -----------------------------------------
* Utilities for group size calculation and
* print-safe layout generation.
*
* Vanilla ECMAScript, framework-agnostic.
*/
/**
* Create group definitions with base sizes
* and remainder distribution.
*
* @param {number} totalPlayers
* @param {Array<string>} groupIds
* @returns {Array<Object>}
*/
export function calculateGroupSizes(totalPlayers, groupIds) {
if (!Array.isArray(groupIds) || groupIds.length === 0) {
throw new Error('groupIds must be a non-empty array');
}
const totalGroups = groupIds.length;
const baseSize = Math.floor(totalPlayers / totalGroups);
const remainder = totalPlayers % totalGroups;
return groupIds.map(function (id, index) {
return {
id: id,
size: baseSize + (index < remainder ? 1 : 0),
players: []
};
});
}
/**
* Assign players to groups sequentially
* based on calculated group sizes.
*
* @param {Array<Object>} players
* @param {Array<Object>} groups
* @returns {Array<Object>}
*/
export function assignPlayersToGroups(players, groups) {
var playerIndex = 0;
groups.forEach(function (group) {
for (var i = 0; i < group.size; i++) {
if (playerIndex >= players.length) break;
var player = players[playerIndex];
player.groupId = group.id;
group.players.push(player);
playerIndex++;
}
});
return groups;
}
/**
* Remove dropped players without rebalancing groups.
*
* @param {Array<Object>} groups
* @param {Array<string|number>} droppedPlayerIds
* @returns {Array<Object>}
*/
export function applyDrops(groups, droppedPlayerIds) {
if (!Array.isArray(droppedPlayerIds)) return groups;
var dropSet = new Set(droppedPlayerIds);
groups.forEach(function (group) {
group.players = group.players.filter(function (player) {
return !dropSet.has(player.id);
});
});
return groups;
}
/**
* Calculate print rows for a group.
*
* @param {Object} group
* @param {number} headerRows
* @param {number} spacerRows
* @returns {number}
*/
export function calculateGroupPrintRows(group, headerRows, spacerRows) {
return headerRows + group.players.length + spacerRows;
}
/**
* Generate print layout with page breaks.
*
* @param {Array<Object>} groups
* @param {Object} options
* @param {number} options.rowsPerPage
* @param {number} options.headerRows
* @param {number} options.spacerRows
* @returns {Array<Object>}
*/
export function generatePrintLayout(groups, options) {
var rowsPerPage = options.rowsPerPage;
var headerRows = options.headerRows || 1;
var spacerRows = options.spacerRows || 1;
var pages = [];
var currentPage = {
pageNumber: 1,
groups: [],
usedRows: 0
};
groups.forEach(function (group) {
var groupRows = calculateGroupPrintRows(group, headerRows, spacerRows);
if (currentPage.usedRows + groupRows > rowsPerPage) {
pages.push(currentPage);
currentPage = {
pageNumber: currentPage.pageNumber + 1,
groups: [],
usedRows: 0
};
}
currentPage.groups.push(group);
currentPage.usedRows += groupRows;
});
pages.push(currentPage);
return pages;
}
/**
* High-level helper that runs the full pipeline.
*
* @param {Array<Object>} players
* @param {Array<string>} groupIds
* @param {Object} printOptions
* @returns {Array<Object>}
*/
export function buildGroupPrintPages(players, groupIds, printOptions) {
var groups = calculateGroupSizes(players.length, groupIds);
assignPlayersToGroups(players, groups);
return generatePrintLayout(groups, printOptions);
}