Téléchargement
Transcription
Téléchargement
LOG1000 - Ingénierie logicielle Automne 2013 Examen final Enseignant : Bram Adams Chargé de lab : Fehmi Jaafar Cet examen comporte 7 questions pour un total de 40 points Pondération : 40% de la note finale Directives : Toute documentation permise, mais aucune calculatrice. Répondez dans votre cahier, pas sur le questionnaire. Remettez les deux documents à la fin de l’examen. LOG1000 – Examen final – Automne 2013 1 Questions générales (5 points) Pour les 5 questions suivantes, choisissez la réponse qui vous semble être la bonne (0.5 point par question). 1.1 Parmi les énoncés suivants concernant le débogage, lequel est inexact ? a) Les erreurs de fuites de mémoire sont difficilement détectables. b) RÉPONSE Avec un outil de débogage, la cause d’une erreur peut être trouvée automatiquement. c) L’approche “diviser pour régner” convient bien au contexte de débogage. d) Les erreurs de syntaxe sont plus faciles à détecter que les erreurs d’exécution. e) Les tests unitaires peuvent être utiles pour trouver les défauts. 1.2 Quand Glenford J. Myers a dit que « Testing is the process of executing a program with the intent of finding errors », il a) était en train d’expliquer la différence entre des tests de performance et des unitaires. b) voulait dire que des testeurs doivent seulement montrer que le système marche dans des conditions normales, pas essayer de trouver des cas de bord qui ne se manifesteront jamais en réalité. c) RÉPONSE voulait dire que des testeurs doivent vraiment faire un effort de casser le système, pas seulement montrer que le système marche dans des conditions normales. d) n’avait pas encore essayé de programmer en C++. e) voulait dire que des tests manuels (en lisant le code) ne sont pas de vrais tests. 1.3 La différence entre la durée de vie et la portée d’une variable est : a) inexistante, ce sont deux mots pour le même concept. b) liée au problème des variables allouées sur le tas (“heap”) qui sont encore utilisées dans le code après être désallouées. c) la différence entre théorie et pratique, c.-à-d. la région maximale de code (par exemple une fonction) où une variable peut exister en théorie versus la région actuelle dans laquelle elle est utilisée. d) très petite. La portée est la distance entre chacune des deux références d’une variable, tandis que la durée de vie d’une variable est la distance entre la première et la dernière référence d’une variable. e) RÉPONSE la différence entre pratique et théorie, c.-à-d. la région actuelle dans laquelle une variable est utilisée versus la région maximale de code (par exemple une fonction) où elle peut exister en théorie. École Polytechnique de Montréal Page 1 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 1.4 Dans un contexte de gestion de projet, parmi les facteurs suivants, lequel aura le moins de risques d’avoir un impact négatif sur le temps de développement ? a) La complexité du système à développer. b) La qualité de l’analyse des exigences. c) RÉPONSE L’utilisation d’outils logiciels appropriés. d) Le degré de formalisation de la conception. e) L’expérience de l’équipe de développement par rapport au domaine applicatif. 1.5. Quel degré de cohésion est illustré par l’exemple de code suivant ? void prepareReport(Data& data, int report) { switch (report) { case SALES_REPORT: prepareSalesReport(data); break; case MANAGEMENT_REPORT: prepareManagementReport(data); break; case DIRECTION_REPORT: prepareDirectionReport(data); break; } } a) Cohésion procédurale. b) RÉPONSE Cohésion logique. c) Cohésion fonctionnelle. d) Cohésion de communication. e) Cohésion temporelle. École Polytechnique de Montréal Page 2 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 Pour chaque énoncé qui suit, dites s’il est vrai ou faux (une bonne réponse vaut 0.5 point et une mauvaise réponse vaut -0.25 point). 1.6 Un test unitaire requiert moins de temps qu’un test d’intégration. V 1.7 Un couplage faible est meilleur qu’une cohésion faible. V La minimisation de la métrique “span” entraîne une réduction de la complexité du logiciel. V En programmation en binôme, il vaut mieux que les différents dévelop- 1.8 1.9 1.10 2 peurs soient jumelés avec desd’un développeurs de même calibre. F sortie En principe, un test consiste jeu d’arguments d’entrée et une expectée. V Code de qualité (8 points) Répondez aux 3 questions suivantes (3 points). a) Pourquoi est-ce que l’on a peur pour « l’érosion de l’abstraction de l’interface après modifications » ? Illustrez avec un exemple en C++. (1 point) Unrelated methods are added over time, making interface more complex and less cohesive. Any two versions of a C++ class interface with methods added, removed, incorrect abstractions used, etc. would work. b) Donnez un exemple d’héritage en C++ où le principe de Liskov n’est pas suivi. Ensuite, expliquez ce que l’on pourrait faire pour résoudre ce problème et illustrez avec votre exemple. (1 point) Example of inheritance with empty version of one method : push that method down to that one subclass instead of in superclass. c) Quel patron de conception est utilisé aux lignes 57 à 61 du code fourni en annexe B ? Donnez (1) son nom, (2) son but concret dans le contexte de l’exemple, et (3) une explication de son implémentation. (1 point) Singleton, one instance of ErrorReporter across the whole program, using static variable of function. Pour les deux questions qui suivent, considérez le code fourni en annexe A (5 points). d) Calculez le span moyen de chacune des variables de la fonction Jedi_ClearPathToSpot (attention : seulement la réponse sera évaluée). Comptez les lignes de commentaires, mais pas les lignes vides ou les lignes contenant seulement { ou }. Si le résultat n’est pas un entier, laissez-le sous forme de fraction simplifiée. Ignorez les variables globales gi, NPC, STEPSIZE et ENTITYNUM_NONE, alors il reste 10 variables (n’oubliez pas la variable i sur la ligne 39 !). (2,5 points) dest :(5+14+1)/3=20/3 impactEntNum :(12)/1=12 trace :(4+1+2+1+21+0)/6=29/6 [attention : multiple occurrence on same line not counted] mins :(2+0+28)/3=10 start :(29+0+1)/3=10 end :(30+0+0)/3=10 École Polytechnique de Montréal Page 3 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 dir :(18+0+9)/3=9 dist :(18+6)/2=12 drop :(21+2+5)/3=28/3 i :(2)/1=2 e) Comment pourrait-on modifier la déclaration des 10 variables de la question précédente afin de minimiser le span ? Pour chaque variable, indiquez avant quelle ligne elle devrait être déclarée pour obtenir le meilleur span moyen. Traitez chaque cas indépendamment. Exemple : “déclarer x avant la ligne 11”. Il ne faut pas recalculer le span. (2,5 points) dest :(rien à faire) impactEntNum :(rien à faire) trace :(9) mins :(7) start :(42) end :(43) dir :(30) dist :(31) drop :(32) i :(rien à faire) École Polytechnique de Montréal Page 4 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 3 Gestion de construction du code (3 points) 100% 90% 80% 70% 60% 50% 40% Tests système 30% Intégration 20% Tests du développeur Codage et débogage 10% Conception détaillée 0% 2K 8K 32K 128K 512K Architecture F IGURE 1 – Effet de la taille sur les activités de développement. a) La période de Noël est la période la plus importante pour les producteurs de logiciels pour des téléphones intelligents (Android, iOS, etc.). Beaucoup de nouveaux produits sont lancés, dans l’espoir d’attirer l’attention des utilisateurs innocents. L’entreprise Adams & co. veut mettre en production un nouveau logiciel réveil qui offre une expérience incroyable, mais Dr. Adams, le PDG de l’entreprise, a été informé que l’entreprise Jaafar & co. est en train de préparer un logiciel pareil. Expliquez les deux concepts d’« estimation » et de « réduction de portée » avec cet exemple. (1 point) Make good estimation of effort required to release on time, if not on time remove unimportant features to reduce scope, so as to still be the first one on the market. b) Expliquez pourquoi le fondateur de Amazon (Jeff Bezos) a dit « if a team can’t be fed with two pizzas, it is too big ». Donnez un exemple. (1 point) Too much communication overhead for training, getting to know what changed, ... . Use formula for combination of 2 out of N to show how communication overhead quickly skyrockets. c) Expliquez la Figure 1, c’est-à-dire qu’est-ce que peut-on y observer, et pourquoi ? (1 point) Integration/architecture/system tests become more important, since bigger system means more teams and hence more subsystems, all of which need to communicate with each École Polytechnique de Montréal Page 5 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 other if one does not improve integration/architecture. Also, bigger need to test the whole system. École Polytechnique de Montréal Page 6 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 4 Débogage (3 points) F IGURE 2 – Outil #1 (http ://software.opensuse.org/package/screenshot/). Répondez aux questions suivantes : a) Quel est le nom et le but de l’outil #1 dans la Figure 2 ? Qu’est-ce qu’un « breakpoint » ? Comment peut-on utiliser un tel « breakpoint » avec une méthode scientifique ? (1 point) gdb debugger, stop and query program to verify series of hypotheses for finding bugs. École Polytechnique de Montréal Page 7 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 F IGURE 3 – Outil #2 (http ://www.drdobbs.com/go-parallel/article/print ?articleId=227100038). b) Quel est le nom et le but de l’outil #2 dans la Figure 3 ? Que pouvez-vous observer dans la Figure concernant le système analysé ? (1 point) gprof profiler, top methods take longest time, although not called that often. F IGURE 4 – Outil #3 (http ://wiki.crc.nd.edu/wiki/index.php/Main_Page). c) Quel est le nom et le but de l’outil #3 dans la Figure 4 ? Que pouvez-vous observer dans la Figure concernant le système analysé ? (1 point) valgrind memory checker, there is leak in main function. École Polytechnique de Montréal Page 8 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 5 Programmation défensive (6 points) a) Considérez le code fourni en annexe B du jeu vidéo Jedi Outcast. Expliquez ce que les développeurs ont fait pour faciliter la programmation défensive. En particulier, donnez le but de (1) la classe en ligne 4, (2) les méthodes en lignes 9, 26 et 57 et (3) les macros en lignes 63 et 70. (2 points) Central error reporting class, which generates report in destructor, allows to signal an error with an error message and line number, and is accessed through singleton instance obtained through method on line 57. In debugging mode, the reporter class is used through the three macros, so developers do not need to know about the class itself, just the macros. In production mode, the empty macros are used instead (no need to remove macros in code). b) Qu’est-ce qui se passera pendant l’exécution de la fonction main en ligne 78 ? Est-ce que le programme est actuellement exécuté par un développeur (pendant le développement) ou par un utilisateur (produit final) ? Dans le premier cas, comment pourrait-on configurer le programme pour un utilisateur ? Dans le deuxième cas, comment pourraiton configurer le programme pour un développeur ? (2 points) Debugging mode, so an error is logged and will pop up in report. Go to production mode by undefining line 77. c) Discutez les lignes 27 et 47. Additionnellement, répondez aux deux questions suivantes : Pourquoi a-t-on choisi une telle approche ? Donnez aussi une approche alternative. (2 points) Video game, so development-time assert is OK (especially since only during debugging the error reported is used). Maybe use generic error message if no message provided. 6 Restructuration du code (6 points) Pour chacun des 6 exemples de code : — Indiquez en une ligne quel est le problème principal (qui vous apparaît le plus évident), s’il y en a un. — S’il y a un problème, décrivez brièvement la restructuration qui serait pertinent d’appliquer afin d’améliorer le code. Pour vous aider, rapportez-vous aux opérations vues en cours. N’indiquez pas le code restructuré. — S’il n’y a pas de problème, expliquez pourquoi. a) Exemple 1 (C++) : 1 2 3 4 5 6 7 //adapté de Audacity 2.0.5, fichier src/ImageManipulation.cpp wxImage *OverlayImage(wxImage * background, wxImage * foreground, wxImage * mask, int xoff, int yoff) { unsigned char *bg = background->GetData(); unsigned char *fg = foreground->GetData(); unsigned char *mk = mask->GetData(); 8 9 10 11 int bgWidth = background->GetWidth(); int fgWidth = foreground->GetWidth(); int mkWidth = mask->GetWidth(); 12 École Polytechnique de Montréal Page 9 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 int bgHeight = background->GetHeight(); int fgHeight = foreground->GetHeight(); int mkHeight = mask->GetHeight(); 13 14 15 16 //Make sure the foreground size is no bigger than the mask int wCutoff = (fgWidth < mkWidth) ? fgWidth : mkWidth; int hCutoff = (fgHeight < mkHeight) ? fgHeight : mkHeight; 17 18 19 20 21 // If the // should wCutoff = hCutoff = 22 23 24 25 masked foreground + offset is bigger than the background, masking only occur within these bounds of the foreground image (bgWidth - xoff > wCutoff) ? wCutoff : bgWidth - xoff; (bgHeight - yoff > hCutoff) ? hCutoff : bgHeight - yoff; 26 27 //Make a new image the size of the background wxImage * dstImage = new wxImage(bgWidth, bgHeight); unsigned char *dst = dstImage->GetData(); memcpy(dst, bg, bgWidth * bgHeight * 3); return dstImage; 28 29 30 31 32 33 } variable spans too large reorder lines to group variables b) Exemple 2 (Java) : 1 2 3 4 5 6 //adapté de https://www.simple-talk.com/dotnet/.net-framework/exploring-smelly-code/ public class Address{ private String addressLine; private String city; private String state; private String postalCode; 7 ... 8 9 public String getAddressLine{ return addressLine; } public String getCity{ return city; } public String getState{ return state; } public String getPostalCode{ return postalCode; } 10 11 12 13 14 15 16 17 18 19 20 21 22 } 23 24 25 public class Order{ private Address currentAddress = null; 26 27 ... 28 29 30 31 32 public String MailingAddress(){ StringBuilder sb = new StringBuilder (); sb.Append(currentAddress.getAddressLine1()); sb.Append("\n"); École Polytechnique de Montréal Page 10 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 sb.Append(currentAddress.getCity() + ", " + currentAddress.getState()); sb.Append("\n"); sb.Append(currentAddress.getPostalCode()); return sb.ToString(); 33 34 35 36 } 37 38 } feature envy move function/responsability to Address École Polytechnique de Montréal Page 11 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 c) Exemple 3 (C++) : 1 2 3 4 5 6 //adapté de Audacity 2.0.5, fichier src/LabelDialog.cpp void LabelDialog::OnCellChange(wxGridEvent &event) { static bool guard = false; int row = event.GetRow(); RowData *rd; 7 if (guard) { return; } guard = true; 8 9 10 11 12 // The change was to an existing label, so go process it based // on which column was changed. rd = mData[row]; switch (event.GetCol()) { case Col_Track: OnChangeTrack(event, row, rd); break; 13 14 15 16 17 18 19 20 21 case Col_Label: OnChangeLabel(event, row, rd); break; 22 23 24 25 case Col_Stime: OnChangeStime(event, row, rd); break; 26 27 28 29 case Col_Etime: OnChangeEtime(event, row, rd); break; 30 31 32 } 33 34 // Done...no need for protection anymore guard = false; 35 36 37 return; 38 39 } no problem event handlers ! École Polytechnique de Montréal Page 12 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 d) Exemple 4 (C++) : 1 2 3 4 5 6 7 8 9 //adapté de Audacity 2.0.5, fichier src/LabelDialog.cpp void LabelDialog::OnChangeStime(wxGridEvent & WXUNUSED(event), int row, RowData *rd) { // Remember the value...no need to repopulate mGrid->GetCellValue(row, Col_Stime).ToDouble(&rd->stime); if (rd->etime < rd->stime) { rd->etime = rd->stime; mGrid->SetCellValue(row, Col_Etime, wxString::Format(wxT("%g"), rd->etime)); } 10 return; 11 12 } 13 14 15 16 17 18 19 20 21 void LabelDialog::OnChangeEtime(wxGridEvent & WXUNUSED(event), int row, RowData *rd) { // Remember the value...no need to repopulate mGrid->GetCellValue(row, Col_Etime).ToDouble(&rd->etime); if (rd->etime < rd->stime) { rd->stime = rd->etime; mGrid->SetCellValue(row, Col_Stime, wxString::Format(wxT("%g"), rd->stime)); } 22 return; 23 24 } 25 26 27 28 29 30 31 32 void LabelDialog::OnOK(wxCommandEvent & WXUNUSED(event)) { if (mGrid->IsCellEditControlShown()) { mGrid->SaveEditControlValue(); mGrid->HideCellEditControl(); return; } 33 // Standard handling if (Validate() && TransferDataFromWindow()) { EndModal(wxID_OK); } 34 35 36 37 38 return; 39 40 } 41 42 43 44 45 46 47 48 49 50 void LabelDialog::OnCancel(wxCommandEvent & WXUNUSED(event)) { if (mGrid->IsCellEditControlShown()) { mGrid->GetCellEditor(mGrid->GetGridCursorRow(), mGrid->GetGridCursorCol()) ->Reset(); mGrid->HideCellEditControl(); return; } 51 // Standard handling EndModal(wxID_CANCEL); 52 53 54 return; 55 56 } duplication/cloning extract common things into one function École Polytechnique de Montréal Page 13 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 e) Exemple 5 (C++) : 1 2 3 4 //adapté de Audacity 2.0.5, fichier src/MixerBoard.h class MixerBoard : public wxWindow { friend class MixerBoardFrame; 5 6 7 8 9 10 11 public: MixerBoard(AudacityProject* pProject, wxFrame* parent, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); virtual ~MixerBoard(); 12 // Add clusters for any tracks we’re not yet showing. // Update pointers for tracks we’re aleady showing. void UpdateTrackClusters(); 13 14 15 16 int GetTrackClustersWidth(); void MoveTrackCluster(const Track* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard. void RemoveTrackCluster(const Track* pTrack); 17 18 19 20 wxBitmap* GetMusicalInstrumentBitmap(const wxString name); 21 22 bool HasSolo(); 23 24 void RefreshTrackCluster(const Track* pTrack, bool bEraseBackground = true); void RefreshTrackClusters(bool bEraseBackground = true); void ResizeTrackClusters(); 25 26 27 28 void ResetMeters(const bool bResetClipping); 29 30 void void void void void 31 32 33 34 35 UpdateName(const Track* pTrack); UpdateMute(const Track* pTrack = NULL); // NULL means update for all tracks. UpdateSolo(const Track* pTrack = NULL); // NULL means update for all tracks. UpdatePan(const Track* pTrack); UpdateGain(const Track* pTrack); 36 void UpdateMeters(const double t1, const bool bLoopedPlay); 37 38 void UpdateWidth(); 39 40 41 42 43 44 45 private: void CreateMuteSoloImages(); int FindMixerTrackCluster(const Track* pTrack, MixerTrackCluster** hMixerTrackCluster) const; void LoadMusicalInstruments(); 46 // event handlers void OnSize(wxSizeEvent &evt); 47 48 49 ... 50 51 }; low cohesion split class École Polytechnique de Montréal Page 14 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 f) Exemple 6 (C++) : 1 2 3 4 5 6 7 8 9 class MixerTrackCluster : public wxPanel { public: MixerTrackCluster(wxWindow* parent, MixerBoard* grandParent, AudacityProject* project, WaveTrack* pLeftTrack, WaveTrack* pRightTrack = NULL, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); virtual ~MixerTrackCluster() {}; 10 11 void HandleResize(); // For wxSizeEvents, update gain slider and meter. 12 13 14 void HandleSliderGain(const bool bWantPushState = false); void HandleSliderPan(const bool bWantPushState = false); 15 16 void ResetMeter(const bool bResetClipping); 17 18 ... 19 20 21 22 23 public: // mTrack is redundant, but simplifies code that operates on either // mLeftTrack or mNoteTrack. Track* mTrack; // either mLeftTrack or mNoteTrack, whichever is not NULL 24 25 26 WaveTrack* mLeftTrack; // NULL if Note Track WaveTrack* mRightTrack; // NULL if mono 27 28 29 //vvv Vaughan, 2010-11-05: NoteTrack* mNoteTrack; // NULL if Wave Track 30 31 32 33 34 private: MixerBoard* mMixerBoard; AudacityProject* mProject; 35 36 37 38 39 40 41 42 43 // controls wxStaticText* mStaticText_TrackName; wxBitmapButton* mBitmapButton_MusicalInstrument; AButton* mToggleButton_Mute; AButton* mToggleButton_Solo; MixerTrackSlider* mSlider_Pan; MixerTrackSlider* mSlider_Gain; Meter* mMeter; 44 45 46 47 public: DECLARE_EVENT_TABLE() }; public attributes make private École Polytechnique de Montréal Page 15 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 7 Tests du développeur (9 points) Pour la question qui suit, considérez à nouveau le code fourni en annexe A. a) Tracez le graphe de flot de contrôle de la fonction Jedi_ClearPathToSpot. Ne recopiez pas le code au complet dans les noeuds, n’utilisez que le ou les numéros de lignes correspondantes, sauf où une ligne appartient à plusieurs nœuds (exemple : (1), (7,8,9), (a<45), etc.). (3 points) Version avec “continue” nodes also accepted, as well as version where “i++” or “continue” nodes are shared : 2-11 12a 14 12b 17 19a 27-32 19b 33-34 21 36-37 23 39 40-45 46a 46b 46c 53-54 48 51 end b) Quelle est la complexité cyclomatique de la fonction Jedi_ClearPathToSpot et que signifie cette valeur dans le contexte de tests de couverture de code ? (2 points) E=30, N=21, alors complexité cyclomatique : 30-21+2=11. Cela représente le nombre maximal de cas de tests nécessaires pour obtenir une couverture complète du code. c) Donnez un ensemble minimal de tests nécessaires pour couvrir la fonction Jedi_ClearPathToSpot École Polytechnique de Montréal Page 16 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 entièrement (chaque ligne), c.-à-d. : (a) Donnez le nombre minimal de différents jeux de paramètres avec lesquels il faut exécuter la fonction. (0.5 point) (b) Donnez pour chaque jeu de paramètres les valeurs et (si nécessaire) les caractéristiques particulières des paramètres. Par exemple, pour un paramètre qui représente un tableau de deux éléments avec des caractéristiques particulières, vous pourriez répondre [“impactEntNum>0”,“dest.isEmpty()”] pour un cas de test spécifique. (1.5 point) 7 : from 39 to 51 we only need 1 instead of 4, by picking for [trace.fraction < 1.0f || trace.allsolid || trace.startsolid] the following ones in the NPC array : (T,F,F), (F,T,F), (F,F,T) and (F,F,F) d) Qu’est-ce qu’un test du flux de données ? Est-ce qu’il faut ajouter des tests du flux de données pour la variable drop, ou est-ce que les tests de flot de contrôle sont suffisants ? Dans le premier cas, indiquez les nouveaux tests sur le graphe de flot de contrôle. (2 points) if we had 27-32 => 33-34 => 39 => 53-54 and 27-32 => 36-37 => 39 => 40-45 => rest of loop before, we now need to add 27-32 => 33-34 => 39 => 40-45 => 39 => 43-54 as well to cover all definition - use of drop Nous vous souhaitons beaucoup de succès dans le restant de vos études et de votre cheminement de carrière ! Bram et Fehmi École Polytechnique de Montréal Page 17 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 Annexe A 1 2 3 4 static qboolean Jedi_ClearPathToSpot( vec3_t dest, int impactEntNum ){ trace_t trace; vec3_t mins, start, end, dir; float dist, drop; 5 //Offset the step height VectorSet( mins, NPC->mins[0], NPC->mins[1], NPC->mins[2] + STEPSIZE ); 6 7 8 gi.trace( &trace, NPC->currentOrigin, mins, NPC->maxs, dest, NPC->s.number, NPC->clipmask ); 9 10 //Do a simple check if ( trace.allsolid || trace.startsolid ){ //inside solid return qfalse; } 11 12 13 14 15 16 if ( trace.fraction < 1.0f ){ //hit something if ( impactEntNum != ENTITYNUM_NONE && trace.entityNum == impactEntNum ){ //hit what we’re going after return qtrue; }else{ return qfalse; } } 17 18 19 20 21 22 23 24 25 26 //otherwise, clear path in a straight line. //Now at intervals of my size, go along the trace and trace down STEPSIZE to make sure //there is a solid floor. VectorSubtract( dest, NPC->currentOrigin, dir ); dist = VectorNormalize( dir ); if ( dest[2] > NPC->currentOrigin[2] ){ //going up, check for steps drop = STEPSIZE; }else{ //going down or level, check for moderate drops drop = 64; } for ( float i = NPC->maxs[0]*2; i < dist; i += NPC->maxs[0]*2 ){ //FIXME: does this check the last spot, too? We’re assuming that should be okay //since the enemy is there? VectorMA( NPC->currentOrigin, i, dir, start ); VectorCopy( start, end ); end[2] -= drop; gi.trace( &trace, start, mins, NPC->maxs, end, NPC->s.number, NPC->clipmask );//NPC->mins? if ( trace.fraction < 1.0f || trace.allsolid || trace.startsolid ){ //good to go, check next one continue; } //no floor here! (or a long drop?) return qfalse; } //we made it! return qtrue; 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 } (adapté de : git://git.code.sf.net/p/jedioutcast/code, fichier code/game/AI_Jedi.cpp) École Polytechnique de Montréal Page 18 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 Annexe B 1 #if G2API_DEBUG 2 3 4 5 6 7 8 9 10 11 #define MAX_ERROR_PRINTS (3) class ErrorReporter{ string mName; map<string,int> mErrors; public: ErrorReporter(const string &name): mName(name) {} ~ErrorReporter(){ int total=0; cerr << "****** " << mess <<" Error Report Begin******\n"; 12 map<string,int>::iterator i; for (i=mErrors.begin();i!=mErrors.end();i++) { total+=(*i).second; cerr << (*i).first.c_str() << " (hits " << (*i).second << ")\n"; } 13 14 15 16 17 18 19 cerr << << << << 20 21 22 23 24 "****** " << mName.c_str() " Error Report End " << total " errors of " << mErrors.size() " kinds******\n"; } 25 26 27 28 29 30 31 32 33 34 35 36 37 int Error(const char *m,int kind,const char *, int line){ assert(m); string full=mName; if (kind==2){ full+=":NOTE: "; }else if (kind==1){ full+=":WARNING: "; }else{ full+=":ERROR : "; } full+=m; cerr << " [line " << line << "]"; 38 int ret=0; map<string,int>::iterator f=mErrors.find(full); if (f==mErrors.end()) { ret++; mErrors.insert(pair<string,int>(full,0)); f=mErrors.find(full); } assert(f!=mErrors.end()); (*f).second++; if ((*f).second<=MAX_ERROR_PRINTS&&kind<2){ cerr << full.c_str() << " (hit # " << (*f).second << ")\n"; } return ret; 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 } }; 55 56 57 58 59 60 61 #include "assert.h" ErrorReporter &G2APIError() { static ErrorReporter singleton("G2API"); return singleton; } 62 63 #define G2ERROR(exp,m) (void)( (exp) || (G2APIError().Error(m,0,__FILE__,__LINE__), 0) ) École Polytechnique de Montréal Page 19 de 20 Département de génie informatique et génie logiciel LOG1000 – Examen final – Automne 2013 64 65 66 #define G2WARNING(exp,m) (void)( (exp) || (G2APIError().Error(m,1,__FILE__,__LINE__), 0) ) #define G2NOTE(exp,m) (void)( (exp) || (G2APIError().Error(m,2,__FILE__,__LINE__), 0) ) #define G2ANIM(ghlInfo,m) (void)((G2APIError().AnimTest(ghlInfo,m,__FILE__,__LINE__), 0) ) 67 68 #else 69 70 71 72 73 #define #define #define #define G2ERROR(exp,m) ((void)0) G2WARNING(exp,m) ((void)0) G2NOTE(exp,m) ((void)0) G2ANIM(ghlInfo,m) ((void)0) 74 75 #endif 76 77 78 79 #define G2API_DEBUG int main(void){ int nr_joueurs=-1; 80 G2ERROR(nr_joueurs>0,"players"); 81 82 } (adapté de : git://git.code.sf.net/p/jedioutcast/code, fichier code/ghoul2/g2_api.cpp) École Polytechnique de Montréal Page 20 de 20 Département de génie informatique et génie logiciel