-1

I am trying to write Drools rules that identify winners. The rules are as follows;

  1. If anyone is named Bob they win
  2. If nobody is named Bob the oldest person wins

Here's what I have:

rule "Bob wins" when $winner : Person(name == "Bob") then $winner.setWinner(true); update($winner); end rule "Oldest person wins" salience -10 // Runs only if there is no Bob when not Person(name == "Bob") $winner : Person() from accumulate( Person($age : age), max($age) ) then $winner.setWinner(true); update($winner); end 

How can I identify the non-winners so I can setWinner(false) on them?

1
  • why the java tag? How is this question about having problems using or understanding Java itself? (as suggested by the tag description) Commented Mar 20 at 9:27

2 Answers 2

1

You need to handle your Bob wins/everyone else loses use cases separately. Otherwise given a situation where there are two Bobs in the contest, and nobody with another name, you'll need to still mark both Bobs the winner regardless of the presence (or lack thereof) of any other non-Bob contestants.

rule "Bob wins" when $winner : Person(name == "Bob") then $winner.setWinner(true); update($winner); end rule "Bob wins - everyone else loses" when exists( Person(name == "Bob") ) // there exists at least one Bob $lost: Person(name != "Bob") then $lost.setWinner(false); update($lost) end 

For every "Bob" in working memory, they are set as the winner. For every non-Bob in working memory, they are set as the loser. If you combined both criteria into a single rule like this:

rule "Bob wins, everyone else loses" when $winner: Person(name == "Bob") $loser: Person (name != "Bob") then // omitted for brevity end 

The "when" clause is not satisfied unless there exists at least one Person in working memory whose name is not Bob and at least one person whose name is Bob. If there are no non-Bobs, the rule doesn't fire at all, and Bob(s) won't be the winner.


Of course, if there are a lot of people in this contest, this is hellishly inefficient because update makes changes to the working memory and then refires all rules. (It's one of the most expensive operations you can do.)

To make it more efficient, one would apply strategies like defaulting the win condition to "false", so you don't have to actually set losers, just the winners. Also, the "Bob wins" condition should ignore any Bob who is already a winner -- that way the rule doesn't re-fire and call update needlessly:

rule "Bob wins" when $winner: Person(name == "Bob", winner == false) // only trigger if there's a Bob who is not a winner then $winner.setWinner(true); update($winner); end 

If the winner flag in Person is a boolean (not a Boolean), then it's probably already defaulted false.

Your "there are no Bobs" rule already does the trick with accumulate and max().

Sign up to request clarification or add additional context in comments.

Comments

0

These rules do the job. There was a problem with my accumulation, and the losers can be found simply by choosing the inverse of the win condition.

rule "Bob wins" when $winner : Person(name == "Bob") $losers: Person(name != "Bob") then $winner.setWinner(true); update($winner); $losers.setWinner(false); update($losers); end rule "Oldest person wins" when not Person(name == "Bob") $winner: Person($age : age) not(Person(age > $age, name != "Bob")) $losers : Person(age < $age) then $winner.setWinner(true); update($winner); $losers.setWinner(false); update($losers); end 

1 Comment

This won't work if everyone is named Bob.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.