Bit pattern to console output
Would you write the whole procedure differently?


Absolutely. In it's current form, it does far too much stuff and (at least in my opinion) is not really flexible enough. Every time you try to add something (e.g. other card patterns, loading patterns from a file, change the card border, ...) the function will just get more and more bloated.

Actually, I'd implement it in a class CardPrinter. This way, you can transfer state (e.g. card patterns) between calls in a nicely, encapsulated way. Also, I'd split the functionality into multiple member functions, so it's easier to reason about them.


  (paraphrasing:) How would you handle multiple patterns?


For patterns as simple as these, I'd probably not bother to encode them in any special format. Just an array of lines is fine (unless you're programming under heavy memory constraints).

These patterns can be set statically, loaded from somewhere or even generated dynamically. Choose what fits your circumstances best! E.g. loading from a file could allow for different patterns, allowing for customization.


  Example:


struct CardPattern {
    std::vector&lt;std::string&gt; lines;
};

class CardPrinter {
    std::vector&lt;CardPattern&gt; patterns;
    std::string delimiter_left;
    std::string delimiter_right;
    std::string delimiter_top;
    std::string delimiter_bottom;
    size_t internal_width;

public:
    CardPrinter(const std::vector&lt;CardPattern&gt;&amp; pats, size_t w = 13, std::string del_left = "|", std::string del_right = "|", std::string del_top = "-", std::string del_bottom = "-")
            : patterns(pats), delimiter_left(del_left), delimiter_right(del_right), delimiter_top(del_top), delimiter_bottom(del_bottom), width(w - del_left.length() - del_right.length()) {
    }

    void print(const Carta&amp; card, std::ostream&amp; stream = std::cout) {
        stream &lt;&lt; get_card_visual(card);
    }
private:
    std::string get_card_title(const Carta&amp; card) {
        auto nome_semi = create_semi(card.seme);
        auto nome_valore = create_nome_valore(card.valore);

        return nome_valore + " " + nome_semi;
    }

    const CardPattern&amp; get_card_pattern(const Carta&amp; card) {
        // assuming pattern exists for that value
        return patterns[card.valore];
    }

    std::string format_line(const std::string&amp; line) {
        // just cut off parts that are too long
        // if too short, fill rest with spaces (could be changed, e.g. center text in that case)
        auto visible_part = line.substr(0, internal_width);
        auto filler = std::string(internal_width - visible_part.length(), ' ');

        return delimiter_left + visible_part + filler + delimiter_right + "\n";
    }

    std::string format_card_pattern(const CardPattern&amp; pattern) {
        auto formatted = std::string("");

        for(auto&amp; line : pattern.lines) {
            formatted += format_line(line);
        }

        return formatted;
    }

    std::string format_top() {
        auto top = std::string();
        while(top.length() &lt; internal_width) {
            top += delimiter_top;
        }

        return format_line(top);
    }

    std::string format_bottom() {
        auto bottom = std::string();
        while(bottom.length() &lt; internal_width) {
            bottom += delimiter_bottom;
        }

        return format_line(bottom);
    }

    std::string get_card_visual(const Carta&amp; card) {
        return format_top() + format_line(get_card_title(card)) + format_card_pattern(get_card_pattern(card)) + format_bottom();
    }
};

// Usage example
auto patterns = /* up to you, e.g. */ load_patterns();
auto printer1 = CardPrinter(patterns);
auto printer2 = CardPrinter(patterns, 15, "::", "::", "=", "=");

auto cards = /* get some cards */;
for(auto&amp; card : cards) {
    printer1.print(card);
    printer2.print(card);
}