cloudHues

tcmts.share.cloudHues · #tpfml6rl · function · runs anywhere

Each cloud's colour, as a place in a palette of count (the page's --cm0…: the graph draws with them and the panel beside it names clouds with them), or -1 for loose ends: the biggest cloud first, each taking the colour least like those of the clouds nearest it.

import type { CloudLayout } from "#codebase/tcmts/share";

export function cloudHues(layout: CloudLayout, count = 14): number[] {
  const clouds = layout.clouds;
  const chosen: (number | undefined)[] = clouds.map(() => undefined);
  const order = [...clouds.keys()].sort((a, b) => clouds[b]!.n - clouds[a]!.n);
  for (const c of order) {
    const me = clouds[c]!;
    if (me.loose) continue;
    const near = clouds
      .map((d, i) => [i, Math.hypot(d.x - me.x, d.y - me.y) - d.r - me.r] as const)
      .filter(([i]) => i !== c && chosen[i] !== undefined)
      .sort((a, b) => a[1] - b[1])
      .slice(0, 6);
    let best = 0;
    let bestScore = -Infinity;
    for (let p = 0; p < count; p++) {
      // (a neighbour's colour costs the more the nearer it is; a colour used often costs a little)
      let score = -chosen.filter((h) => h === p).length * 0.5;
      for (const [i, d] of near) if (chosen[i] === p) score -= 1000 / Math.max(20, d + 60);
      if (score > bestScore) {
        bestScore = score;
        best = p;
      }
    }
    chosen[c] = best;
  }
  return chosen.map((p) => p ?? -1);
}

uses

used by