Chapter 29. Number Guess Example

29.1. Number Guess Example: Loading the Example

final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newClassPathResource( "NumberGuess.drl",
                                                    ShoppingExample.class ),
              ResourceType.DRL );
kbuilder.add( ResourceFactory.newClassPathResource( "NumberGuess.rf",
                                                    ShoppingExample.class ),
              ResourceType.DRF );

final KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
  • The Number Guess example located in NumberGuess.drl shows the use of Rule Flow, a way of controlling the order in which rules are fired. It is loaded as shown above.

29.2. Number Guess Example: Starting the RuleFlow

final StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

KnowledgeRuntimeLogger logger =
  KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "log/numberguess");

ksession.insert( new GameRules( 100, 5 ) );
ksession.insert( new RandomNumber() );
ksession.insert( new Game() );

ksession.startProcess( "Number Guess" );
ksession.fireAllRules();

logger.close();

ksession.dispose();
  • The above code demonstrates the creation of the package and the loading of the rules (using the add() method).
  • There is an additional line to add the Rule Flow (NumberGuess.rf), which provides the option of specifying different rule flows for the same Knowledge Base.
  • Once the Knowledge Base is created it can be used to obtain a Stateful Session. The facts are then inserted.

29.3. Number Guess Example: Classes and Methods

Note

The Number Guess Example classes are all contained within the NumberGuessExample.java file.
  • Class GameRules provides the maximum range and the number of guesses allowed.
  • Class RandomNumber automatically generates a number between 0 and 100 and makes it available to the rules. It does so by insertion via the getValue() method.
  • Class Game keeps track of the number of guesses made.
  • To start the process, the startProcess() method is called.
  • To execute the rules, the fireAllRules() method is called.
  • To clear the Working Memory session, the dispose() method is called.

29.4. Number Guess Example: Observing the RuleFlow

Procedure 29.1. Task

  1. Open the NumberGuess.rf file in the Drools IDE. A diagram will appear that works much like a standard flowchart.
  2. To edit the diagram, use the menu of available components to the left of the diagram in the IDE. This is called a palette.
  3. Save the diagram in XML. (If installed, you can utilise XStream to do this.)
  4. If it is not already open, ensure that the Properties View is visible in the IDE. It can be opened by clicking WindowShow ViewOther where you can select the Properties view. If you do this before you select an item on the rule flow (or click on the blank space in the rule flow) you will see the properties. You can use these properties to identify processes and observe changes.

29.5. Number Guess Example: RuleFlow Nodes

In the Number Guess RuleFlow there are several node types:
  • The Start node (white arrow in a green circle) and the End node (red box) mark beginning and end of the rule flow.
  • A Rule Flow Group box (yellow, without an icon) represents a Rule Flow Groups defined in the rules (DRL) file. For example, when the flow reaches the Rule Flow Group "Too High", only those rules marked with an attribute of ruleflow-group "Too High" can potentially fire.
  • Action nodes (yellow cog-shaped icon) perform standard Java method calls. Most action nodes in this example call System.out.println(), indicating the program's progress to the user.
  • Split and Join Nodes (blue ovals, no icon) such as "Guess Correct?" and "More guesses Join" mark places where the flow of control can split and rejoin.
  • Arrows indicate the flow between the various nodes.

29.6. Number Guess Example: Firing Rules at a Specific Point in NumberGuess.drl

rule "Get user Guess"
    ruleflow-group "Guess"
    no-loop
    when
        $r : RandomNumber()
        rules : GameRules( allowed : allowedGuesses )
        game : Game( guessCount < allowed )
        not ( Guess() )
    then
        System.out.println( "You have " + ( rules.allowedGuesses - game.guessCount )
                            + " out of " + rules.allowedGuesses
                            + " guesses left.\nPlease enter your guess from 0 to "
                            + rules.maxRange );
        br = new BufferedReader( new InputStreamReader( System.in ) );
        i = br.readLine();        
        modify ( game ) { guessCount = game.guessCount + 1 }
        insert( new Guess( i ) );
end
  • The various nodes in combination with the rules make the Number Guess game work. For example, the "Guess" Rule Flow Group allows only the rule "Get user Guess" to fire, because only that rule has a matching attribute of ruleflow-group "Guess".
  • The LHS section (after when) of the rule states that it will be activated for each RandomNumber object inserted into the Working Memory where guessCount is less than allowedGuesses from the GameRules object and where the user has not guessed the correct number.
  • The RHS section (or consequence, after then) prints a message to the user and then awaits user input from System.in. After obtaining this input (the readLine() method call blocks until the return key is pressed) it modifies the guess count and inserts the new guess, making both available to the Working Memory.
  • The package declares the dialect as MVEL and various Java classes are imported.
In total, there are five rules in this file:
  1. Get User Guess, the Rule examined above.
  2. A Rule to record the highest guess.
  3. A Rule to record the lowest guess.
  4. A Rule to inspect the guess and retract it from memory if incorrect.
  5. A Rule that notifies the user that all guesses have been used up.

29.7. Number Guess Example: Viewing RuleFlow Constraints

Procedure 29.2. Task

  1. In the IDE, go to the Properties view and open the Constraints Editor by clicking on the "Constraints" property line.
  2. Click on the Edit button beside To node Too High to open the dialogue which will present you with various options. The values in the Textual Editor window follow the standard rule format for the LHS and can refer to objects in Working Memory. The consequence (RHS) is that the flow of control follows this node (that is, To node Too High) if the LHS expression evaluates to true.

29.8. Number Guess Example: Console Output

You have 5 out of 5 guesses left.
Please enter your guess from 0 to 100
50
Your guess was too high
You have 4 out of 5 guesses left.
Please enter your guess from 0 to 100
25
Your guess was too low
You have 3 out of 5 guesses left.
Please enter your guess from 0 to 100
37
Your guess was too low
You have 2 out of 5 guesses left.
Please enter your guess from 0 to 100
44
Your guess was too low
You have 1 out of 5 guesses left.
Please enter your guess from 0 to 100
47
Your guess was too low
You have no more guesses
The correct guess was 48 

  • Since the file NumberGuess.java contains a main() method, it can be run as a standard Java application, either from the command line or via the IDE. A typical game might result in the interaction above. The numbers in bold were typed in by the user.
  • The main() method of NumberGuessExample.java loads a Rule Base, creates a Stateful Session and inserts Game, GameRules and RandomNumber (containing the target number) objects into it. The method also sets the process flow to be used and fires all rules. Control passes to the RuleFlow.
  • The RuleFlow file NumberGuess.rf begins at the "Start" node.
  • At the Guess node, the appropriate Rule Flow Group ("Get user Guess") is enabled. In this case the Rule "Guess" (in the NumberGuess.drl file) is triggered. This rule displays a message to the user, takes the response, and puts it into Working Memory. Flow passes to the next Rule Flow Node.
  • At the next node, "Guess Correct", constraints inspect the current session and decide which path to take.
    If the guess in step 4 was too high or too low, flow proceeds along a path which has an action node with normal Java code printing a suitable message and a Rule Flow Group causing a highest guess or lowest guess rule to be triggered. Flow passes from these nodes to step 6.
    If the guess in step 4 was right, we proceed along the path towards the end of the RuleFlow. Before this, an action node with normal Java code prints a statement "you guessed correctly". There is a join node here (just before the Rule Flow end) so the no-more-guesses path (step 7) can also terminate the RuleFlow.
  • Control passes as per the RuleFlow via a join node to a "guess incorrect" RuleFlow Group (triggering a rule to retract a guess from Working Memory) and onto the "More guesses" decision node.
  • The "More guesses" decision node (on the right hand side of the rule flow) uses constraints, again looking at values that the rules have put into the working memory, to decide if the user has more guesses and. If so, it moves to step 3. If not, the user proceeds to the end of the RuleFlow via a RuleFlow Group that triggers a rule stating "you have no more guesses".
  • The loop over steps 3 to 7 continues until the number is guessed correctly or the user runs out of guesses.
Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat Documentation

We help Red Hat users innovate and achieve their goals with our products and services with content they can trust.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

© 2024 Red Hat, Inc.