Prolog monkey

In this example we have a simple room, and a simple problem for a monkey to solve. It was originally a prolog problem found on the internet, and we decided to implement a version of it in the SDB language. So, there is a room with three locations, a,b,c, a box, and some bananas just out of reach. To solve the problem the monkey must go to b, push box to c, climb on box, then grab the bananas.

Here is the code that defines the monkey:

|context> => |prolog monkey bananas problem>
url |the context> => |url: http://www.inf.ed.ac.uk/teaching/courses/aipp/lecture_slides/15_Planning.pdf>
-- updated to the version 3.1.1 language
-- updated to use bound functions
-- Last updated: 2021/6/13


-- A transcript making use of the below code:
-- sa: set-up-initial-state
-- |state initiated>
--
-- sa: print-current-state
--
-- monkey is on floor
-- monkey is at a
-- box is on floor
-- box is at b
-- bananas are at c
-- banana status is hanging
-- |>
--
-- sa: go(at |monkey>, |b>)
-- |monkey moved to b>
--
-- sa: print-current-state
--
-- monkey is on floor
-- monkey is at b
-- box is on floor
-- box is at b
-- bananas are at c
-- banana status is hanging
-- |>
--
-- sa: push(|box>, at |monkey>, |c>)
-- |monkey pushed box to c>
--
-- sa: print-current-state
--
-- monkey is on floor
-- monkey is at c
-- box is on floor
-- box is at c
-- bananas are at c
-- banana status is hanging
-- |>
--
-- sa: climb-on(|box>)
-- |monkey climbed on box>
--
-- sa: print-current-state
--
-- monkey is on box
-- monkey is at c
-- box is on floor
-- box is at c
-- bananas are at c
-- banana status is hanging
-- |>
--
-- sa: grab(|bananas>)
-- |monkey grabbed bananas>
--
-- sa: test-for-goal-state
-- |reached goal state!>


-- Now on with the code:
set-up-initial-state |*> #=>
    on |monkey> => |floor>
    on |box> => |floor>
    at |monkey> => |a>
    at |box> => |b>
    at |bananas> => |c>
    status |bananas> => |hanging>
    |state initiated>

test-for-goal-state |*> #=>
    unlearn[goal-state] |count>
    goal-state |count> +=> on |monkey> == |box>
    goal-state |count> +=> on |box> == |floor>
    goal-state |count> +=> at |monkey> == |c>
    goal-state |count> +=> at |box> == |c>
    goal-state |count> +=> at |bananas> == |c>
    goal-state |count> +=> status |bananas> == |grabbed>
    value-if( goal-state |count> == 6|yes>, |reached goal state!>, |not reached goal state>)

print-current-state |*> #=>
    print (|monkey is on> __ on |monkey>)
    print (|monkey is at> __ at |monkey>)
    print (|box is on> __ on |box>)
    print (|box is at> __ at |box>)
    print (|bananas are at> __ at |bananas>)
    print (|banana status is> __ status |bananas>)
    |>





go {current|location>, next|location>} #=>
    unlearn[precondition] |count>
    precondition |count> +=> at |monkey> == current |location>
    precondition |count> +=> on |monkey> == |floor>
    if( precondition |count> == 2|yes> ):
        at |monkey> => next |location>
        |monkey moved to> __ next |location>
    else:
        |monkey failed to move to> __ next |location>
    end:


push {the|object>, current|location>, next|location>} #=>
    unlearn[precondition] |count>
    precondition |count> +=> at |monkey> == current |location>
    precondition |count> +=> at the |object> == current |location>
    precondition |count> +=> on |monkey> == |floor>
    precondition |count> +=> on the |object> == |floor>
    if( precondition |count> == 4|yes> ):
        at |monkey> => next |location>
        at the |object> => next |location>
        |monkey pushed> __ the |object> __ |to> __ next |location>
    else:
        |monkey failed to push> __ the |object> __ |to> __ next |location>
    end:


climb-on {the|object>} #=>
    unlearn[precondition] |count>
    precondition |count> +=> at |monkey> == at the |object>
    precondition |count> +=> on |monkey> == |floor>
    precondition |count> +=> on the |object> == |floor>
    if( precondition |count> == 3|yes> ):
        on |monkey> => the |object>
        |monkey climbed on> __ the |object>
    else:
        |monkey failed to climb on> __ the |object>
    end:

grab {the|object>} #=>
    unlearn[precondition] |count>
    precondition |count> +=> on |monkey> == |box>
    precondition |count> +=> at the |object> == at |box>
    precondition |count> +=> status the |object> == |hanging>
    if( precondition |count> == 3|yes> ):
        status the |object> => |grabbed>
        |monkey grabbed> __ the |object>
    else:
        |monkey failed to grab> __ the |object>
    end:

Here is the code for the solver component:

-- Try to solve the monkey banana problem
-- In this version, we try to solve the problem a little smarter than brute force
-- load prolog-monkey.sw3 before you load this file.

-- updated to the version 3.1.1 language


set-up-initial-state
the |objects> => rel-kets[at]
the |locations> => at rel-kets[at]
the-list-of |operators> => |op: get-go-details> + |op: get-push-details> + |op: get-climb-on-details> + |op: get-grab-details>
not |yes> => |no>
not |no> => |yes>

reset |*> #=>
    unlearn[*] starts-with |depth: >
    current |depth> => |depth: 0>
    unlearn[the] |plan>
    unlearn[the-used] |operators>
    set-up-initial-state
    |>

save-state |*> #=>
    previous-on |monkey> => |floor>
    previous-on |box> => |floor>
    previous-at |monkey> => |a>
    previous-at |box> => |b>
    previous-at |bananas> => |c>
    previous-status |bananas> => |hanging>
    |state saved>

restore-state |*> #=>
    on |monkey> => previous-on |monkey>
    on |box> => previous-on |box>
    at |monkey> => previous-at |monkey>
    at |box> => previous-at |box>
    at |bananas> => previous-at |bananas>
    status |bananas> => previous-status |bananas>
    |state restored>


display-details (*) #=>
    extract-value sselect[1,1] |__self> _ |(> _ smerge[", "] sselect[2, -1] |__self> _ |)>

comma-merge (*,*) #=> |__self1> _ |, > _ |__self2>


get-go-details |*> #=>
    unlearn[move] |to>
    move |to> => pick-elt drop (the |locations> - at |monkey> - attempted-go-move current |depth>)
    attempted-go-move current |depth> +=> move |to>
    the |details> => |op: go> . |> . at |monkey> . move |to>
    value-if( do-you-know move |to>, the |details>, |> )

get-push-details |*> #=>
    unlearn[the] (|choices> + |choice>)
    the |choices> => drop op-for( |op: comma-merge>, the |objects> -1 |monkey>, the |locations> -1 at |monkey>)
    the |choice> => pick-elt drop (the |choices> -1 attempted-push-choice current |depth>)
    the |object> => sselect[1,1] ssplit[", "] the |choice>
    move |to> => sselect[2,2] ssplit[", "] the |choice>
    attempted-push-choice current |depth> +=> the |choice>
    the |details> => |op: push> . |> . the |object> . at |monkey> . move |to>
    value-if( do-you-know the |choice>, the |details>, |> )

get-climb-on-details |*> #=>
    unlearn[climb] |object>
    climb |object> => pick-elt drop (the |objects> -1 |monkey> -1 attempted-climb-on-object current |depth>)
    attempted-climb-on-object current |depth> +=> climb |object>
    the |details> => |op: climb-on> . |> . climb |object>
    value-if( do-you-know climb |object>, the |details>, |> )

get-grab-details |*> #=>
    unlearn[the-grab] |object>
    the-grab |object> => pick-elt drop (the |objects> -1 |monkey> -1 attempted-grab-object current |depth>)
    attempted-grab-object current |depth> +=> the-grab |object>
    the |details> => |op: grab> . |> . the-grab |object>
    value-if( do-you-know the-grab |object>, the |details>, |> )



solve |*> #=>
    reset
    try-operator

try-operator (*) #=>
    unlearn[the-solution] (|operator> + |details> + |result>)
    the-solution |operator> => pick-elt drop (the-list-of |operators> -1 the-used |operators> -1 the-tried-operators current |depth>)
    the-solution |details> => apply(the-solution |operator>, |>)
    the-solution |result> => compile the-solution |details>
    if( or( not do-you-know the-solution |details>, has-prefix["monkey failed to "] the-solution |result> )):
        print |monkey failed at something>
        the-tried-operators current |depth> +=> value-if( do-you-know the-solution |details>, |>, the-solution |operator>)
        if( do-you-know the-solution |operator> ):
            try-operator
        else:
            print |no operators left, resetting ... >
            reset
            try-operator
        end:
    else:
        print |monkey succeeded at something>
        the |plan> .=> display-details the-solution |details>
        the-used |operators> +=> the-solution |operator>
        current |depth> => plus[1] current |depth>
        the-current |state> => test-for-goal-state |>
        print (|The current state:> __ the-current |state> . | >)
        if( the-current |state> == |reached goal state!> ):
            print (|The plan:> __ smerge[" "] the |plan>)
        else:
            try-operator
        end:
    end:
    |>

-- now solve it:
solve

Here is the output from a sample run:

$ ./SDB3_1 prolog-monkey.sw3 smarter-prolog-monkey-solver.sw3

|state initiated>

monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
no operators left, resetting ...
monkey failed at something
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
no operators left, resetting ...
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey succeeded at something
The current state: not reached goal state

monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
no operators left, resetting ...
monkey failed at something
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
no operators left, resetting ...
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
no operators left, resetting ...
monkey failed at something
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey failed at something
monkey failed at something
monkey failed at something
monkey succeeded at something
The current state: not reached goal state

monkey failed at something
monkey succeeded at something
The current state: reached goal state!

The plan: go(a, b) push(box, b, c) climb-on(box) grab(bananas)
|>

Yeah, not the smartest monkey in the world, but he is certainly smarter than the previous monkey we had that just did brute force until the solution was found. So, there is certainly room for improvement in our solve algorithm.