[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