Difference between revisions of "Language"
m |
|||
Line 66: | Line 66: | ||
RETRIEVE "/characters/%1/class" | RETRIEVE "/characters/%1/class" | ||
DISPLAY "Hello mighty %1!" | DISPLAY "Hello mighty %1!" | ||
== Loops == | |||
The whole game code is organized in loops. Each loop has a name and three blocks of commands: ''before-the-loop'', ''in-the-loop'', ''after-the-loop'', executed accordingly. The game begins in the loop named ''main''. | |||
=== The loop itself === | |||
''In-the-loop'' is a special block of commands that are executed iteratively. Also it should contain a special command as its first command, called ''loop specifier''. There are currently two loop classifiers: <code>LOOP N TIMES</code> and <code>LOOP OVER</code>. | |||
<code>LOOP N TIMES</code> simply specifies that the commands in the loop should be executed the number of times specified in the argument: | |||
LOOP N TIMES "20" | |||
DISPLAY "Hi!" | |||
This will display "Hi!" 20 times. From within the loop you can also refer to the iteration number (1-based) using <code>%</code>, so the code: | |||
LOOP N TIMES "20" | |||
DISPLAY "%" | |||
will display numbers from 1 to 20. | |||
The other specifier, <code>LOOP OVER</code>, is a bit more involved, as it iterates over all the subnodes of the specified node in the storage. Therefore, this: | |||
LOOP OVER "/characters" | |||
DISPLAY "%" | |||
will display the data of every character in the game, assuming that we stored them there earlier. | |||
=== Calling other loops === | |||
Loops apart from being... loops, also organize our code into routines that can be invoked from one another. The appropriate command is <code>CALL</code>: | |||
CALL "horribleAdventure" | |||
DISPLAY "Done" | |||
The <code>CALL</code> command will cause the whole code contained in ''horribleAdventure'' loop (including all the iterations of ''in-the-loop'') to execute before displaying "Done". |
Revision as of 14:26, 18 May 2025
Language basics
The language used in Pry with AI is called GameLoops. A game consists of one more game loops, and each game loops contains one or more commands, possibly with arguments, like:
DISPLAY "Hello world!"
By convention command names are written with capitals. All command arguments should be quoted, being formally strings of characters (texts).
Stack
The key concept in GameLoops is a global stack. Some commands can "return" values, and in such a case they push a value at the top of the stack. Like:
PROMPT "Tell me your name:"
asks the player for their name, and puts them at the top of the stack (denoted %1
). So, assuming that the player answered "John", the stack will look like:
%1 "John"
If we then ask the player about their class:
PROMPT "Tell me your class:"
the class will jump on the top of the stack, pushing all the other values "down", and resulting in something like this:
%1 "Warrior" %2 "John"
The thing to remember is that the return values go to the top of the stack, subsequently pushing the existing values "lower".
The values on the stack can be referred to in command arguments. So the command:
DISPLAY "Hello %2, mighty %1!"
will display the text Hello John, mighty Warrior!
The stack in GameLoops can be only pushed to, there is no way to revoke/pop values from it (although they can be retrieved like shown above).
Storing values
Values in GameLoops can also be stored in a single hierarchical storage organized like a tree. Since the values on the stack constantly move downward, the storage provides more predictable way to refer to the most important game data. There are basically two commands for using the storage: STORE
and RETRIEVE
. STORE
puts a value in the tree:
PROMPT "Tell me your name:" STORE "/player/name", "%1" PROMPT "Tell me your class:" STORE "/player/class", "%1"
The first argument above specifies a path (sequence of nodes) in the tree-like storage. So the player name is stored in the subnode "name" of the top-level node "player" and the player class in its subnode "class" in the storage. Both those values can be retrieved at any time to the top of the stack with the RETRIEVE
command:
RETRIEVE "/player/name" DISPLAY "Be greeted %1!"
The storage is hierarchical, so you can also retrieve the whole top-level node "/player":
RETRIEVE "/player" DISPLAY "%1"
The result would be {name: "John", class: "Warrior"}
(as the storage is basically a JSON tree).
Note that it is also perfectly valid to use parameters like %1
in the path, like in the example below:
PROMPT "Tell me your name:" PROMPT "Tell me your class:" STORE "/characters/%2/class", "%1" ... PROMPT "Which character would you like to play?" RETRIEVE "/characters/%1/class" DISPLAY "Hello mighty %1!"
Loops
The whole game code is organized in loops. Each loop has a name and three blocks of commands: before-the-loop, in-the-loop, after-the-loop, executed accordingly. The game begins in the loop named main.
The loop itself
In-the-loop is a special block of commands that are executed iteratively. Also it should contain a special command as its first command, called loop specifier. There are currently two loop classifiers: LOOP N TIMES
and LOOP OVER
.
LOOP N TIMES
simply specifies that the commands in the loop should be executed the number of times specified in the argument:
LOOP N TIMES "20" DISPLAY "Hi!"
This will display "Hi!" 20 times. From within the loop you can also refer to the iteration number (1-based) using %
, so the code:
LOOP N TIMES "20" DISPLAY "%"
will display numbers from 1 to 20.
The other specifier, LOOP OVER
, is a bit more involved, as it iterates over all the subnodes of the specified node in the storage. Therefore, this:
LOOP OVER "/characters" DISPLAY "%"
will display the data of every character in the game, assuming that we stored them there earlier.
Calling other loops
Loops apart from being... loops, also organize our code into routines that can be invoked from one another. The appropriate command is CALL
:
CALL "horribleAdventure" DISPLAY "Done"
The CALL
command will cause the whole code contained in horribleAdventure loop (including all the iterations of in-the-loop) to execute before displaying "Done".