Voilà le dernier projet d'un cours que j'ai suivi. J'utilise la librairie curses pour le mode graphique du jeu. Je ne pense pas qu'elle soit disponible sous windows (ou p-e avec cygwin). Je pense peut-être l'améliorer plus tard, hiérarchie de niveaux, difficultés,etc...Et passer en mode fenêtré avec GTK+ ou autre (nouveau pour moi).
Voilà, le code est propre, commenté (en anglais).
Pour les labirynthes : S=MUR , p=PacMan , d=DRAGON , t=TRESOR , v= Voleur.
Une partie du code est tiré de la solution des profs, le projet étant étalé sur plusieurs semaines. Ce code est toutefois celui que j'ai rendu et sur lequel j'ai été coté.
Voilà c'est tout, le Makefile est fourni avec, pour compiler, il suffit de taper MAKE après avoir dézippé le tout.
MAj : Voila un screen (bizarement g du remmetre des # comme murs car les carres blanc ne marchent plus avec mandrake 10 O_o). J'ai ajouté l'éxéctuable Unix compilé. Pour le win32..wait & see....maybe for a long time.....
Source / Exemple :
//Code du PacMan.c !
#include <pthread.h>
#include "PacManInput.h"
#include "PacManOutput.h"
#include "PacManScene.h"
#include <stdlib.h> // For exit()
#include <stdio.h> // For file reading
#include <stdbool.h> // For booleans
#define _XOPEN_SOURCE 500 /* for usleep() */
#include <unistd.h> /* for usleep() */
#define MUTEX
#ifdef MUTEX
pthread_mutex_t mutex;
#endif
/*---------------------------------------------------------------------*
- Game constants.
- ---------------------------------------------------------------------*/
static const float DRAGON_FAC = 0.5; // Score ratio reaching a dragon
static const float GHOST_FAC = 0.5; // Score ratio reaching a ghost
static const int TREASURE_SUM = 50; // Score bonus reaching a treasure
static const int THIEF_SUM = 100; // Score ratio reaching a thief(boss)
/*---------------------------------------------------------------------*
- Data structure gathering all the informations about a possible
- state of the game.
- ---------------------------------------------------------------------*/
typedef struct pmAgentList_t { // Data type for a linked list of agents
PmAgent agent; // One agent
struct pmAgentList_t *next; // Pointer to the next agent in the list
} PmAgentList;
typedef struct {
int width, height; // Size of the labyrinth
PmAgent pacman; // PacMan's position
PmScene* scene; // Maze description
PmAgentList *dragons; // Linked list of dragons
int numCrumbs; // Number of crumbs yet to eat
int numTreasures; // Number of treasures yet to recover
int initTreasures; // Number of treasures at the start
int score; // Current score
// New fields :
PmAgentList *ghosts; // Linked list of ghosts
PmAgent thief; // Thief's position
bool isKnowthief; // Is there is a thief in the lab
PmiCommand userCommand; // The user command for pacman
} PmState;
/*---------------------------------------------------------------------*
- Error function displaying a message and terminating the program.
*
- PARAMETERS
- msg the error message to display
*
- RETURN:
- nothing
- ---------------------------------------------------------------------*/
static void error_exit(const char *msg)
{
// Close the input and the output
pmiClose();
pmoClose();
printf("Fatal error: %s\n", msg); // Print the message
exit(1); // Terminate the program
}
/*---------------------------------------------------------------------*
*
- PARAMETERS
- pmState the game state to free
*
- RETURN:
- nothing
- ---------------------------------------------------------------------*/
static void freeGameState(PmState *pmState)
{
while (pmState->dragons) { // Free the dragon list
PmAgentList *head = pmState->dragons;
pmState->dragons = head->next;
free(head);
}
while (pmState->ghosts) { // Free the ghosts list
PmAgentList *head = pmState->ghosts;
pmState->ghosts = head->next;
free(head);
}
pmsDeleteScene(pmState->scene); // Free the scene
free(pmState); // Free the game state structure
}
/*---------------------------------------------------------------------*
- Initializes one cell in the labyrinth according to some character
- from the maze description file.
*
- PARAMETERS
- pmState the state of the game
- x, y the coordinates of the cell to initialize
- thisChar the character from the maze description file
- isPacManPositionKnown a pointer to a Boolean flag telling whether
- PacMan's initial position is already known
*
- RETURN:
- nothing
- ---------------------------------------------------------------------*/
static void initCell(PmState *pmState, int x, int y, int thisChar,
bool *isPacManPositionKnown)
{
// Deduce the cell content from the character
if (thisChar != 'S' && thisChar != 'p') {
// The space contains one crumb
pmState->numCrumbs++;
pmsPutCell(pmState->scene, x, y, CRUMB);
if (pmoDrawCell(x, y, CRUMB))
error_exit("pmoDrawCell(CRUMB)");
}
switch (thisChar) {
case ' ' : // Blank space
break;
case 'S' : // Solid space
pmsPutCell(pmState->scene, x, y, SOLID);
if (pmoDrawCell(x, y, SOLID))
error_exit("pmoDrawCell(SOLID)");
break;
case 'p' : // PacMan's initial position
if (*isPacManPositionKnown)
error_exit("Two PacMan's initial positions given");
// Set PacMan's initial position
pmState->pacman.x = x;
pmState->pacman.y = y;
pmState->pacman.type = PACMAN;
- isPacManPositionKnown = true;
pmsPutAgent(pmState->scene, &pmState->pacman);
if (pmoDrawAgent(&pmState->pacman))
error_exit("pmoDrawCell(PACMAN)");
break;
case 'd' : { // Dragon
// Allocate a new dragon
PmAgentList *newDragon = malloc(sizeof(PmAgentList));
if (!newDragon)
error_exit("malloc(dragon)");
// Set informations for the dragon
newDragon->agent.x = x;
newDragon->agent.y = y;
newDragon->agent.type = DRAGON;
// Add the new dragon in the dragon list
newDragon->next = pmState->dragons;
pmState->dragons = newDragon;
pmsPutAgent(pmState->scene, &newDragon->agent);
if (pmoDrawAgent(&newDragon->agent))
error_exit("pmoDrawCell(DRAGON)");
break;
}
case 'g' : { // Ghost
// Allocate a new ghost
PmAgentList *newGhost = malloc(sizeof(PmAgentList));
if (!newGhost)
error_exit("malloc(ghost)");
// Set informations for the ghost
newGhost->agent.x = x;
newGhost->agent.y = y;
newGhost->agent.type = GHOST;
// Add the new ghost in the ghost list
newGhost->next = pmState->ghosts;
pmState->ghosts = newGhost;
pmsPutAgent(pmState->scene, &newGhost->agent);
if (pmoDrawAgent(&newGhost->agent))
error_exit("pmoDrawCell(GHOST)");
break;
}
case 'v' : //Thief
if (pmState->isKnowthief)
error_exit("Two thiefs's initial positions given");
pmState->isKnowthief = true;
// Set Thief's initial position
pmState->thief.x = x;
pmState->thief.y = y;
pmState->thief.type = THIEF;
pmsPutAgent(pmState->scene, &pmState->thief);
if (pmoDrawAgent(&pmState->thief))
error_exit("pmoDrawCell(THIEF)");
break;
case 't' : { // Treasure
pmState->numTreasures++;
pmState->initTreasures++; // For thief factor
pmsPutCell(pmState->scene, x, y, TREASURE);
if (pmoDrawCell(x, y, TREASURE))
error_exit("pmoDrawCell(TREASURE)");
break;
}
default: // Error
error_exit("Unknown cell content");
}
}
/*---------------------------------------------------------------------*
- Reads a maze and display its content on screen.
*
- PARAMETERS
- filename the name of the file containing the labyrinth
- pmState the state of the game
*
- RETURN:
- nothing
- ---------------------------------------------------------------------*/
static void initLabyrinth(const char* filename, PmState *pmState)
{
// Open the given file in read mode
FILE *file = fopen(filename, "r");
if (!file)
error_exit(filename);
// Some useful variables
bool isPacManPositionKnown = false; // Becomes true when 'p' is met
int thisChar = fgetc(file);
while (thisChar != EOF) {
// This block is executed once for each line in the file
int posX = 0;
while (thisChar != '\n' && thisChar != EOF) {
// This block is executed once for each character in the current line
initCell(pmState, posX++, pmState->height, thisChar,
&isPacManPositionKnown);
// Read the next character in the line
thisChar = fgetc(file);
}
if (posX != pmState->width)
error_exit("Maze with different column sizes");
// Read the first character of the next line
if (thisChar != EOF)
thisChar = fgetc(file);
pmState->height++;
}
// The maze is read : close the opened file
fclose(file);
// Check the validity of the maze
if (!isPacManPositionKnown)
error_exit("The maze file doesn't give PacMan's initial position");
}
/*---------------------------------------------------------------------*
- Reads the width of a maze in a labyrinth description file.
*
- PARAMETERS
- filename the name of the file containing the labyrinth
*
- RETURN:
- the width of the maze
- ---------------------------------------------------------------------*/
static int readLabyrinthWidth(const char *filename)
{
// Open the given file in read mode
FILE *file = fopen(filename, "r");
if (!file)
error_exit(filename);
int width = 0;
// Count the number of characters in the first line of the file
while (true) {
int thisChar = fgetc(file);
if (thisChar == '\n' || thisChar == EOF) {
if (!width)
error_exit("Maze with empty columns");
fclose(file);
return width;
}
width++;
}
}
/*---------------------------------------------------------------------*
- Checks whether a cell is accessible for PacMan.
*
- PARAMETERS
- pmState the game state
- x, y the cell coordinates
*
- RETURN:
- true iff the cell is accessible
- ---------------------------------------------------------------------*/
static bool isAccessible(PmState *pmState, int x, int y,PmCellContent type)
{
// Checks whether the cell exists
if (x < 0 || x >= pmState->width ||
y < 0 || y >= pmState->height)
return false;
//Disable the possibily for Dragons & Thief to go
//to a cellule containg a solid or an other agent
//(agent who is not pacman)
if (type == DRAGON || type==THIEF){
if ((pmsGetCell(pmState->scene, x, y) & DRAGON) ||
(pmsGetCell(pmState->scene, x, y) & GHOST) ||
(pmsGetCell(pmState->scene, x, y) & THIEF) ||
(pmsGetCell(pmState->scene, x, y) & SOLID))
return false;
}
//Disable the possibily for Ghosts to go to
//a cellule containing an other
//(agent who is not pacman)
if (type == GHOST){
if ((pmsGetCell(pmState->scene, x, y) & DRAGON) ||
(pmsGetCell(pmState->scene, x, y) & THIEF) ||
(pmsGetCell(pmState->scene, x, y) & GHOST))
return false;
}
//return false if the cellule who want to go pacman
//is a solid.
if (type == PACMAN)
return !(pmsGetCell(pmState->scene, x, y) & SOLID);
//return true, the agent can move.
return true;
}
/*---------------------------------------------------------------------*
*
- PARAMETERS
- pmState the game state
- command the action to do
*
- RETURN:
- nothing
- ---------------------------------------------------------------------*/
static void updateScore(PmState *pmState)
{
// Read PacMan's position
int x = pmState->pacman.x;
int y = pmState->pacman.y;
// Get the contents of this cell
PmCellContent content = pmsGetCell(pmState->scene, x, y);
if (content & CRUMB) { // A crumb is in the cell
pmState->score++;
pmState->numCrumbs--;
pmsClearCell(pmState->scene, x, y, CRUMB);
}
if (content & TREASURE) { // A treasure is in the cell
pmState->score += TREASURE_SUM;
pmState->numTreasures--;
pmsClearCell(pmState->scene, x, y, TREASURE);
}
if (content & DRAGON) // A dragon is in the cell
pmState->score *= DRAGON_FAC;
if (content & GHOST) // A ghost is in the cell
pmState->score *= GHOST_FAC;
if (content & THIEF) // A thief is in the cell
pmState->score -= THIEF_SUM;
}
/*---------------------------------------------------------------------*
- Move Dragons according to the position of Pacman.
*
- PARAMETERS
- params a pointer to pmState structure
*
*
- RETURN:
- NULL
- ---------------------------------------------------------------------*/
void* moveDragons(void* params)
{
//change the void* pointer to a PmState pointer
//Not elegant but this is a solution for the warning
//arg 3(must be void*) in function pthread_create.
PmState* pmThreads = (PmState*)params;
#ifdef MUTEX
pthread_mutex_lock(&mutex);
#endif
while ((pmThreads->score > 0) && (pmThreads->userCommand != QUIT)){
int x = pmThreads->pacman.x;
int y = pmThreads->pacman.y;
int numDragons=0;
PmAgentList *head = pmThreads->dragons;
while (pmThreads->dragons) {
pmThreads->dragons = pmThreads->dragons->next;
numDragons++;
}
pmThreads->dragons = head;
PmiCommand command=NONE;
for (int i=0; i < numDragons; i++){
int agentPosX = pmThreads->dragons->agent.x;
int agentPosY = pmThreads->dragons->agent.y;
PmCellContent agentType = pmThreads->dragons->agent.type;
//Clear the cell where was Dragon
if (pmoDrawCell(agentPosX, agentPosY, pmsClearCell(pmThreads->scene, agentPosX, agentPosY, DRAGON)))
error_exit("pmoDrawCell(DRAGON)");
if (agentPosX < x) {
if (agentPosY == y) command=RIGHT;
else if (agentPosY > y) command=UPRIGHT;
else if (agentPosY < y) command=BOTRIGHT;
}
else if (agentPosX > x) {
if (agentPosY == y) command=LEFT;
else if (agentPosY > y) command=UPLEFT;
else if (agentPosY < y) command=BOTLEFT;
}
else if (agentPosX == x){
if (agentPosY > y) command=UP;
else if (agentPosY < y) command=DOWN;
}
switch (command) {
case UP:
if (isAccessible(pmThreads, agentPosX, agentPosY - 1,agentType))
pmThreads->dragons->agent.y--;
break;
case DOWN:
if (isAccessible(pmThreads, agentPosX, agentPosY + 1,agentType))
pmThreads->dragons->agent.y++;
break;
case LEFT:
if (isAccessible(pmThreads, agentPosX - 1, agentPosY,agentType))
pmThreads->dragons->agent.x--;
break;
case RIGHT:
if (isAccessible(pmThreads, agentPosX + 1, agentPosY,agentType))
pmThreads->dragons->agent.x++;
break;
case BOTRIGHT:
if (isAccessible(pmThreads, agentPosX + 1, agentPosY,agentType))
pmThreads->dragons->agent.x++;
agentPosX = pmThreads->dragons->agent.x;
if (isAccessible(pmThreads, agentPosX, agentPosY + 1,agentType))
pmThreads->dragons->agent.y++;
break;
case BOTLEFT:
if (isAccessible(pmThreads, agentPosX - 1, agentPosY,agentType))
pmThreads->dragons->agent.x--;
agentPosX = pmThreads->dragons->agent.x;
if (isAccessible(pmThreads, agentPosX, agentPosY + 1,agentType))
pmThreads->dragons->agent.y++;
break;
case UPRIGHT:
if (isAccessible(pmThreads, agentPosX + 1, agentPosY,agentType))
pmThreads->dragons->agent.x++;
agentPosX = pmThreads->dragons->agent.x;
if (isAccessible(pmThreads, agentPosX, agentPosY - 1,agentType))
pmThreads->dragons->agent.y--;
break;
case UPLEFT:
if (isAccessible(pmThreads, agentPosX - 1, agentPosY,agentType))
pmThreads->dragons->agent.x--;
agentPosX = pmThreads->dragons->agent.x;
if (isAccessible(pmThreads, agentPosX, agentPosY - 1,agentType))
pmThreads->dragons->agent.y--;
break;
default:
return NULL;
}
//Put the agent at its new position
pmsPutAgent(pmThreads->scene,&pmThreads->dragons->agent);
// Display Dragon at its new position
if (pmoDrawAgent(&pmThreads->dragons->agent))
error_exit("pmoDrawCell(DRAGON)");
// Refresh the display
if (pmoFlush())
error_exit("pmoFlush");
pmThreads->dragons = pmThreads->dragons->next;
}
#ifdef MUTEX
pthread_mutex_unlock(&mutex);
#endif
if (pmThreads->userCommand!=QUIT) sleep(1);
//reset the pointer to the head
pmThreads->dragons = head;
}
return NULL;
}
/*---------------------------------------------------------------------*
- Move Ghosts according to the position of Pacman.
*
- PARAMETERS
- params a pointer to pmState structure
*
*
- RETURN:
- NULL
- ---------------------------------------------------------------------*/
static void* moveGhosts(void* params)
{
//change the void* pointer to a PmState pointer
//Not elegant but this is a solution for the warning
//arg 3(must be void*) in function pthread_create.
PmState* pmThreads = (PmState*)params;
PmiCommand command=NONE;
#ifdef MUTEX
pthread_mutex_lock(&mutex);
#endif
while ((pmThreads->score > 0) && (pmThreads->userCommand!=QUIT)){
int x = pmThreads->pacman.x;
int y = pmThreads->pacman.y;
int numGhosts=0;
//Pointer at the top of the agent list
PmAgentList *head = pmThreads->ghosts;
//Get the number of agent
while (pmThreads->ghosts) {
pmThreads->ghosts = pmThreads->ghosts->next;
numGhosts++;
}
//Reset the pointer to the head of the agent list
pmThreads->ghosts = head;
for (int i=0; i < numGhosts; i++){
int agentPosX = pmThreads->ghosts->agent.x;
int agentPosY = pmThreads->ghosts->agent.y;
PmCellContent agentType = pmThreads->ghosts->agent.type;
//Clear the cell where was Ghost
if (pmoDrawCell(agentPosX, agentPosY, pmsClearCell(pmThreads->scene, agentPosX, agentPosY, GHOST)))
error_exit("pmoDrawCell(GHOST)");
if (agentPosX < x) {
if (agentPosY == y) command=RIGHT;
else if (agentPosY > y) command=UPRIGHT;
else if (agentPosY < y) command=BOTRIGHT;
}
else if (agentPosX > x) {
if (agentPosY == y) command=LEFT;
else if (agentPosY > y) command=UPLEFT;
else if (agentPosY < y) command=BOTLEFT;
}
else if (agentPosX == x){
if (agentPosY > y) command=UP;
else if (agentPosY < y) command=DOWN;
}
switch (command) {
case UP:
if (isAccessible(pmThreads, agentPosX, agentPosY - 1,agentType))
pmThreads->ghosts->agent.y--;
break;
case DOWN:
if (isAccessible(pmThreads, agentPosX, agentPosY + 1,agentType))
pmThreads->ghosts->agent.y++;
break;
case LEFT:
if (isAccessible(pmThreads, agentPosX - 1, agentPosY,agentType))
pmThreads->ghosts->agent.x--;
break;
case RIGHT:
if (isAccessible(pmThreads, agentPosX + 1, agentPosY,agentType))
pmThreads->ghosts->agent.x++;
break;
case BOTRIGHT:
if (isAccessible(pmThreads, agentPosX + 1, agentPosY,agentType)){
pmThreads->ghosts->agent.x++;
agentPosX = pmThreads->ghosts->agent.x;
if (isAccessible(pmThreads, agentPosX, agentPosY + 1,agentType))
pmThreads->ghosts->agent.y++;
}
break;
case BOTLEFT:
if (isAccessible(pmThreads, agentPosX - 1, agentPosY,agentType)){
pmThreads->ghosts->agent.x--;
agentPosX = pmThreads->ghosts->agent.x;
if (isAccessible(pmThreads, agentPosX, agentPosY + 1,agentType))
pmThreads->ghosts->agent.y++;
}
break;
case UPRIGHT:
if (isAccessible(pmThreads, agentPosX + 1, agentPosY,agentType)){
pmThreads->ghosts->agent.x++;
agentPosX = pmThreads->ghosts->agent.x;
}
if (isAccessible(pmThreads, agentPosX, agentPosY - 1,agentType))
pmThreads->ghosts->agent.y--;
break;
case UPLEFT:
if (isAccessible(pmThreads, agentPosX - 1, agentPosY,agentType)){
pmThreads->ghosts->agent.x--;
agentPosX = pmThreads->ghosts->agent.x;
if (isAccessible(pmThreads, agentPosX, agentPosY - 1,agentType))
pmThreads->ghosts->agent.y--;
}
break;
default:
return NULL;
}
//Put the agent at its new position
pmsPutAgent(pmThreads->scene,&pmThreads->ghosts->agent);
// Display Ghost at its new position
if (pmoDrawAgent(&pmThreads->ghosts->agent))
error_exit("pmoDrawCell(GHOST)");
// Refresh the display
if (pmoFlush())
error_exit("pmoFlush");
pmThreads->ghosts = pmThreads->ghosts->next;
}
#ifdef MUTEX
pthread_mutex_unlock(&mutex);
#endif
if (pmThreads->userCommand!=QUIT) sleep(2);
pmThreads->ghosts = head;
}
return NULL;
}
/*---------------------------------------------------------------------*
- Move the Thief according to the position of Pacman.
*
- PARAMETERS
- params a pointer to pmState structure
*
*
- RETURN:
- NULL
- ---------------------------------------------------------------------*/
void* moveThief(void* params)
{
//change the void* pointer to a PmState pointer
//Not elegant but this is a solution for the warning
//arg 3(must be void*) in function pthread_create.
PmState* pmThreads = (PmState*)params;
#ifdef MUTEX
pthread_mutex_lock(&mutex);
#endif
while ((pmThreads->score > 0) && pmThreads->userCommand != QUIT){
int x = pmThreads->pacman.x;
int y = pmThreads->pacman.y;
PmiCommand command=NONE;
int agentPosX = pmThreads->thief.x;
int agentPosY = pmThreads->thief.y;
PmCellContent agentType = pmThreads->thief.type;
//Clear the cell where was Dragon
if (pmoDrawCell(agentPosX, agentPosY, pmsClearCell(pmThreads->scene, agentPosX, agentPosY, THIEF)))
error_exit("pmoDrawCell(THIEF)");
if (agentPosX < x) {
if (agentPosY == y) command=RIGHT;
else if (agentPosY > y) command=UPRIGHT;
else if (agentPosY < y) command=BOTRIGHT;
}
else if (agentPosX > x) {
if (agentPosY == y) command=LEFT;
else if (agentPosY > y) command=UPLEFT;
else if (agentPosY < y) command=BOTLEFT;
}
else if (agentPosX == x){
if (agentPosY > y) command=UP;
else if (agentPosY < y) command=DOWN;
}
switch (command) {
case UP:
if (isAccessible(pmThreads, agentPosX, agentPosY - 2,agentType))
pmThreads->thief.y-=2;
break;
case DOWN:
if (isAccessible(pmThreads, agentPosX, agentPosY + 2,agentType))
pmThreads->thief.y+=2;
break;
case LEFT:
if (isAccessible(pmThreads, agentPosX - 2, agentPosY,agentType))
pmThreads->thief.x-=2;
break;
case RIGHT:
if (isAccessible(pmThreads, agentPosX + 2, agentPosY,agentType))
pmThreads->thief.x+=2;
break;
case BOTRIGHT:
if (isAccessible(pmThreads, agentPosX + 2, agentPosY,agentType))
pmThreads->thief.x+=2;
agentPosX = pmThreads->thief.x;
if (isAccessible(pmThreads, agentPosX, agentPosY + 2,agentType))
pmThreads->thief.y+=2;
break;
case BOTLEFT:
if (isAccessible(pmThreads, agentPosX - 2, agentPosY,agentType))
pmThreads->thief.x-=2;
agentPosX = pmThreads->thief.x;
if (isAccessible(pmThreads, agentPosX, agentPosY + 2,agentType))
pmThreads->thief.y+=2;
break;
case UPRIGHT:
if (isAccessible(pmThreads, agentPosX + 2, agentPosY,agentType))
pmThreads->thief.x+=2;
agentPosX = pmThreads->thief.x;
if (isAccessible(pmThreads, agentPosX, agentPosY - 2,agentType))
pmThreads->thief.y-=2;
break;
case UPLEFT:
if (isAccessible(pmThreads, agentPosX - 2, agentPosY,agentType))
pmThreads->thief.x-=2;
agentPosX = pmThreads->thief.x;
if (isAccessible(pmThreads, agentPosX, agentPosY - 2,agentType))
pmThreads->thief.y-=2;
break;
default:
return NULL;
}
//Put the agent at its new position
pmsPutAgent(pmThreads->scene,&pmThreads->thief);
// Display Dragon at its new position
if (pmoDrawAgent(&pmThreads->thief))
error_exit("pmoDrawCell(THIEF)");
// Refresh the display
if (pmoFlush())
error_exit("pmoFlush");
if (pmThreads->userCommand!=QUIT) sleep(2);
}
#ifdef MUTEX
pthread_mutex_unlock(&mutex);
#endif
return NULL;
}
/*---------------------------------------------------------------------*
- Move PacMan according to some command.
*
- PARAMETERS
- pmState the game state
- command the action to do
*
- RETURN:
- nothing
- ---------------------------------------------------------------------*/
static void movePacman(PmState *pmState, PmiCommand command)
{
// Read PacMan's position
int x = pmState->pacman.x;
int y = pmState->pacman.y;
PmCellContent agentType = pmState->pacman.type;
// Move PacMan according to the command (self-documenting)
switch (command) {
case UP:
if (isAccessible(pmState, x, y - 1,agentType)) pmState->pacman.y--;
break;
case DOWN:
if (isAccessible(pmState, x, y + 1,agentType)) pmState->pacman.y++;
break;
case LEFT:
if (isAccessible(pmState, x - 1, y,agentType)) pmState->pacman.x--;
break;
case RIGHT:
if (isAccessible(pmState, x + 1, y,agentType)) pmState->pacman.x++;
break;
default:
return;
}
// Clear the cell where was PacMan
if (pmoDrawCell(x, y, pmsClearCell(pmState->scene, x, y, PACMAN)))
error_exit("pmoDrawCell(PACMAN)");
// Display PacMan at its new position
if (pmoDrawAgent(&pmState->pacman))
error_exit("pmoDrawCell(PACMAN)");
// Refresh the display
if (pmoFlush())
error_exit("pmoFlush");
}
/*---------------------------------------------------------------------*
- Tests whether the game is over. The game is finished when the score
- becomes negative ; or where there is no crumb and no treasure
- remaining.
*
- PARAMETERS
- pmState the game state
*
- RETURN:
- true only when the game is over
- ---------------------------------------------------------------------*/
static inline bool isGameOver(PmState *pmState)
{
return (pmState->score <= 0 ||
(!pmState->numCrumbs &&
!pmState->numTreasures));
}
/*---------------------------------------------------------------------*
- Display statistics for the game (self-documenting).
*
- PARAMETERS
- pmState the game state
*
- RETURN:
- nothing
- ---------------------------------------------------------------------*/
static void displayStatistics(PmState *pmState)
{
char buffer[64];
sprintf(buffer, "Score : %5d", pmState->score);
if (pmoWriteString(5, pmState->height + 1, buffer))
error_exit("pmoWriteString()");
sprintf(buffer, "Remaining crumbs : %5d", pmState->numCrumbs);
if (pmoWriteString(5, pmState->height + 2, buffer))
error_exit("pmoWriteString()");
sprintf(buffer, "Remaining treasures : %5d", pmState->numTreasures);
if (pmoWriteString(5, pmState->height + 3, buffer))
error_exit("pmoWriteString()");
if (isGameOver(pmState) &&
pmoWriteString(3, pmState->height + 5,
"> Game over, hit q to exit <"))
error_exit("pmoWriteString()");
// Refresh the display
if (pmoFlush())
error_exit("pmoFlush");
}
/*---------------------------------------------------------------------*
- Main function
- ---------------------------------------------------------------------*/
int main(int argc, char* argv[]) {
// Initialize the input and the output
if (pmiOpen()) error_exit("pmiOpen");
if (pmoOpen()) error_exit("pmoOpen");
if (argc < 2)
error_exit("No labyrinth filename given");
//create the threads variables
pthread_t dragonMove;
pthread_t ghostMove;
pthread_t thiefMove;
#ifdef MUTEX
pthread_mutex_init(&mutex, NULL);
#endif
// Initialize the game state
PmState *pmState = malloc(sizeof(PmState));
if (!pmState)
error_exit("malloc(pmState)");
pmState->isKnowthief = false;
pmState->width = readLabyrinthWidth(argv[1]); // Read the maze width
pmState->height = 0;
pmState->scene = pmsInitScene(pmState->width); // Allocate the scene
pmState->dragons = NULL;
pmState->ghosts = NULL;
pmState->numCrumbs = 0;
pmState->numTreasures = 0;
pmState->score = 1;
// Read a game state from the description file given in argument
initLabyrinth(argv[1], pmState);
//a pointer to pmState structure
void* params = pmState;
/* Start three threads: */
if (pthread_create(&dragonMove, NULL, moveDragons, params))
printf("thread error\n");
if (pthread_create(&ghostMove, NULL, moveGhosts, params))
printf("thread error\n");
if (pmState->isKnowthief){
if (pthread_create(&thiefMove, NULL, moveThief, params))
printf("thread error\n");
}
// Main loop
int keepPlaying = true;
PmiCommand command=NONE;
PmiCommand temp;
while (keepPlaying) {
displayStatistics(pmState);
// if the user give a command, the command
// is given to the variable 'command' who
// will change the direction of pacman
if ((temp = pmiGetCommand()) != 0){
command=temp;
pmState->userCommand=command;
}
//Quit if 'q' is given
if (temp == QUIT) {
keepPlaying = false;
}
else if (!isGameOver(pmState)) {
// The game is not finished yet
movePacman(pmState, command);
updateScore(pmState);
}
}
//Waiting the end of threads
if (pmState->ghosts) pthread_join(ghostMove, NULL);
if (pmState->dragons) pthread_join(dragonMove, NULL);
if (pmState->isKnowthief) pthread_join(thiefMove, NULL);
#ifdef MUTEX
pthread_mutex_destroy(&mutex);
#endif
//Free the game state
freeGameState(pmState);
// Close the input and the output
if (pmiClose()) error_exit("pmiClose");
if (pmoClose()) error_exit("pmoClose");
return 0;
}
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.