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().