{"version":3,"sources":["jsdelivr-header.js","/npm/groupster-engine@1.0.0/dist/index.js"],"names":[],"mappings":"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","file":"/npm/groupster-engine@1.0.0/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/groupster-engine@1.0.0/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports[\"default\"] = Group;\nexports.determineGroupSizes = void 0;\n\nvar _lodash = _interopRequireDefault(require(\"lodash\"));\n\nvar _joiBrowser = _interopRequireDefault(require(\"joi-browser\"));\n\nvar _SafeJoi = _interopRequireDefault(require(\"./SafeJoi\"));\n\nvar _buildRuleMap = _interopRequireDefault(require(\"./buildRuleMap\"));\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\n\nvar determineGroupSizes = function determineGroupSizes(idCount, desiredGroupSize) {\n  var errors = [(0, _SafeJoi[\"default\"])(idCount, _joiBrowser[\"default\"].number().min(1), \"idCount must be a number greater than 0 (it was \".concat(idCount, \")\")), (0, _SafeJoi[\"default\"])(desiredGroupSize, _joiBrowser[\"default\"].number().min(2).max(idCount), \"desiredGroupSize must be a number greater than 1 and less than or equal to idCount (it was \".concat(idCount, \")\"))].filter(Boolean);\n  var groups = [];\n\n  if (!errors.length) {\n    while (idCount >= desiredGroupSize) {\n      groups.push(desiredGroupSize);\n      idCount -= desiredGroupSize;\n    } // If some are remaining then the end goal is to have max # of groups of desired size, with minimal # of groups off by 1.\n    // If not possible just drop remaining into group of their own.\n    // Universal rule is that you should never have a group of size 1.\n\n\n    if (idCount > 0) {\n      // See if possible to distribute into other groups\n      var canDistribute = idCount <= groups.length; // See if possible to skim other groups into this group\n\n      var canSkim = idCount + groups.length >= desiredGroupSize - 1;\n\n      if (idCount < desiredGroupSize - 1 && (canSkim || canDistribute) || idCount === 1) {\n        // See how many groups would be affected by distributing remaining into other groups\n        var groupsAffectedByDistribute = idCount; // See how many groups would be affected by skimming other groups by 1 until remainder is almost a full group\n\n        var groupsAffectedBySkim = desiredGroupSize - idCount;\n\n        if (canSkim && canDistribute) {\n          if (groupsAffectedBySkim <= groupsAffectedByDistribute && idCount > 1) {\n            // Prefer skimming -> this leads to smaller groups\n            canDistribute = false;\n          } else {\n            canSkim = false;\n          }\n        }\n\n        if (canSkim) {\n          // Skim groups, starting at end, until remaining is enough for its own group\n          for (var i = groups.length - 1; i >= 0; i -= 1) {\n            groups[i] -= 1;\n            idCount += 1;\n\n            if (idCount >= desiredGroupSize - 1) {\n              groups.push(idCount);\n              break;\n            }\n          }\n        } else {\n          // Distribute remaining among groups, starting at end\n          for (var _i = groups.length - 1; _i >= 0; _i -= 1) {\n            groups[_i] += 1;\n            idCount -= 1;\n\n            if (idCount === 0) {\n              break;\n            }\n          }\n        }\n      } // If neither are possible to get all groups within 1 of the desiredGroupSize then give up and just use remainder as group\n      else {\n          groups.push(idCount);\n        }\n    }\n  }\n\n  return {\n    groups: groups,\n    errors: errors\n  };\n};\n/**\n * Given a array of IDs and an array of the group sizes desired, along with\n * an optional set of rules to govern how they should be grouped, returns\n * an array of arrays containing grouped IDs.\n *\n * @export\n * @param { array } IDs - Array containing [unique] ids to be grouped.\n * @param { number[] } groupSizes -\n *    Array containing sizes of groups desired. The sum of its values must equal the length of 'IDs' param.\n * @param { array } [rules] -\n *    Array of rule objects. A rule object must contain a boolean 'shouldGroup' property and an 'IDs' property\n *    containing an array of IDs for which the rule applies. If the 'shouldGroup' property is false these IDs\n *    will be placed into separate groups (to the extent possible). If true then they will be placed into\n *    the same group (to the extent possible). For now 'shouldGroup: false' rules will take precedence.\n *\n * @returns Array of groups. Each group is an array containing ids.\n * @throws ValidationError if any of the parameters don't conform to their schemas.\n * @throws Error if any IDs are duplicates, or rules reference IDs not present in 'IDs' param.\n */\n\n\nexports.determineGroupSizes = determineGroupSizes;\n\nfunction Group(IDs, groupSizes) {\n  var rules = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];\n  // The keys of ruleMap are deleted as each id is placed\n  var ruleMap = (0, _buildRuleMap[\"default\"])(IDs, groupSizes, rules);\n  var groups = groupSizes.map(function (size) {\n    var list = [];\n    return {\n      get size() {\n        return size;\n      },\n\n      get list() {\n        return list;\n      },\n\n      get roomLeft() {\n        return size - list.length;\n      },\n\n      add: function add(id) {\n        list.push(id);\n      },\n      fitRating: function fitRating(id) {\n        // If room is left\n        if (size - list.length > 0) {\n          return list.reduce(function (acc, otherID) {\n            var rating = ruleMap[id][otherID];\n\n            if (rating === undefined) {\n              return acc + 0;\n            }\n\n            return acc + (rating ? 1 : -1);\n          }, 0);\n        } // If no room\n\n\n        return -Infinity;\n      }\n    };\n  });\n\n  var addToBestGroup = function addToBestGroup(id) {\n    // Add to the best group (preferring one with the most room)\n    var groupRatings = groups.map(function (group, index) {\n      return {\n        index: index,\n        roomLeft: group.roomLeft,\n        rating: group.fitRating(id)\n      };\n    });\n\n    var bestGroupIndex = _lodash[\"default\"].sortBy(groupRatings, ['rating', 'roomLeft'])[groupRatings.length - 1].index;\n\n    groups[bestGroupIndex].add(id); // Remove from ruleMap\n\n    delete ruleMap[id];\n  };\n\n  var dontGroups = rules.filter(function (rule) {\n    return !rule.shouldGroup;\n  }).map(function (rule) {\n    return _lodash[\"default\"].shuffle(rule.IDs);\n  }).sort(function (a, b) {\n    return b.length - a.length;\n  });\n  dontGroups.forEach(function (dontGroup) {\n    var remaining = dontGroup.filter(function (id) {\n      return _lodash[\"default\"].has(ruleMap, id);\n    });\n    remaining.forEach(addToBestGroup);\n  });\n  var doGroups = rules.filter(function (rule) {\n    return rule.shouldGroup;\n  }).map(function (rule) {\n    return _lodash[\"default\"].shuffle(rule.IDs);\n  }).sort(function (a, b) {\n    return b.length - a.length;\n  });\n  doGroups.forEach(function (doGroup) {\n    var remaining = doGroup.filter(function (id) {\n      return _lodash[\"default\"].has(ruleMap, id);\n    });\n    remaining.forEach(addToBestGroup);\n  }); // Place remaining IDs\n\n  _lodash[\"default\"].shuffle(Object.keys(ruleMap)).forEach(addToBestGroup);\n\n  return groups.map(function (group) {\n    return group.list;\n  });\n}"]}