Add support for nesting in random creature generation. (#34)

This builds upon #30 and #33 by adding support for randomly nested symbols in complexity levels 0-4 of the creature page.

Currently, we don't _recursively_ nest symbols, so e.g. we won't make an eye containing an eye containing a cube.  And for now we'll only add a nested symbol if the parent symbol has the `always_nest` metadata property defined.
pull/35/head
Atul Varma 2021-02-27 10:02:07 -05:00 zatwierdzone przez GitHub
rodzic b2aab6fa21
commit c803c41bd0
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
1 zmienionych plików z 36 dodań i 2 usunięć

Wyświetl plik

@ -24,6 +24,19 @@ const SYMBOL_MAP = new Map(
SvgVocabulary.map((symbol) => [symbol.name, symbol])
);
/** Symbols that can be the "root" (i.e., main body) of a creature. */
const ROOT_SYMBOLS = SvgVocabulary.filter(
(data) => data.meta?.always_be_nested !== true
);
/** Symbols that can be attached to the main body of a creature. */
const ATTACHMENT_SYMBOLS = ROOT_SYMBOLS;
/** Symbols that can be nested within any part of a creature. */
const NESTED_SYMBOLS = SvgVocabulary.filter(
(data) => data.meta?.always_nest !== true
);
/**
* Returns the data for the given symbol, throwing an error
* if it doesn't exist.
@ -36,6 +49,25 @@ function getSymbol(name: string): SvgSymbolData {
return symbol;
}
/**
* Given a parent symbol, return an array of random children to be nested within
* it.
*
* Can return an empty array e.g. if the parent symbol doesn't have
* any nesting areas.
*/
function getNestingChildren(parent: SvgSymbolData, rng: Random): JSX.Element[] {
const { meta, specs } = parent;
if (meta?.always_nest && specs?.nesting) {
const indices = range(specs.nesting.length);
const child = rng.choice(NESTED_SYMBOLS);
return [
<CreatureSymbol data={child} key="nested" nestInside indices={indices} />,
];
}
return [];
}
/**
* Randomly creates a symbol with the given number of
* types of attachments. The symbol itself, and where the
@ -46,7 +78,7 @@ function getSymbolWithAttachments(
rng: Random
): JSX.Element {
const children: JSX.Element[] = [];
const root = rng.choice(SvgVocabulary);
const root = rng.choice(ROOT_SYMBOLS);
if (root.specs) {
const attachmentKinds = rng.uniqueChoices(
Array.from(iterAttachmentPoints(root.specs))
@ -55,7 +87,7 @@ function getSymbolWithAttachments(
numAttachmentKinds
);
for (let kind of attachmentKinds) {
const attachment = rng.choice(SvgVocabulary);
const attachment = rng.choice(ATTACHMENT_SYMBOLS);
const indices = range(root.specs[kind]?.length ?? 0);
children.push(
<CreatureSymbol
@ -63,10 +95,12 @@ function getSymbolWithAttachments(
key={children.length}
attachTo={kind}
indices={indices}
children={getNestingChildren(attachment, rng)}
/>
);
}
}
children.push(...getNestingChildren(root, rng));
return <CreatureSymbol data={root} children={children} />;
}