implement helper function findMeanInt
This commit is contained in:
@@ -42,6 +42,51 @@ function findMinPositive<T>(items: T[], evaluate: (item: T) => number) {
|
|||||||
return bestItem;
|
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) {
|
function rectEquals(a: QmlRect, b: QmlRect) {
|
||||||
return a.x === b.x &&
|
return a.x === b.x &&
|
||||||
a.y === b.y &&
|
a.y === b.y &&
|
||||||
|
|||||||
93
src/tests/units/utils/findMean.ts
Normal file
93
src/tests/units/utils/findMean.ts
Normal 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)}` },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user