Add checkbox for randomly inverting some symbols. (#43)

This fixes #39 by adding a "Randomly invert symbols" checkbox.

If the inversion is undesirable, disabling it will keep the existing creature but remove the inversion.

Note that this checkbox is only displayed when the creature complexity isn't bonkers.
pull/48/head^2
Atul Varma 2021-03-06 20:35:58 -05:00 zatwierdzone przez GitHub
rodzic 9a610c4cda
commit 1405810526
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
2 zmienionych plików z 46 dodań i 7 usunięć

Wyświetl plik

@ -93,14 +93,17 @@ function getNestingChildren(
*/
function getSymbolWithAttachments(
numAttachmentKinds: number,
rng: Random
{ rng, randomlyInvert: randomlyInvertSymbols }: CreatureGeneratorOptions
): CreatureSymbol {
const root = rng.choice(ROOT_SYMBOLS);
const randomlyInvertRng = rng.clone();
const shouldInvert = () =>
randomlyInvertSymbols ? randomlyInvertRng.bool() : false;
const result: CreatureSymbol = {
data: root,
attachments: [],
nests: getNestingChildren(root, rng, true),
invertColors: false,
invertColors: shouldInvert(),
};
if (root.specs) {
const attachmentKinds = rng.uniqueChoices(
@ -118,7 +121,7 @@ function getSymbolWithAttachments(
indices,
attachments: [],
nests: getNestingChildren(attachment, rng),
invertColors: false,
invertColors: shouldInvert(),
});
}
}
@ -188,7 +191,12 @@ function randomlyReplaceParts<T extends CreatureSymbol>(
return result;
}
type CreatureGenerator = (rng: Random) => CreatureSymbol;
type CreatureGeneratorOptions = {
rng: Random;
randomlyInvert: boolean;
};
type CreatureGenerator = (options: CreatureGeneratorOptions) => CreatureSymbol;
/**
* Each index of this array represents the algorithm we use to
@ -199,7 +207,7 @@ type CreatureGenerator = (rng: Random) => CreatureSymbol;
*/
const COMPLEXITY_LEVEL_GENERATORS: CreatureGenerator[] = [
...range(5).map((i) => getSymbolWithAttachments.bind(null, i)),
(rng) => randomlyReplaceParts(rng, EYE_CREATURE_SYMBOL),
({ rng }) => randomlyReplaceParts(rng, EYE_CREATURE_SYMBOL),
];
const MAX_COMPLEXITY_LEVEL = COMPLEXITY_LEVEL_GENERATORS.length - 1;
@ -218,6 +226,7 @@ export const CreaturePage: React.FC<{}> = () => {
const svgRef = useRef<SVGSVGElement>(null);
const [bgColor, setBgColor] = useState(DEFAULT_BG_COLOR);
const [randomSeed, setRandomSeed] = useState<number | null>(null);
const [randomlyInvert, setRandomlyInvert] = useState(false);
const [symbolCtx, setSymbolCtx] = useState(createSvgSymbolContext());
const [complexity, setComplexity] = useState(MAX_COMPLEXITY_LEVEL);
const defaultCtx = useContext(CreatureContext);
@ -230,9 +239,13 @@ export const CreaturePage: React.FC<{}> = () => {
const creature =
randomSeed === null
? EYE_CREATURE_SYMBOL
: COMPLEXITY_LEVEL_GENERATORS[complexity](new Random(randomSeed));
: COMPLEXITY_LEVEL_GENERATORS[complexity]({
rng: new Random(randomSeed),
randomlyInvert,
});
const handleSvgExport = () =>
exportSvg(getDownloadFilename(randomSeed), svgRef);
const isBonkers = complexity === MAX_COMPLEXITY_LEVEL;
return (
<>
@ -258,8 +271,20 @@ export const CreaturePage: React.FC<{}> = () => {
newRandomSeed();
}}
/>{" "}
{complexity === MAX_COMPLEXITY_LEVEL ? "bonkers" : complexity}
{isBonkers ? "bonkers" : complexity}
</p>
{!isBonkers && (
<p>
<label>
<input
type="checkbox"
checked={randomlyInvert}
onChange={(e) => setRandomlyInvert(e.target.checked)}
/>
Randomly invert symbols
</label>
</p>
)}
<p>
<button accessKey="r" onClick={newRandomSeed}>
<u>R</u>andomize!

Wyświetl plik

@ -24,6 +24,13 @@ export class Random {
this.latestSeed = seed;
}
/**
* Create an exact replica of this instance.
*/
clone(): Random {
return new Random(this.latestSeed, this.params);
}
/**
* Return a random number that is greater than or equal to zero, and less
* than one.
@ -35,6 +42,13 @@ export class Random {
return this.latestSeed / this.params.modulus;
}
/**
* Return a random boolean with the given probability of being true.
*/
bool(trueProbability: number = 0.5): boolean {
return this.next() < trueProbability;
}
/**
* Return a random item from the given array. If the array is
* empty, an exception is thrown.