Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!doctype html>
- <html>
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>Flood Distribution</title>
- <style>
- html {
- font-family: sans-serif;
- font-size: 18px;
- }
- body {
- margin: 1rem;
- }
- label[for] {
- display: block;
- font-weight: bold;
- }
- input {
- box-sizing: border-box;
- font-size: 1rem;
- }
- input + label {
- margin-top: 1rem;
- }
- input[readonly] {
- border: 0;
- }
- @media (max-width: 800px) {
- html {
- font-size: 26px;
- }
- input {
- width: 100%;
- }
- }
- </style>
- </head>
- <body>
- <label for="fractions">Fractions:</label>
- <input id="fractions" type="number" min="0" max="4" value="2">
- <label for="budget">Budget:</label>
- <input id="budget" type="number" value="100.00" step="0.01">
- <label for="budget">Demanded:</label>
- <input id="demanded" value="50, 20, 75, 10">
- <label for="given">Given:</label>
- <input id="given" readonly/>
- <label for="given">Remaining Budget:</label>
- <input id="remaining" type="number" readonly>
- <script>
- // @ts-check
- /**
- * Distributes the budget by equally raising each party's share until their
- * demand is met, the budget is spent, or the remaining amount can't be divided
- * any further (e.g. $0.01).
- * @param demanded {number[]}
- * @param budget {number}
- * @param fractions {number}
- * @returns {[number[], number]}
- */
- function distribute(demanded, budget, fractions) {
- let multiplier = 10 ** fractions;
- // Ensure it's actually an int.
- // E.g. 10.2 * 100 = 1019.9999999999999
- let remaining = Math.round(budget * multiplier);
- let data = demanded.map(
- (value, index) => ({
- demanded: value * multiplier,
- index,
- got: 0
- })
- );
- // The demand is sorted in ascending order.
- data.sort((a, b) => a.demanded - b.demanded);
- for (let i = 0; i < data.length; i++) {
- let left = data.length - i;
- let demanded = data[i].demanded;
- // Since everyone can get at least as much as the current party demands,
- // this party gets what it asked for.
- if (remaining > demanded * left) {
- data[i].got = demanded;
- remaining -= demanded;
- }
- // If it's less or exactly as much, distribute whatever remains among
- // the remaining parties and quit.
- else {
- let share = Math.floor(remaining / left); // 10 / 3 -> 3
- for (let k = i; k < data.length; k++) {
- data[k].got = share;
- }
- remaining -= share * left; // 3 * 3 -> 9, 1 remains
- break;
- }
- }
- // Restore the original order.
- data.sort((a, b) => a.index - b.index);
- return [data.map(v => v.got / multiplier), remaining / multiplier];
- }
- function main() {
- let qs = document.querySelector.bind(document);
- let $budget = qs('#budget');
- let $demanded = qs('#demanded');
- let $given = qs('#given');
- let $remaining = qs('#remaining');
- let $fractions = qs('#fractions');
- function format(v, f) {
- return v.toFixed(Number.isInteger(v) ? 0 : f);
- }
- function update() {
- let demanded = $demanded.value.split(',').map(s => +s.trim());
- let budget = +$budget.value;
- let fractions = +$fractions.value;
- let [given, remaining] = distribute(demanded, budget, fractions);
- $given.value = given
- .map(v => format(v, fractions))
- .join(', ');
- $remaining.value = format(remaining, fractions);
- }
- $budget.addEventListener('input', update);
- $demanded.addEventListener('input', update);
- $fractions.addEventListener('input', () => {
- let fractions = +$fractions.value;
- $budget.value = (+$budget.value).toFixed(fractions);
- $budget.step = 1 / (10 ** fractions);
- update();
- });
- update();
- }
- document.addEventListener('DOMContentLoaded', main);
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement