/** * 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} groupIds * @returns {Array} */ 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} players * @param {Array} groups * @returns {Array} */ 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} groups * @param {Array} droppedPlayerIds * @returns {Array} */ 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} groups * @param {Object} options * @param {number} options.rowsPerPage * @param {number} options.headerRows * @param {number} options.spacerRows * @returns {Array} */ 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} players * @param {Array} groupIds * @param {Object} printOptions * @returns {Array} */ export function buildGroupPrintPages(players, groupIds, printOptions) { var groups = calculateGroupSizes(players.length, groupIds); assignPlayersToGroups(players, groups); return generatePrintLayout(groups, printOptions); }