Search code examples
droolsfirst-order-logic

Function on left hand side of rule on Drools


Consider the following rule for "locations" r and s:

∀r,s[(danger(r)∧adjacent(r,s))→danger(s)] 

I tried to implement as follows:

function boolean adjacent(Location l1, Location l2) {
    if (l1.x == l2.x)
        return Math.abs(l1.y - l2.y) == 1;
    if (l1.y == l2.y)
        return Math.abs(l1.x - l2.x) == 1;
    return false;
}

rule danger
when
    $s : Location(danger == true)
    $r : Location()
    adjacent($s,$r)
then
    modify($r) { setDanger(true) }
end;

But it does not compile saying that adjacent cannot be resolved. I tried eval(adjacent($s,$r)) but it does not work because rete keeps visiting the same combinations of $s and $r forever.

I tried implementing adjacent() method on Location, but it does not compile either:

$r : Location(adjacent($s) == true)

I thought on some alternatives like: making each Location has a list of adjacent locations; etc. But none of them sounded right for me.

How would be the right way to implement this?


Solution

  • rule danger
    when
      $s : Location( danger )
      $r : Location(! danger, adjacent($s,$r) )
    then
        modify($r) { setDanger(true) }
    end
    

    You can write a boolean expression as a constraint, or inside an eval CE (but never as a pattern all by itself, as you tried).

    To avoid the loop, add a constraint that fails after the modify.