In the mystical realm of Eldoria, a land shrouded in legends and whispered secrets, there lived a young adventurer named Alex. With a heart full of curiosity and a spirit as wild as the wind, Alex had always been drawn to the tales of old, the kind that grandparents would recount by the flickering fireside on starless nights. Among these tales, one stood out - the story of the ancient Castle of Shadows, a place where time seemed to stand still, and where every corridor and chamber held a secret waiting to be uncovered.
...
Find a way to reach The Forbidden Throne Room using two parts of the book discovered in the Whispering Gallery, namely 'castle_domain.pddl' and 'castle_problem_poem.pddl'.
Once you found a plan to escape the castle, your flag content is the first two letters of each room visited in order.
We're given two .pddl
files:
(define (domain castle_escape)
(:requirements :strips :typing :negative-preconditions)
(:types
room
key
)
(:predicates
(at ?r - room)
(opens_with ?r - room ?k1 - key ?k2 - key)
(opened_with ?r - room ?k1 - key ?k2 - key)
(has_key ?k - key ?r - room)
(got_key ?k - key)
(blocks ?r1 - room ?r2 - room)
(blocked ?r - room)
)
(:action move
:parameters (?from - room ?to - room ?bl - room ?k1 - key ?k2 - key)
:precondition (and (at ?from) (not (blocked ?to))
(opens_with ?to ?k1 ?k2) (got_key ?k1) (got_key ?k2) (blocks ?to ?bl))
:effect (and (blocked ?bl) (not (at ?from)) (at ?to) (opened_with ?to ?k1 ?k2)
)
)
(:action pickup_key
:parameters (?r - room ?k - key)
:precondition (and (at ?r) (has_key ?k ?r))
:effect (got_key ?k)
)
)
(define (problem castle_escape_problem)
(:domain castle_escape)
(:objects
whispering_gallery enchanted_hall mirror_chamber dragon_lair wizards_study
moonlit_grove shadowy_vault sunken_crypt frozen_cell phantom_corridor
serpents_nest knights_hall golden_sanctum crystal_cove mystic_garden
starlit_tower silent_tomb echoing_cavern haunted_chamber forbidden_throne - room
sapphire_key ruby_key emerald_key diamond_key amethyst_key
topaz_key opal_key pearl_key garnet_key onyx_key
moonstone_key sunstone_key quartz_key turquoise_key jade_key
obsidian_key amber_key citrine_key lapis_key agate_key - key
)
(:init
;at
In Whispering Gallery begins our tale,
;opens_with
Atop a vault of shadows, silent, steep, topaz, pearl keys awake its sleep.
Crypt sunken 'neath the time's decree, opal, garnet turn the key.
Cell of frostbound, age-old hex, yields to pearl and onyx's behest.
(opens_with phantom_corridor garnet_key moonstone_key)
(opens_with enchanted_hall sapphire_key emerald_key)
(opens_with mirror_chamber ruby_key diamond_key)
(opens_with dragon_lair emerald_key amethyst_key)
Bow of Wizard's study, knowledge bound, diamond, topaz keys unwound.
Grove beneath the moonlit sky, amethyst, opal the secrets ply.
Knight's great hall, strong and tall, with moonstone, quartz, its gates do fall.
Golden sanctum's hidden trust, unveiled by sunstone, turquoise's thrust.
(opens_with crystal_cove quartz_key jade_key)
(opens_with mystic_garden turquoise_key obsidian_key)
(opens_with starlit_tower jade_key amber_key)
(opens_with echoing_cavern amber_key lapis_key)
Haunted chamber's secrets deep, citrine, agate open keep.
Throne's domain, regal, vast, lapis, agate keys hold fast.
Serpents' nest, coils tight, onyx, sunstone keys ignite.
Silent tomb, whispers cease, obsidian, citrine keys release.
;has_key
In the gallery that whispers, sapphire key does rest,
With emerald key beside, in the very same nest.
Ruby key in enchanted hall does dwell,
Sunstone key in the corridor where phantoms tell.
(has_key quartz_key serpents_nest)
(has_key opal_key wizards_study)
(has_key pearl_key moonlit_grove)
(has_key garnet_key shadowy_vault)
Onyx key in the crypt, sunken and deep,
Moonstone key in the frozen cell's keep.
Jade key in the hall where knights do parade,
Obsidian key in the crystal cove's shade.
(has_key amber_key mystic_garden)
(has_key citrine_key starlit_tower)
(has_key lapis_key silent_tomb)
(has_key agate_key echoing_cavern)
(has_key turquoise_key knights_hall)
(has_key diamond_key enchanted_hall)
(has_key diamond_key mirror_chamber)
(has_key amethyst_key mirror_chamber)
(has_key topaz_key mirror_chamber)
(has_key topaz_key wizards_study)
;blocks
In verse, the castle's blockades we now state,
Each line a path, each path a fate.
Wizards' study blocks the mirror's gleam,
Moonlit grove blocks the enchanted hall's dream.
Mystic garden blocks the moonlit grove,
Starlit tower blocks the crypt below.
(blocks silent_tomb shadowy_vault)
(blocks echoing_cavern moonlit_grove)
(blocks haunted_chamber wizards_study)
(blocks forbidden_throne whispering_gallery)
Whispering gallery, enchanted hall blocks,
Enchanted hall, whispering gallery locks.
Mirror chamber, enchanted hall's gate,
Dragon lair, whispering gallery's fate.
(blocks knights_hall serpents_nest)
(blocks crystal_cove serpents_nest)
(blocks shadowy_vault wizards_study)
(blocks sunken_crypt enchanted_hall)
Frozen cell blocks the dragon's lair,
Phantom corridor, shadowy vault's snare.
Serpents' nest blocks the moonlit grove,
Golden sanctum, moonlit grove's trove.
)
;goal
And so the goal, clear and true,
To reach the throne, forbidden view
And claim the crown, the kingdom's due.
)
The first file contains predefined type and function definitions for our program. The second file contains the description of the castle escape "problem", but with some function calls substituted out for poetic verses about what the function calls should do.
With some hints from the comments, our task seems to be to translate each line into its corresponding pddl
syntax to complete the program and
solve the puzzle.
;at
In Whispering Gallery begins our tale,
(at whispering_gallery)
;opens_with
Atop a vault of shadows, silent, steep, topaz, pearl keys awake its sleep.
(opens_with shadowy_vault topaz_key pearl_key)
Looking at the definition in the first pddl
file, the opens_with
function takes in a location and the two keys that open it.
Crypt sunken 'neath the time's decree, opal, garnet turn the key.
(opens_with sunken_crypt opal_key garnet_key)
Cell of frostbound, age-old hex, yields to pearl and onyx's behest.
(opens_with frozen_cell pearl_key onyx_key)
Bow of Wizard's study, knowledge bound, diamond, topaz keys unwound.
Grove beneath the moonlit sky, amethyst, opal the secrets ply.
Knight's great hall, strong and tall, with moonstone, quartz, its gates do fall.
Golden sanctum's hidden trust, unveiled by sunstone, turquoise's thrust.
(opens_with wizards_study diamond_key topaz_key)
(opens_with moonlit_grove amethyst_key opal_key)
(opens_with knights_hall moonstone_key quartz_key)
(opens_with golden_sanctum sunstone_key turquoise_key)
Haunted chamber's secrets deep, citrine, agate open keep.
Throne's domain, regal, vast, lapis, agate keys hold fast.
Serpents' nest, coils tight, onyx, sunstone keys ignite.
Silent tomb, whispers cease, obsidian, citrine keys release.
(opens_with haunted_chamber citrine_key agate_key)
(opens_with forbidden_throne lapis_key agate_key)
(opens_with serpents_nest onyx_key sunstone_key)
(opens_with silent_tomb obsidian_key citrine_key)
;has_key
In the gallery that whispers, sapphire key does rest,
With emerald key beside, in the very same nest.
Ruby key in enchanted hall does dwell,
Sunstone key in the corridor where phantoms tell.
(has_key sapphire_key whispering_gallery)
(has_key emerald_key whispering_gallery) ; serpents nest?
(has_key ruby_key enchanted_hall)
(has_key sunstone_key phantom_corridor)
The has_key
function takes in the key as its first argument and the key's location as its second. (The second line was a bit uncertain
because it used the word "nest", but "very same" implied that it was referring to the same location as the previous instruction.)
Onyx key in the crypt, sunken and deep,
Moonstone key in the frozen cell's keep.
Jade key in the hall where knights do parade,
Obsidian key in the crystal cove's shade.
(has_key onyx_key sunken_crypt)
(has_key moonstone_key frozen_cell)
(has_key jade_key knights_hall)
(has_key obsidian_key crystal_cove)
;blocks
In verse, the castle's blockades we now state,
Each line a path, each path a fate.
The blocks
function is a little less clear, because the definition only tells us that it takes two rooms and not necessarily
which argument corresponds to which. However, assuming that the objects in each line are given in the order they need to be passed
to the function (as was true for has_key
and opens_with
earlier),
Wizards' study blocks the mirror's gleam,
Moonlit grove blocks the enchanted hall's dream.
Mystic garden blocks the moonlit grove,
Starlit tower blocks the crypt below.
(blocks wizards_study mirror_chamber)
(blocks moonlit_grove enchanted_hall)
(blocks mystic_garden moonlit_grove)
(blocks starlit_tower sunken_crypt)
Whispering gallery, enchanted hall blocks,
Enchanted hall, whispering gallery locks.
Mirror chamber, enchanted hall's gate,
Dragon lair, whispering gallery's fate.
(blocks enchanted_hall whispering_gallery)
(blocks whispering_gallery enchanted_hall)
(blocks mirror_chamber enchanted_hall)
(blocks dragon_lair whispering_gallery)
Now it gets complicated, because the sentence structure gets reversed here. Assuming that the function (blocks a b)
corresponds to the
sentence a blocks b
, the sentence c, d blocks
= d blocks c
must correspond to (blocks d c)
.
Frozen cell blocks the dragon's lair,
Phantom corridor, shadowy vault's snare.
Serpents' nest blocks the moonlit grove,
Golden sanctum, moonlit grove's trove.
(blocks frozen_cell dragon_lair)
(blocks phantom_corridor shadowy_vault)
(blocks serpents_nest moonlit_grove)
(blocks moonlit_grove golden_sanctum)
Now they alternate between the regular and flipped sentence structure every line.
Finally, putting in the goal,
;goal
And so the goal, clear and true,
To reach the throne, forbidden view
And claim the crown, the kingdom's due.
(:goal (and
(at forbidden_throne)
; (has crown)
))
(the crown was not defined as an object, so our goal is simply to reach the forbidden throne, despite the other lines in the comment.)
Now that we have a completed pddl
file, we can run it through the solver mentioned in the challenge description to get this path
as a result:

Looking at every room we enter via the move
command (and remembering that we start in the whispering gallery!), our flag is
ictf{whenmiwimoshsufrphsekncrmystsiecfo}
The final pddl
file should look like
(define (problem castle_escape_problem)
(:domain castle_escape)
(:objects
whispering_gallery enchanted_hall mirror_chamber dragon_lair wizards_study
moonlit_grove shadowy_vault sunken_crypt frozen_cell phantom_corridor
serpents_nest knights_hall golden_sanctum crystal_cove mystic_garden
starlit_tower silent_tomb echoing_cavern haunted_chamber forbidden_throne - room
sapphire_key ruby_key emerald_key diamond_key amethyst_key
topaz_key opal_key pearl_key garnet_key onyx_key
moonstone_key sunstone_key quartz_key turquoise_key jade_key
obsidian_key amber_key citrine_key lapis_key agate_key - key
)
(:init
;at
(at whispering_gallery)
;opens_with
(opens_with shadowy_vault topaz_key pearl_key)
(opens_with sunken_crypt opal_key garnet_key)
(opens_with frozen_cell pearl_key onyx_key)
(opens_with phantom_corridor garnet_key moonstone_key)
(opens_with enchanted_hall sapphire_key emerald_key)
(opens_with mirror_chamber ruby_key diamond_key)
(opens_with dragon_lair emerald_key amethyst_key)
(opens_with wizards_study diamond_key topaz_key)
(opens_with moonlit_grove amethyst_key opal_key)
(opens_with knights_hall moonstone_key quartz_key)
(opens_with golden_sanctum sunstone_key turquoise_key)
(opens_with crystal_cove quartz_key jade_key)
(opens_with mystic_garden turquoise_key obsidian_key)
(opens_with starlit_tower jade_key amber_key)
(opens_with echoing_cavern amber_key lapis_key)
(opens_with haunted_chamber citrine_key agate_key)
(opens_with forbidden_throne lapis_key agate_key)
(opens_with serpents_nest onyx_key sunstone_key)
(opens_with silent_tomb obsidian_key citrine_key)
;has_key
(has_key sapphire_key whispering_gallery)
(has_key emerald_key whispering_gallery) ; serpents nest?
(has_key ruby_key enchanted_hall)
(has_key sunstone_key phantom_corridor)
(has_key quartz_key serpents_nest)
(has_key opal_key wizards_study)
(has_key pearl_key moonlit_grove)
(has_key garnet_key shadowy_vault)
(has_key onyx_key sunken_crypt)
(has_key moonstone_key frozen_cell)
(has_key jade_key knights_hall)
(has_key obsidian_key crystal_cove)
(has_key amber_key mystic_garden)
(has_key citrine_key starlit_tower)
(has_key lapis_key silent_tomb)
(has_key agate_key echoing_cavern)
(has_key turquoise_key knights_hall)
(has_key diamond_key enchanted_hall)
(has_key diamond_key mirror_chamber)
(has_key amethyst_key mirror_chamber)
(has_key topaz_key mirror_chamber)
(has_key topaz_key wizards_study)
;blocks
; In verse, the castle's blockades we now state,
; Each line a path, each path a fate.
(blocks wizards_study mirror_chamber)
(blocks moonlit_grove enchanted_hall)
(blocks mystic_garden moonlit_grove)
(blocks starlit_tower sunken_crypt)
(blocks silent_tomb shadowy_vault)
(blocks echoing_cavern moonlit_grove)
(blocks haunted_chamber wizards_study)
(blocks forbidden_throne whispering_gallery)
(blocks enchanted_hall whispering_gallery)
(blocks whispering_gallery enchanted_hall)
(blocks mirror_chamber enchanted_hall)
(blocks dragon_lair whispering_gallery)
(blocks knights_hall serpents_nest)
(blocks crystal_cove serpents_nest)
(blocks shadowy_vault wizards_study)
(blocks sunken_crypt enchanted_hall)
(blocks frozen_cell dragon_lair)
(blocks phantom_corridor shadowy_vault)
(blocks serpents_nest moonlit_grove)
(blocks moonlit_grove golden_sanctum)
)
;goal
(:goal (and
(at forbidden_throne)
; (has crown)
))
; And so the goal, clear and true,
; To reach the throne, forbidden view
; And claim the crown, the kingdom's due.
)