import { useMemo, useState } from 'react';
import { ready, ink } from '../../lib/mrly.js';
import { mount, Page, Row, Slider, Btn, Stats, Stat } from '../../lib/app.jsx';
import { Grid, Markup } from '../../lib/draw.jsx';
import { useSeeds } from '../../lib/select.jsx';
import { useQuery, share } from '../../lib/query.js';
const m = await ready();
const colors = () => [ink.blue, ink.orange, ink.yellow, ink.green, ink.pink];
const COUNTS = m.counting_sequence(4).join(', ');
const BASE3 = m.baseq_sequence(3, 2).join(', ');
const WORLD = { 2: JSON.parse(m.universe(2)), 3: JSON.parse(m.universe(3)) };
const FIRST = { 2: '7', 3: '23' };
const BUDGET = 60000;
const tint = (design) => colors()[design.degree % 5];
const drawn = (seed, designs) => designs[m.random_between(seed, [0], [designs.length - 1])[0]].code;
function thumb(design, dimension) {
const label = `design ${design.code}, ${design.anf}`;
if (dimension === 2) return ;
try {
return ;
} catch {
return ;
}
}
function grown(design, dimension, level) {
const label = `${design.name} grown to level ${level}`;
if (dimension === 2) return ;
try {
return ;
} catch (error) {
return
{String(error.message ?? error)}
;
}
}
function App() {
const s = useSeeds();
const [pick, set] = useQuery({ d: 2 });
const dimension = pick.d === 3 ? 3 : 2;
const world = WORLD[dimension];
const [level, setLevel] = useState(3);
const [code, setCode] = useState(() => (s.get() ? drawn(s.get(), world.designs) : FIRST[dimension]));
const design = world.designs.find((one) => one.code === code) ?? world.designs[0];
const top = m.level_cap(3, dimension, BUDGET);
const grow = Math.min(level, top);
const cards = useMemo(() => world.designs.map((one) => [one, thumb(one, dimension)]), [dimension]);
const swap = (d) => {
set({ d });
setCode(FIRST[d]);
setLevel(Math.min(level, m.level_cap(3, d, BUDGET)));
};
const controls = (
swap(2)}>plane
swap(3)}>cube
setCode(drawn(s.next(), world.designs))}>Randomize
{dimension === 3 && open in the sponge}
);
return (
A code is a bitmask over the corners of a hypercube. Rotations and reflections fold the codes into orbits, and one design per orbit is all there is: {COUNTS} distinct designs in dimensions 1 to 4. Click one to grow it.>}
foot={<>The distinct counts are Burnside averages over the hyperoctahedral group; the gallery enumerates the orbits outright and the two agree. In base 3 the same count runs {BASE3} for dimensions 1 and 2. The two moves this gallery enumerates, a rule on the corners and that rule substituted into itself, are written up in the core.>}>
{world.distinct} designs from {world.total} codes
{cards.map(([one, art]) => (
setCode(one.code)}
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setCode(one.code); } }}>
{art}
{one.code}
{one.anf}
))}
{design.name}
{grown(design, dimension, grow)}
{design.orbit}
{design.degree}
{design.anf}
{m.fills(design.code, 3, dimension, grow, 2)} of {m.grid_total(3, dimension, grow)}
{m.ratio(design.code, 3, dimension, grow, 2).toFixed(4)}
{m.dimension(design.code, 3, dimension, 2).toFixed(4)}
);
}
mount();