Skip to content

game created with GameMaker doesn't understand 'fridge' #236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gari-marcos opened this issue Jun 1, 2020 · 27 comments
Closed

game created with GameMaker doesn't understand 'fridge' #236

gari-marcos opened this issue Jun 1, 2020 · 27 comments

Comments

@gari-marcos
Copy link

gari-marcos commented Jun 1, 2020

Hello, I was trying to create a game with the GameMaker. However, when I create a container named either 'fridge' or 'refrigerator' and I record the quest for the game I get the following message: You can't see any such thing. But it actually appears on the quest:

-= Kitchen =-
You arrive in a kitchen. A typical kind of place. I guess you better just go and
list everything you see here.

You can make out a refrigerator. You bend down to tie your shoe. When you stand
up, you notice a stove. The stove is usual. On the stove you make out a keycard.

If I leave like that when I run the game to play it that element is replaced with other name such as 'Microsoft box' or 'formless chest':

-= Kitchen =-
You've entered a kitchen.

You can make out a safe. Hmmm... what else, what else? You make out a closed
formless chest. You can make out a stove. The stove is usual. On the stove you
can make out a cuboid passkey and an American limited edition keycard.

Do you know what could be causing this problem?

Thank you in advance,

@MarcCote
Copy link
Contributor

MarcCote commented Jun 1, 2020

Hi. Can you share your script? Also which TextWorld version are you using?

One guess would be that the name for the container (e.g., "fridge") was not provided as an argument. For instance, M.new("c", name="fridge") would fix the name and the text generation system (which is called when recording a quest, and compiling/saving the game) shouldn't change it.

@gari-marcos
Copy link
Author

gari-marcos commented Jun 1, 2020

Yeah sure! I am using 1.3.1 version.

import textworld
from textworld import GameMaker
from textworld import g_rng
g_rng.set_seed(20180329)

M = GameMaker()
kitchen = M.new_room("kitchen")
living_room = M.new_room("living room")
bedroom = M.new_room("bedroom")
bathroom = M.new_room("bathroom")
backyard = M.new_room("backyard")

kitchen_living = M.connect(kitchen.east, living_room.west)
living_bedroom = M.connect(living_room.north, bedroom.south)
living_bathroom = M.connect(living_room.east, bathroom.west)
living_backyard = M.connect(living_room.south, backyard.north)

M.set_player(living_room)

kitchen_living_door = M.new_door(kitchen_living, name = "wooden door")
M.add_fact("locked", kitchen_living_door)
living_bedroom_door = M.new_door(living_bedroom, name = "screen door")
M.add_fact("closed", living_bedroom_door)
living_bathroom_door = M.new_door(living_bathroom, name = "metal door")
M.add_fact("open", living_bathroom_door)
living_backyard_door = M.new_door(living_backyard, name = "door")
M.add_fact("open", living_backyard_door)

key = M.new(type = 'k', name = "key")
M.add_fact("match", key, kitchen_living_door)
couch = M.new(type = 's', name = 'couch')
table = M.new(type = 's', name = 'table')
living_room.add(table)
living_room.add(couch)
couch.add(key)


stove = M.new(type = 's', name = 'stove')
chicken = M.new(type = 'f', name = 'chicken')
refrigerator = M.new(type = 'c', name = 'refrigerator')
M.add_fact('closed', refrigerator)
kitchen.add(refrigerator)
kitchen.add(stove)
refrigerator.add(chicken)


bed = M.new(type = 's', name = 'bed')
tv = M.new(type = 's', name ='tv')
bedroom.add(bed)
bedroom.add(tv)

bath = M.new(type = 'c', name = 'bath')
M.add_fact('open', bath)
toilet = M.new(type = 'c', name = 'toilet')
M.add_fact('open', toilet)
sink = M.new(type = 's', name = 'sink')
toothbrush = M.new(type = 'o', name = 'toothbrush')
sink.add(toothbrush)
bathroom.add(bath)
bathroom.add(toilet)
bathroom.add(sink)

bbq = M.new(type = 's', name = 'bbq')
backyard.add(bbq)

M.render(interactive=True)

M.generate_distractors(10)

#quest = M.record_quest()

commands = ['take key from couch', ' unlock wooden door with key', 
			'open wooden door', 'go west', 'open refrigerator', 
			'take chicken from refrigerator', 'put chicken on stove']

quest = M.set_quest_from_commands(commands)



print( " > ".join(quest.commands))
print("\n" + quest.desc)

M.validate()
M.test()

game = M.build()
game_name = "./test_game_1"
game_file = M.compile(game_name)

Last time I tried with 'refrigerator' but I got the same result. When loading the commands from a list, they got processed like this:

take key from couch > unlock wooden door with key > open wooden door > go west > go west > go west > go west

Thank you!

@MarcCote
Copy link
Contributor

MarcCote commented Jun 1, 2020

I see what's wrong. One of the added distractors is a key for the refrigerator which causes a change in the name. By default, the names for the key and its matching container are picked from a predefined list specified in the grammar (.twg files). I've fixed this in #237.

I'll make a 1.3.2 release, once it is merged. If you wish, you can directly install the branch containing the fix. pip install https://github.com/MarcCote/TextWorld/archive/fix_236.zip

@gari-marcos
Copy link
Author

Okay, thank you very much, I finally got it. Just a thing, is there a way to modify the quest description once it's done? I mean, in the game designed above 6 actions are necessary to complete it and in the goal description, they will all appear. Can I modify the goal to mention only the last action?
Thank you again.

@MarcCote
Copy link
Contributor

MarcCote commented Jun 1, 2020

Yes. This is how you can do it.

options = textworld.GameOptions()
options.grammar.only_last_action = True

M = GameMaker(options)

EDIT: you can lookup the available grammar's options and their description here: https://textworld.readthedocs.io/en/stable/textworld.generator.grammar.html#textworld.generator.text_grammar.GrammarOptions

@gari-marcos
Copy link
Author

Okay, that was so helpful! thank you so much!!

@MarcCote
Copy link
Contributor

MarcCote commented Jun 1, 2020

My pleasure. Thanks for giving TextWorld a try :). We are open to feedback especially about the GameMaker's API which is truly a work-in-progress.

@gari-marcos
Copy link
Author

I've been looking through the docs of GameMaker but I haven't been able to figure out if there is a way to insert intermediate rewards during the quest. Is this possible? Thank you again!

@MarcCote
Copy link
Contributor

MarcCote commented Jun 2, 2020

The way you would do that is by defining multiple quests.

quest = M.set_quest_from_commands(commands)

# Adding a subquest.
from textworld.generator import Quest, Event
subgoal = Event(conditions={M.new_fact("open", kitchen_living_door)})
M.quests.append(Quest(win_events=[subgoal]))

Note the use of Quest and Event classes which allow you to define more complex quests.

@MarcCote
Copy link
Contributor

MarcCote commented Jun 2, 2020

Also, there's a PR about better documentation here: https://github.com/microsoft/TextWorld/pull/186/files

@gari-marcos
Copy link
Author

Oh, I see, thank you again!

@gari-marcos
Copy link
Author

gari-marcos commented Jun 10, 2020

Hello, I am trying to set a custom quest description but I don't find any way. Is there any way to change the description of the quest? For instance, the last command is go north but I want the quest to be I need you to go to the bathroom. Is there any way to specify that? I tried adding a descin the last subquest but it didn't work.

commands = ['open chest drawer','take key from chest drawer', 
			'unlock wooden door with key', 'open wooden door', 
			'go east', 'go north']

quest = M.set_quest_from_commands(commands)
subgoal1 = Event(conditions={M.new_fact("open", chest_drawer)})
subgoal2 = Event(conditions={M.new_fact("in", key, M.inventory)})
subgoal3 = Event(conditions={M.new_fact("open", bedroom_kitchen_door)})
subgoal4 = Event(conditions={M.new_fact("at", M.player, kitchen)})
subgoal5 = Event(conditions={M.new_fact("at", M.player, bathroom)})
M.quests.append(Quest(win_events=[subgoal1]))
M.quests.append(Quest(win_events=[subgoal2]))
M.quests.append(Quest(win_events=[subgoal3]))
M.quests.append(Quest(win_events=[subgoal4]))
M.quests.append(Quest(win_events=[subgoal5], desc='I need you to go to the bathroom'))

Thank you!

@MarcCote
Copy link
Contributor

That's a bug! I will make a fix. Keep them coming :)

@gari-marcos
Copy link
Author

Ok, thanks!

@MarcCote
Copy link
Contributor

You can try pip install https://github.com/MarcCote/TextWorld/archive/fix_239.zip. If that works for you I'll make a patch release.

@gari-marcos
Copy link
Author

I tried with that fix, however, when I play the game the quest description doesn't seem to appear.

@MarcCote
Copy link
Contributor

Can you share your whole python script?

@gari-marcos
Copy link
Author

gari-marcos commented Jun 10, 2020

import textworld
from textworld import GameMaker
from textworld import g_rng
g_rng.set_seed(20180329)

from textworld.generator import Quest, Event

options = textworld.GameOptions()
options.grammar.only_last_action = True

M = GameMaker(options)
kitchen = M.new_room("kitchen")
living_room = M.new_room("living room")
bedroom = M.new_room("bedroom")
bathroom = M.new_room("bathroom")
backyard = M.new_room("backyard")

bedroom_kitchen = M.connect(bedroom.east, kitchen.west)
kitchen_living = M.connect(kitchen.south, living_room.north)
kitchen_bathroom = M.connect(kitchen.north, bathroom.south)
kitchen_backyard = M.connect(kitchen.east, backyard.west)

M.set_player(bedroom)

bedroom_kitchen_door = M.new_door(bedroom_kitchen, name = "wooden door")
M.add_fact("locked", bedroom_kitchen_door)
kitchen_backyard_door = M.new_door(kitchen_backyard, name = "screen door")
M.add_fact("locked", kitchen_backyard_door)


key = M.new(type = 'k', name = "key")
M.add_fact("match", key, bedroom_kitchen_door)
chest_drawer = M.new(type = 'c', name = 'chest drawer')
M.add_fact('closed', chest_drawer)
chest_drawer.add(key)
bed = M.new(type = 's', name = 'bed')
tv = M.new(type = 's', name ='tv')
bedroom.add(bed, tv, chest_drawer)


couch = M.new(type = 's', name = 'couch')
table = M.new(type = 's', name = 'table')
living_room.add(table)
living_room.add(couch)


stove = M.new(type = 's', name = 'stove')
apple = M.new(type = 'f', name = 'apple')
refrigerator = M.new(type = 'c', name = 'refrigerator')
M.add_fact('closed', refrigerator)
kitchen.add(refrigerator)
kitchen.add(stove)
refrigerator.add(apple)


bath = M.new(type = 'c', name = "bath")
M.add_fact('open', bath)
toilet = M.new(type = 'c', name = 'toilet')
M.add_fact('open', toilet)
sink = M.new(type = 's', name = 'sink')
toothbrush = M.new(type = 'o', name = 'toothbrush')
sink.add(toothbrush)
bathroom.add(bath)
bathroom.add(toilet)
bathroom.add(sink)

bbq = M.new(type = 's', name = 'bbq')
backyard.add(bbq)

#M.render(interactive=True)

#M.generate_distractors(10)

#quest = M.record_quest()

commands = ['open chest drawer','take key from chest drawer', 
			'unlock wooden door with key', 'open wooden door', 
			'go east', 'go north']

quest = M.set_quest_from_commands(commands)
subgoal1 = Event(conditions={M.new_fact("open", chest_drawer)})
subgoal2 = Event(conditions={M.new_fact("in", key, M.inventory)})
subgoal3 = Event(conditions={M.new_fact("open", bedroom_kitchen_door)})
subgoal4 = Event(conditions={M.new_fact("at", M.player, kitchen)})
subgoal5 = Event(conditions={M.new_fact("at", M.player, bathroom)})
M.quests.append(Quest(win_events=[subgoal1]))
M.quests.append(Quest(win_events=[subgoal2]))
M.quests.append(Quest(win_events=[subgoal3]))
M.quests.append(Quest(win_events=[subgoal4]))
M.quests.append(Quest(win_events=[subgoal5]))
quest.desc='I need you to go to the bathroom'

M.set_walkthrough(commands)

print( " > ".join(quest.commands))
print("\n" + quest.desc)

if not M.validate():
	exit

game = M.build()
game_name = "./test_game_bathroom"
game_file = M.compile(game_name)

This is the script, as you can see the last action is to go north. However, when I play the game this is what I get:

Your objective is to attempt to take a trip south.

-= Bedroom =-
This might come as a shock to you, but you've just moved into a bedroom.

You scan the room, seeing a chest drawer. You can make out a bed. The bed is
typical. However, the bed, like an empty bed, has nothing on it. You bend down
to tie your shoe. When you stand up, you notice a tv. The tv is usual. But the
thing hasn't got anything on it.

There is a closed wooden door leading east.

It says the objective is to go south, I don't know why.

@MarcCote
Copy link
Contributor

MarcCote commented Jun 10, 2020

You can always overwrite the game's objective directly.
game.objective = "I need you to go to the bathroom." after building the game.

@gari-marcos
Copy link
Author

Yeah, I tried but I get the same result as above.

game = M.build()
game.objective = "I need you to go to the bathroom"
game_name = "./test_game_bathroom_1"
game_file = M.compile(game_name)
Your objective is to attempt to take a trip south.

-= Bedroom =-
This might come as a shock to you, but you've just moved into a bedroom.

You scan the room, seeing a chest drawer. You can make out a bed. The bed is
typical. However, the bed, like an empty bed, has nothing on it. You bend down
to tie your shoe. When you stand up, you notice a tv. The tv is usual. But the
thing hasn't got anything on it.

There is a closed wooden door leading east

@MarcCote
Copy link
Contributor

Ok, I'll investigate more but the problem seems to be related to M.set_walkthrough(commands).

@gari-marcos
Copy link
Author

It seems it has something to do with that script because I tried with this one and it's actually working:

commands = ['open chest drawer','take key from chest drawer', 
			'unlock wooden door with key', 'open wooden door', 
			'go east', 'open screen door', 'go east']

quest = M.set_quest_from_commands(commands)
subgoal1 = Event(conditions={M.new_fact("open", chest_drawer)})
subgoal2 = Event(conditions={M.new_fact("in", key, M.inventory)})
subgoal3 = Event(conditions={M.new_fact("open", bedroom_kitchen_door)})
subgoal4 = Event(conditions={M.new_fact("at", M.player, kitchen)})
subgoal5 = Event(conditions={M.new_fact("at", M.player, bathroom)})
subgoal6 = Event(conditions={M.new_fact("open",kitchen_backyard_door)})
subgoal7 = Event(conditions={M.new_fact("at", M.player, backyard)})
M.quests.append(Quest(win_events=[subgoal1]))
M.quests.append(Quest(win_events=[subgoal2]))
M.quests.append(Quest(win_events=[subgoal3]))
M.quests.append(Quest(win_events=[subgoal4]))
M.quests.append(Quest(win_events=[subgoal5]))
M.quests.append(Quest(win_events=[subgoal6]))
M.quests.append(Quest(win_events=[subgoal7]))

#quest.desc='I need you to go to the bathroom'

M.set_walkthrough(commands)

print( " > ".join(quest.commands))
print("\n" + quest.desc)

if not M.validate():
	exit

game = M.build()
game.objective = "I need you to go to the backyard"
I need you to go to the backyard

-= Bedroom =-
This might come as a shock to you, but you've just moved into a bedroom.

You scan the room, seeing a chest drawer. You can make out a bed. The bed is
typical. However, the bed, like an empty bed, has nothing on it. You bend down
to tie your shoe. When you stand up, you notice a tv. The tv is usual. But the
thing hasn't got anything on it.

There is a closed wooden door leading east.

However, when I arrive at the backyard, this is what I get:

-= Backyard =-
Look around you. Take it all in. It's not every day someone gets to be in a
backyard.

You can make out a bbq. But oh no! there's nothing on this piece of junk. Hm. Oh
well

There is an open screen door leading west.


Your score has just gone up by two points.

It gives two points instead of one, and the game doesn't finish.

@gari-marcos gari-marcos reopened this Jun 10, 2020
@MarcCote
Copy link
Contributor

I think you don't need quest = M.set_quest_from_commands(commands)

@MarcCote
Copy link
Contributor

I'm assuming quest and subgoal7 are the same, hence the two points.

@MarcCote
Copy link
Contributor

Also, at the moment, the agent has to finish all "subgoal" before the game ends. That will change with PR #235

@gari-marcos
Copy link
Author

Ok, thank you so much! I just realized I had a subgoal the player had to be at the bathroom and I wasn't aware of it. Now, it's doing okay. Also, the two last points were because of the quest and the subgoal. Thank you very much!

@MarcCote
Copy link
Contributor

I had time to investigate more your original issue (i.e., "Your objective is to attempt to take a trip south." instead of "Your objective is to attempt to take a trip north."). I fixed a bug we had in trying to find the "optimal" trajectory to solve a game, which was used to define the objective of the game when none is provided.

In your example, the optimal trajectory does indeed lead you to the bathroom by going north from the kitchen, but the bug was bringing the player back to the kitchen to satisfy a second time the subgoal #4.

I pushed the fix to the same PR, if you need it. Otherwise, it will be part of the next patch release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants