[SOS] Exemple ?
Cyril Dupuit
cyrildupuit at hotmail.com
Mer 24 Nov 10:31:19 CET 2004
Salut la team,
Suite au dernier mail de D2, je me suis mis à chercher un exemple afin de
démontrer la multiprogrammation enfin je pense que c'est ça qu'il voulait.
J'ai regardé sur le net et j'ai vu que l'on pouvait effectuer des
simulations de petites entités (fourmis, thermites, souris, ...). Bref, j'ai
écrit le code d'un truc qui créé, déplace et détruit des « souris ».
Règles :
- Une souris doit rapporter du fromage à son lieu de naissance (pixel gris)
pour pouvoir créer une autre souris.
- La souris à l'origine rouge passe à la couleur violette dès quelle a
capturé un morceau de fromage.
- Dès que la souris a ramené son fromage, elle reprend sa couleur d'origine
(rouge).
- Les pixels de couleur verte sont des obstacles que la souris doit
contourner.
- Les pixels de couleur jaune représentent le fromage.
- Le pixel de couleur bleu représente la souricière.
- Chaque souris représente un thread.
Code :
/***************************************************************************
* Copyright (C) 2004 by cyril dupuit *
* cyrildupuit at hotmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#define MAP_X 10
#define MAP_Y 24
#define MAP_SIZE MAP_X * MAP_Y
#define Set(Reg, Flag) Reg = (Reg | Flag)
#define Reset(Reg, Flag) Reg = (Reg &(~Flag))
#define IsSet(Reg, Flag) (Reg & Flag)
//Définition des différents types d'éléments
#define MOUSE 0x01
#define CHEESE 0x02
#define OBSTACLE 0x04
#define INPUT 0x08
#define OUTPUT 0x10
#define OBSTACLE_COUNT 10
#define CHEESE_COUNT 200
#define MOUSE_FULL 0x01
#define MOUSE_EMPTY 0x02
#define CHEESE_FOUND 0x04
//*****************************************************************************
struct Point{
int X;
int Y;
};
typedef struct Point Point_t;
//*****************************************************************************
struct Element{
Status_t Type;//Type d'élément
Status_t Status;
Color_t Color;//Couleur de l'élément
Point_t P;//Coordonnées de l'élément
ThreadID_t ThreadID;//Thread associe a la souris
int Way;//Direction de la souris
};
typedef struct Element Element_t;
//*****************************************************************************
static void DrawMap(void);
static Status_t CreateMap(void);
static Status_t InitMapInput(Element_t * * pMap);
static Status_t InitMapOutput(Element_t * * pMap);
static Status_t ElementInit(Element_t * * pMap, unsigned int Type);
static void DestroyMap(Element_t * * pMap);
static void Mouse(unsigned long Param);
static void MouseMove(Point_t * P);
static Point_t ChoosePosition(/*Point_t Org*/Element_t * pMouse, int
Positions[], int Count);
static int EvaluatePositions(Point_t Org, int Positions[], Point_t *
Cheese);
static Status_t IsCollision(Point_t Org, Point_t p, Point_t *Cheese);
static Status_t AffectMovement(Point_t Org, Point_t p);
static void MouseCreator(void);
static Status_t CreateMouse(void);
static Element_t * * pMap;
static SemID_t SemMap;
static SemID_t SemMouse;
static int MouseCount = 0;
static int CheeseCount = 0;
static int ObstacleCount = 0;
//*****************************************************************************
// Point d'entré de la 'simulation'
//*****************************************************************************
void MouseSim(void)
{
// Création de la console d'affichage
if(ConsoleCreate("Simulation", "Souris et fromage", LIGHT_GRAY, BLACK) ==
ERROR)
{//Mémoire disponible insuffisante
FatalError(GetLastError(), "MouseSim");
}
//Création du sémaphore de protection de la carte
SemMap = SemMCreate(SEM_FIFO);
if(SemMap == 0) FatalError(GetLastError(), "MouseSim");
//Création du sémaphore de création de souris
SemMouse = SemCCreate(SEM_FIFO, 2, 2);
if(SemMouse == 0) FatalError(GetLastError(), "MouseSim");
//Création de la carte
if(CreateMap() == ERROR) FatalError(GetLastError(), "MouseSim");
//Création du thread créateur de souris
ThreadCreate((pFunction_t)MouseCreator, 0, 1000, 100);
//Destruction du thread créateur de l'application
ThreadDelete(ThreadIdSelf());
FatalError(GetLastError(), "MouseSim");
}
//*****************************************************************************
// But de la fonction : Créer et initialiser la carte
// Entrée : Aucune
// Paramètre retourne : ERROR si la mémoire est insuffisante, TRUE sinon
//*****************************************************************************
static Status_t CreateMap(void)
{
pMap = (Element_t * *)kmalloc(MAP_SIZE * sizeof(Element_t *));
if(pMap == NULL) return ERROR;
//Mettre la carte a 0
memset(pMap, 0, MAP_SIZE * sizeof(Element_t *));
//Initialisation de l'entrée de la carte
if(InitMapInput(pMap) == ERROR)
{//Mémoire insuffisante
DestroyMap(pMap);
return ERROR;
}
//Initialisation de la sortie de la carte
if(InitMapOutput(pMap) == ERROR)
{//Mémoire insuffisante
DestroyMap(pMap);
return ERROR;
}
//Initialisation du fromage
if(ElementInit(pMap, CHEESE) == ERROR)
{//Mémoire insuffisante
DestroyMap(pMap);
return ERROR;
}
//Initialisation des obstacles
if(ElementInit(pMap, OBSTACLE) == ERROR)
{//Mémoire insuffisante
DestroyMap(pMap);
return ERROR;
}
DrawMap();//Afficher la carte créée
return TRUE;
}
//*****************************************************************************
// But de la procédure : Dessiner la carte a l'écran
// Entrée : Aucune
// Sortie : Aucune
//*****************************************************************************
static void DrawMap(void)
{
unsigned int I;
for(I = 0; I < MAP_SIZE; I++)
{
if(pMap[I] != NULL)
{
DrawPixel(I % MAP_X, I/MAP_X, pMap[I]->Color);
}
else DrawPixel(I % MAP_X, I/MAP_X, BLACK);
}
GotoXY(0, 24);
printf("Souris = %d; Fromages = %d; Obstacles = %d ", MouseCount,
CheeseCount, ObstacleCount);
}
//*****************************************************************************
// But de la fonction : Initialiser l'entrée de la carte
// Entrée :
// pMap : Pointeur sur la carte
// Paramètre retourne : ERROR si mémoire insuffisante, TRUE sinon
//*****************************************************************************
static Status_t InitMapInput(Element_t * * pMap)
{
Element_t * pElement;
//Définir le point d'entrée
pElement = (Element_t *)kmalloc(sizeof(Element_t));
if(pElement == NULL) return ERROR;
//Initialiser l'entrée
pElement->Type = INPUT;
pElement->Status = 0;
pElement->Color = LIGHT_GRAY;
pElement->P.X = 0;
pElement->P.Y = MAP_Y / 2;
pElement->ThreadID = 0;
pMap[(pElement->P.Y * MAP_X) + pElement->P.X] = pElement;
return TRUE;
}
//*****************************************************************************
// But de la fonction : Initialiser la sortie de la carte
// Entrée :
// pMap : Pointeur sur la carte
// Paramètre retourne : ERROR si mémoire insuffisante, TRUE sinon
//*****************************************************************************
static Status_t InitMapOutput(Element_t * * pMap)
{
Element_t * pElement;
//Définir le point de sortie
pElement = (Element_t *)kmalloc(sizeof(Element_t));
if(pElement == NULL) return ERROR;
//Initialiser l'entrée
pElement->Type = OUTPUT;
pElement->Status = 0;
pElement->Color = BLUE;
pElement->P.X = MAP_X - 1;
pElement->P.Y = MAP_Y / 2;
pElement->ThreadID = 0;
pMap[(pElement->P.Y * MAP_X) + pElement->P.X] = pElement;
return TRUE;
}
//*****************************************************************************
// But de la fonction : Initialiser un type d'objet sur la carte
// Entrée :
// pMap : Pointeur sur la carte
// Type : Type d'objet a initialiser
// Paramètre retourne : ERROR si mémoire insuffisante, TRUE sinon
//*****************************************************************************
static Status_t ElementInit(Element_t * * pMap, unsigned int Type)
{
unsigned int I, J;
unsigned int Max;
Color_t Color;
if(Type == CHEESE)
{//Type d'élément = fromage
Max = CHEESE_COUNT;
Color = YELLOW;
}
else if(Type == OBSTACLE)
{//Type d'élément = Obstacle
Max = OBSTACLE_COUNT;
Color = GREEN;
}
else
{//Aucune autre type reconnu
return ERROR;
}
for(I = 0; I < Max; I++)
{//Tirer les fromages
J = rand();
J += rand();
J %= MAP_SIZE;
if(pMap[J] == NULL)
{//Si l'emplacement est libre
pMap[J] = (Element_t *)kmalloc(sizeof(Element_t));
if(pMap[J] == NULL) return ERROR;
pMap[J]->Type = Type;
//Initialiser l'élément
if(Type == CHEESE)
{//Type d'élément = fromage
CheeseCount++;
}
else if(Type == OBSTACLE)
{//Type d'élément = Obstacle
ObstacleCount++;
}
pMap[J]->Color = Color;
pMap[J]->Status = 0;
pMap[J]->Color = Color;
pMap[J]->P.X = J % MAP_X;
pMap[J]->P.Y = J / MAP_X;
pMap[J]->ThreadID = 0;
}
}
return TRUE;
}
//*****************************************************************************
// But de la procédure : Supprimer tout les éléments de la carte ainsi que
la
// carte
// Entrée :
// pMap : Pointeur sur la carte
// Sortie : Aucune
//*****************************************************************************
static void DestroyMap(Element_t * * pMap)
{
unsigned int I;
if(pMap == NULL) return;
for(I = 0; I < MAP_SIZE; I++)
{//Libérer tout les éléments
if(pMap[I] != NULL)
{
if(pMap[I]->ThreadID != 0)
{//Un thread est associe a l'élément
ThreadDelete(pMap[I]->ThreadID);
}
kfree(pMap);
}
}
kfree(pMap);
}
//*****************************************************************************
// But du thread : Déplacer la souris sur la carte selon les règles
établies.
// Règles :
// - La souris doit se placer devant l'entrée puis commence a récolter du
// fromage.
// - Des que la souris a ramasse un morceau de fromage, elle doit aller en
// entrée de la carte afin de déposer sa récolte.
// - Si une souris a prouve sa récolte, une autre souris est créée.
// - Si une souris prend la sortie, elle est éliminée.
//*****************************************************************************
static void Mouse(unsigned long Param)
{
Element_t * pMouse = (Element_t *)Param;
Point_t P;
if(pMouse == NULL) FatalError(INCORRECT_PARAMETER_1, "Mouse");
//Position de départ de la souris
P = pMouse->P;
P = pMouse->P;
while(1)
{//La souris doit se déplacer
SemTake(SemMap, SEM_WAIT_FOREVER);
MouseMove(&P);
SemGive(SemMap);
ThreadDelay(rand() % 10);
}
}
//*****************************************************************************
// But de la procédure : Déplacer la souris de manière aléatoire sur la
carte
// Entrées :
// P : Position courante de la souris
// Sorties :
// P : Position suivante de la souris
//*****************************************************************************
static void MouseMove(Point_t * P)
{
Point_t Org;
Point_t p;
Point_t Cheese;
int Positions[8];
int Count = 0;
Element_t * pMouse;
Org = *P;
pMouse = pMap[Org.X + (Org.Y * MAP_X)];
Count = EvaluatePositions(Org, Positions, &Cheese);
if(Count == 0) return;
p = Org;
if(IsSet(pMouse->Status, CHEESE_FOUND))
{//Prendre le fromage
Reset(pMouse->Status, CHEESE_FOUND);
p = Cheese;
}
else
{//Choisir une position au hasard
p = ChoosePosition(pMouse, Positions, Count);
}
if(AffectMovement(Org, p) == FALSE) return;
//Déplacer la souris
pMap[Org.X + (Org.Y * MAP_X)] = NULL;
pMap[p.X + (p.Y * MAP_X)] = pMouse;
pMouse->P = p;
//Mettre a jour l'affichage
DrawPixel(Org.X, Org.Y, BLACK);
DrawPixel(p.X, p.Y, pMouse->Color);
GotoXY(0, 24);
printf("Souris = %d; Fromages = %d; Obstacles = %d ", MouseCount,
CheeseCount, ObstacleCount);
//Mettre a jour les Coordonnées
*P = p;
}
//*****************************************************************************
// But de la fonction : Choisir un mouvement
// Entrée :
// pMouse : Pointeur sur la souris
// Positions : Tableau de position possible
// Count :Nombre de positions valides
// Sortie : Aucune
// Paramètre retourne : Position choisie
//*****************************************************************************
static Point_t ChoosePosition(Element_t * pMouse, int Positions[], int
Count)
{
int I, J;
Point_t p;
for(J = 0; J < Count; J++)
{//Chercher dans le tableau si cette position est disponible
I = Positions[J];
if(I == pMouse->Way)
{//Poursuivre ce sens d'avance
p = pMouse->P;
switch(I)
{
case 0:
p.Y++;
break;
case 1:
p.X++;
p.Y++;
break;
case 2:
p.X++;
break;
case 3:
p.Y--;
p.X++;
break;
case 4:
p.Y--;
break;
case 5:
p.Y--;
p.X--;
break;
case 6:
p.X--;
break;
case 7:
p.X--;
p.Y++;
break;
}
return p;
}
}
J = rand() % Count;
I = Positions[J];
if(((I + 4) % 8) == pMouse->Way)
{//Eviter le sens inverse
J = (J + 1) % Count;
I = Positions[J];
}
p = pMouse->P;
switch(I)
{//Repère le déplacement
case 0:
p.Y++;
break;
case 1:
p.X++;
p.Y++;
break;
case 2:
p.X++;
break;
case 3:
p.Y--;
p.X++;
break;
case 4:
p.Y--;
break;
case 5:
p.Y--;
p.X--;
break;
case 6:
p.X--;
break;
case 7:
p.X--;
p.Y++;
break;
}
pMouse->Way = I;//Mémoriser la direction sélectionnée
return p;
}
//*****************************************************************************
// But de la fonction : Evaluer les positions possibles et les mémoriser
dans
// un tableau de positions si aucun fromage n'a été détecte. Si du fromage a
// été détecté, il sera sélectionne en premier. La présence d'un fromage est
// indiquée par le drapeau CHEESE_FOUND
// Entrée :
// Org : Position de la souris
// Sorties :
// Positions : Tableau de positions valides
// Cheese : Position du fromage
// Paramètre retourne : Nombre de positions valides
//*****************************************************************************
static int EvaluatePositions(Point_t Org, int Positions[], Point_t * Cheese)
{
int I;
int Count = 0;
Point_t p;
Point_t CheesePos;
for(I = 0; I < 8; I++)
{//Explorer toute les directions
p = Org;
switch(I)
{//Repère le déplacement
case 0:
p.Y++;
break;
case 1:
p.X++;
p.Y++;
break;
case 2:
p.X++;
break;
case 3:
p.Y--;
p.X++;
break;
case 4:
p.Y--;
break;
case 5:
p.Y--;
p.X--;
break;
case 6:
p.X--;
break;
case 7:
p.X--;
p.Y++;
break;
}
//Tester la collision
if(IsCollision(Org, p, &CheesePos) == FALSE)
{//La souris n'a rencontre aucun obstacle
Positions[Count] = I;
Count++;
}
}
*Cheese = CheesePos;
return Count;
}
//*****************************************************************************
// But de la fonction : Affecter un mouvement a la souris
// Entrées :
// Org : Coordonnées de la souris
// p : Coordonnées voulu par la souris
// Paramètre retourne : TRUE si le mouvement a eu lieu, FALSE sinon
//*****************************************************************************
static Status_t AffectMovement(Point_t Org, Point_t p)
{
Element_t * pMouse = pMap[Org.X + (Org.Y * MAP_X)];
Element_t * pElement;
ThreadID_t ThreadID;
pElement = pMap[p.X + (p.Y * MAP_X)];
//La place est libre
if(pElement == NULL) return TRUE;//Autoriser le mouvement
switch(pElement->Type)
{
case CHEESE:
// Liberer l'emplacement mémoire du fromage
kfree(pElement);
pMap[p.X + (p.Y * MAP_X)] = NULL;
//Donner le fromage a la souris
Set(pMouse->Status, MOUSE_FULL);
Reset(pMouse->Status, MOUSE_EMPTY);
pMouse->Color = MAGENTA;
CheeseCount--;
return TRUE;
case OUTPUT:
//Supprimer la souris
ThreadID = pMouse->ThreadID;
kfree(pMouse);
pMap[Org.X + (Org.Y * MAP_X)] = NULL;
MouseCount--;
DrawPixel(Org.X, Org.Y, BLACK);
ThreadDelete(ThreadID);
return FALSE;
default :
return FALSE;
}
return FALSE;
}
//*****************************************************************************
// But de la fonction : Tester si une collision a eu lieu avec un obstacle
// Entrées :
// Org : Coordonnées de la souris
// p : Coordonnées désirées par la souris
// Sortie :
// Cheese : Coordonnées du fromage
// Paramètre retourne : TRUE si une collision a eu lieu, FALSE sinon
//*****************************************************************************
static Status_t IsCollision(Point_t Org, Point_t p, Point_t *Cheese)
{
Element_t * pMouse = pMap[Org.X + (Org.Y * MAP_X)];
Element_t * pElement;
//Tester les bordures de la map
if((p.X < 0)||(p.Y < 0)) return TRUE;
if((p.Y >= MAP_Y)||(p.X >= MAP_X)) return TRUE;
pElement = pMap[p.X + (p.Y * MAP_X)];
//L'élément est vide
if(pElement == NULL) return FALSE;
//Si du fromage a ete trouve, stopper la recherche
if(IsSet(pMouse->Status, CHEESE_FOUND)) return FALSE;
switch(pElement->Type)
{
case CHEESE:
if(IsSet(pMouse->Status, MOUSE_FULL)) return TRUE;
//Indiquer que du fromage a été trouve
Set(pMouse->Status, CHEESE_FOUND);
//Retenir la position du fromage
(*Cheese).X = p.X;
(*Cheese).Y = p.Y;
break;
case INPUT:
if(IsSet(pMouse->Status, MOUSE_EMPTY)) return TRUE;
//Remplir les reserves de fromage
Set(pMouse->Status, MOUSE_EMPTY);
Reset(pMouse->Status, MOUSE_FULL);
pMouse->Color = ROSE;
//Autoriser la création d'une autre souris
SemGive(SemMouse);
return TRUE;
case OUTPUT:
break;
default :
return TRUE;
}
return FALSE;//Aucune collision
}
//*****************************************************************************
// But du thread : Créer une souris et la placer autour de l'entrée
//*****************************************************************************
static void MouseCreator(void)
{
while(1)
{
SemTake(SemMouse, SEM_WAIT_FOREVER);
SemTake(SemMap, SEM_WAIT_FOREVER);
CreateMouse();
SemGive(SemMap);
}
}
//*****************************************************************************
// But de la fonction : Créer une souris et l'insérer dans la carte
// Entrée : Aucune
// Paramètre retourne : ERROR si mémoire insuffisante, FALSE si souris non
// créée, TRUE sinon
//*****************************************************************************
static Status_t CreateMouse(void)
{
Element_t * pElement;
unsigned int I;
Point_t p;
for(I = 0; I < 8; I++)
{//Explorer tous les emplacements
p.X = 0;
p.Y = MAP_Y / 2;
switch(I)
{//Repère le déplacement
case 0:
p.Y++;
break;
case 1:
p.X++;
p.Y++;
break;
case 2:
p.X++;
break;
case 3:
p.Y--;
p.X++;
break;
case 4:
p.Y--;
break;
case 5:
p.Y--;
p.X--;
break;
case 6:
p.X--;
break;
case 7:
p.X--;
p.Y++;
break;
}
if((p.X >= 0)&&(p.Y >= 0)&&(p.X < MAP_X)&&(p.Y < MAP_Y))
{//L'emplacement est valide
pElement = pMap[p.X + (p.Y * MAP_X)];
if(pElement == NULL)
{//Créer la souris
pElement = (Element_t *)kmalloc(sizeof(Element_t));
if(pElement != NULL)
{//Initialiser l'entrée
pElement->Type = MOUSE;
Set(pElement->Status, MOUSE_EMPTY);
pElement->Color = ROSE;
pElement->P = p;
pElement->Way = 0;
pElement->ThreadID = ThreadCreate((pFunction_t)Mouse, (unsigned
long)pElement, 1000, 1000);
if(pElement->ThreadID == 0)
{
kfree(pElement);
pElement = NULL;
}
pMap[p.X + (p.Y * MAP_X)] = pElement;
MouseCount++;
DrawPixel(p.X, p.Y, pElement->Color);
GotoXY(0, 24);
printf("Souris = %d; Fromages = %d; Obstacles = %d ", MouseCount,
CheeseCount, ObstacleCount);
return TRUE;
}
}
}
}
return FALSE;
}
//*****************************************************************************
// C'est fini !!!!
//*****************************************************************************
@+
Cyril
Plus d'informations sur la liste de diffusion Sos