Cartouche

Champ Valeur
Auteur·e Élise
Édition 2023-09-15
Durée une journée
Taille des équipes 1 personne
Rendu via git, dépôt 2023_cpp_c2, droits en lecture à delivery_collector

Barème

Critère Points
AsciiMap construction avec param. 3
Champs privés 1
AsciiMap comportement 8
AsciiMapClip construction avec ref. 3
AsciiMapClip comportement 5
Gestion d’erreur 3
Total des critères 23
Note maximale 20
Fautes de norme -0,5 par ligne

Règlement

La réalisation de cet exercice est assujettie aux règles en vigueur dans l’école en matière de triche et de normalisation. Tricher vous expose à de graves sanctions.

Vous devez être seul·e auteur·e de votre rendu mais vous êtes autorisés et encouragés à communiquer dans le cadre de ce sujet.

Dépôt de référence et norme

Annexe 1 • Norme C++

Dépôt de référence avec règles clang format.

Introduction

Votre objectif aujourd’hui c’est de préparer des classes pour faciliter l’implémentation d’un jeu textuel.

Ce que vous allez implémenter c’est une classe qui permet de manipuler une carte de jeu dont chacune des cases contient un caractère ASCII. Les problématiques soulevées sont similaires à celle de travailler avec un tableau de pixel (sur une dimension) tout en permettant de placer un caractère à l’aide de coordonnées en 2 dimensions. Enfin, ça, c’est à vous de voir, car vous êtes libres de votre implémentation dès lors qu’elle répond aux exigences fixées par ce sujet.

Vous allez aussi devoir implémenter un clip de votre carte. C’est à dire une deuxième classe qui se construit avec la première, mais qui permet de regarder et de modifier une sous-section précise de la map. Si ça n’est pas tout de suite clair pensez std::string_view et faites bien attentions aux exemples qui vous sont donnés.

Tâches

AsciiMap

Fichiers à rendre : AsciiMap.cpp, AsciiMap.hpp, AsciiMap.main.cpp

Consigne

Vous devez implémenter une classe AsciiMap qui doit répondre aux exigences suivantes :

  • construction avec deux nombres en paramètre, la largeur et la hauteur de la carte
  • après la construction votre carte doit être prête à l’usage
  • fonction membre set_cell avec trois paramètres :
    • position x
    • position y
    • caractère à placer dans la case
  • fonction membre get_cell qui renvoie la valeur d’une case, prend en paramètre les coordonnées x et y de la case
  • fonction membre to_stream qui prend en paramètre un flux en sortie, et qui y affiche le contenu de la carte
  • fonction width qui permet d’obtenir la largeur de la map
  • fonction height qui permet d’obtenir la hauteur de la map

Rendez aussi un fichier AsciiMap.main.cpp qui contient un main qui teste votre classe et démontre la façon dont on peut s’en servir.

Exemple

Code d’exemple :

#include <iostream>
#include "AsciiMap.hpp"

void mk_line(AsciiMap &map, unsigned int y)
{
    auto i{0U};

    while (i < map.width()) {
        if (map.get_cell(i, y) == '|') {
            map.set_cell(i, y, '+');
        } else {
            map.set_cell(i, y, '-');
        }
        i += 1;
    }
}

void mk_col(AsciiMap &map, unsigned int x)
{
    auto i{0U};

    while (i < map.height()) {
        if (map.get_cell(x, i) == '-') {
            map.set_cell(x, i, '+');
        } else {
            map.set_cell(x, i, '|');
        }
        i += 1;
    }
}

int main(void)
{
    AsciiMap map{11, 11};

    mk_line(map, 3);
    mk_line(map, 7);
    mk_col(map, 3);
    mk_col(map, 7);
    map.to_stream(std::cout);
}

Sortie attendue :

   |   |
   |   |
   |   |
---+---+---
   |   |
   |   |
   |   |
---+---+---
   |   |
   |   |
   |   |

AsciiMapClip

Fichiers que vous pouvez modifier : AsciiMap.cpp, AsciiMap.hpp, AsciiMap.main.cpp

Nouveaux fichiers à rendre : AsciiMapClip.cpp, AsciiMapClip.hpp, AsciiMapClip.main.cpp

Consignes

Il s’agit d’une classe dont le rôle et de permettre l’observation et la modification d’une AsciiMap mais en partant d’une origine différente de (0,0)(0, 0).

Cela permet de faciliter le dessin d’un même motif à plusieurs endroit sur une même AsciiMap sans que la fonction chargée du dessin n’ai besoin de savoir où l’on souhaite dessiner. On évite aussi de se répéter dans toutes les fonctions de dessins avec le code nécessaire à un changement d’origine.

Par exemple : si on choisi pour origine (5,3)(5, 3) il faudra ajouter 55 aux xx et 3 aux yy de tous les appels à get_cell et set_cell.

Votre Clip doit répondre aux exigences suivantes :

  • construction avec une référence sur une AsciiMap et stockage de cette référence dans les champs de la classe
  • fonction membre set_origin, paramètres x et y à utiliser en origine à la place de (0,0)(0, 0)
  • fonction membre set_size
    • paramètres x et y
    • donnent la valeur max que x et y peuvent avoir dans les appels à set_cell et get_cell
  • fonction membre set_cell, paramètres x, y et caractère
    • prend en compte l’origine et la taille définies par set_origin et set_size
    • assigne à l’emplacement (x,y)+origin(x, y) + origin le caractère donné
  • fonction membre get_cell
    • prend en compte l’origine et la taille définies par set_origin et set_size
    • renvoie le caractère à l’emplacement (x,y)+origin(x, y) + origin

Exemple

void draw_o(AsciiMapClip &clip)
{
    clip.set_cell(1,0,'-');
    clip.set_cell(0,1,'|');
    clip.set_cell(2,1,'|');
    clip.set_cell(1,2,'-');
}

void draw_x(AsciiMapClip &clip)
{
    clip.set_cell(0, 0, '\\');
    clip.set_cell(2, 2, '\\');
    clip.set_cell(1, 1, 'X');
    clip.set_cell(2, 0, '/');
    clip.set_cell(0, 2, '/');
}

int main(void)
{
    AsciiMap map{11, 11};
    AsciiMapClip TopLeft(map), TopRight(map), TopCenter(map);

    TopCenter.set_origin(4, 0);
    TopCenter.set_size(3, 3);
    TopRight.set_origin(8, 0);
    TopRight.set_size(3, 3);

    mk_line(map, 3);
    mk_line(map, 7);
    mk_col(map, 3);
    mk_col(map, 7);
    draw_o(TopCenter);
    draw_x(TopRight);
    map.to_stream(std::cout);
}

Sortie attendue :

   | - |\ /
   || || X
   | - |/ \
---+---+---
   |   |
   |   |
   |   |
---+---+---
   |   |
   |   |
   |   |

Gestion d’erreur

Parmi les fonctions membres que vous avez programmé sur les classes précédentes, plusieurs d’entre elles peuvent échouer à leur tâche.

Si vous y avez fait attention, vous avez peut-être déjà mis des conditions pour empêcher une tentative de changer ou de lire une case dont les coordonnées vont au delà de la largeur et hauteur de votre Map ou de votre Clip.

En plus d’une protection, ce que l’on peut faire c’est ajouter des exceptions.

int main(void)
{
	AsciiMap map(5, 5);

	try {
		map.set_cell(5, 5, 'a');
		std::cout << "it shouldn't have workded\n";
	} catch (std::exception &err) {
		std::cerr << err.what() << std::endl;
	}
}

Dans AsciiMap et AsciiMapClip ajoutez des exceptions lorsque des coordonnées vous sont données en dehors.