Suppose you have a game in which advancing to the next level depends on having all agents of a certain kind taken. For instance, in the game of Sokoban you need to have each target covered by a wooden crate. In the game of Pac-man you need to have eaten all the pills. What is a good way to program this? Two approaches are discussed here but the second one, while being a litter harder to implement, is generally the better one.
Approach 1: count to zero with an agent attribute
Lets say there are 35 pills in your Pac-man level and you need to eat each pill to advance to the next level.
Add an agent attribute to your main agent, the Pac-man.
- Select the pac-man in the worksheet.
- Select the SET action in the action palette. Adjust the action to:
<SET "pills" to 35>
Hit the test button to execute this action. The agent now owns a new attribute called "pills" with a value of 35
Save the worksheet. This will also save the pac-man pills attribute.
Extend the behavior of the pac-man to reduce the value of the pills by 1 every time the pac-man eats a pill by adding this set action to the rule where pac-man currently eats the pills:
<SET "pills" to "pills - 1">
Add a new rule to check the value of the attribute and switch to the next level of the game. This rule should be the first one to make sure level change takes precedence over any other action of the game:
IF <IS "pills" = "0"> THEN <switch-to-worksheet "Level 2">
This approach is simple to implement but does depend on the number of agents, in the example the number of pills, to be correct. The moment when you edit worksheet and add or remove the some pills the number would no longer be correct and result either in premature level switching or level switching that can never occur at all. Also, you would have to adjust this number when you do switch levels. In programming the use of hard coded number such as the "35" are generally considered bad practice by creating unwanted dependencies. This leads to approach #2.
Approach 2: poll agents
Use broadcast to implement a poll of agents. This approach is much more robust as it will allow you to freely edit your worksheet without the need to update a so called "hard coded" count of agents.
Add a polling rule to your main agent, the pac-man, to frequently broadcast a "poll" message to all of the "pill" agents in your worksheet, where ever they are:
IF <once-every 0.5> THEN <SET "@pills" to "0"> <broadcast "pill" "poll"> <make * "switch_level">
Add a new "switch_level" method to the pac-man agent:
<method "switch_level"> IF <is "@pills" = "0"> THEN <switch-to-worksheet "level2">
Add a new "poll" method to the pill agent:
<method "poll"> IF < no condition > THEN <set "@pills" to "@pills + 1">
Notice the use of the "@" sign to use global simulation properties and NOT agent attributes. In essence, you set a global simulation property "@pills" to 0, and broadcast a poll message to all the pill agents. Every pill agent will increment the value of @pills by one. However, if there are no pill agents left then the value of @pills will remain 0. In that case you all the pills are gone and you can safely switch to the next level of the game or show some kind of "you won!" message.
The polling pattern involves two kinds of agents. The poller, e.g., the pac-man agent, counts the number of pollees, e.g., pills.
Create a polling agent, the poller, and a global simulation property. The poller could be a separate agent like a game master agent or if you have only a single main game agent, e.g., the pac-man in the pac-man game, you can just extend that main agent. The poller sets the global simulation property to zero, broadcasts a “poll” message all pollees, and sends itself a “switch_level” message. Each pollee responds to the “poll” by incrementing the global simulation property by 1. The poller responds to the “switch_level” message by testing the global simulation property: if its value is zero, there are no pollees left, and the game can end or advance to a different level.