AnssiR66 / AlanStdLib

The Standard Library for ALAN Interactive Fiction Language
Other
5 stars 2 forks source link

About Liquids in Null Vessels #48

Closed tajmone closed 2 years ago

tajmone commented 5 years ago

Ciao Anssi,

I wanted to share with you an idea to improve the Library handling of liquids, specifically liquids which have a null_vessel. But then, I might also be missing out something about how such liquids should be implemented — in which case you could help me understand better their implementation method.

The problem I see is that in real case scenarios such liquids and their container are treated as one thing. Assuming a simple example:

IMPORT 'library.i'. -- ALAN Standard Library v2.1
THE my_game IsA DEFINITION_BLOCK END THE.
THE field IsA site. END THE.
THE river IsA liquid AT field.
  NAME river.
  NAME water.
END THE river.
Start at field.

Then trying to do things with the 'water' will result in answers referring to the 'river':

> take water
You can’t carry the river around in your bare hands.

So, I thought that we could add to every liquid an extra string attribute that could be used to store the reference to the liquid — E.g.:

  HAS liq_name "water".

Then, verbs which are intended to act on the liquid rather than its container (but only when the liquid has a null_vessel) should check if the liquid has a liq_name string set, and if yes use that in a message response instead of the container name. The assumption here would be that the player would rarely try to interact with the null vessel, and that the real object of such verbs is most likely the liquid itself.

On the other hand, this attribute being optional (and an empty string by default), the current behaviour would be preserved unless the author explicitly sets a value in it.

Of course, this might add a bit of extra code in the verbs that deal with liquids, for they would require separate response messages which can't rely on the use of $+1 (thus making the response attributes useless here); but after all it won't be a huge amount of code and IMO it would spare a lot of trouble to end users.

Currently, it seems that the only way to avoid odd looking responses like the above example is to actually implement the river as a fixed in place container, and the water as a separate liquid inside it.

Am I wrong on this last point? i.e. are there better and simple ways to create similar liquids in a smooth way?

AnssiR66 commented 5 years ago

Hi Tristano! That's a good idea definitely. The problem is - which verbs should we count in dealing with liquids? That's probably quite a lot of the transitive verbs, and not only the ones listed under 'liquid' in lib_classes.i. Otherwise I don't see a problem, and it isn't too much coding anyway, just as you suggested. I am just trying to think first if there is something else we could do, for example with MENTIONED (because MENTIONED takes IF statements etc). But that might be difficult. We could also try to change the default response to not mentioning the object: "You can't do that with your bare hands." or "That's not possible with your bare hands only." Or, the author should think about the hero trying to take the water in this case and program a custom response (because it is possible to take some water to the cup of your hands, etc...), a warning in the manual, about making the vessel and the liquid synonymous could also do. I am just trying to think more economical ways of dealing with this problem first, instead of introducing new checks to a lot of verbs.... I'll get back to this shortly. Meanwhile, what is your take on these ideas? -Anssi


From: Tristano Ajmone notifications@github.com Sent: Sunday, November 25, 2018 1:09 PM To: AnssiR66/AlanStdLib Cc: Subscribed Subject: [AnssiR66/AlanStdLib] About Liquids in Null Vessels (#48)

Ciao Anssi,

I wanted to share with you an idea to improve the Library handling of liquids, specifically liquids which have a null_vessel. But then, I might also be missing out something about how such liquids should be implemented — in which case you could help me understand better their implementation method.

The problem I see is that in real case scenarios such liquids and their container are treated as one thing. Assuming a simple example:

IMPORT 'library.i'. -- ALAN Standard Library v2.1 THE my_game IsA DEFINITION_BLOCK END THE. THE field IsA site. END THE. THE river IsA liquid AT field. NAME river. NAME water. END THE river. Start at field.

Then trying to do things with the 'water' will result in answers referring to the 'river':

take water You can’t carry the river around in your bare hands.

So, I thought that we could add to every liquid an extra string attribute that could be used to store the reference to the liquid — E.g.:

HAS liq_name "water".

Then, verbs which are intended to act on the liquid rather than its container (but only when the liquid has a null_vessel) should check is the liquid has a liq_name string set, and if yes use that in a message response instead of the container name. The assumption here would be that the player would rarely try to interact with the null vessel, and that the real object of such verbs is most likely the liquid itself.

On the other hand, this attribute being optional (and an empty string by default), the current behaviour would be preserved unless the author explicitly sets a value in it.

Of course, this might add a bit of extra code in the verbs that deal with liquids, for they would require separate response messages which can't rely on the use of $+1 (thus making the response attributes useless here); but after all it won't be a huge amount of code and IMO it would spare a lot of trouble to end users.

Currently, it seems that the only way to avoid odd looking responses like the above example is to actually implement the river as a fixed in place container, and the water as a separate liquid inside it.

Am I wrong on this last point? i.e. are there better and simple ways to create similar liquids in a smooth way?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHubhttps://github.com/AnssiR66/AlanStdLib/issues/48, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AF2lHmuuzwYHLuGH5ePEaH6xIbeLD1Zgks5uynpcgaJpZM4Yx0c9.

tajmone commented 5 years ago

I totally agree with your approach, the simpler the better. Also, I've just stumbled on the problem while trying to implement a swimming pool and a river, and noticed that for some verbs the responses looked odd. But, having said that, I haven't really been able to work out all the possible implications, and which verbs might apply to one or the other aspects of these liquids — it somewhat reminds me of a two-faced coins, where sometimes we need to show its face, while others we need the tail.

What I see as a general problem is the fact that almost any verb that could be used with this kind of liquid will probably produce a response that mentions it by the vessel name (due to $ references to the parameter), even when failing. Maybe, a solution could be to implement some DOES BEFORE verbs on liquids, allowing to change the liquid's MENTIONED to either the vessel or liquid name, depending on the verb being executed next? This solution would allow defining on liquid a whole bunch of verbs with symmetrical syntaxes at once, again looking for an optional string attribute to use for this operation (if non empty) and only if the liquid has a null vessel.

I was also wondering if the ideal solution might be for the author to create two separate objects, one for the vessel and one for the actual liquid, so that attempting an action on either of them will actually produce a different response. But this would be a manual approach, rather than the library taking care of it (I believe that the limit here is that Alan can't create objects dynamically), so it would somehow defeat the original intention of preserving the current structure of null-vessel liquids being handled smartly.

I'll try to play around with this, attempting different solutions and angles to the problem.

Definitely, it's something worth looking into, as similar liquids are going to be rather common (rivers, lakes, seas, pools, etc.).

AnssiR66 commented 5 years ago

Hi Tristano, sorry for the late reply to this topic. It's definitely worth thinking about a solution to this problem, as, like you said, programming something like lakes, ponds and rivers etc would be quite a commonplace undertaking, and then taking water from these instances, or referring to the water in some other way, would be nothing out of the ordinary. I haven't yet come across a neat solution, apart from instructing the player to program separate containers ("lake") and liquids ("water"), as we need to also account for cases such as "pour water in lake" when the hero is carrying an amount of water. Here, we cannot have "water" as a synonym (or a liquid name) for "lake", as then there would be an disambiguation problem. So, even if it is a manual chore, separate vessels and liquids might be the only thinkable solution here... ? -Anssi


From: Tristano Ajmone notifications@github.com Sent: Monday, November 26, 2018 4:18 PM To: AnssiR66/AlanStdLib Cc: AnssiR66; Comment Subject: Re: [AnssiR66/AlanStdLib] About Liquids in Null Vessels (#48)

I totally agree with your approach, the simpler the better. Also, I've just stumbled on the problem while trying to implement a swimming pool and a river, and noticed that for some verbs the responses looked odd. But, having said that, I haven't really been able to work out all the possible implications, and which verbs might apply to one or the other aspects of these liquids — it somewhat reminds me of a two-faced coins, where sometimes we need to show its face, while others we need the tail.

What I see as a general problem is the fact that almost any verb that could be used with this kind of liquid will probably produce a response that mentions it by the vessel name (due to $ references to the parameter), even when failing. Maybe, a solution could be to implement some DOES BEFORE verbs on liquids, allowing to change the liquid's MENTIONED to either the vessel or liquid name, depending on the verb being executed next? This solution would allow defining on liquid a whole bunch of verbs with symmetrical syntaxes at once, again looking for an optional string attribute to use for this operation (if non empty) and only if the liquid has a null vessel.

I was also wondering if the ideal solution might be for the author to create two separate objects, one for the vessel and one for the actual liquid, so that attempting an action on either of them will actually produce a different response. But this would be a manual approach, rather than the library taking care of it (I believe that the limit here is that Alan can't create objects dynamically), so it would somehow defeat the original intention of preserving the current structure of null-vessel liquids being handled smartly.

I'll try to play around with this, attempting different solutions and angles to the problem.

Definitely, it's something worth looking into, as similar liquids are going to be rather common (rivers, lakes, seas, pools, etc.).

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/AnssiR66/AlanStdLib/issues/48#issuecomment-441653826, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AF2lHkB2JgiXah8-mTcFn1dFxpLlBIcHks5uy_g0gaJpZM4Yx0c9.

tajmone commented 5 years ago

Here, we cannot have "water" as a synonym (or a liquid name) for "lake", as then there would be an disambiguation problem.

Looks like the nature of the problem here is first of all semantic in nature, so it might be a good idea to try and make a list of different possible situations and use cases that exemplify how these would be usually handled in terms of natural language, for it might be that the whole issue requires different solutions depending on the type of liquid and vessel. Hopefully, subclasses specialization and attributes might help.

For the sake of exploring languistic possibilities, here are some examples of how a player might naturally try to interact with the lake, and the expected responses:

input semantic param possible replies
"drink from lake" vessel You drink the lake water
"drink water" liq You drink the lake water
"drink water from lake" liq + vessel You drink the lake water
"pour wine in lake" vessel You pure wine into the lake
"pour wine in water" liq You pure wine into the lake
"enter lake" vessel You enter the lake
"enter water" liq You enter the lake

It seems that depending on the verb, the lake and its water are sometimes perceived as separate things, while other time they are treated as a single entity. E.g. you enter the whole lake, but you don't drink the lake but just its water.

Basically, the nature of the problem revolves around simulating these semantics in both input handling and responses. Probably disambiguation is going to be a problem here, for it can't be controlled via the library but is hardcoded.

In the semantics of "drink water from lake", if 'water' and 'lake' where two synonyms of the same liquid a verb could check if the two parameters point to the same object and handle it.

The big question here is if the above model applies to all kinds of liquids with null vessels. For example, a cascade would an edge case for (semantically) it doesn't really have a container at all but it's in a state of fall — i.e., it's a interruption in a flowing river, leaving the river bed to fall down a cliff and rejoin with the river bed below. While you can still take the water of a cascade, actions like "enter" might have a more ambiguos meaning (e.g. walking through it? going under it?).

I'm trying to think of different kinds of null-vesseled liquids that might fall under the issue discussed here, just to see if they fall all under a same category or if subclassing might better handle different cases:

liquid notes
cascade Might be best implemented without a vessel at all?
lake
puddle
river
sea
swimming pool The pool has borders, so it might require a real vessel
blood i.e. a 'pool of blood' spilt on the floor
wine i.e. wine spilt on the floor

The above lists already makes it clear that there is a difference between liquids which have been spilt on the floow (a pool of blood, poured wine, etc) and natural water formations like lakes, seas, rivers, etc. In the former, the liquid is perceived as a single item, while in the latter it's seen as a part of a whole which has a semantic meaning of its own. Probably these are the two main categories which we are dealing with here, for the former are truely vessel less, while the former have a semantic vessel, so to speak.

This is an interesting topic, which is a common source of problems in all IF authoring systems, so it might be worth looking how other tools are handling it (e.g. Inform 7 Recepies, etc). It might also be worthy bringing up the issue on the Alan list, and see what creative proposal our fellow users would come up with.

AnssiR66 commented 5 years ago

Seems like this didn't raise much discussion on the public Alan list. The problem still persists, I am intending to take a look at how Inform 7 handles it. My feeling is, however, that the procedure there is to allow both 'water' and 'lake' for a lake, for example, and then the default message would not mention separately either. I will, however, look how 'take water' and 'take lake', etc, are distinguished, if at all. I'll be writing back later.

AnssiR66 commented 5 years ago

Inform7 seems to handle 'water' and 'lake' (etc) as synonymous, and then the default messages are vague enough to pull it off successfully. I will explore still some further commands/behavior connected with it, but that seems to be the general approach.

tajmone commented 5 years ago

I didn't manage to look at i7 yet (sorry for that); but from what I recall from my authoring experience with it it's easier to handle these cases in i7 because it allows to override only the action report part of a verb, while Alan's DOES ONLY hijacks the whole execution and report at once. Also, i7 allows complex in-string substitutions with dynamic redefinable attributes and conditional branching via square bracketing.

I'm still working my head on this issue and haven't come up with any viable solution yet. But the more I tinker with it, the more I'm convinced that it will require a subclass to handle null-vesseled liquid pools where the vessel has a meaningful name that might be referenced both in player input and output library messages.

Also, just the other day I was going over the possible input examples. The table below illustrates how the liquid and its vessel name might interplay into player input, assuming that "water" and "lake" are defined as synonyms (problematic input shown in italic):

command parsed as
drink water <verb> (obj)
drink lake <verb> (obj)
drink water from lake <verb> (obj) from (obj)
drink water from water <verb> (obj) from (obj)
drink lake from lake <verb> (obj) from (obj)
drink from lake <verb> from (obj)
drink from water <verb> from (obj)

So, using synonyms would also require adding some alternative syntaxes (like (obj) from (obj)) to cover some possible usages — for example, in the same location there might be different water supplies, so using "water from lake" might be required to disambiguate (but I doubt that synonyms will prevent Alan from requesting a disambiguation).

Of course, usually the expectation is that the player will type commands which make sense, and the fact that the parser accepts and understands odd variations is usually something that is almost hydden. But in these cases chances are that sometimes lake and water have different meanings.

The more I look into it, the more I'm convinced that lake-type liquids are a category (subclass) in their own right, for they have an implicit vessel with peculiar features.

AnssiR66 commented 5 years ago

I see this as more straightforward and would go with how I7 approaches it, even if there is more flexibility in I7 to an extent than in Alan. The problematic input in the table of commands in your post below (the verbs with 'from' in the syntax, like 'drink from lake' or 'drink water from lake' are non-standard, in the way that usually 'drink water' or 'drink lake' would be recognized only, in any standard IF. Probably even the player might not expect that the 'from' formulations should work. At least these formulations are not in the current library, and in my opinion we don't have to bother with what is outside the library scope and what the author might wish to formulate or implement individually. In my opinion it would be their problem to implement these various subclasses (lake-type liquids etc) if they wish, rather than being our problem... But let's just recap what happens if we treat 'water' and 'lake' as synonyms, like Inform does:

enter lake = enter water - ok ("That's not something you can enter") drink lake = drink water - if the water is not drinkable, "That's not something you can drink."

Except that one case above (with 'drink') where we could modify the default message, I don't see any problem... unless, please remind me if there was something we discussed earlier that requires specific attention...

In the recent game Cragne Manor, drinking from a pond produces this same response, whether the player types 'drink water' or 'drink pond': "In the interest of self-preservation, you think better of drinking from the pond." ('drink from pond' was not recognized by the parser) So, it can be the author's duty to ensure there is a suitable answer, but I think the current library is already sufficient in providing all needed cases, except for some wordings we could work on.

But by all means, do present a counter-argument if you see that this still would need more work. My ultimate point would be that the problems you see are presented by the 'from' formulations, which are not in the library anyway....

-Anssi


From: Tristano Ajmone notifications@github.com Sent: Saturday, January 19, 2019 11:52 AM To: AnssiR66/AlanStdLib Cc: AnssiR66; Comment Subject: Re: [AnssiR66/AlanStdLib] About Liquids in Null Vessels (#48)

I didn't manage to look at i7 yet (sorry for that); but from what I recall from my authoring experience with it it's easier to handle these cases in i7 because it allows to override only the action report part of a verb, while Alan's DOES ONLY hijacks the whole execution and report at once. Also, i7 allows complex in-string substitutions with dynamic redefinable attributes and conditional branching via square bracketing.

I'm still working my head on this issue and haven't come up with any viable solution yet. But the more I tinker with it, the more I'm convinced that it will require a subclass to handle null-vesseled liquid pools where the vessel has a meaningful name that might be referenced both in player input and output library messages.

Also, just the other day I was going over the possible input examples. The table below illustrates how the liquid and its vessel name might interplay into player input, assuming that "water" and "lake" are defined as synonyms (problematic input shown

command parsed as drink water (obj) drink lake (obj) drink water from lake (obj) from (obj) drink water from water (obj) from (obj) drink lake from lake (obj) from (obj) drink from lake from (obj) drink from water from (obj)

So, using synonyms would also require adding some alternative syntaxes (like (obj) from (obj)) to cover some possible usages — for example, in the same location there might be different water supplies, so using "water from lake" might be required to disambiguate (but I doubt that synonyms will prevent Alan from requesting a disambiguation).

Of course, usually the expectation is that the player will type commands which make sense, and the fact that the parser accepts and understands odd variations is usually something that is almost hydden. But in these cases chances are that sometimes lake and water have different meanings.

The more I look into it, the more I'm convinced that lake-type liquids are a category (subclass) in their own right, for they have an implicit vessel with peculiar features.

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/AnssiR66/AlanStdLib/issues/48#issuecomment-455765693, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AF2lHkrtnW5yDv7h3BiwVdqxCqC_yP4Vks5vEurVgaJpZM4Yx0c9.

tajmone commented 5 years ago

You're right and you've convinced me 100%.

So, to resume (using the "lake" as an example):

The area of improvement here could be to add an extra string attribute vessel_name on the liquid class which could be used in some default responses of lake-like cases:

This way, it would be completely optional to use and it won't break backward compatibility either. If an author wishes the reply to mention the vessel (eg "lake") it only has to set vessel_name to "lake".

After adding this optional attribute, we'd only need to work out which responses should check for it and use it — i.e. which verbs should refer to the vessel in lake-like objects. This means we'd have to think over some practical examples and decide in which contexts the liquid name sounds bad and the vessel name (or whatever the author defined) sound better. Of course, it's not easy as different case examples might differ.

If it turns out that all cases are alike, then a single attribute would do for all lake-like cases (rivers, swimming pools, etc.). If not, an alternative approach could be to use multiple attributes targetting specific verbs — Example:

This would allow authors to gain fine-grain control over which verbs responses should use an alternative output name instead of the liquid's base name. The list of verbs affecting liquids is not huge, and only some of them might be targeted for alternative output, so in the worst case scenario we'd be looking at something like 4-6 attributes at the most.

Hopefully, a single attribute should cover most cases.