Skip to: Site menu | Main content

Drools

Java Rules Engine

Miss Manners Example Print

Introduction

Miss Manners is a program which handles the problem of finding an acceptable seating arrangement for guests at a dinner party. It will attempt to match people with the same hobbies, and to seat everyone next to a member of the opposite sex. Manners is a small program, which has only few rules, and employs a depth-first search approach to the problem.

Running Miss Manners

Change into the drools-examples directory and run the Miss Manners example:

D:\java\workspaces\drools-2.0\drools-examples>maven manners-java
 __  __
|  \/  |__ _Apache__ ___
| |\/| / _` \ V / -_) ' \  ~ intelligent projects ~
|_|  |_\__,_|\_/\___|_||_|  v. 1.0

(bunch of output)

manners-java:
    [java] Using drl: manners.java.drl
    [java] FIRE: find first seat: {name=n14,sex=m,hobbies=[h3, h1]}
    [java] FIRE: find seating: {seat1=1,guest1={name=n14,sex=m,hobbies=[h3, h1]},seat2=2,guest2=null} {name=n1,sex=f,hobbies=[h2, h1]}
    [java] FIRE: find seating: {seat1=2,guest1={name=n1,sex=f,hobbies=[h2, h1]},seat2=3,guest2=null} {name=n9,sex=m,hobbies=[h2, h3, h1]}
    [java] FIRE: find seating: {seat1=3,guest1={name=n9,sex=m,hobbies=[h2, h3, h1]},seat2=4,guest2=null} {name=n5,sex=f,hobbies=[h3, h1, h2]}
    [java] FIRE: find seating: {seat1=4,guest1={name=n5,sex=f,hobbies=[h3, h1, h2]},seat2=5,guest2=null} {name=n11,sex=m,hobbies=[h1, h3]}
    [java] FIRE: find seating: {seat1=5,guest1={name=n11,sex=m,hobbies=[h1, h3]},seat2=6,guest2=null} {name=n10,sex=f,hobbies=[h2, h1, h3]}
    [java] FIRE: find seating: {seat1=6,guest1={name=n10,sex=f,hobbies=[h2, h1, h3]},seat2=7,guest2=null} {name=n7,sex=m,hobbies=[h1, h2]}
    [java] FIRE: find seating: {seat1=7,guest1={name=n7,sex=m,hobbies=[h1, h2]},seat2=8,guest2=null} {name=n8,sex=f,hobbies=[h1, h3, h2]}
    [java] FIRE: find seating: {seat1=8,guest1={name=n8,sex=f,hobbies=[h1, h3, h2]},seat2=9,guest2=null} {name=n13,sex=m,hobbies=[h2, h1, h3]}
    [java] FIRE: find seating: {seat1=9,guest1={name=n13,sex=m,hobbies=[h2, h1, h3]},seat2=10,guest2=null} {name=n3,sex=f,hobbies=[h2, h3]}
    [java] FIRE: find seating: {seat1=10,guest1={name=n3,sex=f,hobbies=[h2, h3]},seat2=11,guest2=null} {name=n12,sex=m,hobbies=[h1, h2]}
    [java] FIRE: find seating: {seat1=11,guest1={name=n12,sex=m,hobbies=[h1, h2]},seat2=12,guest2=null} {name=n4,sex=f,hobbies=[h2, h1, h3]}
    [java] FIRE: find seating: {seat1=12,guest1={name=n4,sex=f,hobbies=[h2, h1, h3]},seat2=13,guest2=null} {name=n15,sex=m,hobbies=[h1, h3]}
    [java] FIRE: find seating: {seat1=13,guest1={name=n15,sex=m,hobbies=[h1, h3]},seat2=14,guest2=null} {name=n6,sex=f,hobbies=[h1, h3]}
    [java] FIRE: find seating: {seat1=14,guest1={name=n6,sex=f,hobbies=[h1, h3]},seat2=15,guest2=null} {name=n16,sex=m,hobbies=[h2, h3]}
    [java] FIRE: find seating: {seat1=15,guest1={name=n16,sex=m,hobbies=[h2, h3]},seat2=16,guest2=null} {name=n2,sex=f,hobbies=[h3, h1, h2]}
    [java] FIRE: we are done
    [java] {seat=1,name=n14}
    [java] {seat=2,name=n1}
    [java] {seat=3,name=n9}
    [java] {seat=4,name=n5}
    [java] {seat=5,name=n11}
    [java] {seat=6,name=n10}
    [java] {seat=7,name=n7}
    [java] {seat=8,name=n8}
    [java] {seat=9,name=n13}
    [java] {seat=10,name=n3}
    [java] {seat=11,name=n12}
    [java] {seat=12,name=n4}
    [java] {seat=13,name=n15}
    [java] {seat=14,name=n6}
    [java] {seat=15,name=n16}
    [java] {seat=16,name=n2}
    [java] Elapsed time: 140ms
BUILD SUCCESSFUL
Total time: 54 seconds
Finished at: Mon Mar 28 01:27:08 CEST 2005

Understanding the Miss Manners Example

<!--
Initialize the root seating element.
-->
<rule name="find first seat" salience="40">
   <parameter identifier="context">
       <class>Context</class>
   </parameter>
   <parameter identifier="guest">
       <class>Guest</class>
   </parameter>

   <java:condition>
      context.isState("start")
   </java:condition>

    <java:consequence>
       System.out.println("FIRE: find first seat: " + guest);

       drools.assertObject(new Seating(1, guest, null));

       context.setState("find_seating");
       drools.modifyObject(context);
    </java:consequence>
</rule>
<!--
Find guest for empty seat.
-->
<rule name="find seating" salience="30">
  <parameter identifier="context">
      <class>Context</class>
  </parameter>
  <parameter identifier="guest">
      <class>Guest</class>
  </parameter>
  <parameter identifier="seating">
      <class>Seating</class>
  </parameter>

  <java:condition>
     context.isState("find_seating")
  </java:condition>

  <java:condition>
     seating.getGuest2() == null
  </java:condition>

  <java:condition>
     !seating.getTabooList().contains(guest)
  </java:condition>

  <java:condition>
     seating.getGuest1().hasOppositeSex(guest)
  </java:condition>

  <java:condition>
     seating.getGuest1().hasSameHobby(guest)
  </java:condition>

  <java:consequence>
     System.out.println("FIRE: find seating: " + seating + " " + guest);

     Seating nextSeat = new Seating(seating.getSeat2(), guest, seating);
     drools.assertObject(nextSeat);

     seating.setGuest2(guest);
     seating.getTabooList().add(guest);
     drools.modifyObject(seating);

  </java:consequence>
</rule>
<!--
Reached dead end, try another path.
-->
<rule name="try another path" salience="20">
  <parameter identifier="context">
      <class>Context</class>
  </parameter>
  <parameter identifier="lastSeat">
      <class>LastSeat</class>
  </parameter>
  <parameter identifier="seating">
      <class>Seating</class>
  </parameter>

  <java:condition>
     context.isState("find_seating")
  </java:condition>

  <java:condition>
     lastSeat.getSeat() > seating.getSeat1()
  </java:condition>

  <java:condition>
     seating.getGuest2() == null
  </java:condition>

  <java:consequence>
     System.out.println("FIRE: try another path: " + seating);

     Seating prevSeat = seating.getPrevSeat();
     prevSeat.setGuest2(null);
     drools.modifyObject(prevSeat);

     drools.retractObject(seating);
  </java:consequence>
</rule>
<!--
All seats are taken.
-->
<rule name="we are done" salience="10">
  <parameter identifier="context">
      <class>Context</class>
  </parameter>
  <parameter identifier="lastSeat">
      <class>LastSeat</class>
  </parameter>
  <parameter identifier="seating">
      <class>Seating</class>
  </parameter>

  <java:condition>
     context.isState("find_seating")
  </java:condition>

  <java:condition>
     lastSeat.getSeat() == seating.getSeat1()
  </java:condition>

  <java:consequence>
     System.out.println("FIRE: we are done");

     List list = new ArrayList();
     while(seating != null) {
        Seat seat = new Seat(seating.getSeat1(), seating.getGuest1().getName());
        seating = seating.getPrevSeat();
        list.add(seat);
     }

     for (int i = list.size(); i > 0; i--) {
        Seat seat = (Seat)list.get(i-1);
        System.out.println(seat);
        drools.assertObject(seat);
     }

     context.setState("all_done");
     drools.modifyObject(context);
  </java:consequence>
</rule>