Old school text adventure as a way of re-learning coding

General discussion for topics related to the FreeBASIC project or its community.
olympic sleeper
Posts: 41
Joined: Jun 07, 2020 15:47

Old school text adventure as a way of re-learning coding

Post by olympic sleeper »

Hello,

I have been positing in the beginners forum as I'm new to Free Basic but old to coding. I haven't written anything in years, but having played through the Infocom text adventure Zork, wondered if I could write something like it to re-learn techniques (and I guess Basic, though most of my experience was in C).

Anyhoo.

Things are progressing and I thought I'd open a project for future pleas for help – which I suspect will be numerous.

I am currently tackling the conundrum of 'them' for the pre-processor. This takes the user's sentence in English and hammers it into something more logical for the main interpreter. So far it can handle things like – give the bone to the large dog and look and wear the blue shirt and put the yellow ball under the red table and look at it.

'It' is preprocessed to be the previous adjective/noun combination (in the above ‘red table’ is classed as a container). A simpler example - 'look at the bone and give it to the dog' preprocesses to 'look_at bone and give bone to dog'.

'Them' however is causing real problems as it can refer to one or more previous objects - 'get the shirts and put them on the shelf' or 'get the red shirt and the blue shirt and put them on the shelf', or a person as in ‘say hello to shopkeeper and then buy a shirt from them'.

In the 1st example 'them' refers to 'shirts', or the word immediately before the last 'and', this is also true of the last example, where them means 'shopkeeper'. However the middle example fails as the 'word' before the 'and' is the adjective/noun pair 'blue shirt'. We know this is a single item but the code does not and my logic is currently failing here. I thought about parsing back to the last verb (get) but this would fail if the player had 'typed get the red shirt and get the blue shirt and put them on the shelf'.

Any suggestions how I might untangle this?
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Old school text adventure as a way of re-learning coding

Post by BasicCoder2 »

Perhaps break the sentence into parts,
"get the red shirt", "get the blue shirt", "put them on the shelf"
So you have two get commands and "them" can become a label for all the things that the agent has in the have list?
Thus "get the red shirt"
becomes "have red shirt"
So "them" is replaced by all the things in the "have list"?
The put command would remove items from the have list to the "items on shelf" list or whatever destination list is appropriate?
Then there might be this sentence,
"get the red shirt and the blue shirt and then put them on the shelf"
with only one get command
With "'get the shirts and put them on the shelf"
"get shirts"
"put them on the shelf"
"shirts" are a type of object so search all the lists for "shirt" objects and "get" them.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Old school text adventure as a way of re-learning coding

Post by paul doe »

Now this is an interestin problem. I've seen it tackled like this: divide the sentences into nouns/pronouns, verbs, and prepositions, like this:

'get the shirts and put them on the shelf

Now, if you remove the clutter, you're left with:

get shirts put them on table

You can take advantage of the fact that the sentences you give to the adventure are almost always imperative:

Code: Select all

get( shirts ) ;
put( them, table ) ;
go( north ) ;
wear( helmet ) ;
See? Now, for cases like 'them': as BasicCoder2 points out, you can simply collect nouns on a list when parsing, and make sure that the list has more than one item, or the noun 'them' refers to is plural before calling the 'them' function. This sentence, for example, is incorrect from this standpoint:

say hello to shopkeeper and then buy a shirt from them

'Them' here can't refer to the shopkeeper, because he/she is a singular noun. It should refer to 'the shopkeepers' or 'the store', but it isn't clear in this context. Also, consider this case:

Fetch the bag and the towel. Get the jar and put them on the table

How would you handle that case? 'Them' in this context can refer to 'bag' and 'towel', not necessarily 'jar'. The above can be rephrased to:

Get the bag, the towel and the jar; put them on the table OR
Get the bag, the towel and the jar and put them on the table

So you now have:

Code: Select all

get( bag )
get( towel )
get( jar )
put( them, table )
So, the parser simply collects nouns as appropriate (in a list called, say, nouns_list), and when the put function is applied with the 'them' argument, it traverses the list and does its stuff:

Code: Select all

put( noun, where ) {
  /*
    Code to put an object somewhere. If a pronoun is used, the appropriate
    function is called.
  */
  select( noun ) {
    case where:
      put_where( nouns_list, where ) ;
   }
}

put_them( nouns_list, where ) {
  for each noun in nouns_list {
    put( noun, where ) ;
  }
}
Not all ambiguous cases can be resolved algorithmically. If that was the case, Google Translate would actually work as intended and not merely as an 'approximation' to the original meaning of the text XD
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Old school text adventure as a way of re-learning coding

Post by BasicCoder2 »

I assume a user will soon learn what kinds of sentences the game can handle and the game can always request the sentence be repeated another way or in a simpler form or even as a series of sentences.

Just as we adjust our sentences according to the age of the listener so to we can adjust our sentences to the level the game can understand.

A simple game might have an action as its first word.

LOOK north.

becomes LOOK(north)

The LOOK function then describes what you can see.

"There key on the table in front of you"

PICK up key

becomes PICK_UP(key)

The PICK_UP function adds the key to your inventory.

And so on ... ?
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Old school text adventure as a way of re-learning coding

Post by paul doe »

@BasicCoder2: Indeed, most adventures allowed either one or two word inputs. If there were just one word, it would be a noun (ie 'inventory', 'n' as a shorthand for 'Go North'); if two, it had to take the form <verb> <noun>. However, the OP stated he wanted something like Zork, which was notorious for being able to parse virtually any input. So, while the scheme proposed will work most of the time, it won't handle incoherent input nicely:

look at the bone and give it to the dog

Could be written as:

look fdskfhdkjfhdsf bone asdhsjdh give it ashdjhsadk dog

And the parser would still accept it as valid input, if the allowed lexemes are at the expected positions. For that, special handling of 'syntactic sugar' will need to be in place, unfortunately...

@olympic sleeper: it all boils down to how verbose do you want the input to be. If you do want 'proper English', then the parser can still be doable, but pronouns would have to be implemented a certain way to work. For example, 'them' would only apply to the nouns collected since the beginning of the sentence...

To that end, it would be nice if the valid sentences could be defined in BNF or EBNF, to facilitate the writing of a parser for them:

http://www.cs.utsa.edu/~wagner/CS3723/g ... mples.html
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Old school text adventure as a way of re-learning coding

Post by fxm »

@Admin,
can you remove this duplicate (with viewtopic.php?f=8&t=28659) ?
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Old school text adventure as a way of re-learning coding

Post by dodicat »

‘say hello to shopkeeper and then buy a shirt from them'
This doesn't make sense, them is for plural, shopkeeper is only one.
You are more than likely a native English speaker who has made a typo, anybody who says anyhoo has got a good grasp of the English language.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Old school text adventure as a way of re-learning coding

Post by BasicCoder2 »

paul doe wrote: However, the OP stated he wanted something like Zork, which was notorious for being able to parse virtually any input.
Sure I understood that. So the first thing I did was search the internet for an explanation or at least a description of how Zork parses a sentence. One such page seemed to indicate that much better parses now exist.

http://thomaswc.com/serious/ifzorkcould.html
In one of history's least noticed ironies, the commercial viability of interactive fiction (aka, text adventures such as Adventure and Zork) died at almost precisely the same time AI researchers discovered how to efficiently and effectively parse English sentences.

There is an assumption in olympic sleeper's question and that is that there are others here who understand the actual problems involved and can guess what he has done so far.

" So far it can handle things like – give the bone to the large dog and look and wear the blue shirt and put the yellow ball under the red table and look at it."

Ok. So how does that work and where is the code that can do it?

The subject matter does interest me which is why I responded. Perhaps my interest is not so much in adventure games per se but the problem of converting a human language sentence into a set of actions on some data is.

Ultimately I assume that any sentence will have to be translated into a set of actions that change the state of the data base. So I am guessing the sentence has to be translated into a series of calls to functions that perform the required changes in the data base? So those functions and the data base would be the starting point?
Imortis
Moderator
Posts: 1923
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: Old school text adventure as a way of re-learning coding

Post by Imortis »

fxm wrote:@Admin,
can you remove this duplicate (with viewtopic.php?f=8&t=28659) ?
Got it.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Old school text adventure as a way of re-learning coding

Post by BasicCoder2 »

dodicat wrote:‘say hello to shopkeeper and then buy a shirt from them'
This doesn't make sense, them is for plural, shopkeeper is only one.
So how would you write it when the gender of the shopkeeper is unknown?
"Singular they is the use in English of the pronoun they or its inflected or derivative forms, them, their, theirs, and themselves (or themself), as an epicene (gender-neutral) singular pronoun."
I would say a sentence makes sense if you know what is being said regardless of the grammar or spelling used.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Old school text adventure as a way of re-learning coding

Post by paul doe »

BasicCoder2 wrote:So how would you write it when the gender of the shopkeeper is unknown?
"Singular they is the use in English of the pronoun they or its inflected or derivative forms, them, their, theirs, and themselves (or themself), as an epicene (gender-neutral) singular pronoun."
...
Ah, that's a good point. But, at any rate, it might simplify things: just collect nouns in a list, and 'them' will act on all of them (even if there's just one). 'It', 'him' or 'her', on the other hand, may only refer to the last, proper noun (the tail of the list). Or is this an oversimplification? Thank goodness the adventure is in English; Spanish is actually much more difficult to parse.
BasicCoder2 wrote: ...
I would say a sentence makes sense if you know what is being said regardless of the grammar or spelling used.
Totally agree: if the parser can 'figure out' what you're communicating, it should suffice (eg no 'proper' English). However, without proper context, a parser that correctly parses the intent (not only the input) of a sentence might be pretty hard to code.

The link you provided is interesting. Much of the common input for a text adventure relies on being imperative, but if conversations are involved, then it might be much more difficult (and ambiguous) to parse the input.

@olympic sleeper: do you plan to have conversations? If that's the case, then you're in for a challenge, indeed. Any code (or pseudocode) for what you're currently working on will allow us to provide more directed feedback than just having to guess what you're trying to achieve...
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Old school text adventure as a way of re-learning coding

Post by dodicat »

BasicCoder2 wrote:
dodicat wrote:‘say hello to shopkeeper and then buy a shirt from them'
This doesn't make sense, them is for plural, shopkeeper is only one.
So how would you write it when the gender of the shopkeeper is unknown?
"Singular they is the use in English of the pronoun they or its inflected or derivative forms, them, their, theirs, and themselves (or themself), as an epicene (gender-neutral) singular pronoun."
I would say a sentence makes sense if you know what is being said regardless of the grammar or spelling used.
It should be surely
‘say hello to shopkeepers and then buy a shirt from them'
That is say, after this pandemic thing, and all the shops are open again, go on the telly and say hello to shopkeepers, and buy a shirt the next day from a shop.
Them is surely always plural.
Them and Us is a favourite class rant.
Them and me might be I alone against many. (A bit like me trying to save the woodland, (which is still there), and them being those wanting to exploit it for cash)
But I am no expert in English grammar,-- hated it at the school.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Old school text adventure as a way of re-learning coding

Post by paul doe »

To help disambiguate the cases you mention, you could lean on the game context to resolve, besides the parsing context. In the case of:

‘say hello to shopkeeper and then buy a shirt from them'

The game context could like this at the moment (over simplified):

Code: Select all

"person" : {
  "name"       : "Joe" ,
  "age"        : "43" ,
  "occupation" : "vendor"
  }

"location" : {
  "name" : "Joe's Clothings" , 
  "purpose" : "store" ,
  "shopkeepers" : [ "Joe" ] ,
  "inventory" : {
    "item" : {
      "name" : "shirt" , 
      "purpose" : "Renders you less nude" ,
      "cost" : "10"
      }
    }
  }
So, the player entered 'Joe's Clothings', which is a 'store', its shopkeeper is 'Joe', and it has a 'shirt' in its inventory. This should put several nouns in the parser's context too: 'store', 'shopkeeper', 'vendor', 'Joe' and 'shirt'. Then, to disambiguate the 'buy a shirt from them' part, you traverse the list of nouns, and simply discard things that don't 'make sense': in the sentence, you can't 'buy a shirt from a shirt', you have to buy it from a 'store'. Also, the 'shirt' is in the store's inventory, not Joe's. So, 'them' in this case disambiguates to the 'location' (which is a 'store'; you can buy and sell things there), the inventory for the store is traversed, and the 'shirt' is removed from it, added to the player's inventory, and 10 is payed to 'Joe' or the 'store' for it.

Now for the first one:

'get the red shirt and the blue shirt and put them on the shelf'

The game context at that location might resemble something like this:

Code: Select all

"location" {
  "name" : "somewhere" ,
  "floor" : {
    "item" {
      "name" : "red shirt" ,
      "type" : "shirt"
      } ,
    "item" {
      "name" : "blue shirt" ,
      "type" : "shirt"
      } ,
    "furniture" {
      "name" : "shelf"
      }
    }
  }
So, the 'shelf' is empty, and both 'items' (the 'red shirt' and the 'blue shirt') are on the 'floor'. So, since you can't 'get' the 'shelf' (it is not an 'item', but 'furniture', which can be interacted with and/or serve as decoration but cannot be transported), 'them' in this case can only refer to those two 'items'.

See what I mean? If you go about collecting nouns as you parse, and compliment them with the game state, you can disambiguate a lot of cases just by virtue of their data representations. You could even simplify the sentence to:

'put the shirts on the shelf'

And the parser can lean on the game context to tell that there are two shirts on the floor, which can be transported, so the 'get' step is skipped and it simply updates the game state accordingly:

Code: Select all

"location" {
  "name" : "somewhere" ,
  "floor" : { } ,
    "furniture" {
      "name" : "shelf" ,
      "item" {
        "name" : "red shirt" ,
        "type" : "shirt"
        } ,
      "item" {
        "name" : "blue shirt" ,
        "type" : "shirt"
      }
    }
  }
The reverse is also true:

'put the shirts on the floor'

The parser now knows from the game state that those two 'shirts' are on the shelf, and they should be put back to the floor.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Old school text adventure as a way of re-learning coding

Post by BasicCoder2 »

paul doe wrote:@olympic sleeper: do you plan to have conversations?
Graphic adventure games usually have other characters to fight, to buy things from and have simple conversations. A character might provide information to the player or be a source of some item the player might need.

It seems to me the difference between these text adventure games graphic adventure games is one of replacing images with a description of a location. The cursor keys or joystick and buttons are replaced with commands. A sentence is thus converted to a one or more commands from a of a set of possible commands.

As is usually the case with other people's projects I have been inspired to work on a simple text adventure game myself. I don't want to hijack this thread so I will start up another one with my take on how to code it.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Old school text adventure as a way of re-learning coding

Post by paul doe »

Here's another example of how you could lean on the game context to help the parser. Suppose you have this state:

Code: Select all

"person" : {
  "name"       : "Joe" ,
  "age"        : "43" ,
  "occupation" : "blacksmith"
  }
"person" : {
  "name" : "Anne" ,
  "age"  : "19" ,
  "occupation" : "apothecary"
  }

"store" : {
  "name" : "joe's smitty" ,
  "type" : "smitty" ,
  "owner" : "Joe" ,
  "inventory" : {
    "item" : {
      "name" : "broad sword" ,
      "type" : "sword" , 
      "purpose" : "Hurts people a lot" ,
      "cost" : "1000"
      }
    }
  }

"store" : {
  "name" : "anne's herbs" ,
  "type" : "apothecary" ,
  "owner" : "Anne" ,
  "inventory" : {
    "item" : {
      "name" : "green herb" ,
      "type" : "herb" , 
      "purpose" : "Makes you feel less dizzy" ,
      "cost" : "100"
      }
    }
  }

"location" : {
  "name" : "Joe & Annie's Junction" ,
  "stores" : [ "joe's smitty" , "anne's apothecary" ] }
That is, you now have one location but two stores in it. It might seem difficult to disambiguate 'them' here, but it again comes down to how do you associate data. A sentence like:

'Greet the shopkeepers and buy a green herb and a broad sword from them'

can be resolved simply by having the parser look at game context: in this location, there is only one 'green herb' and ony one 'broad sword' each one in a different shopkeeper. So, the game state can be queried to see who has the green herb, buy it, pay it to the appropriate store/vendor, and put it in the player's inventory. Same for the 'broad sword'. Now, if there are two people that have two instances of the same item, as in:

Code: Select all

"store" : {
  "name" : "joe's smitty" ,
  "type" : "smitty" ,
  "owner" : "Joe" ,
  "inventory" : {
    "item" : {
      "name" : "broad sword" ,
      "type" : "sword" , 
      "purpose" : "Hurts people a lot" ,
      "cost" : "1000"
      }
    "item" : {
      "name" : "green herb" ,
      "type" : "herb" , 
      "purpose" : "Makes you feel less dizzy" ,
      "cost" : "100"
      }
    }
  }

"store" : {
  "name" : "anne's herbs" ,
  "type" : "apothecary" ,
  "owner" : "Anne" ,
  "inventory" : {
    "item" : {
      "name" : "green herb" ,
      "type" : "herb" , 
      "purpose" : "Makes you feel less dizzy" ,
      "cost" : "100"
      }
    }
  }

"location" : {
  "name" : "Joe & Annie's Junction" ,
  "stores" : [ "joe's smitty" , "anne's apothecary" ] }
you can distinguish both 'green herbs' because each belong to a different vendor. So, you either don't let this happen or, resolve by asking the player from whom he should buy the 'green herb' (from the apothecary or from the blacksmith). The process could go:

p: 'Greet the shopkeepers and buy a green herb and a broad sword from them'
c: *Tries to buy the 'green herb' and there is ambiguity; mark it to resolve*
c: *Buys the 'broad sword from the blacksmith*

Now the program tries to give back the input to the player, but there's a command that needs to be resolved first. So, it could go like this:

c (asks): 'From whom should I buy the green herb?'

And now the player can respond:

p: 'from the apothecary' (there should be parsing context already for the 'from')
p: 'buy the green herb from the apothecary' (provides the full context)

Also, the sentence could be phrased specifically:

'buy the green herb from the apothecary and the broad sword from the blacksmith'

Or, the player can simply respond:

'nevermind'

And this should just drop the ongoing command to resolve ('buy the green herb')
I hope that these ideas are useful.
Post Reply