mirror of
https://github.com/Xevion/100prisoners.git
synced 2025-12-09 16:06:26 -06:00
Further explanation, add BoxLoop graphic, move getColors into helpers.ts
This commit is contained in:
74
src/components/BoxLoop.tsx
Normal file
74
src/components/BoxLoop.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import React, {FunctionComponent, useState} from "react";
|
||||
import Chance from "chance";
|
||||
import {classNames, getColor, range} from "@/utils/helpers";
|
||||
import {create} from "domain";
|
||||
import BoxGraphic from "@/components/BoxGraphic";
|
||||
import Xarrow from "react-xarrows";
|
||||
|
||||
interface BoxLoopProps {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a loop of numbers in the given range & length.
|
||||
* @param loopRange An array describing the range of numbers to pick from.
|
||||
* @param count The number of items in the loop.
|
||||
*/
|
||||
function createLoop(loopRange: [number, number], count: number): { start: number, loop: Record<number, number>, list: number[] } | undefined {
|
||||
if (loopRange[0] >= loopRange[1]) return undefined;
|
||||
const chance = new Chance();
|
||||
const available = chance.pickset(range(loopRange[0], loopRange[1]), Math.min(count, loopRange[1] - loopRange[0]));
|
||||
const loop: Record<number, number> = {};
|
||||
|
||||
const list: number[] = [];
|
||||
const start = available.pop() as number;
|
||||
let current = start;
|
||||
list.push(start);
|
||||
while (available.length > 0) {
|
||||
const next = available.pop() as number;
|
||||
loop[current] = next;
|
||||
list.push(next);
|
||||
current = next;
|
||||
}
|
||||
loop[current] = start; // Finish the loop
|
||||
|
||||
return {start, loop, list};
|
||||
}
|
||||
|
||||
const BoxLoop: FunctionComponent<BoxLoopProps> = ({}: BoxLoopProps) => {
|
||||
const count = 5;
|
||||
const [{loop, start, list}] = useState(createLoop([1, 100], count)!);
|
||||
|
||||
return <div className="grid grid-cols-5 gap-x-10 pb-5">
|
||||
{list.map((i, index) => {
|
||||
const [sourceKey, destinationKey] = [`x-${i}`, `x-${loop[i]}`];
|
||||
let anchor = ["top", "bottom"];
|
||||
if (index % 2 == 0) anchor.reverse()
|
||||
const isLast = index == count - 1;
|
||||
|
||||
return (
|
||||
<div key={i} className={"col-span-1 aspect-square"}>
|
||||
<div
|
||||
className="box flex items-center justify-center aspect-square relative">
|
||||
<div
|
||||
className="text flex items-center justify-center w-full h-full text-[150%] absolute pt-[30%] cursor-pointer">{loop[i]}</div>
|
||||
<BoxGraphic id={sourceKey}
|
||||
className="w-full transition-all cursor-pointer relative z-30">
|
||||
{i}
|
||||
</BoxGraphic>
|
||||
{loop[i] ?
|
||||
<Xarrow path="smooth" curveness={1.4} color={getColor(i)}
|
||||
startAnchor={isLast ? "bottom" : "right"} endAnchor={isLast ? "bottom" : "left"}
|
||||
showHead={!isLast} headSize={4}
|
||||
_cpy1Offset={isLast ? 100 : 0}
|
||||
_cpx1Offset={isLast ? -200 : 0}
|
||||
start={sourceKey} end={destinationKey.toString()}
|
||||
zIndex={50 + i} divContainerProps={{className: "arrow"}}/> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
|
||||
export default BoxLoop;
|
||||
@@ -3,6 +3,7 @@ import Head from "next/head";
|
||||
import BoxTable from "@/components/BoxTable";
|
||||
import NoSSR from "react-no-ssr";
|
||||
import Page from "@/components/Page";
|
||||
import BoxLoop from "@/components/BoxLoop";
|
||||
|
||||
const Home: NextPage = () => {
|
||||
return (
|
||||
@@ -45,7 +46,7 @@ const Home: NextPage = () => {
|
||||
All prisoners must be successful - if even one fails, they all lose.
|
||||
</li>
|
||||
<li>
|
||||
Prisoners cannot mark, relay or in any way communicate with each other.
|
||||
Prisoners cannot mark boxes, relay information or in any way communicate with each other.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
@@ -53,6 +54,39 @@ const Home: NextPage = () => {
|
||||
this challenge to be impossible - but it turns out there is a strategy that guarantees a
|
||||
<b> 31%</b> chance of success!
|
||||
</p>
|
||||
<p>
|
||||
Here's how it works: <br/>
|
||||
<ol>
|
||||
<li>
|
||||
Go to the box with your number labeled on top of it. Open it.
|
||||
</li>
|
||||
<li>
|
||||
If the number inside is not your slip, then go to the box with the number you just
|
||||
found.
|
||||
</li>
|
||||
<li>
|
||||
Repeat until you find your number.
|
||||
</li>
|
||||
</ol>
|
||||
Due to an interesting mathematical quirk of some (assumed) properties of the game,
|
||||
the boxes have an interesting structure to their existence.
|
||||
</p>
|
||||
<div className="pt-4 pb-2">
|
||||
<BoxLoop/>
|
||||
</div>
|
||||
<p>
|
||||
No matter what number of configuration of boxes is given, a loop, a sequence of numbers that
|
||||
will
|
||||
return to the first one you picked, will exist.
|
||||
<br/>
|
||||
Given that there are only 100 boxes, you won't find a loop that goes on forever,
|
||||
and you won't find a box without a number under it (one that goes nowhere).
|
||||
<br/>
|
||||
</p>
|
||||
<p>
|
||||
Essentially, by following the boxes, it is certain that you will find your slip.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</Page>
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
import Chance from "chance";
|
||||
|
||||
const colors = [
|
||||
"#EF4444",
|
||||
"#F97316",
|
||||
"#F59E0B",
|
||||
"#EAB308",
|
||||
"#84CC16",
|
||||
"#22C55E",
|
||||
"#10B981",
|
||||
"#14B8A6",
|
||||
"#06B6D4",
|
||||
"#0EA5E9",
|
||||
"#3B82F6",
|
||||
"#6366F1",
|
||||
"#8B5CF6",
|
||||
"#A855F7",
|
||||
"#D946EF",
|
||||
"#EC4899",
|
||||
"#F43F5E",
|
||||
]
|
||||
|
||||
export const range = (start: number, stop: number, step = 1) =>
|
||||
Array.from({length: (stop - start) / step + 1}, (_, i) => start + i * step);
|
||||
|
||||
@@ -7,4 +29,9 @@ export function classNames(...classes: (string | null | undefined)[]) {
|
||||
|
||||
export function sum(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
export function getColor(seed: number) {
|
||||
const chance = Chance(seed);
|
||||
return chance.pickone(colors);
|
||||
}
|
||||
Reference in New Issue
Block a user