Scenario

CritterWorld is a simulation of the habitat of a group of small cybernetic creatures, called Critters. They run around in mazes, eat food to gain energy and lose energy when they move, and sometimes they fight with each other.

What makes them interesting is that you have to program their “brains” to determine how they behave. See image.

Last year, Critters were given the goal of having to surviving as long as possible whilst fighting with each other over a limited resource (food). That turned out not to be as exciting as it sounds, so this year we‟ve added a twist: Critters now must compete in a race to be the first to reach a designated area of the map, shown by a green circle. (See the picture above.) The Critter with the fastest average time into the circle is the winner. Of course, they still need food and can still fight with each other on the way to the finish line.

Our plan is to run a fun competition in the final week of classes to let you pit your Critter brains against each other. Sorry, there will be no prizes or awards; only the unending admiration of your colleagues should you win!

Whilst this might seem like a somewhat trivial game, such simulations have a long and respected history. A similar idea first appeared in the late 1970‟s on the Apple II as “Robot Wars,” coded by the famous game developer Silas Warner, who also wrote the original, 2D, view-from-above version of “Castle Wolfenstein.”1 Since the original, the idea has been resurrected numerous times and is now considered a classic – though perhaps somewhat under-recognised and under- appreciated – subgenre of computer gaming.

It also has serious aspects: Similar simulations were the motivation for the first implementation of object oriented programming in the late 1960s, and are closely related to current research into artificial intelligence and multi-agent systems. The latest version of CritterWorld is available on Course Resources. Your job is to:

  • Write part of the simulation environment, and
  • Develop one or more competitive Critter “brains”.

These two tasks are detailed below:

Task 1

You must (re-)create a Configuration class to maintain the configuration options for CritterWorld. It used to exist, but Dave accidently deleted it. You‟ll see comments in the source code where the references to it used to be. Dave replaced the references to the Configuration class with explicit literals, as he hastily tried to cover up evidence of his abject idiocy by fixing the program so it would still run.

You must also write the code to edit, save, and load the configuration options. You may write any other classes you need to complete this task. You should create a modal form to allow the CritterWorld user to edit the configuration properties. The file format you use to store the configuration options is up to you.

Once you‟ve created the Configuration class, you‟ll need to determine a reasonable range of values for each property in the Configuration class, and include appropriate code to make sure that each property cannot go outside its reasonable range of values.

Despite being unable to recall even what he had for breakfast, through some lesser miracle of cognitive retrieval, Dave managed to remember one of the property definitions from the Configuration class and it is included here as an example: See image.

See how RefreshRate cannot go lower than 5 or above 60? You should do something similar for all properties that need to be constrained to a reasonable range. You need to search through the source code for CritterWorld to find all of the commented out references to Utilily.GetConfiguration() to find all of the configuration options that need to be edited. This will tell you the Properties you need to provide in the Configuration class. For example, for the refresh rate, you will see the following code: See image.

Once you have implemented your Configuration class correctly, you can uncomment the line above and remove the line that sets framesPerSecond to 12. Note that you will also need to uncomment the following lines in Utility.cs:

// static Configuration configuration = null;

And: See image.

This just creates a new instance of a configuration class if one does not already exist. Finally, you need to add code to the method editConfigurationToolStripMenuItem_Click in CritterWorldForm.cs to call the configuration edit dialog and update the contents of the Configuration class with the changes.

Task 2

The CritterWorld executable (provided to you) contains all of the logic required to handle the bodies of Critters. However, in order to run, Critters also need brains. CritterWorld dynamically loads the brains for Critters from dynamic link libraries2 (class libraries) at run-time and creates a Critter for each brain that it loads.

You must write a brain for a Critter. The specifications of the classes you need to provide are provided in the Appendix below. More information will be given in the lecture on 28th March. The aim is for your Critter to reach the specified destination as quickly as possible. At a minimum, the Critter controlled by the brain written by you should be able to do the following:

  • Be displayed in the table on the CritterWorld screen with the correct name. In order to do this you must implement the classes required correctly and provide suitable implementations for some of the properties.
  • Move around the displayed terrain in a manner defined by you.
  • Respond, in a manner defined by yourself, to hitting terrain and to being bumped by other Critters

The behaviour exhibited by the Critter control is completely up to you. I am looking for imagination and some thought to be applied to how your Critter behaves.

You have been provided with a Visual Studio solution that contains much of the code for CritterWorld. You must use this solution as your starting point. It has been set up with all of the references that you code will need and contains the executable and other dynamic link libraries you need in order to do this assignment.

Read this assignment specification carefully! It contains all of the information you need. Although the CritterWorld environment will include programming concepts you have not seen before (such as multi-threading), you have covered everything you need to complete this assignment in this module.

Important Note

Like so many software projects, CritterWorld is a work in progress. The authors will release one or more updates to CritterWorld any time from now until up to a week before the hand-in date in order to fix bugs and/or add enhancements. You may have to alter your code to adapt to changes in the CritterWorld code.

Developing code in the face of changing infrastructure and requirements is a fundamental and inescapable reality of the software business. It is something we will explore further in next year‟s Team Software Development module or Applied Game Development.

Running CritterWorld

When you run CritterWorld, to start the Critters, select World->Start World from the main menu. All of the Critters that have brains will be created. As you will see, five demonstration Critters have been supplied for your Critter to interact with. Food will also be displayed in the world for your Critter to eat. Food gives your Critter energy. When your Critter moves or interacts with other creatures, it loses energy. When a Critter eats a piece of food, the food will disappear and a new food source will be created somewhere else in the world. Food sources decay after a certain time period and new pieces of food will appear (unless configured not to) in random locations to replace them.

To test your critter(s) ability to locate the objective, select World->Start Campaign. Then you can use the appropriate calls on the ICritter interface to find the destination your critter needs to reach.

If the energy of your Critter goes below zero, your Critter will die.

If you are having problems, select Settings->Display Log Window to open a window that displays diagnostic messages that might be helpful.

The Visual Studio Solution

You have been provided with a Visual Studio 2010 solution called CritterWorld. This is the entirety of CritterWorld. The solution, as provided, will build and execute so you can see the actions of five demonstration Critters.

Writing a Brain for a Critter

When CritterWorld is executed, it looks for dynamic link library files (DLLs) in the same folder as itself. In each DLL found, CritterWorld looks for a class that implements the interface ICritterFactory. If a class that implements ICritterFactory is found, a new instance of that class is created. The DLL must also contain at least one class that implements the ICritterBrain interface. You need to write the classes that implement ICritterFactory and ICritterBrain.

ICritterFactory

The following is a definition of ICritterFactory: See image.

It consists of one method, CreateCritterBrains, which returns an array of objects that implement the interface ICritterBrain. In most cases, the array will only contain one element, but the design allows for a DLL to contain more than one brain (this is done in DemoCritter.dll).

ICritterBrain

ICritterBrain is defined as follows: See image.

The properties that you need to implement are as follows:

  • Name Returns the name of the Critter. This is the name displayed in the grid in CritterWorld.
  • Creator Returns the name of the person who created this brain, i.e. you. It should be in the form „name (student number)‟, e.g., Fred Bloggs (123456789)
  • Images An array containing images to be used to display your Critter. The images should be 15x15 pixels. If they are a different size, CritterWorld will resize them. CritterWorld will cycle through the images in sequence to form an animation. If Images returns null, CritterWorld will provide a sequence of images to be used.
  • Body Once the class that implements ICritterBrain has been loaded, CritterWorld will set this property to reference an object that provides the body of the Critter. This object implements the interface ICritter and you can call methods on this object to move your Critter, attack other Critters, etc.

The methods that you need to implement are as follows. All methods need to exist, but it is acceptable for any of them to be empty:

  • NotifyBlockedByTerrain Called if your Critter hits any terrain. The speed of the Critter will be set to 0 before NotifyBlockedByTerrain is called.
  • NotifyBumped Called if you bump into another object or are bumped by another object. You are passed a reference to an object that represents the other object that can be used in some of the methods provided by the ICritter interface. The speed of the Critter is set to 0.
  • NotifyEaten Called if your Critter has just eaten food
  • NotifyCloseToFood Called if your Critter is close to food. You are passed a reference to an object that represents the food object that can be used in some of the methods provided by the ICritter interface.
  • NotifyCloseToCritter Called if your Critter is close to another Critter. You are passed a reference to an object that represents the other Critter that can be used in some of the methods provided by the ICritter interface.
  • Birth Called when the Critter has been created. It can be used for any initial setup.
  • Think Called at periodic intervals (approximately every 100 milliseconds). This is where you can change the behaviour of your Critter at times other than simply responding to notification events. You must exit from Think(), or you will not receive any Notify* events! Assignment 2010/2011 10 Application Development (4CC051) In other words, Think() should not contain an endless loop. If you spend a lot of time before you exit Think(), the Notify* events may be significantly delayed.

ICritter

The Body property in your class will be set to reference an object that implements ICritter. This provides the following properties and methods that you can use. See image.

The properties implemented by ICritter are:

  • Speed Returns the current speed of the Critter. The smallest value is 0, the largest is 10.
  • Direction The current direction that the Critter is moving. The value is an angle between 0 and 359, where 0 is straight up, 90 is move to the right, 180 is straight down and so on.
  • Energy The current energy of the Critter. If the energy falls below zero, it dies. The energy of all Critters is set to the same value when they are born. Energy is gained by eating. Energy is lost by moving (energy is lost faster if the Critter moves faster), by aging and by attacking other Critters.
  • Age The current age of the Critter

The methods implemented by ICritter are:

  • MoveCritter Makes the critter move at the specified speed
  • StopCritter Stops the Critter moving (sets speed to 0)
  • GetDirectionTo Gets the direction to the specified object (food or Critter) using the reference provided by NotifyCloseToFood or NotifyCloseToCritter
  • GetDestination Gets the goal, which is the rectangular region your Critter needs to move to in order to score a point. It‟s shown on the screen as a green circle.
  • IsTerrainBlockingRoute Returns true if the direction to the other object (food or Critter) or coordinate is blocked by terrain, false if there is no terrain in the way
  • GetStrength Returns the energy of the other Critter (using the reference provided by NotifyBumped or NotifyCloseToCritter) relative to the energy of the current Critter. The value returned is one of the following values: See image.
  • Attack Attacks a Critter that has bumped you (using the reference provided by NotifyBumped). The chance of killing the other Critter depends on the energy of the other Critter relative to your energy (as returned by GetStrength) as follows: See image.

IWorldObject and IOtherCritter

Many of the Notify methods provide a reference to an object that implements IWorldObject or IOtherCritter. These provide two additional properties if you wish to use them (IOtherCritter inherits from IWorldObject): See image.

These provide the X and Y co-ordinates of the other object.

Other Comments

These are some additional comments that might be useful when you are deciding on the behaviour of your Critter and might help you with the assignment:

  • When a Critter eats a piece of food, it disappears. A new piece of food will magically appear somewhere else.
  • Food decays after a certain time period. New food appears when old food decays.
  • You can only attack another Critter once you have bumped into it (i.e. you have received a call to NotifyBumped).
  • Your class that implements ICritterBrain should include the following using statements at the top of the class: See image.
Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.