2009年11月13日金曜日

Drools でハノイの塔

Drools で再帰を試したくてハノイの塔(Tower of Hanoi)を書いてみた。思ったよりだいぶスッキリと書ける。
package com.sample
 
import com.sample.HanoiTest.Tower;
import com.sample.HanoiTest.Action;
 
rule "move one disk"
   when
      a: Action($height: height, 
         $from: fromTower, $to: toTower, 
         height==1)
   then
      $from.moveOneDisk($to);
end

rule "move disks"
   when
      a: Action($height: height, 
         $from: fromTower, $to: toTower, $other: otherTower, 
         height>1)
   then
      insert(new Action($height - 1, $other, $to, $from));
      insert(new Action(1, $from, $to, $other));
      insert(new Action($height - 1, $from, $other, $to));
      retract(a);
end
package com.sample;

import 略

public class HanoiTest {
   public static final void main(String[] args) throws Exception {

      KnowledgeBase kbase = readKnowledgeBase();
      StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

      final Tower t1 = new Tower(1, "A", "B", "C", "D");
      final Tower t2 = new Tower(2);
      final Tower t3 = new Tower(3);

      ksession.insert(t1);
      ksession.insert(t2);
      ksession.insert(t3);
      ksession.insert(new Action(4, t1, t3, t2));

      ksession.addEventListener(new DefaultAgendaEventListener() {
         public void afterActivationFired(AfterActivationFiredEvent event) {
            String ruleName = event.getActivation().getRule().getName();
            if ("move one disk".equals(ruleName)) {
               System.out.printf("%-15s%-15s%-15s%n", t1, t2, t3);
            }
         }
      });
      System.out.printf("%-15s%-15s%-15s%n", t1, t2, t3);
      ksession.fireAllRules();
   }
   
   private static KnowledgeBase readKnowledgeBase() ・・・ 略
   
   public static class Tower {
      private final int number;
      private final Stack<String> disks = new Stack<String>();
      public Tower(int number, String...disks) {
         this.number = number;
         this.disks.addAll(Arrays.asList(disks));
      }
      public int getNumber() {
         return number;
      }
      public String toString() {
         return String.format("塔%d%s", number, disks.toString());
      }
      public void moveOneDisk(Tower to) {
         to.disks.push(disks.pop());
      }
   }
   public static class Action {
      private int height;
      private Tower fromTower;
      private Tower toTower;
      private Tower otherTower;
      コンストラクタとgetter/setter 略
   }
}
予定通りの出力になる。
塔1[A, B, C, D] 塔2[]           塔3[]           
塔1[A, B, C]    塔2[D]          塔3[]           
塔1[A, B]       塔2[D]          塔3[C]          
塔1[A, B]       塔2[]           塔3[C, D]       
塔1[A]          塔2[B]          塔3[C, D]       
塔1[A, D]       塔2[B]          塔3[C]          
塔1[A, D]       塔2[B, C]       塔3[]           
塔1[A]          塔2[B, C, D]    塔3[]           
塔1[]           塔2[B, C, D]    塔3[A]          
塔1[]           塔2[B, C]       塔3[A, D]       
塔1[C]          塔2[B]          塔3[A, D]       
塔1[C, D]       塔2[B]          塔3[A]          
塔1[C, D]       塔2[]           塔3[A, B]       
塔1[C]          塔2[D]          塔3[A, B]       
塔1[]           塔2[D]          塔3[A, B, C]    
塔1[]           塔2[]           塔3[A, B, C, D] 

0 件のコメント:

コメントを投稿