mirror of
https://github.com/Xevion/100prisoners.git
synced 2025-12-09 10:06:28 -06:00
Show full loop, add onClick box filtering
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import {range} from "../utils/helpers";
|
||||
import {classNames, range} from "../utils/helpers";
|
||||
import BoxGraphic from "./BoxGraphic";
|
||||
import Xarrow from "react-xarrows";
|
||||
|
||||
@@ -30,18 +30,53 @@ const BoxTable = () => {
|
||||
const [sources] = useState<number[]>(range(1, 100));
|
||||
const [destinations] = useState<number[]>(chance.shuffle(sources));
|
||||
const [boxes] = useState<[number, number][]>(sources.map((e, i) => [e, destinations[i] as number]))
|
||||
const [boxesBySource] = useState<Record<number, number>>(Object.fromEntries(boxes));
|
||||
|
||||
const extractLoop = (start: number): number[] => {
|
||||
const results: number[] = [];
|
||||
results.push(start);
|
||||
|
||||
while (true) {
|
||||
const last = results[results.length - 1] as number;
|
||||
const next = boxesBySource[last] as number;
|
||||
if (next == start) break;
|
||||
results.push(next)
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
const [filteredBoxes, setFilteredBoxes] = useState<Record<number, boolean>>(Object.fromEntries(
|
||||
sources.map(n => [n, false])
|
||||
));
|
||||
|
||||
const [enabledLines, setEnabledLines] = useState<Record<number, boolean>>(Object.fromEntries(
|
||||
sources.map(n => [n, false])
|
||||
));
|
||||
|
||||
const showLine = (from: number) => {
|
||||
setEnabledLines((prev) => ({...prev, [from]: true}))
|
||||
const [isFiltered, setFiltered] = useState(false);
|
||||
|
||||
const toggleLines = (from: number) => {
|
||||
hideLine(from);
|
||||
const newState = !isFiltered;
|
||||
setFiltered(newState);
|
||||
showLine(from, newState);
|
||||
|
||||
const loop = Object.fromEntries(extractLoop(from).map(n => [n, false]));
|
||||
setFilteredBoxes((prev) => {
|
||||
const outsideLoop = Object.fromEntries(Object.entries(prev).map(([n]) => [n, newState]))
|
||||
return {...outsideLoop, ...loop};
|
||||
})
|
||||
}
|
||||
|
||||
const showLine = (from: number, showLess: boolean | null = null) => {
|
||||
const loop = Object.fromEntries(extractLoop(from).slice(0, (showLess ?? isFiltered) ? 15 : 3).map(n => [n, true]));
|
||||
setEnabledLines((prev) => ({...prev, ...loop}))
|
||||
}
|
||||
|
||||
const hideLine = (from: number) => {
|
||||
setEnabledLines((prev) => ({...prev, [from]: false}))
|
||||
const loop = Object.fromEntries(extractLoop(from).slice(0, isFiltered ? 15 : 3).map(n => [n, false]));
|
||||
setEnabledLines((prev) => ({...prev, ...loop}))
|
||||
}
|
||||
|
||||
const getColor = (seed: any) => {
|
||||
@@ -55,7 +90,9 @@ const BoxTable = () => {
|
||||
<div className="grid w-full space-y-2"
|
||||
style={{gridTemplateColumns: `repeat(${Math.max(3, columns)}, minmax(0, 1fr))`}}>
|
||||
{boxes.map(([source, destination]) =>
|
||||
<div key={source} className="col-span-1 px-2" onMouseEnter={() => showLine(source)}
|
||||
<div key={source}
|
||||
className={classNames("col-span-1 px-2", isFiltered && filteredBoxes[source] ? "opacity-0 pointer-events-none" : null)}
|
||||
onClick={() => toggleLines(source)} onMouseEnter={() => showLine(source)}
|
||||
onMouseLeave={() => hideLine(source)}>
|
||||
<div
|
||||
className="box flex items-center justify-center aspect-square relative">
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
export const range = (start: number, stop: number, step = 1) =>
|
||||
Array.from({length: (stop - start) / step + 1}, (_, i) => start + i * step);
|
||||
Array.from({length: (stop - start) / step + 1}, (_, i) => start + i * step);
|
||||
|
||||
export function classNames(...classes: (string | null | undefined)[]) {
|
||||
return classes.filter(Boolean).join(" ");
|
||||
}
|
||||
Reference in New Issue
Block a user