From ef7b8aaead2df6666846aeab99701303dfcaa0cb Mon Sep 17 00:00:00 2001 From: HakiRose Date: Mon, 23 Sep 2019 16:08:48 -0400 Subject: [PATCH 1/5] Description of logic files --- docs/source/notes/How_to_design_new_logic.rst | 357 ++++++++++++++++++ docs/source/notes/images/thing_sample.png | Bin 0 -> 91955 bytes 2 files changed, 357 insertions(+) create mode 100644 docs/source/notes/How_to_design_new_logic.rst create mode 100644 docs/source/notes/images/thing_sample.png diff --git a/docs/source/notes/How_to_design_new_logic.rst b/docs/source/notes/How_to_design_new_logic.rst new file mode 100644 index 00000000..c6a1647a --- /dev/null +++ b/docs/source/notes/How_to_design_new_logic.rst @@ -0,0 +1,357 @@ +How to Design a Customized Logic +================================== + +TextWorld is a framework to train and test reinforcement learning agents to play text-based games. It enables +generating games from a game distribution parameterized by the map size, the number of objects, quest length and +complexity, richness of text descriptions, and more. + +The platform is designed to support basic elements of the game such as rooms, doors, supporters, containers, etc. +Each basic element has a specific type (such as thing, player, etc.) and is defined in a logic file with `.twl` +extension. In fact, a logic file basically defines every required logic of the game to communicate with the framework +of the TextWorld as well as Inform7. Each element of the game has a logic file; however, all those files are aggregated +to each other and create a single logic for the whole game. Figure 1 depicts a sample of an element which its type is +"Thing". + +.. |thing_sample| image:: ./images/thing_sample.png + :alt: Thing version + ++------------------+ +| |thing_sample| | ++==================+ +| Thing | ++------------------+ + +There are different sections in a logic file which provide required data to the framework as well as Inform7 to +follow the state change of the game. The basic question is how? +This tutorial addresses this question by designing a new type of element for the game which can perform in addition +to the rest of the elements within the TextWorld platform. + +Moreover, each new game may require new type of element(s) beyond those basic elements provided in the platform. +As an example, a game happening in spaceship requires either some new elements or editing some features of basic +elements. All these customized logic files, which belong to the new game, should be stored in separate folder rather +than the framework's data files. Further details are described at section {Design A new game}. + +First things first; let's start with a new logic file. + +A. Design Of A New Logic +========================== +Each logic file contains various sections based on the features the designer would like to define for the element. +The body of a logic file is two things: type and descriptions. + +Type of an element defines the category of the element within the TextWorld environment, such as thing, object, door, +etc. Each element type can be define with a letter or word; e.g. a thing can be called as `t` and a door can be called +as either `d` or `door`. Each game includes various types in which some types are grouped into a super type, for +instance "thing" is a super type which includes door, container, etc., and "inventory" is a single type which is +independent from thing. Members of a super type are named such that the element and its main category are clarified, +like `d : t` which indicates that the door is a sub-category of the thing. This is given as + +.. code-block:: bash + + type d : t + +After defining the type of an element, the description of the logic comes inside two curly brackets `{.}`. The +description includes various sections. Let's explore each section in details. + +TextWorld performs with two different languages simultaneously; the TextWorld's logic language (called TWLL) and the +Inform7 language (I7L). The TextWorld compiler understands TWLL and the Inform7 can communicate with I7L. Any logic +that the designer creates or edits for a game, should be defined in both languages. So far we have only defined the +element's type in TWLL. The type and potential characteristics of this type (which the latter is optional) should also +be defined in I7L. Each logic file includes some sections which each is used to define a feature of the logic. The +first section, which is introduced, is the inform7 section. In this section, any logic (syntax) defined in TWLL is also +translated to I7L and collected in the inform7 section. Following is an example in which the type of the object is +defined in both languages. + +.. code-block:: bash + + type d : t { + + inform7 { + type { + kind :: "door"; + definition :: "door is openable and lockable."; + } + } + } + +The above example presents the type in both languages. The designer, here, prefers to add two features to the "door +type", as openable and lockable. Any feature which is supposed to be as general feature of this type can be mentioned +in `definition`. Moreover, if there is an initial state that the designer prefers to define to start the game with, +should be mentioned in the definition part. For instance, the designer of our example game likes to have all doors in +the game locked by default, when the game starts. Then "A door is usually locked." is added to definition. Similarly +for a cloth, we can say "cloth are cleanable. A cloth is usually clean.". + +Each game usually include a few rooms with various elements in them. The combination of the initial state of each +element of the game (like a door which is either locked or open) creates the initial state of the game in general. The +game continues state-to-state when the current state of any element of the game changes, e.g. the locked door changes +to unlocked (but closed). This is how the Text-based games perform. + +The next section of a logic file is a "Predicate", which describes various state definition of the logic of the element +using the TWLL. For instance, the states of a door can be either open/close or locked/unlocked. Another feature that +can be defined as predicate is the connectivity of this element with other element(s) in the environment. For example, +a door can link two rooms, described as `link(r, d, r')`, or an object like a glass can be put on a supporter like a +table, described as `on(o, s)`, which `o` stands for object type and `s` stands for supporter type. Any other feature +which defines the state of the element (in some way it also describes the state of the game), and designer would like +to add it, should be described for the framework in TWLL format in the predicate part. Following +is an example of the possible states of a door, in TWLL: + +.. code-block:: bash + + predicates { + open(d); + closed(d); + locked(d); + + link(r, d, r'); + } + +In this example the door can be locked, closed, or open. The unlock state is implicitly defined by closed state. This +door also links two rooms as described. After defining predicates in TWLL, similar to previous part, the predicates +should be described in I7L as well. The following code presents this in both languages + +.. code-block:: bash + + # door + type d : t { + predicates { + open(d); + closed(d); + locked(d); + + link(r, d, r'); + } + + inform7 { + type { + kind :: "door"; + definition :: "door is openable and lockable."; + } + + predicates { + open(d) :: "The {d} is open"; + closed(d) :: "The {d} is closed"; + locked(d) :: "The {d} is locked"; + + link(r, d, r') :: ""; # No equivalent in Inform7. + } + } + } + +There are important notes in this example which is good to elaborate them: + + a. The Inform7 language is very close to simple English language. However, some conditions and exceptions are + applied. For details of Inform7 language please check `http://inform7.com`. + + b. Each type has a unique name which can be a letter or a word. The letter `d` here refers generally to a door type + of element in the game. A door also have a specific name in the game which helps to identify it among all the doors + in the game e.g. "wwoden door". Assigning a specific name to each element of the game is generally an appropriate + solution to distinguish between different elements of the same type (like wooden door vs. glass door). This name + is assigned to `{d}` in the I7L-based text; i.e. "The wooden door is open". + + c. There might be some predicates that the designer would like to define as the logic of the game and they don't + have an I7L equivalent necessarily, like `link(.)` in this example. The framework basically understands it by + defining as empty I7L-based description and performs as designer's wish with no harm. + + d. To make a line as comment, just put a `#` sign at the beginning of the line. + +Door is a simple example to start learning the TWLL and I7L in a logic file. However, door is a built-in element inside +the TextWorld framework. Basically a door links two rooms and if it lockable, there is a key in the game which is +matched with this door. Key is also a built-in element. TextWorld has some built-in designed elements and many games +may require other element(s) rather than the built-in ones. One relevant example which is NOT already in the built-in +elements list is "push button". The framework doesn't know neither what is a push button nor whether it can +open a door, i.e. let's assume that a game designer likes to create a game in which a door can be unlock and open by a +push button. What does she/he do? +Similar to the door, we first need to describe the type and predicates of the push button as described here: + +.. code-block:: bash + + # push button + type b : t { + predicates { + pushed(b); + unpushed(b); + + pair(b, d); + } + + inform7 { + type { + kind :: "button-like"; + definition :: "A button-like can be either pushed or unpushed. A button-like is usually unpushed. A button-like is fixed in place."; + } + + predicates { + pushed(b) :: "The {b} is pushed"; + unpushed(b) :: "The {b} is unpushed"; + + pair(b, d) :: "The {b} pairs to {d}"; + } + } + } + +The push button is presented by `b` letter, it is basically a sub-set of thing, and it is paired with a door. However, +"pair" action is not defined in I7L, thus it should be defined and described for Inform7 that what it means when a door +and a push button are paired. The description of new concept to I7L is provided in "code" sub-section within the +inform7 section in the logic file. + +.. code-block:: bash + + # push button + type b : t { + ... + + inform7 { + ... + + code :: """ + + connectivity relates a button-like to a door. The verb to pair to means the connectivity relation. + + Understand the command "push" as something new. + Understand "push [something]" as _pushing. + _pushing is an action applying to a thing. + + Carry out _pushing: + if a button-like (called pb) pairs to door (called dr): + if dr is locked: + Now the pb is pushed; + Now dr is unlocked; + Now dr is open; + otherwise: + Now the pb is unpushed; + Now dr is locked. + + Report _pushing: + if a button-like (called pb) pairs to door (called dr): + if dr is unlocked: + say "You push the [pb], and [dr] is now open."; + otherwise: + say "You push the [pb] again, and [dr] is now locked." + """ + } + } + +In this example, the "push" command is defined; the compiler expects to have a syntax such as "push [something]" which +the [something] usually is replaced by the name assigned to the push button. It is also described that what changes +are expected to happen when the button is pushed; the button state should change from `unpushed` to `pushed`, the door +state also should be changed from `unlocked` to `open`. The last block is for human interaction and prints out these +changes, thus, it is not mandatory. + +After defining the new instructions to model push button in the game based on inform7 language, next step is to define +a command (or rule) to activate the action on both languages. "Rule" section is another section of logic file. It +describes how the game transforms from one state to another by using the command; see the below example for a simple +`open` rule for a door, + +.. code-block:: bash + + open/d :: $at(P, r) & $link(r, d, r') & $link(r', d, r) & closed(d) -> open(d) & free(r, r') & free(r', r); + +where `at(P, r)` means "the player is at the room" and `free(r, r')` means the path from room r to room r' is clear. +This rule includes two columns which are separated by a `::`. The left column presents the rule's name. This name +should be unique for each rule, thus, if we have two states with different conditions, then their names should be +different, for instance "open/d" vs "open/c" which stand for open door and open container, consecutively. + +The right column of the above rule describes the state change of the game according to the current change and the next +state which the game will turn to, by using this command. As it is depicted, each state contains some predicates +which describe the conditions applied to the elements of the game at that moment (or state) of the game, and provides +eligibility for the defined rule to be applied/called. After calling the rule, it is activated and makes some changes +into the state of the game (or equivalently some selected elements of the game) as it is described on the right side of +the arrow. By these changes, the game will finally transit to the next state. Please be notified that any predicate +which is supported by `$` sign will be kept as unchanged at the next state. + +Equivalently, the I7L version of this rule should be coded in the inform7 part, which is translated again as `open {d}`. +When this command is imported by the player, the inform7 will return a response as the game state, which in this example +is `opening {d}`. This inform-based output is important for the TextWorld framework to identify that the inform +compiler has taken the action of the command (here opening the door) and has transited to the next state. This can be +assumed as acknowledgment to the framework to change the status. All these information are coded in `command` +sub-section inside the inform7 part in the logic file, which is given as + +.. code-block:: bash + + inform7 { + ... + + commands { + open/d :: "open {d}" :: "opening {d}"; + } + } + } + +Similarly, to open a locked door with a push button, it is necessary to have the player at the same room as the push +button is. Then the door is paired with the button, and the two rooms that this door connects to each other should be +declared (note: the door and the button can be located in two different rooms, see the second set of rules below). +Also the door is locked and the button is unpushed. From the `code` section, we realized that the defined command for +this state transition is "push {b}". After this action, the door is unlocked and open and the button is changed to +pushed. The rest of the conditions (predicates) are unchanged. This process is presented in following example for two +scenarios: a) the button and the door ar at the same room, b) the push button is in separate room than the door. + +.. code-block:: bash + + rules { + lock/close/db :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r) & $link(r, d, r') & pushed(b) & open(d) & free(r, r') & free(r', r) -> unpushed(b) & locked(d); + unlock/open/db :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r) & $link(r, d, r') & unpushed(b) & locked(d) -> pushed(b) & open(d) & free(r, r') & free(r', r); + + lock/close/d/b :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r'') & $link(r'', d, r') & pushed(b) & open(d) & free(r', r'') & free(r'', r') -> unpushed(b) & locked(d); + unlock/open/d/b :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r'') & $link(r'', d, r') & unpushed(b) & locked(d) -> pushed(b) & open(d) & free(r', r'') & free(r'', r'); + } + + reverse_rules { + lock/close/d/b :: unlock/open/d/b; + lock/close/db :: unlock/open/db; + } + + inform7 { + ... + + commands { + lock/close/d/b :: "push {b}" :: "_pushing the {b}"; + unlock/open/d/b :: "push {b}" :: "_pushing the {b}"; + + lock/close/db :: "push {b}" :: "_pushing the {b}"; + unlock/open/db :: "push {b}" :: "_pushing the {b}"; + } + } + +As this example illustrates, since the same command is used for an action in two different situations, the rule names +are different, although the command and the inform7 acknowledgement are all the same. + +Have you noticed the reverse_rule section? In this section, the reverse rules are connected to each other to inform the +framework that after taking an action what would be the reverse action to get back to the current state. This provides +the possibility of getting back to a state after moving from it, also provides back and forth exploration within the +environment. + +The last section of a logic file is the `constraints` which defines the failure rules; i.e. describes that which +predicates cannot occur simultaneously in a state. This section is only required to be defined in TWLL. Following is an +example of some selected constraints applied to our example, + +.. code-block:: bash + + constraints { + # Predicate conflicts + d1 :: open(d) & closed(d) -> fail(); + d2 :: open(d) & locked(d) -> fail(); + d3 :: closed(d) & locked(d) -> fail(); + + # A door can't be used to link more than two rooms. + link1 :: link(r, d, r') & link(r, d, r'') -> fail(); + link2 :: link(r, d, r') & link(r'', d, r''') -> fail(); + } + + +Design A New Text Grammar +============================ + + +Design A New Game +==================== +Let's start designing of a new game and learn how to do it. + +Step 1 : Define the New File Directory of the Data Files +---------------------------------------------------------- +The first step of this process is to define the directory of the + + +Step 2 : Create a Game Object +------------------------------- +The first step of each new game design is the creation of an object sample of game maker, called `GameMaker`. + + diff --git a/docs/source/notes/images/thing_sample.png b/docs/source/notes/images/thing_sample.png new file mode 100644 index 0000000000000000000000000000000000000000..0184240bd72bf43806ce43386e649124c91e0d46 GIT binary patch literal 91955 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
O~iR72mjs4B|^09s1e;j7EFXzKth#OASkJx7hgG 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 literal 0 HcmV?d00001 From 1327cf35e7bd9e655cb890bcc12d5ef4c352a950 Mon Sep 17 00:00:00 2001 From: HakiRose Date: Wed, 25 Sep 2019 15:48:20 -0400 Subject: [PATCH 2/5] Description of game design and some minor updates on logic files --- docs/source/notes/How_to_design_new_logic.rst | 145 +++++++++++++++--- 1 file changed, 125 insertions(+), 20 deletions(-) diff --git a/docs/source/notes/How_to_design_new_logic.rst b/docs/source/notes/How_to_design_new_logic.rst index c6a1647a..3a66289a 100644 --- a/docs/source/notes/How_to_design_new_logic.rst +++ b/docs/source/notes/How_to_design_new_logic.rst @@ -1,5 +1,5 @@ -How to Design a Customized Logic -================================== +Chapter 1 : How to Design a Customized Logic +============================================== TextWorld is a framework to train and test reinforcement learning agents to play text-based games. It enables generating games from a game distribution parameterized by the map size, the number of objects, quest length and @@ -127,11 +127,11 @@ should be described in I7L as well. The following code presents this in both lan } predicates { - open(d) :: "The {d} is open"; - closed(d) :: "The {d} is closed"; - locked(d) :: "The {d} is locked"; + open(d) :: "The {d} is open"; + closed(d) :: "The {d} is closed"; + locked(d) :: "The {d} is locked"; - link(r, d, r') :: ""; # No equivalent in Inform7. + link(r, d, r') :: ""; # No equivalent in Inform7. } } } @@ -296,7 +296,7 @@ scenarios: a) the button and the door ar at the same room, b) the push button is reverse_rules { lock/close/d/b :: unlock/open/d/b; - lock/close/db :: unlock/open/db; + lock/close/db :: unlock/open/db; } inform7 { @@ -332,26 +332,131 @@ example of some selected constraints applied to our example, d3 :: closed(d) & locked(d) -> fail(); # A door can't be used to link more than two rooms. - link1 :: link(r, d, r') & link(r, d, r'') -> fail(); - link2 :: link(r, d, r') & link(r'', d, r''') -> fail(); + link1 :: link(r, d, r') & link(r, d, r'') -> fail(); + link2 :: link(r, d, r') & link(r'', d, r''') -> fail(); } -Design A New Text Grammar -============================ +Chapter 2 : How To Design A New Text Grammar +============================================== -Design A New Game -==================== -Let's start designing of a new game and learn how to do it. -Step 1 : Define the New File Directory of the Data Files ----------------------------------------------------------- -The first step of this process is to define the directory of the +Chapter 3 : How To Design A New Game +============================================== +To design a new game, TextWorld framework provides a library to make a game called `GameMaker`. This library requires +to use game logic and text grammar files which we already discussed about them in previous two chapters. By default, +it employs the built-in versions of these two files. If the new design of the game requires the customized version of +them, they should be addressed and imported to the GameMaker. Thus, the first action, needs to be taken, is importation +of the path in which the customized files are stored. The following three lines of code provide this information for +GameMaker library. + +.. code-block:: bash + + from textworld.generator.data import KnowledgeBase + + PATH = pjoin(os.path.dirname(__file__), 'textworld_data') + kb = KnowledgeBase.load(target_dir=PATH) + +To handcraft a new game, the next is to create an object of GameMaker and start creating rooms and elements of the game. +Assume that our handcrafting game is happening in a spaceship and includes two rooms and there is two doors in the game, +one connects these two rooms and one is on the second room opening to outside (nowhere in this scenario). The `player` +is in the first room and both doors are locked. There is a key and a push button matched with each of these doors. The +goal of the game is to find the keys and go out from the second room. The two rooms and the doors are added to the +world by following block of codes. + +.. code-block:: bash + + from textworld import GameMaker + + # ===== World, Rooms, and Doors Design ============================================================================= + gm = GameMaker(kb=kb, theme='spaceship') + room_1 = gm.new_room("Sleep Station") + room_2 = gm.new_room("Control Room") + + corridor = gm.connect(room_1.east, room_2.west) + doorA = gm.new_door(corridor, name="door A") + gm.add_fact("locked", doorA) # Add a fact about the door, e.g. here it is locked. + + doorB = gm.new_door(room_2.south, name="door B") + gm.add_fact("locked", doorB) + +which the `new_room` method is designed to create and add a room to the world; the assigned name of the room should be +imported to the method. `Connect` method is used to connect two rooms to each other. The two inputs of this method +are those rooms which are connected in addition to the direction that the connection is occurred; e.g. here room_1 is +connected to room_2 from its "east" side. If there is a door between two rooms, i.e. the connection includes a door; +`new_door` defines this door and asks to describe the location of the door and its name. The final step is adding the +initial state (i.e. fact) of the door to the game, by using `add_fact`. Facts are basically the state of each element +when the game starts. + +Now, let's define a key and a table in the Sleep station, in which the key is on the table and it is matched with door +A. The method to create both of these elements is `new`. In this method, the type of new element is defined according +to the type definition of the corresponding element at logic files (.twl file). Also, if the designer wants to add some +description to the element it can add it by the `.info.desc` code. This description is displayed any time that the +player imports `look {.}` command. The newly created item should be located somewhere at the world and if it requires +initial state setup, that is defined as well (see `add` and `add_fact` methods). Look the following example + +.. code-block:: bash + + # ===== Box and Key Design ========================================================================================= + table = gm.new(type='s') # Table is a supporter which is fixed in place in the Sleep Station. + table.infos.desc = "It is a metal sturdy table." + room_1.add(table) + + key = gm.new(type='k', name="electronic key") + key.infos.desc = "This key opens the door into the control room area." + table.add(key) + + gm.add_fact("match", key, doorA) # Tell the game 'Electronic key' is matching with door A's lock + +From above code, the key is similarly designed and it is on the table. The key and its corresponding door should be +defined by `add_fact` function again, while the fact is `match`, be advised that match fact accepts two inputs. as a +recall, we defined `on(o, s)` as a predicate which means the object is on the supporter (table here), since the key is +defined as a sub-category of object, the `table.add(key)` syntax models this predicate. For the push button, we assume +that it is in room_2. As we observed so far, adding a push button is similar to the rest and just requires `new` method. + +.. code-block:: bash + + # ===== Push Button Design ========================================================================================= + push_button = gm.new(type='b', name="exit push button") + push_button.infos.desc = "This push button is a an object which opens door B."\ + "This push button is installed on the wall at the control room." + gm.add_fact("unpushed", push_button) + room_2.add(push_button) + +The player and its inventory are also two important parts of the world which should be defined for the game. If the +designer doesn't define where the player is, then the game will put it automatically at the first designed room. When a +player is set by `set_player` command its location is assigned. The graphical representation of the world is also +available by using `render` method. We recommend the readers of this tutorial, to check all above mentioned methods to +find out more details of how they can be employed more flexible within the design of a new game. The last but not least, +the `quest_record` method compiles the new game, generates the world, and starts the game to play. At each state the game, +the player can see the description of the scene and all the corresponding avaialble actions which transforms the player +to another state. + +.. code-block:: bash + + # ===== Player and Inventory Design ================================================================================ + gm.set_player(sleep_station) + + gm.render(interactive=True) + + gm.record_quest() + +The visualization of this game is illustrated at below figure, + +.. |game_sample| image:: ./images/thing_sample.png + :alt: Game version + ++------------------+ +| |game_sample| | ++==================+ +| Game | ++------------------+ + +This tutorial tried to shed a light to Textworld framework and elaborates how new games can be handcrafted using this +framework and cooperate with the customized logic and grammar files. +For further questions please communicate with the technical team of TextWorld project at Microsoft, via ... -Step 2 : Create a Game Object -------------------------------- -The first step of each new game design is the creation of an object sample of game maker, called `GameMaker`. From 79b05e1ad453dcbb27049f14ca9efceafe454f8e Mon Sep 17 00:00:00 2001 From: HakiRose Date: Fri, 27 Sep 2019 16:06:39 -0400 Subject: [PATCH 3/5] First draft of the Game Design Tutorial, includes logic, text-grammar, and game design Documentation --- docs/source/notes/How_to_design_new_logic.rst | 197 +++++++++++++++++- docs/source/notes/images/GameDesign.png | Bin 0 -> 31025 bytes 2 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 docs/source/notes/images/GameDesign.png diff --git a/docs/source/notes/How_to_design_new_logic.rst b/docs/source/notes/How_to_design_new_logic.rst index 3a66289a..3c0c1361 100644 --- a/docs/source/notes/How_to_design_new_logic.rst +++ b/docs/source/notes/How_to_design_new_logic.rst @@ -339,7 +339,188 @@ example of some selected constraints applied to our example, Chapter 2 : How To Design A New Text Grammar ============================================== +In addition to logic files, each game requires a grammar file in which it describes various sentences to be used within +the game. For example, when the player enters a room, a few lines of the greetings to the game, introduction of the +room, the items inside the room, etc. are displayed for the player. This text is compiled by a word parser at Inform7 +using a customized text-grammar file. This file also should be designed by the designer of the game and stored with +`.twg` extension. +To describe this file, it is better to start with greetings. Greetings is a set of various sentences which will be +picked by the parser randomly and will be displayed on output anytime the player either enters into the game or enters +into a room. The greeting should include a general description about the state of the game, the room, or the current +elements of the game. If the generated sentence requires importation of elements or status of the game, that should +also be coded into the sentence. The question is how? Here, we practice writing such sentences. + +Let's first explore a fixed type of greetings. + +.. code-block:: bash + + GREETING : GREETING!;GREETINGS TREKKIE!;HELLO ASTRONAUT!;ALRIGHT THEN!; HEY TREKKIE + +Here, `GREETING` is the code to call the greeting sentence and the right side of semicolon is an array-like of different +options that the parser can pick between them; e.g. in above example, there are five different options and each time the +parser randomly picks one of them as the greeting of the game. Each of these five has the same probability; thus, if we +want to increase the probability of one item, we can repeat that as much as we wish. Moreover, each phrase above is +fixed and will be used as it is. However, it is possible to have a sentence which can be reformed based on the +situation. Following is an example of flexible greeting, + +.. code-block:: bash + + Flex_greeting : #GREETING#, it is TextWorld + +This example explains that we may have "Greeting!, it is TextWorld" or "HEY TREKKIE!, it is TextWorld", or any other +combinations that we can mix and match from "Flex_greeting" and "GREETING". In other words, any word (or combination of +words which are attached by hyphen) and comes in between "#", is like a symbol of another vector of phrases and is +replaced by the parser with one of the phrases from that vector. Following is another example of the creation of the +flexible sentence: + +.. code-block:: bash + + dec : #GREETING# #dec_type##suffix_(r)#;#dec_type##suffix_(r)# + + dec_type : #reg-0#;#difficult-0# + suffix_(r) : . Okay, just remember what is your mission here to do, and everything will go great.; \ + . You try to gain information on your surroundings by using a technique you call 'looking.'; \ + . You can barely contain your excitement.; + . The room seems oddly familiar, as though it were only superficially different from the other rooms in the spacecraft.; \ + . You decide to just list off a complete list of everything you see in the module, because hey, why not?; + + reg-0 : #01#;#02# + difficult-0 : #03# + + 01 : #dec_find-yourself# in a (name);#dec_guess-what# (name) + 02 : Well, here we are in #dec_a_the# (name) + 03 : You're now in #dec_a_the# (name) + + dec_find-yourself : You #dec_what# + dec_guess-what : #dec_well-guess#, you are in #dec_a_the# place we're calling #dec_a_the# + dec_a_the : a;the + dec_what : are;find yourself;arrive + dec_well-guess : Guess what;Well how about that;Well I'll be + +In this example, assume that the #GREETING# #dec_type##suffix_(r)# is randomly picked, to replace GREETING, dec_type, +and suffix_(r) variables, respectively, the "HELLO ASTRONAUT!", "reg-0", and ". Okay, just remember what is your mission +here to do, and everything will go great." are chosen. To replace reg-0, the parser randomly picks "02", and to replace +"02", the "Well, here we are in #dec_a_the# (name)" is selected. In the latter choice of phrase we have two type of +variables, one is "dec_a_the" and the other is "(name)". The first has already described and let's assume that "the" is +picked. For the second, the (name) is replaced by the name of a room that the player is in. Rooms and their names are +described in next chapter. Finally, the created sentence is as follows: + +.. code-block:: bash + + HELLO ASTRONAUT! Well, here we are in the (name). Okay, just remember what is your mission here to do, and everything will go great. + +This sentence is made for a sample state and anytime the game reaches to this state the (name) is replace with the +corresponding room's name and is printed on the screen. To increase the variety of the outputs, a designer can expand +those sentence block to more and more options. However, it is always important to notice that these sentences +should comply with the scenario of the game in general and the specific scene of the game in each state. We recommend +to make a good use of general sentences, and specific type of sentences which can be fed by variable from the game +state (between parentheses variables). Following this advice can give better sentence in accordance to the game story. + +Although the design of a text-grammar file is more depend on the designer's preference rather than the logic file, yet, +there are some sections which should be considered in .twg file. The fundamental sections are named as + + 1. Expandables : All required combinations, structures, etc of words, letters, and numbers which are used in the whole text of the grammar. + 2. Verbs : All verbs which are used as action or simply as verb in the text are collected. + 3. Types & Variables : Type of objects and variables of the game are defined and coded. + 4. Objects Garmmar : The grammar of each object of the game is defined in this section. + 5. Room Description Grammar : All the texts which are used to describe the game inside different rooms are defined and expanded. + 6. Instructions Grammar : The grammar of instructions for compound commands, etc are described. + +Expandables are all the variables which comes in between "#"s and expand to create a sentence. Verbs are also some sort +of expandable in which different synonyms and tense of the verb and its corresponding synonyms are clarified to be used +in text creation and hesitate from repeating a verb frequently, see below example for "take" verb, + +.. code-block:: bash + + take : #take_syn_v# the #obj_types# from the (r).;#take_syn_v# the #obj_types# that's in the (r). + take_syn_v : take;retrieve;grab + take_syn_pp : taken;got;picked + taking : taking;getting;picking + + take/s : #take_syn_v# the #obj_types# from the #on_var#. + + take/c : #take_syn_v# the #obj_types# from the #on_var#. + +"take_syn_v" and "take_syn_pp" respectively refer to the list of synonyms and the past participle of those +synonyms; the ing-form of the verb is the following line. Similar to the logic file description, if we have to assign a +word in different application, like take vs. take from a table, these two can be distinguished by assigning different +code words for each set. To understand this, take a look at above example and compare the definition of "take" with +"take/s". + +Types of all elements in the game can be coded for the grammar to address much easier. For example, "obj_types : (o|k|f)" +indicates all the object, key, or food with the `obj_types`, while "on_types : (c|s)" refers to container or supporter +types which object-like can be put `on` it. Recall that the left-side of the semicolon is just a symbolic way of +representing something which comes on the left-side; so, it is just for text generation and there is no logic behind it. + +In "Objects Grammar" section, every element of the game can have their own grammar and customized nouns and adjectives +to create more sense of the world that the designer tries to build. As an instance, a room can generally be expanded by +an adjective and a noun; if the game refers to an office (work type of room), then the list of adjective-noun pairs +could be different, and based on the game story, the designer can add as much as combinations she/he wishes, to add +more flavour to her/his game. Below is a good example of how different rooms can be assigned with their +own grammar, + +.. code-block:: bash + # --- Rooms --------------------------------------------------------------------- + ## List each type of room with a ';' between each + ## Each roomType must have specific rooms + ### Creating a room: first, take the name of the roomtype as listed under #room_type# (let's call it X for now). + ### Then, create three symbols with this: X_(r), X_(r)_noun, and X_(r)_adj. + ### X_(r) will always be composed of X_(r)_adj | X_(r)_noun. If you want to subdivide a roomtype into two or more variants, you can add _type1, _type2, etc at the end of the noun and adj symbols. + ### Make sure that these changes are also accounted for in the X_(r) token. + + room_type : clean;cook;rest;work;storage + + (r) : #(r)_adj# | #(r)_noun# + (r)_noun : sleep station;crew cabin;washroom;closet;kitchenette;module;lab;lounge + (r)_adj : nondescript;plain + + ### > Rest Room + ### >> Sleep Room + rest_(r) : #rest_(r)_adj_type_1# | #rest_(r)_noun_type_1#;#rest_(r)_adj_type_2# | #rest_(r)_noun_type_2# + + rest_(r)_noun_type_1 : sleep station;sleep station;sleep station;sleeping bag;crew cabin + rest_(r)_adj_type_1 : cozy;relaxing;pleasant;sleepy + ### >> fun with friends + rest_(r)_noun_type_2 : lounge;playroom;recreation zone;crew cabin;crew cabin;crew cabin + rest_(r)_adj_type_2 : fun;entertaining;exciting;well lit;silent + +Majority of the text which is created by the parser belongs to the description of a room. The Room Description Grammar +expands all the grammar which is used for a room to describe the room as well as the scenario at that room. This process +is very similar to what we described in Greetings section. + +Last but not least is the "Instructions Grammar". This part basically includes all the required grammatical structures +which the text-based game needs to compound two actions (like unlock and open), separate two sentence from each other or +to connect them with a word, etc. which are important in the expansion of the sentences all over the game. Following is +a few examples of what is designed for the Spaceship game: + +.. code-block:: bash + # --- Compound Command Description Functions ------------------------------------ + ig_unlock_open : open the locked #lock_types# using the (k).; \ + unlock and open the #lock_types#.; \ + unlock and open the #lock_types# using the (k).; \ + open the #lock_types# using the (k). + ig_unlock_open_take : open the locked #lock_types# using the (k) and take the #obj_types_no_key#.; \ + unlock the #lock_types# and take the #obj_types_no_key#.; \ + unlock the #lock_types# using the (k), and take the #obj_types_no_key#.; \ + take the #obj_types_no_key# from within the locked #lock_types#. + + # --- Separators ----------------------------------------------------------------- + ## *--- Action separators + action_separator_take : #afterhave# #take_syn_pp# the #obj_types#, ; \ + #after# #taking# the #obj_types#, ; \ + With the #obj_types#, ; \ + If you can get your hands on the #obj_types#, ; \ + #emptyinstruction#; + action_separator_eat : #afterhave# #eat_syn_pp# the #eat_types#, ; \ + #after# #eating# the #obj_types#, ; \ + #emptyinstruction#; + + ## *--- Separator Symbols + afterhave : After you have;Having;Once you have;If you have + after : After; + +For further details on these expandables, please check the TextWorld's Spaceship game. Chapter 3 : How To Design A New Game @@ -370,15 +551,17 @@ world by following block of codes. from textworld import GameMaker # ===== World, Rooms, and Doors Design ============================================================================= - gm = GameMaker(kb=kb, theme='spaceship') + gm = GameMaker(kb=kb, theme='Spaceship') room_1 = gm.new_room("Sleep Station") room_2 = gm.new_room("Control Room") + room_3 = gm.new_room("Space") - corridor = gm.connect(room_1.east, room_2.west) - doorA = gm.new_door(corridor, name="door A") - gm.add_fact("locked", doorA) # Add a fact about the door, e.g. here it is locked. + corridor1 = gm.connect(room_1.east, room_2.west) + doorA = gm.new_door(corridor1, name="door A") + gm.add_fact("locked", doorA) # Add a fact about the door, e.g. here it is locked. - doorB = gm.new_door(room_2.south, name="door B") + corridor2 = gm.connect(room_2.east, room_3.west) + doorB = gm.new_door(corridor2, name="door B") gm.add_fact("locked", doorB) which the `new_room` method is designed to create and add a room to the world; the assigned name of the room should be @@ -436,7 +619,7 @@ to another state. .. code-block:: bash # ===== Player and Inventory Design ================================================================================ - gm.set_player(sleep_station) + gm.set_player(room_1) gm.render(interactive=True) @@ -444,7 +627,7 @@ to another state. The visualization of this game is illustrated at below figure, -.. |game_sample| image:: ./images/thing_sample.png +.. |game_sample| image:: ./images/GameDesign.png :alt: Game version +------------------+ diff --git a/docs/source/notes/images/GameDesign.png b/docs/source/notes/images/GameDesign.png new file mode 100644 index 0000000000000000000000000000000000000000..efd6c3d5b49e73e514dae40d4831b3a2e7640f1c GIT binary patch literal 31025 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 Date: Tue, 1 Oct 2019 20:36:00 -0400 Subject: [PATCH 4/5] Rewording, splitting chapters in different files --- docs/source/notes/How_to_design_new_logic.rst | 645 ------------------ docs/source/notes/designing_new_game.rst | 116 ++++ docs/source/notes/designing_new_grammar.rst | 184 +++++ docs/source/notes/designing_new_logic.rst | 351 ++++++++++ .../{thing_sample.png => thing.twl.png} | Bin 5 files changed, 651 insertions(+), 645 deletions(-) delete mode 100644 docs/source/notes/How_to_design_new_logic.rst create mode 100644 docs/source/notes/designing_new_game.rst create mode 100644 docs/source/notes/designing_new_grammar.rst create mode 100644 docs/source/notes/designing_new_logic.rst rename docs/source/notes/images/{thing_sample.png => thing.twl.png} (100%) diff --git a/docs/source/notes/How_to_design_new_logic.rst b/docs/source/notes/How_to_design_new_logic.rst deleted file mode 100644 index 3c0c1361..00000000 --- a/docs/source/notes/How_to_design_new_logic.rst +++ /dev/null @@ -1,645 +0,0 @@ -Chapter 1 : How to Design a Customized Logic -============================================== - -TextWorld is a framework to train and test reinforcement learning agents to play text-based games. It enables -generating games from a game distribution parameterized by the map size, the number of objects, quest length and -complexity, richness of text descriptions, and more. - -The platform is designed to support basic elements of the game such as rooms, doors, supporters, containers, etc. -Each basic element has a specific type (such as thing, player, etc.) and is defined in a logic file with `.twl` -extension. In fact, a logic file basically defines every required logic of the game to communicate with the framework -of the TextWorld as well as Inform7. Each element of the game has a logic file; however, all those files are aggregated -to each other and create a single logic for the whole game. Figure 1 depicts a sample of an element which its type is -"Thing". - -.. |thing_sample| image:: ./images/thing_sample.png - :alt: Thing version - -+------------------+ -| |thing_sample| | -+==================+ -| Thing | -+------------------+ - -There are different sections in a logic file which provide required data to the framework as well as Inform7 to -follow the state change of the game. The basic question is how? -This tutorial addresses this question by designing a new type of element for the game which can perform in addition -to the rest of the elements within the TextWorld platform. - -Moreover, each new game may require new type of element(s) beyond those basic elements provided in the platform. -As an example, a game happening in spaceship requires either some new elements or editing some features of basic -elements. All these customized logic files, which belong to the new game, should be stored in separate folder rather -than the framework's data files. Further details are described at section {Design A new game}. - -First things first; let's start with a new logic file. - -A. Design Of A New Logic -========================== -Each logic file contains various sections based on the features the designer would like to define for the element. -The body of a logic file is two things: type and descriptions. - -Type of an element defines the category of the element within the TextWorld environment, such as thing, object, door, -etc. Each element type can be define with a letter or word; e.g. a thing can be called as `t` and a door can be called -as either `d` or `door`. Each game includes various types in which some types are grouped into a super type, for -instance "thing" is a super type which includes door, container, etc., and "inventory" is a single type which is -independent from thing. Members of a super type are named such that the element and its main category are clarified, -like `d : t` which indicates that the door is a sub-category of the thing. This is given as - -.. code-block:: bash - - type d : t - -After defining the type of an element, the description of the logic comes inside two curly brackets `{.}`. The -description includes various sections. Let's explore each section in details. - -TextWorld performs with two different languages simultaneously; the TextWorld's logic language (called TWLL) and the -Inform7 language (I7L). The TextWorld compiler understands TWLL and the Inform7 can communicate with I7L. Any logic -that the designer creates or edits for a game, should be defined in both languages. So far we have only defined the -element's type in TWLL. The type and potential characteristics of this type (which the latter is optional) should also -be defined in I7L. Each logic file includes some sections which each is used to define a feature of the logic. The -first section, which is introduced, is the inform7 section. In this section, any logic (syntax) defined in TWLL is also -translated to I7L and collected in the inform7 section. Following is an example in which the type of the object is -defined in both languages. - -.. code-block:: bash - - type d : t { - - inform7 { - type { - kind :: "door"; - definition :: "door is openable and lockable."; - } - } - } - -The above example presents the type in both languages. The designer, here, prefers to add two features to the "door -type", as openable and lockable. Any feature which is supposed to be as general feature of this type can be mentioned -in `definition`. Moreover, if there is an initial state that the designer prefers to define to start the game with, -should be mentioned in the definition part. For instance, the designer of our example game likes to have all doors in -the game locked by default, when the game starts. Then "A door is usually locked." is added to definition. Similarly -for a cloth, we can say "cloth are cleanable. A cloth is usually clean.". - -Each game usually include a few rooms with various elements in them. The combination of the initial state of each -element of the game (like a door which is either locked or open) creates the initial state of the game in general. The -game continues state-to-state when the current state of any element of the game changes, e.g. the locked door changes -to unlocked (but closed). This is how the Text-based games perform. - -The next section of a logic file is a "Predicate", which describes various state definition of the logic of the element -using the TWLL. For instance, the states of a door can be either open/close or locked/unlocked. Another feature that -can be defined as predicate is the connectivity of this element with other element(s) in the environment. For example, -a door can link two rooms, described as `link(r, d, r')`, or an object like a glass can be put on a supporter like a -table, described as `on(o, s)`, which `o` stands for object type and `s` stands for supporter type. Any other feature -which defines the state of the element (in some way it also describes the state of the game), and designer would like -to add it, should be described for the framework in TWLL format in the predicate part. Following -is an example of the possible states of a door, in TWLL: - -.. code-block:: bash - - predicates { - open(d); - closed(d); - locked(d); - - link(r, d, r'); - } - -In this example the door can be locked, closed, or open. The unlock state is implicitly defined by closed state. This -door also links two rooms as described. After defining predicates in TWLL, similar to previous part, the predicates -should be described in I7L as well. The following code presents this in both languages - -.. code-block:: bash - - # door - type d : t { - predicates { - open(d); - closed(d); - locked(d); - - link(r, d, r'); - } - - inform7 { - type { - kind :: "door"; - definition :: "door is openable and lockable."; - } - - predicates { - open(d) :: "The {d} is open"; - closed(d) :: "The {d} is closed"; - locked(d) :: "The {d} is locked"; - - link(r, d, r') :: ""; # No equivalent in Inform7. - } - } - } - -There are important notes in this example which is good to elaborate them: - - a. The Inform7 language is very close to simple English language. However, some conditions and exceptions are - applied. For details of Inform7 language please check `http://inform7.com`. - - b. Each type has a unique name which can be a letter or a word. The letter `d` here refers generally to a door type - of element in the game. A door also have a specific name in the game which helps to identify it among all the doors - in the game e.g. "wwoden door". Assigning a specific name to each element of the game is generally an appropriate - solution to distinguish between different elements of the same type (like wooden door vs. glass door). This name - is assigned to `{d}` in the I7L-based text; i.e. "The wooden door is open". - - c. There might be some predicates that the designer would like to define as the logic of the game and they don't - have an I7L equivalent necessarily, like `link(.)` in this example. The framework basically understands it by - defining as empty I7L-based description and performs as designer's wish with no harm. - - d. To make a line as comment, just put a `#` sign at the beginning of the line. - -Door is a simple example to start learning the TWLL and I7L in a logic file. However, door is a built-in element inside -the TextWorld framework. Basically a door links two rooms and if it lockable, there is a key in the game which is -matched with this door. Key is also a built-in element. TextWorld has some built-in designed elements and many games -may require other element(s) rather than the built-in ones. One relevant example which is NOT already in the built-in -elements list is "push button". The framework doesn't know neither what is a push button nor whether it can -open a door, i.e. let's assume that a game designer likes to create a game in which a door can be unlock and open by a -push button. What does she/he do? -Similar to the door, we first need to describe the type and predicates of the push button as described here: - -.. code-block:: bash - - # push button - type b : t { - predicates { - pushed(b); - unpushed(b); - - pair(b, d); - } - - inform7 { - type { - kind :: "button-like"; - definition :: "A button-like can be either pushed or unpushed. A button-like is usually unpushed. A button-like is fixed in place."; - } - - predicates { - pushed(b) :: "The {b} is pushed"; - unpushed(b) :: "The {b} is unpushed"; - - pair(b, d) :: "The {b} pairs to {d}"; - } - } - } - -The push button is presented by `b` letter, it is basically a sub-set of thing, and it is paired with a door. However, -"pair" action is not defined in I7L, thus it should be defined and described for Inform7 that what it means when a door -and a push button are paired. The description of new concept to I7L is provided in "code" sub-section within the -inform7 section in the logic file. - -.. code-block:: bash - - # push button - type b : t { - ... - - inform7 { - ... - - code :: """ - - connectivity relates a button-like to a door. The verb to pair to means the connectivity relation. - - Understand the command "push" as something new. - Understand "push [something]" as _pushing. - _pushing is an action applying to a thing. - - Carry out _pushing: - if a button-like (called pb) pairs to door (called dr): - if dr is locked: - Now the pb is pushed; - Now dr is unlocked; - Now dr is open; - otherwise: - Now the pb is unpushed; - Now dr is locked. - - Report _pushing: - if a button-like (called pb) pairs to door (called dr): - if dr is unlocked: - say "You push the [pb], and [dr] is now open."; - otherwise: - say "You push the [pb] again, and [dr] is now locked." - """ - } - } - -In this example, the "push" command is defined; the compiler expects to have a syntax such as "push [something]" which -the [something] usually is replaced by the name assigned to the push button. It is also described that what changes -are expected to happen when the button is pushed; the button state should change from `unpushed` to `pushed`, the door -state also should be changed from `unlocked` to `open`. The last block is for human interaction and prints out these -changes, thus, it is not mandatory. - -After defining the new instructions to model push button in the game based on inform7 language, next step is to define -a command (or rule) to activate the action on both languages. "Rule" section is another section of logic file. It -describes how the game transforms from one state to another by using the command; see the below example for a simple -`open` rule for a door, - -.. code-block:: bash - - open/d :: $at(P, r) & $link(r, d, r') & $link(r', d, r) & closed(d) -> open(d) & free(r, r') & free(r', r); - -where `at(P, r)` means "the player is at the room" and `free(r, r')` means the path from room r to room r' is clear. -This rule includes two columns which are separated by a `::`. The left column presents the rule's name. This name -should be unique for each rule, thus, if we have two states with different conditions, then their names should be -different, for instance "open/d" vs "open/c" which stand for open door and open container, consecutively. - -The right column of the above rule describes the state change of the game according to the current change and the next -state which the game will turn to, by using this command. As it is depicted, each state contains some predicates -which describe the conditions applied to the elements of the game at that moment (or state) of the game, and provides -eligibility for the defined rule to be applied/called. After calling the rule, it is activated and makes some changes -into the state of the game (or equivalently some selected elements of the game) as it is described on the right side of -the arrow. By these changes, the game will finally transit to the next state. Please be notified that any predicate -which is supported by `$` sign will be kept as unchanged at the next state. - -Equivalently, the I7L version of this rule should be coded in the inform7 part, which is translated again as `open {d}`. -When this command is imported by the player, the inform7 will return a response as the game state, which in this example -is `opening {d}`. This inform-based output is important for the TextWorld framework to identify that the inform -compiler has taken the action of the command (here opening the door) and has transited to the next state. This can be -assumed as acknowledgment to the framework to change the status. All these information are coded in `command` -sub-section inside the inform7 part in the logic file, which is given as - -.. code-block:: bash - - inform7 { - ... - - commands { - open/d :: "open {d}" :: "opening {d}"; - } - } - } - -Similarly, to open a locked door with a push button, it is necessary to have the player at the same room as the push -button is. Then the door is paired with the button, and the two rooms that this door connects to each other should be -declared (note: the door and the button can be located in two different rooms, see the second set of rules below). -Also the door is locked and the button is unpushed. From the `code` section, we realized that the defined command for -this state transition is "push {b}". After this action, the door is unlocked and open and the button is changed to -pushed. The rest of the conditions (predicates) are unchanged. This process is presented in following example for two -scenarios: a) the button and the door ar at the same room, b) the push button is in separate room than the door. - -.. code-block:: bash - - rules { - lock/close/db :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r) & $link(r, d, r') & pushed(b) & open(d) & free(r, r') & free(r', r) -> unpushed(b) & locked(d); - unlock/open/db :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r) & $link(r, d, r') & unpushed(b) & locked(d) -> pushed(b) & open(d) & free(r, r') & free(r', r); - - lock/close/d/b :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r'') & $link(r'', d, r') & pushed(b) & open(d) & free(r', r'') & free(r'', r') -> unpushed(b) & locked(d); - unlock/open/d/b :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r'') & $link(r'', d, r') & unpushed(b) & locked(d) -> pushed(b) & open(d) & free(r', r'') & free(r'', r'); - } - - reverse_rules { - lock/close/d/b :: unlock/open/d/b; - lock/close/db :: unlock/open/db; - } - - inform7 { - ... - - commands { - lock/close/d/b :: "push {b}" :: "_pushing the {b}"; - unlock/open/d/b :: "push {b}" :: "_pushing the {b}"; - - lock/close/db :: "push {b}" :: "_pushing the {b}"; - unlock/open/db :: "push {b}" :: "_pushing the {b}"; - } - } - -As this example illustrates, since the same command is used for an action in two different situations, the rule names -are different, although the command and the inform7 acknowledgement are all the same. - -Have you noticed the reverse_rule section? In this section, the reverse rules are connected to each other to inform the -framework that after taking an action what would be the reverse action to get back to the current state. This provides -the possibility of getting back to a state after moving from it, also provides back and forth exploration within the -environment. - -The last section of a logic file is the `constraints` which defines the failure rules; i.e. describes that which -predicates cannot occur simultaneously in a state. This section is only required to be defined in TWLL. Following is an -example of some selected constraints applied to our example, - -.. code-block:: bash - - constraints { - # Predicate conflicts - d1 :: open(d) & closed(d) -> fail(); - d2 :: open(d) & locked(d) -> fail(); - d3 :: closed(d) & locked(d) -> fail(); - - # A door can't be used to link more than two rooms. - link1 :: link(r, d, r') & link(r, d, r'') -> fail(); - link2 :: link(r, d, r') & link(r'', d, r''') -> fail(); - } - - -Chapter 2 : How To Design A New Text Grammar -============================================== -In addition to logic files, each game requires a grammar file in which it describes various sentences to be used within -the game. For example, when the player enters a room, a few lines of the greetings to the game, introduction of the -room, the items inside the room, etc. are displayed for the player. This text is compiled by a word parser at Inform7 -using a customized text-grammar file. This file also should be designed by the designer of the game and stored with -`.twg` extension. - -To describe this file, it is better to start with greetings. Greetings is a set of various sentences which will be -picked by the parser randomly and will be displayed on output anytime the player either enters into the game or enters -into a room. The greeting should include a general description about the state of the game, the room, or the current -elements of the game. If the generated sentence requires importation of elements or status of the game, that should -also be coded into the sentence. The question is how? Here, we practice writing such sentences. - -Let's first explore a fixed type of greetings. - -.. code-block:: bash - - GREETING : GREETING!;GREETINGS TREKKIE!;HELLO ASTRONAUT!;ALRIGHT THEN!; HEY TREKKIE - -Here, `GREETING` is the code to call the greeting sentence and the right side of semicolon is an array-like of different -options that the parser can pick between them; e.g. in above example, there are five different options and each time the -parser randomly picks one of them as the greeting of the game. Each of these five has the same probability; thus, if we -want to increase the probability of one item, we can repeat that as much as we wish. Moreover, each phrase above is -fixed and will be used as it is. However, it is possible to have a sentence which can be reformed based on the -situation. Following is an example of flexible greeting, - -.. code-block:: bash - - Flex_greeting : #GREETING#, it is TextWorld - -This example explains that we may have "Greeting!, it is TextWorld" or "HEY TREKKIE!, it is TextWorld", or any other -combinations that we can mix and match from "Flex_greeting" and "GREETING". In other words, any word (or combination of -words which are attached by hyphen) and comes in between "#", is like a symbol of another vector of phrases and is -replaced by the parser with one of the phrases from that vector. Following is another example of the creation of the -flexible sentence: - -.. code-block:: bash - - dec : #GREETING# #dec_type##suffix_(r)#;#dec_type##suffix_(r)# - - dec_type : #reg-0#;#difficult-0# - suffix_(r) : . Okay, just remember what is your mission here to do, and everything will go great.; \ - . You try to gain information on your surroundings by using a technique you call 'looking.'; \ - . You can barely contain your excitement.; - . The room seems oddly familiar, as though it were only superficially different from the other rooms in the spacecraft.; \ - . You decide to just list off a complete list of everything you see in the module, because hey, why not?; - - reg-0 : #01#;#02# - difficult-0 : #03# - - 01 : #dec_find-yourself# in a (name);#dec_guess-what# (name) - 02 : Well, here we are in #dec_a_the# (name) - 03 : You're now in #dec_a_the# (name) - - dec_find-yourself : You #dec_what# - dec_guess-what : #dec_well-guess#, you are in #dec_a_the# place we're calling #dec_a_the# - dec_a_the : a;the - dec_what : are;find yourself;arrive - dec_well-guess : Guess what;Well how about that;Well I'll be - -In this example, assume that the #GREETING# #dec_type##suffix_(r)# is randomly picked, to replace GREETING, dec_type, -and suffix_(r) variables, respectively, the "HELLO ASTRONAUT!", "reg-0", and ". Okay, just remember what is your mission -here to do, and everything will go great." are chosen. To replace reg-0, the parser randomly picks "02", and to replace -"02", the "Well, here we are in #dec_a_the# (name)" is selected. In the latter choice of phrase we have two type of -variables, one is "dec_a_the" and the other is "(name)". The first has already described and let's assume that "the" is -picked. For the second, the (name) is replaced by the name of a room that the player is in. Rooms and their names are -described in next chapter. Finally, the created sentence is as follows: - -.. code-block:: bash - - HELLO ASTRONAUT! Well, here we are in the (name). Okay, just remember what is your mission here to do, and everything will go great. - -This sentence is made for a sample state and anytime the game reaches to this state the (name) is replace with the -corresponding room's name and is printed on the screen. To increase the variety of the outputs, a designer can expand -those sentence block to more and more options. However, it is always important to notice that these sentences -should comply with the scenario of the game in general and the specific scene of the game in each state. We recommend -to make a good use of general sentences, and specific type of sentences which can be fed by variable from the game -state (between parentheses variables). Following this advice can give better sentence in accordance to the game story. - -Although the design of a text-grammar file is more depend on the designer's preference rather than the logic file, yet, -there are some sections which should be considered in .twg file. The fundamental sections are named as - - 1. Expandables : All required combinations, structures, etc of words, letters, and numbers which are used in the whole text of the grammar. - 2. Verbs : All verbs which are used as action or simply as verb in the text are collected. - 3. Types & Variables : Type of objects and variables of the game are defined and coded. - 4. Objects Garmmar : The grammar of each object of the game is defined in this section. - 5. Room Description Grammar : All the texts which are used to describe the game inside different rooms are defined and expanded. - 6. Instructions Grammar : The grammar of instructions for compound commands, etc are described. - -Expandables are all the variables which comes in between "#"s and expand to create a sentence. Verbs are also some sort -of expandable in which different synonyms and tense of the verb and its corresponding synonyms are clarified to be used -in text creation and hesitate from repeating a verb frequently, see below example for "take" verb, - -.. code-block:: bash - - take : #take_syn_v# the #obj_types# from the (r).;#take_syn_v# the #obj_types# that's in the (r). - take_syn_v : take;retrieve;grab - take_syn_pp : taken;got;picked - taking : taking;getting;picking - - take/s : #take_syn_v# the #obj_types# from the #on_var#. - - take/c : #take_syn_v# the #obj_types# from the #on_var#. - -"take_syn_v" and "take_syn_pp" respectively refer to the list of synonyms and the past participle of those -synonyms; the ing-form of the verb is the following line. Similar to the logic file description, if we have to assign a -word in different application, like take vs. take from a table, these two can be distinguished by assigning different -code words for each set. To understand this, take a look at above example and compare the definition of "take" with -"take/s". - -Types of all elements in the game can be coded for the grammar to address much easier. For example, "obj_types : (o|k|f)" -indicates all the object, key, or food with the `obj_types`, while "on_types : (c|s)" refers to container or supporter -types which object-like can be put `on` it. Recall that the left-side of the semicolon is just a symbolic way of -representing something which comes on the left-side; so, it is just for text generation and there is no logic behind it. - -In "Objects Grammar" section, every element of the game can have their own grammar and customized nouns and adjectives -to create more sense of the world that the designer tries to build. As an instance, a room can generally be expanded by -an adjective and a noun; if the game refers to an office (work type of room), then the list of adjective-noun pairs -could be different, and based on the game story, the designer can add as much as combinations she/he wishes, to add -more flavour to her/his game. Below is a good example of how different rooms can be assigned with their -own grammar, - -.. code-block:: bash - # --- Rooms --------------------------------------------------------------------- - ## List each type of room with a ';' between each - ## Each roomType must have specific rooms - ### Creating a room: first, take the name of the roomtype as listed under #room_type# (let's call it X for now). - ### Then, create three symbols with this: X_(r), X_(r)_noun, and X_(r)_adj. - ### X_(r) will always be composed of X_(r)_adj | X_(r)_noun. If you want to subdivide a roomtype into two or more variants, you can add _type1, _type2, etc at the end of the noun and adj symbols. - ### Make sure that these changes are also accounted for in the X_(r) token. - - room_type : clean;cook;rest;work;storage - - (r) : #(r)_adj# | #(r)_noun# - (r)_noun : sleep station;crew cabin;washroom;closet;kitchenette;module;lab;lounge - (r)_adj : nondescript;plain - - ### > Rest Room - ### >> Sleep Room - rest_(r) : #rest_(r)_adj_type_1# | #rest_(r)_noun_type_1#;#rest_(r)_adj_type_2# | #rest_(r)_noun_type_2# - - rest_(r)_noun_type_1 : sleep station;sleep station;sleep station;sleeping bag;crew cabin - rest_(r)_adj_type_1 : cozy;relaxing;pleasant;sleepy - ### >> fun with friends - rest_(r)_noun_type_2 : lounge;playroom;recreation zone;crew cabin;crew cabin;crew cabin - rest_(r)_adj_type_2 : fun;entertaining;exciting;well lit;silent - -Majority of the text which is created by the parser belongs to the description of a room. The Room Description Grammar -expands all the grammar which is used for a room to describe the room as well as the scenario at that room. This process -is very similar to what we described in Greetings section. - -Last but not least is the "Instructions Grammar". This part basically includes all the required grammatical structures -which the text-based game needs to compound two actions (like unlock and open), separate two sentence from each other or -to connect them with a word, etc. which are important in the expansion of the sentences all over the game. Following is -a few examples of what is designed for the Spaceship game: - -.. code-block:: bash - # --- Compound Command Description Functions ------------------------------------ - ig_unlock_open : open the locked #lock_types# using the (k).; \ - unlock and open the #lock_types#.; \ - unlock and open the #lock_types# using the (k).; \ - open the #lock_types# using the (k). - ig_unlock_open_take : open the locked #lock_types# using the (k) and take the #obj_types_no_key#.; \ - unlock the #lock_types# and take the #obj_types_no_key#.; \ - unlock the #lock_types# using the (k), and take the #obj_types_no_key#.; \ - take the #obj_types_no_key# from within the locked #lock_types#. - - # --- Separators ----------------------------------------------------------------- - ## *--- Action separators - action_separator_take : #afterhave# #take_syn_pp# the #obj_types#, ; \ - #after# #taking# the #obj_types#, ; \ - With the #obj_types#, ; \ - If you can get your hands on the #obj_types#, ; \ - #emptyinstruction#; - action_separator_eat : #afterhave# #eat_syn_pp# the #eat_types#, ; \ - #after# #eating# the #obj_types#, ; \ - #emptyinstruction#; - - ## *--- Separator Symbols - afterhave : After you have;Having;Once you have;If you have - after : After; - -For further details on these expandables, please check the TextWorld's Spaceship game. - - -Chapter 3 : How To Design A New Game -============================================== -To design a new game, TextWorld framework provides a library to make a game called `GameMaker`. This library requires -to use game logic and text grammar files which we already discussed about them in previous two chapters. By default, -it employs the built-in versions of these two files. If the new design of the game requires the customized version of -them, they should be addressed and imported to the GameMaker. Thus, the first action, needs to be taken, is importation -of the path in which the customized files are stored. The following three lines of code provide this information for -GameMaker library. - -.. code-block:: bash - - from textworld.generator.data import KnowledgeBase - - PATH = pjoin(os.path.dirname(__file__), 'textworld_data') - kb = KnowledgeBase.load(target_dir=PATH) - -To handcraft a new game, the next is to create an object of GameMaker and start creating rooms and elements of the game. -Assume that our handcrafting game is happening in a spaceship and includes two rooms and there is two doors in the game, -one connects these two rooms and one is on the second room opening to outside (nowhere in this scenario). The `player` -is in the first room and both doors are locked. There is a key and a push button matched with each of these doors. The -goal of the game is to find the keys and go out from the second room. The two rooms and the doors are added to the -world by following block of codes. - -.. code-block:: bash - - from textworld import GameMaker - - # ===== World, Rooms, and Doors Design ============================================================================= - gm = GameMaker(kb=kb, theme='Spaceship') - room_1 = gm.new_room("Sleep Station") - room_2 = gm.new_room("Control Room") - room_3 = gm.new_room("Space") - - corridor1 = gm.connect(room_1.east, room_2.west) - doorA = gm.new_door(corridor1, name="door A") - gm.add_fact("locked", doorA) # Add a fact about the door, e.g. here it is locked. - - corridor2 = gm.connect(room_2.east, room_3.west) - doorB = gm.new_door(corridor2, name="door B") - gm.add_fact("locked", doorB) - -which the `new_room` method is designed to create and add a room to the world; the assigned name of the room should be -imported to the method. `Connect` method is used to connect two rooms to each other. The two inputs of this method -are those rooms which are connected in addition to the direction that the connection is occurred; e.g. here room_1 is -connected to room_2 from its "east" side. If there is a door between two rooms, i.e. the connection includes a door; -`new_door` defines this door and asks to describe the location of the door and its name. The final step is adding the -initial state (i.e. fact) of the door to the game, by using `add_fact`. Facts are basically the state of each element -when the game starts. - -Now, let's define a key and a table in the Sleep station, in which the key is on the table and it is matched with door -A. The method to create both of these elements is `new`. In this method, the type of new element is defined according -to the type definition of the corresponding element at logic files (.twl file). Also, if the designer wants to add some -description to the element it can add it by the `.info.desc` code. This description is displayed any time that the -player imports `look {.}` command. The newly created item should be located somewhere at the world and if it requires -initial state setup, that is defined as well (see `add` and `add_fact` methods). Look the following example - -.. code-block:: bash - - # ===== Box and Key Design ========================================================================================= - table = gm.new(type='s') # Table is a supporter which is fixed in place in the Sleep Station. - table.infos.desc = "It is a metal sturdy table." - room_1.add(table) - - key = gm.new(type='k', name="electronic key") - key.infos.desc = "This key opens the door into the control room area." - table.add(key) - - gm.add_fact("match", key, doorA) # Tell the game 'Electronic key' is matching with door A's lock - -From above code, the key is similarly designed and it is on the table. The key and its corresponding door should be -defined by `add_fact` function again, while the fact is `match`, be advised that match fact accepts two inputs. as a -recall, we defined `on(o, s)` as a predicate which means the object is on the supporter (table here), since the key is -defined as a sub-category of object, the `table.add(key)` syntax models this predicate. For the push button, we assume -that it is in room_2. As we observed so far, adding a push button is similar to the rest and just requires `new` method. - -.. code-block:: bash - - # ===== Push Button Design ========================================================================================= - push_button = gm.new(type='b', name="exit push button") - push_button.infos.desc = "This push button is a an object which opens door B."\ - "This push button is installed on the wall at the control room." - gm.add_fact("unpushed", push_button) - room_2.add(push_button) - -The player and its inventory are also two important parts of the world which should be defined for the game. If the -designer doesn't define where the player is, then the game will put it automatically at the first designed room. When a -player is set by `set_player` command its location is assigned. The graphical representation of the world is also -available by using `render` method. We recommend the readers of this tutorial, to check all above mentioned methods to -find out more details of how they can be employed more flexible within the design of a new game. The last but not least, -the `quest_record` method compiles the new game, generates the world, and starts the game to play. At each state the game, -the player can see the description of the scene and all the corresponding avaialble actions which transforms the player -to another state. - -.. code-block:: bash - - # ===== Player and Inventory Design ================================================================================ - gm.set_player(room_1) - - gm.render(interactive=True) - - gm.record_quest() - -The visualization of this game is illustrated at below figure, - -.. |game_sample| image:: ./images/GameDesign.png - :alt: Game version - -+------------------+ -| |game_sample| | -+==================+ -| Game | -+------------------+ - -This tutorial tried to shed a light to Textworld framework and elaborates how new games can be handcrafted using this -framework and cooperate with the customized logic and grammar files. -For further questions please communicate with the technical team of TextWorld project at Microsoft, via ... - - - - diff --git a/docs/source/notes/designing_new_game.rst b/docs/source/notes/designing_new_game.rst new file mode 100644 index 00000000..da70fe3b --- /dev/null +++ b/docs/source/notes/designing_new_game.rst @@ -0,0 +1,116 @@ +Chapter 3 : How To Design A New Game +============================================== +To design a new game, TextWorld framework provides a library to make a game called `GameMaker`. This library requires +to use game logic and text grammar files which we already discussed about them in previous two chapters. By default, +it employs the built-in versions of these two files. If the new design of the game requires the customized version of +them, they should be addressed and imported to the GameMaker. Thus, the first action, needs to be taken, is importation +of the path in which the customized files are stored. The following three lines of code provide this information for +GameMaker library. + +.. code-block:: bash + + from textworld.generator.data import KnowledgeBase + + PATH = pjoin(os.path.dirname(__file__), 'textworld_data') + kb = KnowledgeBase.load(target_dir=PATH) + +To handcraft a new game, the next is to create an object of GameMaker and start creating rooms and elements of the game. +Assume that our handcrafting game is happening in a spaceship and includes two rooms and there is two doors in the game, +one connects these two rooms and one is on the second room opening to outside (nowhere in this scenario). The `player` +is in the first room and both doors are locked. There is a key and a push button matched with each of these doors. The +goal of the game is to find the keys and go out from the second room. The two rooms and the doors are added to the +world by following block of codes. + +.. code-block:: bash + + from textworld import GameMaker + + # ===== World, Rooms, and Doors Design ============================================================================= + gm = GameMaker(kb=kb, theme='Spaceship') + room_1 = gm.new_room("Sleep Station") + room_2 = gm.new_room("Control Room") + room_3 = gm.new_room("Space") + + corridor1 = gm.connect(room_1.east, room_2.west) + doorA = gm.new_door(corridor1, name="door A") + gm.add_fact("locked", doorA) # Add a fact about the door, e.g. here it is locked. + + corridor2 = gm.connect(room_2.east, room_3.west) + doorB = gm.new_door(corridor2, name="door B") + gm.add_fact("locked", doorB) + +which the `new_room` method is designed to create and add a room to the world; the assigned name of the room should be +imported to the method. `Connect` method is used to connect two rooms to each other. The two inputs of this method +are those rooms which are connected in addition to the direction that the connection is occurred; e.g. here room_1 is +connected to room_2 from its "east" side. If there is a door between two rooms, i.e. the connection includes a door; +`new_door` defines this door and asks to describe the location of the door and its name. The final step is adding the +initial state (i.e. fact) of the door to the game, by using `add_fact`. Facts are basically the state of each element +when the game starts. + +Now, let's define a key and a table in the Sleep station, in which the key is on the table and it is matched with door +A. The method to create both of these elements is `new`. In this method, the type of new element is defined according +to the type definition of the corresponding element at logic files (.twl file). Also, if the designer wants to add some +description to the element it can add it by the `.info.desc` code. This description is displayed any time that the +player imports `look {.}` command. The newly created item should be located somewhere at the world and if it requires +initial state setup, that is defined as well (see `add` and `add_fact` methods). Look the following example + +.. code-block:: bash + + # ===== Box and Key Design ========================================================================================= + table = gm.new(type='s') # Table is a supporter which is fixed in place in the Sleep Station. + table.infos.desc = "It is a metal sturdy table." + room_1.add(table) + + key = gm.new(type='k', name="electronic key") + key.infos.desc = "This key opens the door into the control room area." + table.add(key) + + gm.add_fact("match", key, doorA) # Tell the game 'Electronic key' is matching with door A's lock + +From above code, the key is similarly designed and it is on the table. The key and its corresponding door should be +defined by `add_fact` function again, while the fact is `match`, be advised that match fact accepts two inputs. as a +recall, we defined `on(o, s)` as a predicate which means the object is on the supporter (table here), since the key is +defined as a sub-category of object, the `table.add(key)` syntax models this predicate. For the push button, we assume +that it is in room_2. As we observed so far, adding a push button is similar to the rest and just requires `new` method. + +.. code-block:: bash + + # ===== Push Button Design ========================================================================================= + push_button = gm.new(type='b', name="exit push button") + push_button.infos.desc = "This push button is a an object which opens door B."\ + "This push button is installed on the wall at the control room." + gm.add_fact("unpushed", push_button) + room_2.add(push_button) + +The player and its inventory are also two important parts of the world which should be defined for the game. If the +designer doesn't define where the player is, then the game will put it automatically at the first designed room. When a +player is set by `set_player` command its location is assigned. The graphical representation of the world is also +available by using `render` method. We recommend the readers of this tutorial, to check all above mentioned methods to +find out more details of how they can be employed more flexible within the design of a new game. The last but not least, +the `quest_record` method compiles the new game, generates the world, and starts the game to play. At each state the game, +the player can see the description of the scene and all the corresponding avaialble actions which transforms the player +to another state. + +.. code-block:: bash + + # ===== Player and Inventory Design ================================================================================ + gm.set_player(room_1) + + gm.render(interactive=True) + + gm.record_quest() + +The visualization of this game is illustrated at below figure, + +.. |game_sample| image:: ./images/GameDesign.png + :alt: Game version + ++------------------+ +| |game_sample| | ++==================+ +| Game | ++------------------+ + +This tutorial tried to shed a light to Textworld framework and elaborates how new games can be handcrafted using this +framework and cooperate with the customized logic and grammar files. +For further questions please communicate with the technical team of TextWorld project at Microsoft, via ... diff --git a/docs/source/notes/designing_new_grammar.rst b/docs/source/notes/designing_new_grammar.rst new file mode 100644 index 00000000..78f559d8 --- /dev/null +++ b/docs/source/notes/designing_new_grammar.rst @@ -0,0 +1,184 @@ +Chapter 2 : How To Design A New Text Grammar +============================================== +In addition to logic files, each game requires a grammar file in which it describes various sentences to be used within +the game. For example, when the player enters a room, a few lines of the greetings to the game, introduction of the +room, the items inside the room, etc. are displayed for the player. This text is compiled by a word parser at Inform7 +using a customized text-grammar file. This file also should be designed by the designer of the game and stored with +`.twg` extension. + +To describe this file, it is better to start with greetings. Greetings is a set of various sentences which will be +picked by the parser randomly and will be displayed on output anytime the player either enters into the game or enters +into a room. The greeting should include a general description about the state of the game, the room, or the current +elements of the game. If the generated sentence requires importation of elements or status of the game, that should +also be coded into the sentence. The question is how? Here, we practice writing such sentences. + +Let's first explore a fixed type of greetings. + +.. code-block:: bash + + GREETING : GREETING!;GREETINGS TREKKIE!;HELLO ASTRONAUT!;ALRIGHT THEN!; HEY TREKKIE + +Here, `GREETING` is the code to call the greeting sentence and the right side of semicolon is an array-like of different +options that the parser can pick between them; e.g. in above example, there are five different options and each time the +parser randomly picks one of them as the greeting of the game. Each of these five has the same probability; thus, if we +want to increase the probability of one item, we can repeat that as much as we wish. Moreover, each phrase above is +fixed and will be used as it is. However, it is possible to have a sentence which can be reformed based on the +situation. Following is an example of flexible greeting, + +.. code-block:: bash + + Flex_greeting : #GREETING#, it is TextWorld + +This example explains that we may have "Greeting!, it is TextWorld" or "HEY TREKKIE!, it is TextWorld", or any other +combinations that we can mix and match from "Flex_greeting" and "GREETING". In other words, any word (or combination of +words which are attached by hyphen) and comes in between "#", is like a symbol of another vector of phrases and is +replaced by the parser with one of the phrases from that vector. Following is another example of the creation of the +flexible sentence: + +.. code-block:: bash + + dec : #GREETING# #dec_type##suffix_(r)#;#dec_type##suffix_(r)# + + dec_type : #reg-0#;#difficult-0# + suffix_(r) : . Okay, just remember what is your mission here to do, and everything will go great.; \ + . You try to gain information on your surroundings by using a technique you call 'looking.'; \ + . You can barely contain your excitement.; + . The room seems oddly familiar, as though it were only superficially different from the other rooms in the spacecraft.; \ + . You decide to just list off a complete list of everything you see in the module, because hey, why not?; + + reg-0 : #01#;#02# + difficult-0 : #03# + + 01 : #dec_find-yourself# in a (name);#dec_guess-what# (name) + 02 : Well, here we are in #dec_a_the# (name) + 03 : You're now in #dec_a_the# (name) + + dec_find-yourself : You #dec_what# + dec_guess-what : #dec_well-guess#, you are in #dec_a_the# place we're calling #dec_a_the# + dec_a_the : a;the + dec_what : are;find yourself;arrive + dec_well-guess : Guess what;Well how about that;Well I'll be + +In this example, assume that the #GREETING# #dec_type##suffix_(r)# is randomly picked, to replace GREETING, dec_type, +and suffix_(r) variables, respectively, the "HELLO ASTRONAUT!", "reg-0", and ". Okay, just remember what is your mission +here to do, and everything will go great." are chosen. To replace reg-0, the parser randomly picks "02", and to replace +"02", the "Well, here we are in #dec_a_the# (name)" is selected. In the latter choice of phrase we have two type of +variables, one is "dec_a_the" and the other is "(name)". The first has already described and let's assume that "the" is +picked. For the second, the (name) is replaced by the name of a room that the player is in. Rooms and their names are +described in next chapter. Finally, the created sentence is as follows: + +.. code-block:: bash + + HELLO ASTRONAUT! Well, here we are in the (name). Okay, just remember what is your mission here to do, and everything will go great. + +This sentence is made for a sample state and anytime the game reaches to this state the (name) is replace with the +corresponding room's name and is printed on the screen. To increase the variety of the outputs, a designer can expand +those sentence block to more and more options. However, it is always important to notice that these sentences +should comply with the scenario of the game in general and the specific scene of the game in each state. We recommend +to make a good use of general sentences, and specific type of sentences which can be fed by variable from the game +state (between parentheses variables). Following this advice can give better sentence in accordance to the game story. + +Although the design of a text-grammar file is more depend on the designer's preference rather than the logic file, yet, +there are some sections which should be considered in .twg file. The fundamental sections are named as + + 1. Expandables : All required combinations, structures, etc of words, letters, and numbers which are used in the whole text of the grammar. + 2. Verbs : All verbs which are used as action or simply as verb in the text are collected. + 3. Types & Variables : Type of objects and variables of the game are defined and coded. + 4. Objects Garmmar : The grammar of each object of the game is defined in this section. + 5. Room Description Grammar : All the texts which are used to describe the game inside different rooms are defined and expanded. + 6. Instructions Grammar : The grammar of instructions for compound commands, etc are described. + +Expandables are all the variables which comes in between "#"s and expand to create a sentence. Verbs are also some sort +of expandable in which different synonyms and tense of the verb and its corresponding synonyms are clarified to be used +in text creation and hesitate from repeating a verb frequently, see below example for "take" verb, + +.. code-block:: bash + + take : #take_syn_v# the #obj_types# from the (r).;#take_syn_v# the #obj_types# that's in the (r). + take_syn_v : take;retrieve;grab + take_syn_pp : taken;got;picked + taking : taking;getting;picking + + take/s : #take_syn_v# the #obj_types# from the #on_var#. + + take/c : #take_syn_v# the #obj_types# from the #on_var#. + +"take_syn_v" and "take_syn_pp" respectively refer to the list of synonyms and the past participle of those +synonyms; the ing-form of the verb is the following line. Similar to the logic file description, if we have to assign a +word in different application, like take vs. take from a table, these two can be distinguished by assigning different +code words for each set. To understand this, take a look at above example and compare the definition of "take" with +"take/s". + +Types of all elements in the game can be coded for the grammar to address much easier. For example, "obj_types : (o|k|f)" +indicates all the object, key, or food with the `obj_types`, while "on_types : (c|s)" refers to container or supporter +types which object-like can be put `on` it. Recall that the left-side of the semicolon is just a symbolic way of +representing something which comes on the left-side; so, it is just for text generation and there is no logic behind it. + +In "Objects Grammar" section, every element of the game can have their own grammar and customized nouns and adjectives +to create more sense of the world that the designer tries to build. As an instance, a room can generally be expanded by +an adjective and a noun; if the game refers to an office (work type of room), then the list of adjective-noun pairs +could be different, and based on the game story, the designer can add as much as combinations she/he wishes, to add +more flavour to her/his game. Below is a good example of how different rooms can be assigned with their +own grammar, + +.. code-block:: bash + # --- Rooms --------------------------------------------------------------------- + ## List each type of room with a ';' between each + ## Each roomType must have specific rooms + ### Creating a room: first, take the name of the roomtype as listed under #room_type# (let's call it X for now). + ### Then, create three symbols with this: X_(r), X_(r)_noun, and X_(r)_adj. + ### X_(r) will always be composed of X_(r)_adj | X_(r)_noun. If you want to subdivide a roomtype into two or more variants, you can add _type1, _type2, etc at the end of the noun and adj symbols. + ### Make sure that these changes are also accounted for in the X_(r) token. + + room_type : clean;cook;rest;work;storage + + (r) : #(r)_adj# | #(r)_noun# + (r)_noun : sleep station;crew cabin;washroom;closet;kitchenette;module;lab;lounge + (r)_adj : nondescript;plain + + ### > Rest Room + ### >> Sleep Room + rest_(r) : #rest_(r)_adj_type_1# | #rest_(r)_noun_type_1#;#rest_(r)_adj_type_2# | #rest_(r)_noun_type_2# + + rest_(r)_noun_type_1 : sleep station;sleep station;sleep station;sleeping bag;crew cabin + rest_(r)_adj_type_1 : cozy;relaxing;pleasant;sleepy + ### >> fun with friends + rest_(r)_noun_type_2 : lounge;playroom;recreation zone;crew cabin;crew cabin;crew cabin + rest_(r)_adj_type_2 : fun;entertaining;exciting;well lit;silent + +Majority of the text which is created by the parser belongs to the description of a room. The Room Description Grammar +expands all the grammar which is used for a room to describe the room as well as the scenario at that room. This process +is very similar to what we described in Greetings section. + +Last but not least is the "Instructions Grammar". This part basically includes all the required grammatical structures +which the text-based game needs to compound two actions (like unlock and open), separate two sentence from each other or +to connect them with a word, etc. which are important in the expansion of the sentences all over the game. Following is +a few examples of what is designed for the Spaceship game: + +.. code-block:: bash + # --- Compound Command Description Functions ------------------------------------ + ig_unlock_open : open the locked #lock_types# using the (k).; \ + unlock and open the #lock_types#.; \ + unlock and open the #lock_types# using the (k).; \ + open the #lock_types# using the (k). + ig_unlock_open_take : open the locked #lock_types# using the (k) and take the #obj_types_no_key#.; \ + unlock the #lock_types# and take the #obj_types_no_key#.; \ + unlock the #lock_types# using the (k), and take the #obj_types_no_key#.; \ + take the #obj_types_no_key# from within the locked #lock_types#. + + # --- Separators ----------------------------------------------------------------- + ## *--- Action separators + action_separator_take : #afterhave# #take_syn_pp# the #obj_types#, ; \ + #after# #taking# the #obj_types#, ; \ + With the #obj_types#, ; \ + If you can get your hands on the #obj_types#, ; \ + #emptyinstruction#; + action_separator_eat : #afterhave# #eat_syn_pp# the #eat_types#, ; \ + #after# #eating# the #obj_types#, ; \ + #emptyinstruction#; + + ## *--- Separator Symbols + afterhave : After you have;Having;Once you have;If you have + after : After; + +For further details on these expandables, please check the TextWorld's Spaceship game. diff --git a/docs/source/notes/designing_new_logic.rst b/docs/source/notes/designing_new_logic.rst new file mode 100644 index 00000000..36353cb1 --- /dev/null +++ b/docs/source/notes/designing_new_logic.rst @@ -0,0 +1,351 @@ +Chapter 1 : Extending the Game Logic +==================================== + +TextWorld is a framework to train and test reinforcement learning agents to play text-based games. It enables +generating games from a game distribution parameterized by the map size, the number of objects, quest length and +complexity, richness of text descriptions, and more. Each generated game will follow the same dynamics as +defined by the TextWorld's Game Logic (i.e. entity types, predicates, rules, and contraints). + +TextWorld comes with a basic Game Logic that can be used to build games. For instance, it has a limited +set of entity types such as rooms, doors, supporters, containers, objects, etc. +While the builtin Game Logic is very basic, TextWorld allows users to extend it by +modifying or writing new logic files `*.twl`. [TODO: mention where to find those files.] +For convenience, game logic can be split into multiple `.twl` files which +are going to be aggregated to each other at runtime. + +Figure 1 depicts a sample of the `thing` entity. + + +.. figure:: ./images/thing.twl.png + :align: center + :alt: Logic example - Thing entity + + Part of the logic file `thing.twl` describing the `thing` entity. + +As we can see in the figure, there are different sections in a logic file which need to be provided. +Notably, there's a whole section about Inform7_, a programming language and design system for interactive fiction. +TextWorld has to deal with two different languages simultaneously: the TextWorld's Logic Language (TWLL) +and the Inform7 Language (I7L). TextWorld's engine interprets TWLL while Inform7 compiles I7L into either +Z-Machine (.z8) or Glulx (.ulx) games. +Any additions or modifications to the logic should be defined in **both** languages. + +This tutorial goes over the steps needed to add a new type of entity - a push button - in TextWorld. + +A. Declaring a new type +----------------------- +Each entity within a TextWorld environment has a *type*. A *type* defines the possible interactions the +player can have with different objects (e.g., open door), as well as their states (e.g. open/closed or +unlock/locked door). +Each type must be represented by a unique identifier composed of letters and dashes. + +Let's define the a push button type as follows + +.. code-block:: bash + + type push-button { + } + +[TODO: show all basic types and their hierarchy] + +NB: notice how `INVENTORY` is all uppercase. This is used to indicate that there should only be one +object of that type per game. + +A *type* can be a subtype (e.g. `food` is a subtype of `portable_object`) which means it will inherit all +of its parent behaviors (e.g. `food` is also *portable*) and can also define new ones (e.g. `food` is edible). + +Let's our push button be a subtype of `thing`, so we can interact with it in a game: +.. code-block:: bash + + type push-button : thing { + } + + +NB: the type `thing` represents everything that is tangible in a game (e.g. `food`, `containers, etc.) +opposed to abstract concept like `rooms` and `INVENTORY`. + +B. Defining a type +------------------ + +After declaring the type of an element, its definition needs to be put between curly braces `{...}`. Its +definition includes various sections. + +So far, the `push-button` type will only be recognized by the TextWorld Engine but not the Inform7 compiler. +To fix that, a mapping between TWLL's type and I7L's counterpart - a `kind` - must be establish. + +Let's add the relevant I7L code for the `push-button`: +.. code-block:: bash + + type push-button : thing { + + inform7 { + type { + kind :: "push-button"; + } + } + } + +The above example presents the type in both languages. The designer, here, prefers to add two features to the "door +type", as openable and lockable. Any feature which is supposed to be as general feature of this type can be mentioned +in `definition`. Moreover, if there is an initial state that the designer prefers to define to start the game with, +should be mentioned in the definition part. For instance, the designer of our example game likes to have all doors in +the game locked by default, when the game starts. Then "A door is usually locked." is added to definition. Similarly +for a cloth, we can say "cloth are cleanable. A cloth is usually clean.". + +Each game usually include a few rooms with various elements in them. The combination of the initial state of each +element of the game (like a door which is either locked or open) creates the initial state of the game in general. The +game continues state-to-state when the current state of any element of the game changes, e.g. the locked door changes +to unlocked (but closed). This is how the Text-based games perform. + +The next section of a logic file is a "Predicate", which describes various state definition of the logic of the element +using the TWLL. For instance, the states of a door can be either open/close or locked/unlocked. Another feature that +can be defined as predicate is the connectivity of this element with other element(s) in the environment. For example, +a door can link two rooms, described as `link(r, d, r')`, or an object like a glass can be put on a supporter like a +table, described as `on(o, s)`, which `o` stands for object type and `s` stands for supporter type. Any other feature +which defines the state of the element (in some way it also describes the state of the game), and designer would like +to add it, should be described for the framework in TWLL format in the predicate part. Following +is an example of the possible states of a door, in TWLL: + +.. code-block:: bash + + predicates { + open(d); + closed(d); + locked(d); + + link(r, d, r'); + } + +In this example the door can be locked, closed, or open. The unlock state is implicitly defined by closed state. This +door also links two rooms as described. After defining predicates in TWLL, similar to previous part, the predicates +should be described in I7L as well. The following code presents this in both languages + +.. code-block:: bash + + # door + type d : t { + predicates { + open(d); + closed(d); + locked(d); + + link(r, d, r'); + } + + inform7 { + type { + kind :: "door"; + definition :: "door is openable and lockable."; + } + + predicates { + open(d) :: "The {d} is open"; + closed(d) :: "The {d} is closed"; + locked(d) :: "The {d} is locked"; + + link(r, d, r') :: ""; # No equivalent in Inform7. + } + } + } + +There are important notes in this example which is good to elaborate them: + + a. The Inform7 language is very close to simple English language. However, some conditions and exceptions are + applied. For details of Inform7 language please check `http://inform7.com`. + + b. Each type has a unique name which can be a letter or a word. The letter `d` here refers generally to a door type + of element in the game. A door also have a specific name in the game which helps to identify it among all the doors + in the game e.g. "wooden door". Assigning a specific name to each element of the game is generally an appropriate + solution to distinguish between different elements of the same type (like wooden door vs. glass door). This name + is assigned to `{d}` in the I7L-based text; i.e. "The wooden door is open". + + c. There might be some predicates that the designer would like to define as the logic of the game and they don't + have an I7L equivalent necessarily, like `link(.)` in this example. The framework basically understands it by + defining as empty I7L-based description and performs as designer's wish with no harm. + + d. To make a line as comment, just put a `#` sign at the beginning of the line. + +Door is a simple example to start learning the TWLL and I7L in a logic file. However, door is a built-in element inside +the TextWorld framework. Basically a door links two rooms and if it lockable, there is a key in the game which is +matched with this door. Key is also a built-in element. TextWorld has some built-in designed elements and many games +may require other element(s) rather than the built-in ones. One relevant example which is NOT already in the built-in +elements list is "push button". The framework doesn't know neither what is a push button nor whether it can +open a door, i.e. let's assume that a game designer likes to create a game in which a door can be unlock and open by a +push button. What does she/he do? +Similar to the door, we first need to describe the type and predicates of the push button as described here: + +.. code-block:: bash + + # push button + type b : t { + predicates { + pushed(b); + unpushed(b); + + pair(b, d); + } + + inform7 { + type { + kind :: "button-like"; + definition :: "A button-like can be either pushed or unpushed. A button-like is usually unpushed. A button-like is fixed in place."; + } + + predicates { + pushed(b) :: "The {b} is pushed"; + unpushed(b) :: "The {b} is unpushed"; + + pair(b, d) :: "The {b} pairs to {d}"; + } + } + } + +The push button is presented by `b` letter, it is basically a sub-set of thing, and it is paired with a door. However, +"pair" action is not defined in I7L, thus it should be defined and described for Inform7 that what it means when a door +and a push button are paired. The description of new concept to I7L is provided in "code" sub-section within the +inform7 section in the logic file. + +.. code-block:: bash + + # push button + type b : t { + ... + + inform7 { + ... + + code :: """ + + connectivity relates a button-like to a door. The verb to pair to means the connectivity relation. + + Understand the command "push" as something new. + Understand "push [something]" as _pushing. + _pushing is an action applying to a thing. + + Carry out _pushing: + if a button-like (called pb) pairs to door (called dr): + if dr is locked: + Now the pb is pushed; + Now dr is unlocked; + Now dr is open; + otherwise: + Now the pb is unpushed; + Now dr is locked. + + Report _pushing: + if a button-like (called pb) pairs to door (called dr): + if dr is unlocked: + say "You push the [pb], and [dr] is now open."; + otherwise: + say "You push the [pb] again, and [dr] is now locked." + """ + } + } + +In this example, the "push" command is defined; the compiler expects to have a syntax such as "push [something]" which +the [something] usually is replaced by the name assigned to the push button. It is also described that what changes +are expected to happen when the button is pushed; the button state should change from `unpushed` to `pushed`, the door +state also should be changed from `unlocked` to `open`. The last block is for human interaction and prints out these +changes, thus, it is not mandatory. + +After defining the new instructions to model push button in the game based on inform7 language, next step is to define +a command (or rule) to activate the action on both languages. "Rule" section is another section of logic file. It +describes how the game transforms from one state to another by using the command; see the below example for a simple +`open` rule for a door, + +.. code-block:: bash + + open/d :: $at(P, r) & $link(r, d, r') & $link(r', d, r) & closed(d) -> open(d) & free(r, r') & free(r', r); + +where `at(P, r)` means "the player is at the room" and `free(r, r')` means the path from room r to room r' is clear. +This rule includes two columns which are separated by a `::`. The left column presents the rule's name. This name +should be unique for each rule, thus, if we have two states with different conditions, then their names should be +different, for instance "open/d" vs "open/c" which stand for open door and open container, consecutively. + +The right column of the above rule describes the state change of the game according to the current change and the next +state which the game will turn to, by using this command. As it is depicted, each state contains some predicates +which describe the conditions applied to the elements of the game at that moment (or state) of the game, and provides +eligibility for the defined rule to be applied/called. After calling the rule, it is activated and makes some changes +into the state of the game (or equivalently some selected elements of the game) as it is described on the right side of +the arrow. By these changes, the game will finally transit to the next state. Please be notified that any predicate +which is supported by `$` sign will be kept as unchanged at the next state. + +Equivalently, the I7L version of this rule should be coded in the inform7 part, which is translated again as `open {d}`. +When this command is imported by the player, the inform7 will return a response as the game state, which in this example +is `opening {d}`. This inform-based output is important for the TextWorld framework to identify that the inform +compiler has taken the action of the command (here opening the door) and has transited to the next state. This can be +assumed as acknowledgment to the framework to change the status. All these information are coded in `command` +sub-section inside the inform7 part in the logic file, which is given as + +.. code-block:: bash + + inform7 { + ... + + commands { + open/d :: "open {d}" :: "opening {d}"; + } + } + } + +Similarly, to open a locked door with a push button, it is necessary to have the player at the same room as the push +button is. Then the door is paired with the button, and the two rooms that this door connects to each other should be +declared (note: the door and the button can be located in two different rooms, see the second set of rules below). +Also the door is locked and the button is unpushed. From the `code` section, we realized that the defined command for +this state transition is "push {b}". After this action, the door is unlocked and open and the button is changed to +pushed. The rest of the conditions (predicates) are unchanged. This process is presented in following example for two +scenarios: a) the button and the door ar at the same room, b) the push button is in separate room than the door. + +.. code-block:: bash + + rules { + lock/close/db :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r) & $link(r, d, r') & pushed(b) & open(d) & free(r, r') & free(r', r) -> unpushed(b) & locked(d); + unlock/open/db :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r) & $link(r, d, r') & unpushed(b) & locked(d) -> pushed(b) & open(d) & free(r, r') & free(r', r); + + lock/close/d/b :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r'') & $link(r'', d, r') & pushed(b) & open(d) & free(r', r'') & free(r'', r') -> unpushed(b) & locked(d); + unlock/open/d/b :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r'') & $link(r'', d, r') & unpushed(b) & locked(d) -> pushed(b) & open(d) & free(r', r'') & free(r'', r'); + } + + reverse_rules { + lock/close/d/b :: unlock/open/d/b; + lock/close/db :: unlock/open/db; + } + + inform7 { + ... + + commands { + lock/close/d/b :: "push {b}" :: "_pushing the {b}"; + unlock/open/d/b :: "push {b}" :: "_pushing the {b}"; + + lock/close/db :: "push {b}" :: "_pushing the {b}"; + unlock/open/db :: "push {b}" :: "_pushing the {b}"; + } + } + +As this example illustrates, since the same command is used for an action in two different situations, the rule names +are different, although the command and the inform7 acknowledgement are all the same. + +Have you noticed the reverse_rule section? In this section, the reverse rules are connected to each other to inform the +framework that after taking an action what would be the reverse action to get back to the current state. This provides +the possibility of getting back to a state after moving from it, also provides back and forth exploration within the +environment. + +The last section of a logic file is the `constraints` which defines the failure rules; i.e. describes that which +predicates cannot occur simultaneously in a state. This section is only required to be defined in TWLL. Following is an +example of some selected constraints applied to our example, + +.. code-block:: bash + + constraints { + # Predicate conflicts + d1 :: open(d) & closed(d) -> fail(); + d2 :: open(d) & locked(d) -> fail(); + d3 :: closed(d) & locked(d) -> fail(); + + # A door can't be used to link more than two rooms. + link1 :: link(r, d, r') & link(r, d, r'') -> fail(); + link2 :: link(r, d, r') & link(r'', d, r''') -> fail(); + } + + +.. _Inform7: http://www.inform7.com/ diff --git a/docs/source/notes/images/thing_sample.png b/docs/source/notes/images/thing.twl.png similarity index 100% rename from docs/source/notes/images/thing_sample.png rename to docs/source/notes/images/thing.twl.png From f31c731dcf57bae25c54ee81555d9fa0f7129c80 Mon Sep 17 00:00:00 2001 From: HakiRose <38758670+HakiRose@users.noreply.github.com> Date: Thu, 10 Oct 2019 10:52:37 -0400 Subject: [PATCH 5/5] Update designing_new_logic.rst Update version V3 on the desgn of new logic --- docs/source/notes/designing_new_logic.rst | 295 +++++++++++++--------- 1 file changed, 173 insertions(+), 122 deletions(-) diff --git a/docs/source/notes/designing_new_logic.rst b/docs/source/notes/designing_new_logic.rst index 36353cb1..51c16259 100644 --- a/docs/source/notes/designing_new_logic.rst +++ b/docs/source/notes/designing_new_logic.rst @@ -1,5 +1,5 @@ -Chapter 1 : Extending the Game Logic -==================================== +Chapter 2 : Extending the Game Logic +===================================== TextWorld is a framework to train and test reinforcement learning agents to play text-based games. It enables generating games from a game distribution parameterized by the map size, the number of objects, quest length and @@ -9,9 +9,13 @@ defined by the TextWorld's Game Logic (i.e. entity types, predicates, rules, and TextWorld comes with a basic Game Logic that can be used to build games. For instance, it has a limited set of entity types such as rooms, doors, supporters, containers, objects, etc. While the builtin Game Logic is very basic, TextWorld allows users to extend it by -modifying or writing new logic files `*.twl`. [TODO: mention where to find those files.] -For convenience, game logic can be split into multiple `.twl` files which -are going to be aggregated to each other at runtime. +modifying or writing new logic files `*.twl`. The basic logic files are collected at following directory: +`TextWorld \\ textworld \\ generator \\ data \\ logic`. These files are built-in logic files and cannot be modified by +the designer for any new theme. Hence, usually designers collect their own files in the following directory: +`TextWorld \\ textworld \\ challenges \\ (new_game_name) \\ textworld_data \\ logic`. Any changes into the basic +entities or any newly designed entity is provided here, and should be called during the "new game design" (This process +is described in `designing_new_game.rst` with more details). For convenience, game logic can be split into multiple +`.twl` files which are going to be aggregated to each other at runtime. Figure 1 depicts a sample of the `thing` entity. @@ -33,9 +37,9 @@ This tutorial goes over the steps needed to add a new type of entity - a push bu A. Declaring a new type ----------------------- -Each entity within a TextWorld environment has a *type*. A *type* defines the possible interactions the -player can have with different objects (e.g., open door), as well as their states (e.g. open/closed or -unlock/locked door). +World in any text-based game contains various entities which create the world. Each entity within a TextWorld +environment has a *type*. A *type* defines the possible interactions the player can have with different objects (e.g., +open door), as well as their states (e.g. open/closed or unlock/locked door). Each type must be represented by a unique identifier composed of letters and dashes. Let's define the a push button type as follows @@ -45,7 +49,19 @@ Let's define the a push button type as follows type push-button { } -[TODO: show all basic types and their hierarchy] +The basic logic entities, which are categorized as built-in entities in TextWorld framework, are defined and +organized as follows: + +.. code-block:: bash + + - room (as "r") + - Player (as "P") + - INVENTORY (as "I") + - thing (as "t") ----------> supporter (as "s") + |---> door (as "d") + |---> container (as "c") + |---> object (as "o") ---------->> food (as "f") + |--->> key (as "k") NB: notice how `INVENTORY` is all uppercase. This is used to indicate that there should only be one object of that type per game. @@ -54,25 +70,26 @@ A *type* can be a subtype (e.g. `food` is a subtype of `portable_object`) which of its parent behaviors (e.g. `food` is also *portable*) and can also define new ones (e.g. `food` is edible). Let's our push button be a subtype of `thing`, so we can interact with it in a game: + .. code-block:: bash type push-button : thing { } - -NB: the type `thing` represents everything that is tangible in a game (e.g. `food`, `containers, etc.) +NB: the type `thing` represents everything that is tangible in a game (e.g. `food`, `containers`, etc.) opposed to abstract concept like `rooms` and `INVENTORY`. B. Defining a type ------------------ -After declaring the type of an element, its definition needs to be put between curly braces `{...}`. Its +After declaring the type of an entity, its definition needs to be put between curly braces `{...}`. Its definition includes various sections. So far, the `push-button` type will only be recognized by the TextWorld Engine but not the Inform7 compiler. To fix that, a mapping between TWLL's type and I7L's counterpart - a `kind` - must be establish. Let's add the relevant I7L code for the `push-button`: + .. code-block:: bash type push-button : thing { @@ -84,35 +101,55 @@ Let's add the relevant I7L code for the `push-button`: } } -The above example presents the type in both languages. The designer, here, prefers to add two features to the "door -type", as openable and lockable. Any feature which is supposed to be as general feature of this type can be mentioned -in `definition`. Moreover, if there is an initial state that the designer prefers to define to start the game with, -should be mentioned in the definition part. For instance, the designer of our example game likes to have all doors in -the game locked by default, when the game starts. Then "A door is usually locked." is added to definition. Similarly -for a cloth, we can say "cloth are cleanable. A cloth is usually clean.". +The above example presents the type in both languages. Another relevant and simple example is a built-in entity inside +the TextWorld framework, called `door`. Below is the details of the door entity: + +.. code-block:: bash + + # door + type door : thing { + + inform7 { + type { + kind :: "door"; + definition :: "door is openable and lockable. A door is usually locked."; + } + } + } + +The designer, here, prefers to add two features to the `door` type, as openable and lockable. Any feature which is +supposed to be as general feature of this type can be mentioned in `definition`. Moreover, if there is an initial state +that the designer prefers to define to start the game with, should be mentioned in the definition part. For instance, +the designer of our example game likes to have all doors in the game locked by default, when the game starts. Then "A +door is usually locked." is added to definition. Similarly for a cloth, we can say "cloth are cleanable. A cloth is +usually clean.". -Each game usually include a few rooms with various elements in them. The combination of the initial state of each -element of the game (like a door which is either locked or open) creates the initial state of the game in general. The -game continues state-to-state when the current state of any element of the game changes, e.g. the locked door changes +Each game usually include a few rooms with various entities in them. The combination of the initial state of each +entity of the game (like a door which is either locked or open) creates the initial state of the game in general. The +game continues state-to-state when the current state of any entity of the game changes, e.g. the locked door changes to unlocked (but closed). This is how the Text-based games perform. -The next section of a logic file is a "Predicate", which describes various state definition of the logic of the element + +C. Defining a predicate +------------------------- + +The next section of a logic file is a "Predicate", which describes various state definition of the logic of the entity using the TWLL. For instance, the states of a door can be either open/close or locked/unlocked. Another feature that -can be defined as predicate is the connectivity of this element with other element(s) in the environment. For example, -a door can link two rooms, described as `link(r, d, r')`, or an object like a glass can be put on a supporter like a +can be defined as predicate is the connectivity of this entity with other entity(ies) in the environment. For example, +a door can link two rooms, described as `link(r, door, r')`, or an object like a glass can be put on a supporter like a table, described as `on(o, s)`, which `o` stands for object type and `s` stands for supporter type. Any other feature -which defines the state of the element (in some way it also describes the state of the game), and designer would like -to add it, should be described for the framework in TWLL format in the predicate part. Following -is an example of the possible states of a door, in TWLL: +which defines the state of the entity (in some way it also describes the state of the game), and designer would like +to add it, should be described for the framework in TWLL format in the predicate part. Following is an example of the +possible states of a door, in TWLL: .. code-block:: bash predicates { - open(d); - closed(d); - locked(d); + open(door); + closed(door); + locked(door); - link(r, d, r'); + link(room, door, room'); } In this example the door can be locked, closed, or open. The unlock state is implicitly defined by closed state. This @@ -122,27 +159,27 @@ should be described in I7L as well. The following code presents this in both lan .. code-block:: bash # door - type d : t { + type door : thing { predicates { - open(d); - closed(d); - locked(d); + open(door); + closed(door); + locked(door); - link(r, d, r'); + link(room, door, room'); } inform7 { type { kind :: "door"; - definition :: "door is openable and lockable."; + definition :: "door is openable and lockable. A door is usually locked."; } predicates { - open(d) :: "The {d} is open"; - closed(d) :: "The {d} is closed"; - locked(d) :: "The {d} is locked"; + open(door) :: "The {door} is open"; + closed(door) :: "The {door} is closed"; + locked(door) :: "The {door} is locked"; - link(r, d, r') :: ""; # No equivalent in Inform7. + link(room, door, room') :: ""; # No equivalent in Inform7. } } } @@ -152,11 +189,11 @@ There are important notes in this example which is good to elaborate them: a. The Inform7 language is very close to simple English language. However, some conditions and exceptions are applied. For details of Inform7 language please check `http://inform7.com`. - b. Each type has a unique name which can be a letter or a word. The letter `d` here refers generally to a door type - of element in the game. A door also have a specific name in the game which helps to identify it among all the doors - in the game e.g. "wooden door". Assigning a specific name to each element of the game is generally an appropriate - solution to distinguish between different elements of the same type (like wooden door vs. glass door). This name - is assigned to `{d}` in the I7L-based text; i.e. "The wooden door is open". + b. Each type has a unique name which can contain a letter, a word, or combination of either with dash. A door also + have a specific name in the game which helps to identify it among all the doors in the game e.g. "wooden door". + Assigning a specific name to each entity of the game is generally an appropriate solution to distinguish between + different entities of the same type (like wooden door vs. glass door). This name is assigned to `{door}` in the + I7L-based text; i.e. "The wooden door is open". c. There might be some predicates that the designer would like to define as the logic of the game and they don't have an I7L equivalent necessarily, like `link(.)` in this example. The framework basically understands it by @@ -164,24 +201,24 @@ There are important notes in this example which is good to elaborate them: d. To make a line as comment, just put a `#` sign at the beginning of the line. -Door is a simple example to start learning the TWLL and I7L in a logic file. However, door is a built-in element inside -the TextWorld framework. Basically a door links two rooms and if it lockable, there is a key in the game which is -matched with this door. Key is also a built-in element. TextWorld has some built-in designed elements and many games -may require other element(s) rather than the built-in ones. One relevant example which is NOT already in the built-in -elements list is "push button". The framework doesn't know neither what is a push button nor whether it can -open a door, i.e. let's assume that a game designer likes to create a game in which a door can be unlock and open by a -push button. What does she/he do? -Similar to the door, we first need to describe the type and predicates of the push button as described here: +Basically a door links two rooms and if it is lockable, there is a key in the game which is +matched with this door. Key is also a built-in entity. As we have already mentioned, TextWorld has some built-in +designed entities and many games may require other entity(ies) in addition to the built-in ones. Our push-button example +is one relevant example which is NOT already defined in the built-in entities list. The framework doesn't know what is +a push button. Moreover, let's assume that a game designer likes to create a game in which a door can be unlock and open +by a push button. What does she/he do, since the framework doesn't know that the entity, like push button, can unlock +and open a door? Similar to the door, some primary predicates is required to be defined for a push button, as described +here: .. code-block:: bash # push button - type b : t { + type push-button : thing { predicates { - pushed(b); - unpushed(b); + pushed(push-button); + unpushed(push-button); - pair(b, d); + pair(push-button, door); } inform7 { @@ -191,23 +228,72 @@ Similar to the door, we first need to describe the type and predicates of the pu } predicates { - pushed(b) :: "The {b} is pushed"; - unpushed(b) :: "The {b} is unpushed"; + pushed(push-button) :: "The {push-button} is pushed"; + unpushed(push-button) :: "The {push-button} is unpushed"; + + pair(push-button, door) :: "The {push-button} pairs to {door}"; + } + } + } + + +D. Defining a command +----------------------- + +A command (or rule) activates an action in the game and should be defined in both languages. "Rule" section is another +section of logic file. It describes how the game transforms from one state to another by using the command; see the +below example for a simple `open` rule which is used to open a door, + +.. code-block:: bash + + open/d :: $at(P, room) & $link(room, door, room') & $link(room', door, room) & closed(door) -> open(door) & free(room, room') & free(room', room); + +where `at(P, room)` means "the player is at the room" and `free(room, room')` means the path from firs room (called +`room` here) to the second room (which is called `room'`) is clear. This rule includes two columns which are separated +by a `::`. The left column presents the rule's name. This name should be unique for each rule, thus, if we have two +states with different conditions, then their names should be different, for instance "open/d" vs "open/c" which stand +for open door and open container, consecutively. + +The right column of the above rule describes the state change of the game according to the current change and the next +state which the game will turn to, by using this command. As it is depicted, each state contains some predicates +which describe the conditions applied to the entities of the game at that moment (or state) of the game, and provides +eligibility for the defined rule to be applied/called. After calling the rule, it is activated and makes some changes +into the state of the game (or equivalently some selected entities of the game) as it is described on the right side of +the arrow. By these changes, the game will finally transit to the next state. Please be notified that any predicate +which is supported by `$` sign will be kept as unchanged at the next state. Therefore, it is not necessary to repeat +them at the right side of the arrow. + +Equivalently, the I7L version of this rule should be coded in the inform7 part, which is translated again as `open {d}`. +When this command is imported by the player, the inform7 will return a response as the game state, which in this example +is `opening {d}`. This inform-based output is important for the TextWorld framework to identify that the inform +compiler has taken the action of the command (here opening the door) and has transited to the next state. This can be +assumed as acknowledgment to the framework to change the status. All these information are coded in `command` +sub-section inside the inform7 part in the logic file, which is given as + +.. code-block:: bash - pair(b, d) :: "The {b} pairs to {d}"; + inform7 { + ... + + commands { + open/d :: "open {d}" :: "opening {d}"; } } } -The push button is presented by `b` letter, it is basically a sub-set of thing, and it is paired with a door. However, -"pair" action is not defined in I7L, thus it should be defined and described for Inform7 that what it means when a door -and a push button are paired. The description of new concept to I7L is provided in "code" sub-section within the -inform7 section in the logic file. + +E. Defining a new command to Inform7 +------------------------------------- + +The push button is basically a sub-set of thing, and it is paired with a door. However, "pair" action is not defined in +I7L, thus it should be defined and described for Inform7 that what it means when a door and a push button are paired. +The description of new concept to I7L is always provided in "code" sub-section within the inform7 section in the logic +file. As a continuum to our example, below the "pair" and corresponding action, `push`, is defined for I7L: .. code-block:: bash # push button - type b : t { + type push-button : thing { ... inform7 { @@ -247,49 +333,10 @@ are expected to happen when the button is pushed; the button state should change state also should be changed from `unlocked` to `open`. The last block is for human interaction and prints out these changes, thus, it is not mandatory. -After defining the new instructions to model push button in the game based on inform7 language, next step is to define -a command (or rule) to activate the action on both languages. "Rule" section is another section of logic file. It -describes how the game transforms from one state to another by using the command; see the below example for a simple -`open` rule for a door, - -.. code-block:: bash - - open/d :: $at(P, r) & $link(r, d, r') & $link(r', d, r) & closed(d) -> open(d) & free(r, r') & free(r', r); - -where `at(P, r)` means "the player is at the room" and `free(r, r')` means the path from room r to room r' is clear. -This rule includes two columns which are separated by a `::`. The left column presents the rule's name. This name -should be unique for each rule, thus, if we have two states with different conditions, then their names should be -different, for instance "open/d" vs "open/c" which stand for open door and open container, consecutively. - -The right column of the above rule describes the state change of the game according to the current change and the next -state which the game will turn to, by using this command. As it is depicted, each state contains some predicates -which describe the conditions applied to the elements of the game at that moment (or state) of the game, and provides -eligibility for the defined rule to be applied/called. After calling the rule, it is activated and makes some changes -into the state of the game (or equivalently some selected elements of the game) as it is described on the right side of -the arrow. By these changes, the game will finally transit to the next state. Please be notified that any predicate -which is supported by `$` sign will be kept as unchanged at the next state. - -Equivalently, the I7L version of this rule should be coded in the inform7 part, which is translated again as `open {d}`. -When this command is imported by the player, the inform7 will return a response as the game state, which in this example -is `opening {d}`. This inform-based output is important for the TextWorld framework to identify that the inform -compiler has taken the action of the command (here opening the door) and has transited to the next state. This can be -assumed as acknowledgment to the framework to change the status. All these information are coded in `command` -sub-section inside the inform7 part in the logic file, which is given as - -.. code-block:: bash - - inform7 { - ... - - commands { - open/d :: "open {d}" :: "opening {d}"; - } - } - } - -Similarly, to open a locked door with a push button, it is necessary to have the player at the same room as the push -button is. Then the door is paired with the button, and the two rooms that this door connects to each other should be -declared (note: the door and the button can be located in two different rooms, see the second set of rules below). +To open a locked door with a push button, it is necessary to have the player at the same room as the push button is. +Then the door is paired with the button, and the two rooms that this door connects to each other should be declared +(note: the door and the button can be located in two different rooms, compare the first and the second set of rules +in below example). Also the door is locked and the button is unpushed. From the `code` section, we realized that the defined command for this state transition is "push {b}". After this action, the door is unlocked and open and the button is changed to pushed. The rest of the conditions (predicates) are unchanged. This process is presented in following example for two @@ -298,11 +345,11 @@ scenarios: a) the button and the door ar at the same room, b) the push button is .. code-block:: bash rules { - lock/close/db :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r) & $link(r, d, r') & pushed(b) & open(d) & free(r, r') & free(r', r) -> unpushed(b) & locked(d); - unlock/open/db :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r) & $link(r, d, r') & unpushed(b) & locked(d) -> pushed(b) & open(d) & free(r, r') & free(r', r); + lock/close/db :: $at(P, room) & $at(push-button, room) & $pair(push-button, door) & $link(room', door, room) & $link(room, door, room') & pushed(push-button) & open(door) & free(room, room') & free(room', room) -> unpushed(push-button) & locked(door); + unlock/open/db :: $at(P, room) & $at(push-button, room) & $pair(push-button, door) & $link(room', door, room) & $link(room, door, room') & unpushed(push-button) & locked(door) -> pushed(push-button) & open(door) & free(room, room') & free(room', room); - lock/close/d/b :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r'') & $link(r'', d, r') & pushed(b) & open(d) & free(r', r'') & free(r'', r') -> unpushed(b) & locked(d); - unlock/open/d/b :: $at(P, r) & $at(b, r) & $pair(b, d) & $link(r', d, r'') & $link(r'', d, r') & unpushed(b) & locked(d) -> pushed(b) & open(d) & free(r', r'') & free(r'', r'); + lock/close/d/b :: $at(P, room) & $at(push-button, room) & $pair(push-button, door) & $link(room', door, room'') & $link(room'', door, room') & pushed(push-button) & open(door) & free(room', room'') & free(room'', room') -> unpushed(push-button) & locked(door); + unlock/open/d/b :: $at(P, room) & $at(push-button, room) & $pair(push-button, door) & $link(room', door, room'') & $link(room'', door, room') & unpushed(push-button) & locked(door) -> pushed(push-button) & open(door) & free(room', room'') & free(room'', room'); } reverse_rules { @@ -314,11 +361,11 @@ scenarios: a) the button and the door ar at the same room, b) the push button is ... commands { - lock/close/d/b :: "push {b}" :: "_pushing the {b}"; - unlock/open/d/b :: "push {b}" :: "_pushing the {b}"; + lock/close/d/b :: "push {push-button}" :: "_pushing the {push-button}"; + unlock/open/d/b :: "push {push-button}" :: "_pushing the {push-button}"; - lock/close/db :: "push {b}" :: "_pushing the {b}"; - unlock/open/db :: "push {b}" :: "_pushing the {b}"; + lock/close/db :: "push {push-button}" :: "_pushing the {push-button}"; + unlock/open/db :: "push {push-button}" :: "_pushing the {push-button}"; } } @@ -330,6 +377,10 @@ framework that after taking an action what would be the reverse action to get ba the possibility of getting back to a state after moving from it, also provides back and forth exploration within the environment. + +F. Defining constraints +----------------------- + The last section of a logic file is the `constraints` which defines the failure rules; i.e. describes that which predicates cannot occur simultaneously in a state. This section is only required to be defined in TWLL. Following is an example of some selected constraints applied to our example, @@ -338,13 +389,13 @@ example of some selected constraints applied to our example, constraints { # Predicate conflicts - d1 :: open(d) & closed(d) -> fail(); - d2 :: open(d) & locked(d) -> fail(); - d3 :: closed(d) & locked(d) -> fail(); + d1 :: open(door) & closed(door) -> fail(); + d2 :: open(door) & locked(door) -> fail(); + d3 :: closed(door) & locked(door) -> fail(); # A door can't be used to link more than two rooms. - link1 :: link(r, d, r') & link(r, d, r'') -> fail(); - link2 :: link(r, d, r') & link(r'', d, r''') -> fail(); + link1 :: link(room, door, room') & link(room, door, room'') -> fail(); + link2 :: link(room, door, room') & link(room'', door, room''') -> fail(); }