Designing a Random Table Generator

Here's a link to TableSmith's syntax example:
TableSmith 5.1

It appears that TS considers each thing to be a table file. So even your top-level "roll me some stuff" is basically a table. Hence it's standard .Start table definition in the file.

I think the example syntax I've expanded upon from Morrus would be a bit cleaner.

namely, always use the same begin/end symbol for the macros [] or {} but don't mix. I recommend using something nobody would normally use in their own natural writing, like {} as only programmers use those.

allow for dice notation within the macro {1d6 Monster} which would generate 1-6 monster names

allow for capturing the result as a variable like {$result=Monster} so we can use it again. Note {Monster} and {Monster} would roll up 2 indpendent results, and probably not show the same monster name like a normal person might think.
 

log in or register to remove this ad

But the hard part is ensuring the foundation is expandable.
This!

You're basically facing one of the common problems in object-oriented design:
You need to make sure your 'building-pieces' have the right granularity.

E.g. when creating your EVIL DRAGON COLOUR table you already have to have realized that
a) there are several 'categories' of dragons, i.e. a table DRAGON COLOUR would be to 'loose'
b) it makes sense to keep these categories in separate tables to be more flexible when creating 'meta-tables'.

Finding out late in the process that it would make sense to modifiy a 'base' table's scope can result in a domino-chain of changes to every table referencing your base table.
 

This!

You're basically facing one of the common problems in object-oriented design:
You need to make sure your 'building-pieces' have the right granularity.

E.g. when creating your EVIL DRAGON COLOUR table you already have to have realized that
a) there are several 'categories' of dragons, i.e. a table DRAGON COLOUR would be to 'loose'
b) it makes sense to keep these categories in separate tables to be more flexible when creating 'meta-tables'.

Finding out late in the process that it would make sense to modifiy a 'base' table's scope can result in a domino-chain of changes to every table referencing your base table.

Agreed. this is also where random table generators don't tend to split up individual tables on the output, but instead chain the answer together:

so instead of the dragon is [alignment] [color] [age] the usage is:
there is a [dragon] in front of you

and the dragon table cascades through the other tables (just like the actual printed tables do) to return the result that contains those 3 values as text.
 

So, as someone pointed out to me on CM, there's a fundamental flaw in the logic here.

How do we prevent people creating infinite loops? All it takes is a table (or one of the tables in the tree below it) to refer back to itself or one of the tables above it and the server goes into infinite grind mode.
 

This!

You're basically facing one of the common problems in object-oriented design:
You need to make sure your 'building-pieces' have the right granularity.

E.g. when creating your EVIL DRAGON COLOUR table you already have to have realized that
a) there are several 'categories' of dragons, i.e. a table DRAGON COLOUR would be to 'loose'
b) it makes sense to keep these categories in separate tables to be more flexible when creating 'meta-tables'.

Finding out late in the process that it would make sense to modifiy a 'base' table's scope can result in a domino-chain of changes to every table referencing your base table.

I think that the approach is to have every table have a unique name and a description, with a good browsing/search engine to find the table you want.

So I might create MORRUS EVIL DRAGON COLOURS and someone else might create BOBS EVIL DRAGON COLORS and someone else might create EVIL DRAGON COLOURS OF 5E or what-have-you. As long as each has a decent description, you can browse the tables and simply use the one you like best; or make another one of your own with its own unique name.
 

So, as someone pointed out to me on CM, there's a fundamental flaw in the logic here.

How do we prevent people creating infinite loops? All it takes is a table (or one of the tables in the tree below it) to refer back to itself or one of the tables above it and the server goes into infinite grind mode.

with a syntax that makes it clear what a table name is, it's pretty easy to handle table name uniqueness and refactoring (renaming a table and fixing all references to it).

Part of the "save table" function in the editor can include a recursion check to build a list of all referenced tables (and their table references) to verify the current table doesn't appear in the list (meaning some other table refers to it that the current table refers to).

additionally, each table calling another table puts the caller on the stack (this is how functions in code that call other functions work). when the stack gets full, that's a stack overflow exception. We catch for that and report the problem, and execution is safely terminated.

Basically, it won't really be a problem if it happens, and we can detect it as part of the validation stage when saving a table in the editor
 

I think that the approach is to have every table have a unique name and a description, with a good browsing/search engine to find the table you want.

So I might create MORRUS EVIL DRAGON COLOURS and someone else might create BOBS EVIL DRAGON COLORS and someone else might create EVIL DRAGON COLOURS OF 5E or what-have-you. As long as each has a decent description, you can browse the tables and simply use the one you like best; or make another one of your own with its own unique name.

most definitely, every table/block will have to be uniquely named. It's the only way this will work.

TableSmith appears to have some advanced namespace naming schema so they can specify [Treasure.Art]

But in simple terms, all that really means is they made a table called Treasure.Art and another table called Treasure.Jewelry

I definitely advice against allowing spaces. Spaces should be delimiters for parameters, values, and whatever else we need. Just like spaces are delimiters in normal writing (that means it seperates the words).

that means [MORRUS EVIL DRAGON COLOURS] should really be [MORRUS_EVIL_DRAGON_COLOURS] or [MORRUS.EVIL.DRAGON.COLOURS] or [MORRUSEVILDRAGONCOLOURS] as examples.

though I really like being able to use variables to recieve the value from a table or calculate a table name by concatenating variables, the refactoring and recursion check is happiest when it is guarranteed that we can search all text for [MORRUS EVIL DRAGON COLOURS] and replace it with [MORRUS.EVIL.DRAGON.COLOURS]

any extra wierd crap in there makes it harder to do that with.

this might be why TableSmith uses [] to denote a table reference and {} to do logic or dice notation. Basically clearing delineate the name of an asset (table or block) versus logical bits that have to be computed (like dice notation or if.else logic).

Normal people are going to use the table notation. Keep it simple.

Advanced users are going to use the logic notation, that needs to be robust enough for the job.
 

You're starting to lose me in terminology, I'm afraid (obviously I won't be writing this myself, but I need to create the specifications for it).
 

You're starting to lose me in terminology, I'm afraid (obviously I won't be writing this myself, but I need to create the specifications for it).

Sorry about that, I'm working out the concept myself as we go....

I had written up a nice bit of more explanation, but alas my browser has dumped the whole post before I could copy or submit it.

Just nod your head about how insightful it must have been...
 

Let's start at this layer:

Let's assume there will be 2 kinds of markup, Lookups and Scripts.

Lookups are for Tables and Blocks. They are framed with square brackets and the unique name of the table or block is inside. For example:
this will lookup a dragon from a table [dragon].
Lookups are pretty much exactly what you intended.

At present, there are 2 kinds of Lookups:

Table
this does a die roll, looks up the result and returns the result. The result MAY have have markup to be processed for another LookUp or Script.


Block
Blocks are rich text formatted, multi-line blobs of content. They can contain markup, and be referenced by tables, etc. These let you define stat blocks, descriptive text, whatever is meaty.


Scripts need to be differentiated from Lookups so parsing is easier. Scripts are really for denoting dice rolls and logical/programming statements that clever users can make more powerful things happen. Scripts should use curly braces to define a script section. For example:
This will show the result of 1d6 = {1d6}.

Whenever the Parsing Engine is given content, it looks for {} or [] and replaces them in the original content with the correct content. If it sees [dragon] then it will find the Dragon table and replace that with the result.
The parsing engine applies the same process to every result it returns, so a table result may have markup to indicate further processing is to be done.

It is important that all Lookups be treated the same. The editor can easily manage handling renaming of a table because we can search all text in the system including lookup text for [oldname] and replace it with [newname].

We can also look for infinite loops because when I am saving a table called "MyTable" I can find all other tables/blocks that mine uses and so on and see if [MyTable] occurs or not.

Hopefully this writeup saves, and will be useful to you.
 

Remove ads

Top