implement helper function findMeanInt

This commit is contained in:
Peter Fajdiga
2024-10-20 23:44:41 +02:00
parent b459ba6d4e
commit 4fea81423a
2 changed files with 138 additions and 0 deletions

View File

@@ -42,6 +42,51 @@ function findMinPositive<T>(items: T[], evaluate: (item: T) => number) {
return bestItem;
}
function findMeanInt(sum: number, constraints: { min: number, max: number }[]) {
let mean = Math.floor(sum / constraints.length);
while (true) {
let actualSum = 0;
let increasable = 0;
let decreasable = 0;
let low = -Infinity;
let high = Infinity;
for (const constraint of constraints) {
const value = clamp(mean, constraint.min, constraint.max);
actualSum += value;
if (mean > constraint.min) {
decreasable++;
if (value > low) {
low = value;
}
}
if (mean < constraint.max) {
increasable++;
if (value < high) {
high = value;
}
}
}
const oldMean = mean;
const error = actualSum - sum;
if (error > 0) {
// need to decrease mean
if (decreasable > 0) {
mean = Math.floor(low - error / decreasable);
}
} else if (error < 0) {
// need to increase mean
if (increasable > 0) {
mean = Math.floor(high - error / increasable);
}
}
if (mean === oldMean) {
return mean;
}
}
}
function rectEquals(a: QmlRect, b: QmlRect) {
return a.x === b.x &&
a.y === b.y &&

View File

@@ -0,0 +1,93 @@
tests.register("findMean", 1, () => {
const testCases: {
sum: number,
constraints: { min: number, max: number }[],
check: (result: number) => boolean,
}[] = [
{
sum: 600,
constraints: [
{ min: 10, max: 600 },
{ min: 10, max: 600 },
],
check: r => r === 300,
},
{
sum: 600,
constraints: [
{ min: 10, max: 250 },
{ min: 10, max: 500 },
],
check: r => r === 350,
},
{
sum: 600,
constraints: [
{ min: 10, max: 250 },
{ min: 400, max: 500 },
],
check: r => r === 200,
},
{
sum: 765,
constraints: [
{ min: 10, max: 250 },
{ min: 10, max: 254 },
{ min: 10, max: 500 },
],
check: r => r === 261,
},
{
sum: 600,
constraints: [
{ min: 10, max: 150 },
{ min: 400, max: 500 },
],
check: r => r === 450,
},
{
sum: 750,
constraints: [
{ min: 10, max: 250 },
{ min: 10, max: 250 },
{ min: 400, max: 500 },
{ min: 10, max: 300 },
],
check: r => r === 116,
},
{
sum: 750,
constraints: [
{ min: 10, max: 250 },
{ min: 120, max: 250 },
{ min: 400, max: 500 },
{ min: 10, max: 300 },
],
check: r => r === 115,
},
{
sum: 1200,
constraints: [
{ min: 10, max: 250 },
{ min: 10, max: 500 },
],
check: r => r >= 500,
},
{
sum: 5,
constraints: [
{ min: 10, max: 250 },
{ min: 10, max: 500 },
],
check: r => r <= 10,
},
];
for (const testCase of testCases) {
const result = findMeanInt(testCase.sum, testCase.constraints);
Assert.assert(
testCase.check(result),
{ message: `got ${result} for test case ${JSON.stringify(testCase)}` },
);
}
});