Available nodes

 Byzantines circonvolutions

Imaginez faire partie de l'aristocratie. Une aristocratie déchue, exclue, délaissée… Dans cet univers froid où vous cherchez des réponses à vos questions, vous savez au moins que celles-ci sont liées à un étrange manoir, intimement mais subtilement relié à votre passé. Un passé dont vous ne connaissez que des bribes. Mais au fond de ce manoir, vous savez qu'il existe une salle permettant de comprendre la clé de ce passé, et c'est devenu votre unique raison de vivre. Le problèmes, c'est que le manoir en question possèdes des propriétés fantasmagoriques. D'une part, vous ne pouvez l'explorer qu'un temps fini à chaque fois, avant que la fatigue ne vous submerge. Et d'autre part, tel un cauchemar fantastique, l'arrangement des pièces du manoir change à chaque exploration. Tout ce dont vous êtes certain, c'est qu'il est constitué de pièces carrées avec plus ou moins de sorties possibles à chaque fois, comme par exemple :
Un ensemble de salles possibles, comportant plus ou moins de sorties chacune ( Source sur le Wiki du jeu Blue Prince)
L'objectif de ce jeu étrange, puisque c'en est un, est d'arriver à atteindre la sortie de ce manoir, en partant de son entrée, et en explorant au fur et à mesure les pièces pour tenter d'atteindre la position de l'ultime salle, celle où toutes les questions trouveront toutes les réponses. Quitte, tel un Sisyphe moderne, à recommencer sans relâche pour sortir de ce mauvais rêve.
Les inspirations de ce sujet sont tirées du jeu Blue Prince développé par le studio DoguBomb. Le sujet ne demande aucune connaissance particulière du jeu, et n'envisage en aucun cas d'arriver à reproduire tout ou partie de sa mécanique. Néanmoins, la composante labyrinthique est au coeur de ce sujet. Et l'exploration du wiki en question peut fournir des idées pour l'écriture du jeu.
À propos des achievements : ce sujet de projet est construit sur la notion d'achievement. Un achievement est un ensemble de fonctionnalités à développer pour le projet. Les achievements doivent être réalisés dans l'ordre, et de manière cumulative. Ils seront débloqués à chaque fois qu'au moins une équipe de projet aura rempli les conditions de l'achievement précédent et aura fait valider la chose par son encadrant. La version de base correspond à l'achievement initial. L'évaluation du projet est basée en partie sur le nombre d'achievements réalisés, et la version de base n'est pas forcément représentative du travail nécessaire pour atteindre la moyenne.

 Ressources et tuiles

Le jeu se déroule dans un manoir rectangulaire, aux dimensions (BOARD_WIDTH, BOARD_HEIGHT). Le nombre de cases du manoir est noté comme BOARD_SIZE := BOARD_WIDTH * BOARD_HEIGHT. Chaque case de ce manoir est identifiée par une position (et le type struct location_t), représentant une abscisse et une ordonnée. Les positions valides pour jouer ont des abscisses dans [0; BOARD_WIDTH[ et des ordonnées dans [0; BOARD_HEIGHT[. Pour les besoins du projet, les valeurs de BOARD_WIDTH et BOARD_HEIGHT pourront varier, mais elles seront toujours au moins égales à 3. L'interface pour manipuler les positions est définie dans le fichier location.h. Pour identifier le lien entre deux positions adjacentes, on utilise une direction (à travers le type enum dir_t), qui énumère les quatre directions cardinales. La direction NORTH correspond aux ordonnées croissantes, tandis que la direction EAST correspond aux abscisses croissantes. L'interface pour manipuler les directions est définie dans le fichier dir.h.
Toutes les actions réalisées dans le manoir peuvent coûter ou générer des ressources (à travers le type enum resource_t1). Le nombre de ressources différentes en jeu est NUM_RESOURCES. Pour les besoins du projet, il est possible de faire varier NUM_RESOURCES, mais ce nombre est censé être compris dans l'intervalle [2; MAX_RESOURCES[, avec MAX_RESOURCES fixé à 10. L'interface pour manipuler les ressources est définie dans le fichier resource.h. Pour représenter des ensembles de ressources, on utilise des poches2 (dans le code des struct stash_t), qui ne sont guère plus que des tableaux de ressources stockés sous la forme de vecteurs d'entiers. Une poche est dite finie lorsqu'elle ne contient aucune ressource en quantité UINT_MAX (sinon elle est dite infinie). L'interface pour manipuler les poches est définie dans le fichier stash.h. Elle donne des exemples d'une poche finie ONE_STEP_STASH représentant un unique pas, ainsi qu'une poche infinie INFINITE_STEP_STASH.
Chaque case du manoir est censée contenir une tuile (de type struct tile_t). Une tuile est caractérisée par :
  • son nom (par exemple, "Chambre à coucher");
  • le coût pour traverser la tuile (par exemple un unique pas, i.e ONE_STEP_STASH, mais d'autres coûts sont envisageables);
  • le coût pour ouvrir la tuile dans une direction donnée (cf. plus tard).
L'interface pour manipuler les tuiles est définie dans le fichier tile.h. Il existe trois types de tuiles spéciales dans le jeu :
  • les tuiles vides, qui ne sont pas réellement des tuiles, mais simplement des marqueurs pour indiquer que la position correspondante n'a pas encore été découverte;
  • la tuile de départ, qui peut s'ouvrir dans les 4 directions possibles, qui ne peut apparaître qu'une seule fois dans le manoir, et qui sert de point de départ au joueur;
  • la tuile d'arrivée, qui peut s'ouvrir dans les 4 directions possibles, qui ne peut apparaître qu'une seule fois dans le manoir, et qui sert d'objectif d'arrivée.
Dans la version de base du jeu, on n'applique pas de rotation aux tuiles.
Le type utilisé pour représenter les tuiles est un type abstrait et il doit être défini dans un fichier tile.c. Conséquence du fait que ce type soit abstrait, dans les fichiers autres que tile.c, on est obligé de ne manipuler les tuiles qu'à travers des pointeurs. Le bénéfice apporté par cette complication est la possibilité de proposer d'autres implémentations des tuiles, que l'on pourra (un jour) substituer en fonction des besoins de jeu.
Le manoir associe à chaque position valide une tuile. Au début de la partie, il doit contenir une tuile de départ (située dans le jeu original au milieu des positions d'ordonnée 0), ainsi que d'une tuile d'arrivée (située au milieu des positions d'ordonnée BOARD_HEIGHT-1). Toutes les autres tuiles sont initialement des tuiles vides.
Pour les besoins du projet, il est interdit de modifier les 5 fichiers d'interface précédents. Il est par contre tout à fait possible, voire encouragé, d'en ajouter de nouveaux.

 Déroulement de la partie

Le jeu commence avec avec le joueur initialement placé sur la tuile de départ. L'objectif du jeu consiste à réussir, en partant de la tuile de départ, à atteindre la tuile d'arrivée, en se déplaçant de case en case, en ouvrant successivement des tuiles dans le manoir. Le jeu est gagné si le joueur arrive à se déplacer sur la tuile d'arrivée. Pour aider au débuggage, le jeu est perdu si le nombre de tours joué dépasse MAX_TURNS (initialement fixé à 100). Le joueur possède initialement un nombre de ressources égal à 4 * BOARD_SIZE / 3 pas (arrondi à l'entier supérieur).

A chaque tour de jeu, le joueur peut réaliser l'une des deux actions suivantes :

  • Ouverture d'une tuile adjacente : Il n'est possible d'ouvrir une tuile que si celle-ci est vide et adjacente à la position courante, et que le coût d'ouverture depuis la tuile courante est fini. Si c'est le cas, on applique une mécanique de tirage de tuiles (drafting) :
    1. Le jeu tire aléatoirement au plus NUM_TILES_PER_TURN tuiles différentes qu'il propose au joueur. Le jeu assure que chacune de ces tuiles est telle que les coûts pour ouvrir dans les deux sens sont finis. S'il n'y pas de tuile vérifiant ces propriétés, l'ouverture d'une tuile sur la case sélectionnée n'est pas possible.
    2. Le joueur sélectionne alors une des tuiles en question, et il doit simplement payer le coût d'ouverture de la tuile d'arrivée. Il ne se déplace alors pas. La tuile dans le manoir à la position adjacente est alors remplacée par la tuile sélectionnée. Si le joueur ne peut payer le coût d'aucune des tuiles proposées, c'est une fin de partie.
  • Déplacement sur une tuile adjacente : Il n'est possible de se déplacer d'une tuile à une tuile adjacente que si ces deux tuiles sont non vides, et que les coûts pour ouvrir dans les deux sens sont finis. Dans ce cas, le joueur doit simplement payer le coût de traversée de la tuile d'arrivée, et appliquer le déplacement.
Chaque ouverture et chaque déplacement ont donc des coûts, qu'il faudra payer, que ce soit pour ouvrir et se déplacer sur les tuiles. Si un joueur se retrouver dans l'incapacité de payer un coût, l'action n'est pas réalisable. Si le joueur n'a plus d'actions réalisables à son tour de jeu, la partie se termine sur une défaite.
L'exemple suivant permet d'illustrer un petit morceau de partie. La tuile de départ (ici le "Entrance Hall") est située à la position (0,0), et le joueur commence lui aussi à cette position. La position du joueur est indiquée par une pastille rouge. La liste des actions suivantes pour le joueur représente alors une partie valide, en supposant que tous les coûts de déplacements et d'ouverture sont abordables pour le joueur :
  1. il (le joueur) ouvre la case au nord, et place la tuile "Security";
  2. il ouvre la case à l'est, et place la tuile "Den";
  3. il se déplace à l'est;
  4. il ouvre la case au nord, et place la tuile "Pantry";
  5. il se déplace au nord;
  6. il se déplace à l'ouest;
Etat initial
(images du wiki sur Fandom)
Tour 1
(images du wiki sur Fandom)
    … 
Etat final
(images du wiki sur Fandom)

Dans ces images, l'existence d'une porte ouverte sur une tuile donnée correspond à un coût d'ouverture fini. La dernière action de la partie (i.e le déplacement de la "Pantry" vers la "Security") est possible parce que les deux tuiles sont adjacentes, non vides, et supposément avec des coûts d'ouverture finis. La situation suivante donne un exemple dans lequel il n'est pas possible de se déplacer entre la case "Pantry" et la case "Security", du fait d'un coût infini dans un seul des deux sens (ici depuis la "Pantry", vers l'est) :
Passage impossible (images tirées du wiki sur Fandom)

Dans cette situation, le coût d'ouverture de la "Security" vers l'ouest est fini (la tuile contient une ouverture), mais le coût d'ouverture de la "Pantry" vers l'est est infini (la tuile contient un mur). Comme les deux coûts ne sont pas finis, il n'est pas possible de passer d'une tuile à l'autre.

 Quelques tuiles pour démarrer

Ensemble de tuiles : selon l'ensemble de tuiles avec lesquelles on joue, le jeu peut devenir plus ou moins intéressant. Ainsi, si toutes les tuiles sont des Cloîtres qui s'ouvrent dans les 4 directions, ne coûtent rien à ouvrir et à traverser, le jeu devient trivialement facile. A l'opposé, si toutes les tuiles sont des Terrasses qui ne s'ouvrent que dans une unique direction, le jeu devient impossible. Pour pallier ce problème, nous proposons de jouer avec l'ensemble de tuiles suivant par défaut. Noter que ce n'est qu'une suggestion et que cela ne fait pas partie des exigences du projet :
Cloister (poids 2) Terrace (poids 1) E-W Corridor (poids 1) N-S Corridor (poids 1)
Le choix des coûts des tuiles est une question épineuse pour l'équilibrage du jeu, mais a peu d'importance dans la version de base. Néanmoins, pour fixer les choses, dans le jeu de base, chaque tuile a un coût de traversée de ONE_STEP_STASH, et un coût d'ouverture de ONE_STEP_STASH.

Processus de sélection : le jeu demande à chaque ouverture de case de pouvoir tirer NUM_TILES_PER_TURN tuiles avec des propriétés particulières. Pour commencer, on assigne un poids à chaque tuile dans le jeu. Dans l'exemple précédent, chaque tuile pourrait avoir le même poids 1, sauf le cloître qui aurait le poids 2. Ensuite la sélection se fait de la manière suivante (cet algorithme de sélection fait partie de la version de base, contrairement aux ensembles de tuiles précédents) :

  1. Tout d'abord, on sélectionne uniquement les tuiles qui satisfont les critères pour pouvoir être placées sur la case sélectionnée (typiquement les coûts d'ouverture);
  2. Ensuite, on tire les tuiles au hasard parmi l'ensemble des tuiles précédentes, et cela proportionnellement à leur poids;
  3. Enfin, si le processus précédent a engendré des doublons, on retire les tuiles en double.
Il est donc parfaitement possible que ce processus renvoie moins de NUM_TILES_PER_TURN tuiles au final. Les tuiles en question sont ensuite passées au joueur, qui sélectionne celle qui lui semble la plus appropriée pour poursuivre sa partie.

 Base version

Pour valider la version de base du projet, il est demandé de produire un programme avec les caractéristiques décrites dans ce paragraphe.

Le programme doit mettre en place une boucle permettant de jouer une partie en suivant les règles précédemment énoncées. Toute décision impliquant plusieurs choix possibles sera prise de manière aléatoire. Le pseudo-algorithme de la boucle principale est le suivant :

  • init_tiles(0);                   // Use parameter equal to 0 by default
    game_state = init_state();
    current_turn = 1;
    while current_turn <= MAX_TURNS and exit_not_reached(game_state)
        possible_locations = list_empty_locations_with_finite_opening_cost(game_state)
        if available_directions.count > 0 and decides_to_place_tile()
            selected_location = select_one(possible_locations)
            available_tiles = generate_some_tiles(NUM_TILES_PER_TURN)
            selected_tile = select_one(available_tiles)
            place_tile(game_state, selected_location, selected_tile)
        else // decides_to_move()
            possible_locations = list_open_locations(game_state)
            selected_location = select_one(possible_locations)
            move_player(game_state, selected_location)
    player_has_won = exit_reached(game_state)
  • Exemple de début de partie :
    tiles = { Entrance, Security, Pantry, Den };
    board = {
      Entrance at (0,0), (1,0), (2,0), (3,0),
      (0,1),             (1,1), (2,1), (3,1),
      (0,2),             (1,2), (2,2), Exit at (3,2),
    };
    game_state = { steps = 10, board = board, location = (0,0) };
    place_tile(Den, (1,0));    // pay the cost of opening Den (from the West)
    place_tile(Pantry, (0,1)); // pay the cost of opening Pantry (from the South)
    move_player((1,0));        // pay the traversal cost of the Den
    ...        

Le projet suggère la décomposition des tâches suivante :

 Achievement 1 : Rotation des tuiles

Dans la version de base, les tuiles sont rigides, au sens où une fois décidé de leur orientation, il n'est plus possible d'en changer. Évidemment, il est possible de dupliquer les tuiles pour chaque sens de rotation (comme il est fait pour les Corridors dans la description des tuiles par défaut). Mais d'une part, ce n'est pas très élégant, au sens où cela entraîne de la duplication de code, et cela complique le réglage des algorithmes de tirage de tuiles.
On demande donc à ce que le jeu permette d'effectuer des rotations des tuiles avec lesquelles on joue (uniquement dans les directions cardinales, à savoir 90°, 180° ou 270°). Cela entraîne deux types de modification :
  • Le processus de sélection est modifié de la manière suivante : la première étape du processus produit une première liste de tuiles sélectionnables de la manière suivante :
    • une première liste de tuiles satisfaisant les critères pour l'ouverture est générée (en utilisant la fonction tile_draft avec la bonne direction);
    • une seconde liste de tuiles quelconque est générée (en utilisant la fonction tile_draft avec la direction INVALID_DIR), puis, pour chaque tuile dans cette second liste ne satisfaisant pas les critères pour l'ouverture, on applique une rotation aléatoire (90°, 180° ou 270°), et on l'enlève de la liste si après rotation elle ne satisfait pas les critères d'ouverture;
    • le résultat final est l'union des deux listes.
  • Le joueur dispose au départ de sa partie de NUM_INITIAL_ROTATIONS rotations disponibles (fixé initialement à BOARD_WIDTH * BOARD_HEIGHT / 10). Tant qu'il possède des rotations disponibles, lorsqu'il pose une tuile sélectionnée par le processus de sélection, il calcule les rotations appliquables qui préservent les critères pour l'ouverture, en tire une au hasard et l'applique.

 Achievement 1.5 : Vérification des ressources

Cet achievement est une petite amélioration de jeu proposée par plusieurs élèves. Actuellement, lors de l'ouverture d'une tuile, il est possible que la fonction tile_draft ne propose au joueur que des tuiles pour lesquelles il ne peut pas se payer les coûts d'ouverture. On se propose donc d'ajouter la fonction suivante au fichier tile.h :
/** The same function as `tile_draft`, but takes a `resources`
    parameter, and ensures that the opening cost for the each tiles
    stored in the `results` array does not exceed `resources`. */
unsigned int tile_draft_with_resources(enum dir_t d, struct stash_t resources,
                                       struct tile_t** results);
Implémenter une fonction permettant ce raffinement dans le fichier tile.c. A partir de cet achievement, il doit toujours être possible au joueur de déterminer s'il pourra ouvrir une tuile ou pas pendant son tour (quitte à faire le draft avant de lui laisser le choix et vérifier s'il y a bien une tuile dans le résultat). S'il ne peut pas ouvrir de tuile, il doit alors obligatoirement se déplacer.

 Achievement 2 : Objectifs à atteindre

A partir de cet achievement, on considère que NUM_RESOURCES >= 4. Les ressources d'arrivée sont définies comme les trois ressources [ NUM_RESOURCES-2, NUM_RESOURCES-1, NUM_RESOURCES ]. Les coûts d'ouverture de la tuile d'arrivée sont tous égaux à une poche contenant exactement un exemplaire de chaque ressource d'arrivée. Avant le démarrage de la partie, le manoir sélectionne aléatoirement trois positions différentes de celle de la tuile de départ et de la tuile d'arrivée. Ces positions sont appelées les positions-objectifs. A chacune de ces positions-objectif est associée une ressource d'arrivée différente. Les positions-objectifs sont connues du joueur. L'idée de cet achievement est de rendre nécessaire pour le joueur d'ouvrir une tuile sur chaque position-objectif pour gagner la partie.
Cet achievement demande donc de faire les modifications suivantes :
  • Lorsque le joueur ouvre pour la première fois une tuile sur une positions-objectif, il gagne un exemplaire de la ressource d'arrivée associée.
  • Au début de la partie, le joueur calcule sa distance de Manhattan à chaque position-objectif, et les ordonne selon cette distance.
  • A chaque tour de jeu, il cherche à jouer de manière à se rapprocher de la première position-objectif qu'il n'a pas encore visitée. Cela implique de :
    1. calculer l'ensemble des positions des tuiles que l'on peut ouvrir,
    2. de sélectionner la plus proche du point de vue de la distance de Manhattan de la position-objectif,
    3. de trouver une tuile déjà ouverte adjacente,
    4. de s'y déplacer éventuellement si on ne s'y trouve pas déjà, puis d'ouvrir la tuile qui rapproche de la position-objectif.

 Achievement 3 : Equipements fonctionnels

Cet achievement se propose d'implémenter des équipements pour le joueur permettant de modifier l'état du jeu de manière variée. A chaque ouverture de salle, le joueur a une chance sur BOARD_WIDTH * BOARD_HEIGHT de trouver un équipement au hasard qu'il ne possède pas déjà. Ensuite, l'équipement modifie les règles du jeu de la manière suivante :
  • la pelle : à chaque ouverture de pièce, le joueur gagne une ressource aléatoire (entre 1 et NUM_RESOURCES) avec une probabilité BOARD_WIDTH * BOARD_HEIGHT;
  • le porte-monnaie : chaque fois que du GOLD est gagné (par exemple avec la pelle), et quelle que soit la quantité, le joueur gagne un GOLD supplémentaire,
  • les chaussures de course : chaque fois qu'un déplacement est réalisé, il y a une chance sur trois que les chaussures remboursent un STEP au joueur,
  • les chaupelles de monnaie : à chaque ouverture de pièce, à chaque gain de ressource et à chaque déplacement, le joueur gagne un STEP.
L'idée dans cet achievement est que tous ces équipements devraient être gérés comme un seul type de données. Les effets des équipements doivent être attachés aux équipements sous la forme d'un pointeur de fonction. Aux instants dédiés (ouverture d'une pièce, dépense de ressources, gain de ressources), le joueur regarde les pièces d'équipement qu'il a trouvées et qui peuvent s'appliquer dans cette situation, et applique leurs fonctions à l'état du jeu. Pour se faire une idée, les pointeurs de fonctions peuvent correspondre aux types suivants :
void (*on_tile_open)(struct game_state_t*, const struct tile_t*);       // the game state and the tile that was just opened
void (*on_ressource_gain)(struct game_state_t*, const struct stash_t*); // the game state and the stash that was just gained
void (*on_move)(struct game_state_t*, const struct stash_t*);           // the game state and the cost of the last move

 Achievement 4 : Equilibrage des ressources

Cet achievement propose d'équilibrer les coûts en ressources des différentes tuiles du jeu. Pour cela, on propose de jouer un nombre NUM_RANDOM_GAMES de parties au hasard (fixé à 1000 par défaut), et de faire des analyses statistiques sur le nombre de fois qu'une entrée d'une tuile est utilisée pour être ouverte, ainsi que le nombre de fois que le joueur la traverse. L'un des attraits de cet achievement est de rendre le code capable de jouer plusieurs parties de manière indépendante en une seule exécution.
  • Générer des coûts d'ouverture aléatoires pour les tuiles;
  • Écrire le code nécessaire pour calculer les statistiques précédentes (en supposant que le joueur a des ressources infinies);
  • Estimer (empiriquement) le coût moyen d'une partie;
  • Adapter les ressources de départ du joueur de manière à assurer que le joueur gagne 80% de ses parties.
On pourra supposer que les variables aléatoires considérées suivent des lois exponentielles indépendantes, et modéliser le processus de manière probabiliste. L'achievement ne demande pas de réaliser un calcul exact, mais de mettre en place une démarche scientifique claire.

 Achievement 5

 Écriture du code

Le code écrit est censé respecter les standards de codage suivant :
  • Le code devra être organisé en répertoires comme suit :
    Makefile
    src/
    test/
    Sans surprise, le répertoire src correspond au code source, tandis que le répertoire test doit contenir le code nécessaire aux tests. Les différents achievements devront être marqués dans le dépôt à l'aide d'étiquettes (ou tags) git. Ajouter une étiquette se fait avec les commandes suivantes :
    git tag achiev0    # Create tag 'achiev0'
    git push --tags    # Push tags on server
    git tag            # List available tags
    La version de base est considérée comme l'achievement 0, les autres achievements sont numérotés à partir de 1.
    Les tags marquent les achievements réalisés, et suivent une syntaxe bien particulière, à savoir achiev[0-9\.]+. Noter qu'une fois un tag mis sur le dépôt, il n'est plus possible de le modifier. Seul le code avec le dernier tag sera considéré pour le rendu final. S'il n'existe pas de tel tag, il sera considéré qu'il n'y a pas de code rendu. Un projet sans code rendu ne valide pas les projets. Afin de simplifier la vie, la syntaxe des tags autorise les tags suivants correspondant tous à l'achievement 0 : achiev0, achiev0.1 ou encore achiev0.1.2.3.4.
  • L'exécutable du projet doit se nommer project, doit pouvoir exécuter une partie du jeu décrit dans ce projet. En plus de cela, il doit pouvoir prendre comme paramètres optionnels :
    • un paramètre optionnel -s pour initialiser la graine du générateur aléatoire.
    • un paramètre optionnel -t qui sera passé à la fonction init_tiles.
    • un paramètre optionnel -n qui fixe le nombre maximum de tours de jeu possible.
    L'analyse de la ligne de commande se fera au moyen de la bibliothèque getopt (voir getopt(3) et getopt_long(3)). La page de manuel de getopt donne un exemple de code d'utilisation. Les exemples suivants donnent des idées sur les possibilités d'utilisation :
    ./project                   # No parameters, manor BOARD_WIDTH*BOARD_HEIGHT
                                # random initialization of the RNG, init_tiles is called with parameter equal to 0
    ./project -s 156 -t 2 -n 10 # One optional parameter to pass to init_tiles (here 2)
                                # an optional parameter limit the number of turns (here 10)
                                # and an optional parameter to initialize the RNG (here 156)
    Il est tout à fait envisageable d'ajouter d'autres types de paramètres à cet exécutable.
  • Le dépôt doit contenir un fichier Makefile permettant d'exécuter les tests. Pour cela, il devra comporter au moins les règles ci-après :
    • Une règle principale permettant de compiler l'ensemble du code et des tests, dont en particulier un exécutable appelé project décrit dans le paragraphe précédent. La règle de compilation doit permettre de paramétrer les tailles des plateaux de jeu en passant trois variables d'environnement BOARD_WIDTH, BOARD_HEIGHT et NUM_RESOURCES. Ainsi, la ligne suivante doit produire un exécutable jouant dans un manoir de taille 5x6, avec seulement 3 ressources différentes :
      make BOARD_WIDTH=5 BOARD_HEIGHT=6 NUM_RESOURCES=3
      Le fichier Makefile fourni en exemple permet déjà de réaliser ce paramétrage. Il conviendra à chacun de comprendre comment il fonctionne ou de poser la question à un de ses encadrants.
    • Une règle test lançant l'ensemble des tests pour le dernier achievement réalisé. Il est tout à fait envisageable d'avoir plusieurs exécutables de tests différents, mais ils devront tous être lancés par la commande make test.
Un code qui ne compile pas est un code sans intérêt, et un code qui n'intéresse pas le responsable des projets est un code qui ne valide pas les projets.

 Contact

Pour toute information complémentaire, contacter : David RENAULT disponible aux séances d'encadrement le mardi et le vendredi.

1.L'anglais est joueur ici, il faudra faire attention au nombre de 's' selon la langue utilisée …
2.L'influence du Sud-Ouest se fait clairement ressentir sur ce sujet.