问题
I am trying to create a CLIPS program that will take any initial stack and rearrange it into any goal-stack. I am asserting this, but it doesn't seem to do anything.
(assert (stack A B C) (stack D E F) (goal-stack D C B) (goal-stack A) (goal-stack F E))
This is my code so far:
(defrule move-direct
;(declare (salience 10000))
?stack1 <- (stack ?block1 $?bottom1)
?stack2 <- (stack ?block2 $?bottom2)
(goal-stack ?block1 ?block2 $?goalbottom)
=>
(retract ?stack1 ?stack2)
(assert (stack ?block1 ?block2 ?bottom2))
(assert (stack $?bottom1))
(printout t ?block1 " moved on top of " ?block2 crlf))
(defrule move-on-floor
; (declare (salience 10000))
?stack1 <- (stack ?top $?blocks ?movethisblock $?bottom1)
;(goal-stack ?movethisblock $?bottom1)
(goal-stack $?blocks ?movethisblock $?bottom2)
=>
(retract ?stack1)
(assert (stack ?top))
(assert (stack $?blocks ?movethisblock $?bottom1))
(printout t ?top " moved on to the floor" crlf))
回答1:
Debugging code usually involves questioning your expectations. You expect the move-direct and move-on-floor rules to do something, but why? For the move-direct rule and the assertions you've made, the only possible values for ?block1 and ?block2 in the first two patterns are either A or D. So the third pattern must match a goal-stack that starts with either A A, A D, D A, or D D. Such a goal-stack does not exist, so this rule is unmatched.
For the move-on-floor rule, look at each case. If (goal-stack A) matches the goal-stack pattern where ?move-this-block is A and $?blocks is (), then there must be stack that has a block on top of A (the variable ?top). Since A is at the top of the stack, the rule won't be matched for this goal-stack.
if (goal-stack F E) matches the goal-stack pattern, the sequence ($?blocks ?move-this-block) is either (F E) or F. There is no stack with either of these sequences where there's just a single block on top, so the rule won't be matched for this sequence.
If (goal-stack D C B) matches the goal-stack pattern the sequence from the goal-stack that must match the stack is either (D C B), (D C) or (D). Again there's no stack that contains this sequence with just a single block on top of the sequence.
In the logic for the move-direct rule, you only want to directly move the block when the existing stack matches the bottom portion of a goal-stack. For the move-on-floor rule you also want to insure that you're not moving blocks off a partially completed stack.
CLIPS (6.31 2/3/18)
CLIPS>
(defrule move-direct
(declare (salience 10))
?stack1 <- (stack ?block1 $?bottom)
?stack2 <- (stack ?block2 $?goalbottom)
(goal-stack $? ?block1 ?block2 $?goalbottom)
=>
(retract ?stack1 ?stack2)
(assert (stack ?block1 ?block2 ?goalbottom))
(assert (stack $?bottom))
(printout t ?block1 " moved on top of " ?block2 crlf))
CLIPS>
(defrule move-on-floor
(goal-stack $? ?next $?goalbottom)
(not (stack $? ?next $?goalbottom))
?stack <- (stack $?top ?bottom)
(test (member$ ?next ?top))
=>
(retract ?stack)
(assert (stack (nth$ 1 ?top)))
(assert (stack (rest$ ?top) ?bottom))
(printout t (nth$ 1 ?top) " moved on to the floor" crlf))
CLIPS>
(assert (stack A B C)
(stack D E F)
(goal-stack D C B)
(goal-stack A)
(goal-stack F E))
<Fact-5>
CLIPS> (run)
D moved on to the floor
E moved on to the floor
F moved on top of E
A moved on to the floor
B moved on to the floor
C moved on top of B
D moved on top of C
CLIPS> (facts)
f-0 (initial-fact)
f-3 (goal-stack D C B)
f-4 (goal-stack A)
f-5 (goal-stack F E)
f-10 (stack F E)
f-11 (stack)
f-12 (stack A)
f-17 (stack D C B)
For a total of 8 facts.
CLIPS> (reset)
CLIPS>
(assert (stack A B C)
(goal-stack A B)
(goal-stack C))
<Fact-3>
CLIPS> (run)
A moved on to the floor
B moved on to the floor
A moved on top of B
CLIPS> (facts)
f-0 (initial-fact)
f-2 (goal-stack A B)
f-3 (goal-stack C)
f-7 (stack C)
f-8 (stack A B)
f-9 (stack)
For a total of 6 facts.
CLIPS>
来源:https://stackoverflow.com/questions/52683741/clips-blocks-world