fillSpace: distribute remainder

This commit is contained in:
Peter Fajdiga
2024-10-26 18:23:32 +02:00
parent 98b2d8b882
commit 44c5c43c25
2 changed files with 36 additions and 10 deletions

View File

@@ -1,12 +1,16 @@
function fillSpace(availableSpace: number, items: { min: number, max: number }[]) {
if (items.length === 0) {
return [];
}
const middleSize = findMiddleSize(availableSpace, items);
return items.map(item => clamp(middleSize, item.min, item.max));
const sizes = items.map(item => clamp(middleSize, item.min, item.max));
if (middleSize !== Math.floor(availableSpace / items.length)) {
distributeRemainder(availableSpace, middleSize, sizes, items);
}
return sizes;
function findMiddleSize(availableSpace: number, items: { min: number, max: number }[]) {
if (items.length === 0) {
return 0;
}
const ranges = buildRanges(items);
let requiredSpace = items.reduce((acc, item) => acc + item.min, 0);
for (const range of ranges) {
@@ -50,6 +54,28 @@ function fillSpace(availableSpace: number, items: { min: number, max: number }[]
return array;
}
function distributeRemainder(availableSpace: number, middleSize: number, sizes: number[], constraints: { max: number }[]) {
const indexes = Array.from(sizes.keys())
.filter(i => sizes[i] === middleSize);
indexes.sort((a, b) => constraints[a].max - constraints[b].max);
const requiredSpace = sum(...sizes);
let remainder = availableSpace - requiredSpace;
let n = indexes.length;
for (const i of indexes) {
if (remainder <= 0) {
break;
}
const enlargable = constraints[i].max - sizes[i];
if (enlargable > 0) {
const enlarge = Math.min(enlargable, Math.ceil(remainder / n));
sizes[i] += enlarge;
remainder -= enlarge;
}
n--;
}
}
type Range = {
start: number,
end: number,

View File

@@ -58,7 +58,7 @@ tests.register("fillSpace", 1, () => {
{ min: 400, max: 500 },
{ min: 10, max: 300 },
],
expected: [116, 116, 400, 116],
expected: [117, 117, 400, 116],
},
{
availableSpace: 750,
@@ -98,7 +98,7 @@ tests.register("fillSpace", 1, () => {
{ min: 109, max: 800 },
{ min: 10, max: 800 },
],
expected: [114, 93, 93, 93, 93, 93, 110, 110],
expected: [114, 93, 93, 93, 93, 93, 111, 110],
},
{
availableSpace: 801,
@@ -126,7 +126,7 @@ tests.register("fillSpace", 1, () => {
{ min: 109, max: 800 },
{ min: 10, max: 95 },
],
expected: [120, 93, 93, 93, 93, 93, 120, 95],
expected: [121, 93, 93, 93, 93, 93, 120, 95],
},
{
availableSpace: 799,
@@ -140,7 +140,7 @@ tests.register("fillSpace", 1, () => {
{ min: 10, max: 91},
{ min: 105, max: 800 },
],
expected: [79, 107, 107, 107, 107, 107, 79, 105],
expected: [80, 107, 107, 107, 107, 107, 79, 105],
},
{
availableSpace: 1029,
@@ -184,7 +184,7 @@ tests.register("fillSpace", 1, () => {
{ min: 10, max: 600 },
{ min: 10, max: 600 },
],
expected: [204, 199, 199, 199],
expected: [204, 200, 200, 199],
},
{
availableSpace: 900,