Give the graph a loop, and build Tetris with it
A Tetris example project needs to draw 200 board cells and scan rows for a full line. Neither is expressible without iteration, so the node system gets a Repeat node plus the missing text side: Substring, Find text and To number. The interpreter drops its data cache once per round -- otherwise every round would recompute with the first round's values. Object by name takes its name as an input now, not just as a setting; addressing "c" + index is impossible otherwise. An unconnected input reads the stored setting, so saved projects are untouched. The board itself is a 200-character text, "." for empty. That makes both operations of Tetris a single expression instead of a loop, and each frame attempts exactly one move -- rotate beats sideways beats fall -- so the fit check exists once in the whole graph. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9c4148dc1b
commit
4f78c7518c
16 files changed
+1479
-25
No files matched your search
@@ -0,0 +1,16 @@
|
||||
import type { NodeDef } from '../../NodeRegistry';
|
||||
import { asString } from '../../values';
|
||||
import { num, str } from '../shared';
|
||||
|
||||
export const FindText: NodeDef = {
|
||||
type: 'FindText',
|
||||
label: 'Find text',
|
||||
category: 'data',
|
||||
description: 'Where "search" first appears in "text", counting from 0, and −1 when it does not appear.',
|
||||
inputs: [str('text'), str('search')],
|
||||
outputs: [num('index')],
|
||||
params: [],
|
||||
run: (_ctx, inputs) => ({
|
||||
outputs: { index: asString(inputs.text).indexOf(asString(inputs.search)) },
|
||||
}),
|
||||
};
|
||||
@@ -1,13 +1,16 @@
|
||||
import type { NodeDef } from '../../NodeRegistry';
|
||||
import { obj } from '../shared';
|
||||
import { asString } from '../../values';
|
||||
import { obj, str } from '../shared';
|
||||
|
||||
export const ObjectByName: NodeDef = {
|
||||
type: 'ObjectByName',
|
||||
label: 'Object by name',
|
||||
category: 'data',
|
||||
description: 'Finds a scene object by its name.',
|
||||
inputs: [],
|
||||
description:
|
||||
'Finds a scene object by its name. The name is an input, so it can be put together at runtime ' +
|
||||
'("cell" + index).',
|
||||
inputs: [str('name')],
|
||||
outputs: [obj('object')],
|
||||
params: [{ key: 'name', label: 'Name', kind: 'text', default: '' }],
|
||||
run: (ctx, _inputs, params) => ({ outputs: { object: ctx.findByName(String(params.name ?? '')) } }),
|
||||
params: [],
|
||||
run: (ctx, inputs) => ({ outputs: { object: ctx.findByName(asString(inputs.name)) } }),
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { NodeDef } from '../../NodeRegistry';
|
||||
import { asNumber, asString } from '../../values';
|
||||
import { num, str, withDefault } from '../shared';
|
||||
|
||||
export const Substring: NodeDef = {
|
||||
type: 'Substring',
|
||||
label: 'Substring',
|
||||
category: 'data',
|
||||
description:
|
||||
'A part of a text: "count" characters starting at "start" (the first is 0). ' +
|
||||
'A negative count reaches to the end.',
|
||||
inputs: [str('text'), num('start'), withDefault(num('count'), -1)],
|
||||
outputs: [str('text')],
|
||||
params: [],
|
||||
run: (_ctx, inputs) => {
|
||||
const text = asString(inputs.text);
|
||||
const start = Math.max(0, Math.floor(asNumber(inputs.start)));
|
||||
const count = Math.floor(asNumber(inputs.count));
|
||||
return { outputs: { text: count < 0 ? text.slice(start) : text.slice(start, start + count) } };
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { NodeDef } from '../../NodeRegistry';
|
||||
import { asNumber } from '../../values';
|
||||
import { any, num } from '../shared';
|
||||
|
||||
export const ToNumber: NodeDef = {
|
||||
type: 'ToNumber',
|
||||
label: 'To number',
|
||||
category: 'data',
|
||||
description: 'Reads a text as a number. Anything that is not one – an empty text, a word – reads as 0.',
|
||||
inputs: [any('value')],
|
||||
outputs: [num('result')],
|
||||
params: [],
|
||||
run: (_ctx, inputs) => ({ outputs: { result: asNumber(inputs.value) } }),
|
||||
};
|
||||
Reference in new issue
Block a user