Dans le cadre de notre cours de oz-mozart nous avons du programmer un petit jeu calqué sur le célèbre jeu de notre enfance: WarCraft !! Ayant pris ce projet très à coeur, car étant un grand amateur de ce jeux quand j’étais petit, on s’y est mis à fond Julien et moi. Voici un petit billet pour vous partager le sources de ce programme s’il peut vous être utile pour une raison quelconque
Pour commencer, voici la liste des fichiers:
- WozCraft-final-v090158mai06.tar.gz (Dans ce fichier se trouve tous les fichier sources pour l’execution du programme ainsi que le README et les diagrammes d’état
Pour compiler le code il va de soi que vous devez posseder une version de oz-mozart sur votre ordinateur. Ensuite vous n’avez qu’à executer le script shell se trouvant dans le fichier « start » ou bien compiler avec le makefile.
Un README a été rédigé pour le jeu afin d’expliquer brièvement les choix qui ont été faits pour l’implémentation. N’hésitez pas à y jeter un oeil.
Si vous avez pris le courage de tester notre code, ca me ferais plaisir d’avoir vos commentaires ou remarques. N’hésitez pas à vous manifester.
Voici aussi quelques screenshots pour vous donner une idée de ce que ca donne 😉
Voici l’énoncé du projet
You are going to write a strategy game simulator where two multi-agent teams will fight each other. We will take Warcraft as inspiration, but you will be free to adapt it as long as you respect the basic requirements of the project. We will have two players representing Orcs and Humans, and a subset of units. Human units are peasant and footman. Orc units are peon and grunt. We will refer to peon or peasant as peon, and to grunt or footman as soldier .
To play the game, the user must load the code representing 3 brains of every race: player, peon and soldier. The player will be able to send messages to its units asking them to do particular activities such as building, fighting or resource collection.The game will be developed in a board, which also contains buildings and resources, which are described bellow.
The board is made of WIDTH by HEIGHT squares, delimiting the movement of the agents. Each square of the board can contain one type of fixed element, and one type of mobile unit. Fixed element are resources and buildings. Mobile units are peons or soldiers. Having this restriction, consider that mobile unit can walk over resources and through buildings.
Each unit has:
- a position on the board,
- health (an integer),
- a brain (a function).
Units receive commands from their master player to perform particular actions. Soldiers are the simplest entities because they just fight, being able to hit other units and buildings. It is not requested, but you can implement guarding activities as well. Peons are more complex because they perform more activities. They can collect resources, build farms and barracks, and they can also fight, but causing less damage than a soldier.
Every unit take independent decisions according to their brain, but they must also react immediately to the request of players. Every player has also a brain, and according to the information they can observe in the board, they can send messages to their units (as described in the above section).
The goal of the game is to eliminate all the units from the other team, and destroy all their buildings.
This section describes a minimal set of rules that every entity must follow. Feel free to add more rules to the game, but be sure that you document them.
The board is made of WIDTH by HEIGHT. Initially, RESOURCE units of resource are placed on RESOURCESQUARES. Arrangement of these squares is not specified. It can be fixed, random, user-specified, etc. Every race starts with 1 Town Hall, 2 peons and 2 soldiers. No farms, no barracks. Each square can contain at most one unit, and one building or resource (greater than zero).
Each unit is completely independent of the others. But you can coordinate them sending them messages from the player.
Each unit repeatedly does:
- Take a snapshot of its local environment.
- Execute it’s brain function with this snapshot as argument.
- React according to the brain function’s result.
- Messages from the master player can interrupt any activity they are performing
- If a unit is attacked, its health must be reduced inmediately.
Since the units are executing independently, the situation when the action is taken may be different from the situation in the snapshot. For instance, if a unit saw an enemy in the snapshot, and decide to attack him, it is possible that when tries to hit the enemy, he already run away.
The argument to the brain function is a record, having an action to perform, and a local environment having the following grammar:
<brain argument> ::= info(action:<action type> env:<local env>) <action type> ::= build(<building type>) <local env> ::= env(n:<square desc> s:<square desc> e:<square desc> w:<square desc> ne:<square desc> nw:<square desc> se:<square desc> sw:<square desc>) <square desc> ::= sq(fixed:<fixed> mobile:<mobile>)  nil <fixed> ::= resource(<integer>)  <race>(<building type>)  none <mobile> ::= <race>(<unit type>)  none <building type> ::= hall  farm  barrack <unit type> ::= peon  soldier <race> ::= human  orc
The n, s, e, w, ne, nw, se and sw features of the record correspond to the square on the top, bottom, right, left, top-right, top-left, bottom-right and bottom-left of the agent’s current square. A square description saying nil means that the square does not exist. This situation happens in the border of the board.
The result of the brain function is an atom or record corresponding to this grammar:
<action> ::= <coordinate>  fight(<coordinate>)  build(<coordinate>)  collect(<coordinate>) <coordinate> ::= n  s  e  w  ne  nw  se  sw
The actions with a coordinate represent the next movement of the agent. If the destination square was already occupied when the action is taken, the agent remains in its position. Check some brain samples. Note that the grammar of the argument for the player’s brain contains more information
<players brain argument> ::= info(env:<local env> resources:<integer> farms:<integer> barracks:<integer> barrackslist:<list> peons:<integer> peonslist:<list> soldiers:<integer> soldierslist:<list> hall:<hall>)
The action of build(<coordinate>) will take BUILDING time to be perform, and BUILDINGCOST will be reduced from the resources of the team. They must be constructed in an empty square. Here is a description to be consid
- Every building has a health indicator, and a price. They are built by peons.
- Town Hall and Great Hall are the basic building for every race. They create peasants and peons. Starting health 500. They cannot be built, and every race starts with only one of them.
- Farms for humans and Pig Farms for Orcs are needed to feed the units. One Farm is needed per every 10 units. Starting health 100, Price 100 resources.
- Barracks. This building is necessary to create soldiers. Starting health 250, Price 200
The action of fighting causes damage in other units and buildings, reducing randomly their health according to the following description. Every unit starts with a health of 100. When the unit reach 0 health, it will logically die.
|Soldier||Peon||40 – 80|
|Soldier||Soldier||20 – 50|
|Peon||Peon||20 – 50|
|Peon||Soldier||20 – 30|
The action of collecting resources can only be perform by peons, and not by soldiers. It takes COLLECT milliseconds to get 30 resources from a square, which starts from RESOURCE resources (180 is a convenient number).
The game must have a time out set with the GUI before the simulation. When the time out is reached, the winner will be the race with more units and buildings. Before the time out, the game is finished when one of the races looses all its units and buildings.
You have to make a QTk GUI. The GUI will ask for 3 codes per race (player, peon and soldier), and show the evolution of the battle. A very simple graphical representation of a board is provided here. When the game is finished a window will give the information of the winner.
Compiler.virtualStringToValue can be used to convert the code given by the player to an Oz function. This function can take a lot of time and memory, so use it only once per player per game.
Extension to the declarative model
In general, you are only allowed to use ports. No cells, no dictionaries, no locks, no classes, no arrays, and no entity that manage state explicitly.
Concurrency is cheap but not for free. Use threads if you need them.