/*************************************************************************** * Copyright (C) 2004 by cyril dupuit * * cyrildupuit@hotmail.com * * http://perso.wanadoo.fr/koalys/ * * (Adaptation for SOS by d2 -- 2004/12/20) * * * * 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. * ***************************************************************************/ //***************************************************************************** // Nom du module : MouseSim.c // Description : Creation et destruction de souris mangeuse de fromages //***************************************************************************** #include #include #include #include #include #include // Historique : // 20/12/04 : Suppr DestroyMap et suppr handler kbd dans version LM (d2) // 26/11/04 : Bug trouve et resolu dans la fonction DestroyMap // 21/11/04 : Creation du module V1.0 //***************************************************************************** // Definition des equivalences : //***************************************************************************** #define MAP_X 76 #define MAP_Y 12 #define MAP_SIZE MAP_X * MAP_Y #define MOUSE 0x01 #define CHEESE 0x02 #define OBSTACLE 0x04 #define INPUT 0x08 #define OUTPUT 0x10 #define OBSTACLE_COUNT 100 #define CHEESE_COUNT 650 #define MOUSE_FULL 0x01 #define MOUSE_EMPTY 0x02 #define CHEESE_FOUND 0x04 #define MOUSE_EXITED 0x08 #define MOUSE_SPEED_MAX 1000 #define MOUSE_SPEED_MIN 4 typedef unsigned int Color_t; struct Point{ int X; int Y; }; typedef struct Point Point_t; #define Set(Reg, Flag) Reg = (Reg | Flag) #define Reset(Reg, Flag) Reg = (Reg &(~Flag)) #define IsSet(Reg, Flag) (Reg & Flag) //***************************************************************************** // Structure de gestion d'un element //***************************************************************************** struct Element{ sos_ui32_t Type;//Type d'element sos_ui32_t Status; Color_t Color;//Couleur de l'element Point_t P;//Coordonnees de l'element struct sos_thread * ThreadID;//Thread associe a la souris int Way;//Direction de la souris }; typedef struct Element Element_t; //***************************************************************************** // Prototypes des fonctions/procedures : //***************************************************************************** static void DrawMap(void); static sos_ret_t CreateMap(void); static sos_ret_t InitMapInput(Element_t * * pMap); static sos_ret_t InitMapOutput(Element_t * * pMap); static sos_ret_t ElementInit(Element_t * * pMap, unsigned int Type); static void Mouse(unsigned long Param); static void MouseMove(Point_t * P); static Point_t ChoosePosition(Element_t * pMouse, int Positions[], int Count); static int EvaluatePositions(Point_t Org, int Positions[], Point_t * Cheese); static sos_bool_t IsCollision(Point_t Org, Point_t p, Point_t *Cheese); static sos_bool_t AffectMovement(Point_t Org, Point_t p); static void MouseCreator(void); static sos_ret_t CreateMouse(void); //***************************************************************************** // Variables globales de ce module : //***************************************************************************** static Element_t * * pMap; static struct sos_ksema SemMap; static struct sos_ksema SemMouse; static int MouseCount = 0; static int CheeseCount = 0; static int ObstacleCount = 0; static int MouseSpeed = 100; //***************************************************************************** // Koalys Glue //***************************************************************************** void DrawPixel(int x, int y, Color_t color) { sos_x86_videomem_putchar(y+3, x+2, color, 219); } //***************************************************************************** // Point d'entre de la 'simulation' //***************************************************************************** void MouseSim(void) { //Creation du semaphore de protection de la carte SOS_ASSERT_FATAL(SOS_OK == sos_ksema_init(& SemMap, "SemMap", 1, SOS_KWQ_ORDER_FIFO)); //Creation du semaphore de creation de souris SOS_ASSERT_FATAL(SOS_OK == sos_ksema_init(& SemMouse, "SemMouse", 2, SOS_KWQ_ORDER_FIFO)); //Creation de la carte SOS_ASSERT_FATAL(SOS_OK == CreateMap()); //Creation du thread createur de souris SOS_ASSERT_FATAL(sos_create_kernel_thread("MouseCreator", (sos_kernel_thread_start_routine_t)MouseCreator, 0, SOS_SCHED_PRIO_TS_LOWEST-1) != NULL); } //***************************************************************************** // But de la fonction : Creer et initialiser la carte // Entree : Aucune // Parametre retourne : ERROR si la memoire est insuffisante, TRUE sinon //***************************************************************************** static sos_ret_t CreateMap(void) { pMap = (Element_t * *)sos_kmalloc(MAP_SIZE * sizeof(Element_t *), 0); if(pMap == NULL) return -SOS_ENOMEM; //Mettre la carte a 0 memset(pMap, 0, MAP_SIZE * sizeof(Element_t *)); //Initialisation de l'entree de la carte if(SOS_OK != InitMapInput(pMap)) {//Memoire insuffisante return -SOS_EFATAL; } //Initialisation de la sortie de la carte if(InitMapOutput(pMap) != SOS_OK) {//Memoire insuffisante return -SOS_EFATAL; } //Initialisation du fromage if(ElementInit(pMap, CHEESE) != SOS_OK) {//Memoire insuffisante return -SOS_EFATAL; } //Initialisation des obstacles if(ElementInit(pMap, OBSTACLE) != SOS_OK) {//Memoire insuffisante return -SOS_EFATAL; } DrawMap();//Afficher la carte creee return SOS_OK; } //***************************************************************************** // But de la procedure : Dessiner la carte a l'ecran // Entree : 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, SOS_X86_VIDEO_FG_BLACK); } sos_x86_videomem_printf(23, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Souris = %d; Fromages = %d; Obstacles = %d ", MouseCount, CheeseCount, ObstacleCount); } //***************************************************************************** // But de la fonction : Initialiser l'entree de la carte // Entree : // pMap : Pointeur sur la carte // Parametre retourne : ERROR si memoire insuffisante, TRUE sinon //***************************************************************************** static sos_ret_t InitMapInput(Element_t * * pMap) { Element_t * pElement; //Definir le point d'entree pElement = (Element_t *)sos_kmalloc(sizeof(Element_t), 0); if(pElement == NULL) return -SOS_ENOMEM; //Initialiser l'entree pElement->Type = INPUT; pElement->Status = 0; pElement->Color = SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE; pElement->P.X = 0; pElement->P.Y = MAP_Y / 2; pElement->ThreadID = 0; pMap[(pElement->P.Y * MAP_X) + pElement->P.X] = pElement; return SOS_OK; } //***************************************************************************** // But de la fonction : Initialiser la sortie de la carte // Entree : // pMap : Pointeur sur la carte // Parametre retourne : ERROR si memoire insuffisante, TRUE sinon //***************************************************************************** static sos_ret_t InitMapOutput(Element_t * * pMap) { Element_t * pElement; //Definir le point de sortie pElement = (Element_t *)sos_kmalloc(sizeof(Element_t), 0); if(pElement == NULL) return -SOS_ENOMEM; //Initialiser l'entree pElement->Type = OUTPUT; pElement->Status = 0; pElement->Color = SOS_X86_VIDEO_FG_LTBLUE; 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 SOS_OK; } //***************************************************************************** // But de la fonction : Initialiser un type d'objet sur la carte // Entree : // pMap : Pointeur sur la carte // Type : Type d'objet a initialiser // Parametre retourne : ERROR si memoire insuffisante, TRUE sinon //***************************************************************************** static sos_ret_t ElementInit(Element_t * * pMap, unsigned int Type) { unsigned int I, J; unsigned int Max; Color_t Color; if(Type == CHEESE) {//Type d'element = fromage Max = CHEESE_COUNT; Color = SOS_X86_VIDEO_FG_YELLOW; } else if(Type == OBSTACLE) {//Type d'element = Obstacle Max = OBSTACLE_COUNT; Color = SOS_X86_VIDEO_FG_GREEN; } else {//Aucune autre type reconnu return -SOS_EINVAL; } for(I = 0; I < Max; I++) {//Tirer les fromages J = random(); J += random(); J %= MAP_SIZE; if(pMap[J] == NULL) {//Si l'emplacement est libre pMap[J] = (Element_t *)sos_kmalloc(sizeof(Element_t), 0); if(pMap[J] == NULL) return -SOS_ENOMEM; pMap[J]->Type = Type; //Initialiser l'element if(Type == CHEESE) {//Type d'element = fromage CheeseCount++; } else if(Type == OBSTACLE) {//Type d'element = 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 SOS_OK; } //***************************************************************************** // But du thread : Deplacer la souris sur la carte selon les regles etablies. // Regles : // - La souris doit se placer devant l'entree puis commence a recolter du // fromage. // - Des que la souris a ramasse un morceau de fromage, elle doit aller en // entree de la carte afin de deposer sa recolte. // - Si une souris a prouve sa recolte, une autre souris est creee. // - Si une souris prend la sortie, elle est eliminee. //***************************************************************************** static void Mouse(unsigned long Param) { Element_t * pMouse = (Element_t *)Param; Point_t P; SOS_ASSERT_FATAL(pMouse != NULL); //Position de depart de la souris P = pMouse->P; P = pMouse->P; while(1) { int delay_ms; struct sos_time delay; //La souris doit se deplacer sos_ksema_down(& SemMap, NULL); MouseMove(&P); sos_ksema_up(& SemMap); // Est-ce que la souris est sortie ? if (IsSet(pMouse->Status, MOUSE_EXITED)) // Oui => on sort break; // Delai entre MOUSE_SPEED_MIN et MouseSpeed - 1 delay_ms = MOUSE_SPEED_MIN + (random() % MouseSpeed); delay.sec = delay_ms / 1000; delay.nanosec = (delay_ms % 1000) * 1000000; sos_thread_sleep(& delay); } // Libere la structure associee sos_kfree((sos_vaddr_t)pMouse); } //***************************************************************************** // But de la procedure : Deplacer la souris de maniere aleatoire sur la carte // Entrees : // 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; //Deplacer 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, SOS_X86_VIDEO_FG_BLACK); DrawPixel(p.X, p.Y, pMouse->Color); sos_x86_videomem_printf( 23,0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Souris = %d; Fromages = %d; Obstacles = %d ", MouseCount, CheeseCount, ObstacleCount); //Mettre a jour les coordonnees *P = p; } //***************************************************************************** // But de la fonction : Choisir un mouvement // Entree : // pMouse : Pointeur sur la souris // Positions : Tableau de position possible // Count :Nombre de positions valides // Sortie : Aucune // Parametre 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 = random() % 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) {//Repere le deplacement 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;//Memoriser la direction selectionnee return p; } //***************************************************************************** // But de la fonction : Evaluer les positions possibles et les memoriser dans // un tableau de positions si aucun fromage n'a ete detecte. Si du fromage a // ete detecte, il sera selectionne en premier. La presence d'un fromage est // indiquee par le drapeau CHEESE_FOUND // Entree : // Org : Position de la souris // Sorties : // Positions : Tableau de positions valides // Cheese : Position du fromage // Parametre 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) {//Repere le deplacement 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 // Entrees : // Org : Coordonnees de la souris // p : Coordonnees voulu par la souris // Parametre retourne : TRUE si le mouvement a eu lieu, FALSE sinon //***************************************************************************** static sos_bool_t AffectMovement(Point_t Org, Point_t p) { Element_t * pMouse = pMap[Org.X + (Org.Y * MAP_X)]; Element_t * pElement; 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 memoire du fromage sos_kfree((sos_vaddr_t)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 = SOS_X86_VIDEO_FG_MAGENTA; CheeseCount--; return TRUE; case OUTPUT: //Supprimer la souris pMap[Org.X + (Org.Y * MAP_X)] = NULL; MouseCount--; DrawPixel(Org.X, Org.Y, SOS_X86_VIDEO_FG_BLACK); sos_x86_videomem_printf( 23,0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Souris = %d; Fromages = %d; Obstacles = %d ", MouseCount, CheeseCount, ObstacleCount); Set(pMouse->Status, MOUSE_EXITED); return FALSE; default : return FALSE; } return FALSE; } //***************************************************************************** // But de la fonction : Tester si une collision a eu lieu avec un obstacle // Entrees : // Org : Coordonnees de la souris // p : coordonnees desirees par la souris // Sortie : // Cheese : Coordonnees du fromage // Parametre retourne : TRUE si une collision a eu lieu, FALSE sinon //***************************************************************************** static sos_bool_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'element 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 ete 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 = SOS_X86_VIDEO_FG_LTRED; //Autoriser la creation d'une autre souris sos_ksema_up(& SemMouse); return TRUE; case OUTPUT: break; default : return TRUE; } return FALSE;//Aucune collision } //***************************************************************************** // But du thread : Creer une souris et la placer autour de l'entree //***************************************************************************** static void MouseCreator(void) { while(1) { sos_ksema_down(& SemMouse, NULL); sos_ksema_down(& SemMap, NULL); CreateMouse(); sos_ksema_up(& SemMap); } } //***************************************************************************** // But de la fonction : Creer une souris et l'inserer dans la carte // Entree : Aucune // Parametre retourne : ERROR si memoire insuffisante, FALSE si souris non // cree, TRUE sinon //***************************************************************************** static sos_ret_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) {//Repere le deplacement 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) {//Creer la souris pElement = (Element_t *)sos_kmalloc(sizeof(Element_t), 0); if(pElement != NULL) {//Initialiser l'entree pElement->Type = MOUSE; Set(pElement->Status, MOUSE_EMPTY); pElement->Color = SOS_X86_VIDEO_FG_LTRED; pElement->P = p; pElement->Way = 0; pElement->ThreadID = sos_create_kernel_thread("Mouse", (sos_kernel_thread_start_routine_t)Mouse, pElement, SOS_SCHED_PRIO_TS_LOWEST-1); if(pElement->ThreadID == 0) { sos_kfree((sos_vaddr_t)pElement); pElement = NULL; return -SOS_ENOMEM; } pMap[p.X + (p.Y * MAP_X)] = pElement; MouseCount++; DrawPixel(p.X, p.Y, pElement->Color); sos_x86_videomem_printf(23, 0, SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE, "Souris = %d; Fromages = %d; Obstacles = %d ", MouseCount, CheeseCount, ObstacleCount); return SOS_OK; } } } } return -SOS_EBUSY; } //***************************************************************************** // C'est fini !!!! //*****************************************************************************