Team. Coco
Team. Coco

Reputation: 87

C++: How to print two ASCII pictures side by side?

So i need to make a method that takes two ASCII pictures that i have created and prints them side by side, so the method call:

concatHz(Picture l, Picture r);

Where Picture is an object that stores the ASCII picture as a string in fields l.result and r.result.

If r was

+------+ 
|This  | 
|is the| 
|String| 
+------+

and l was:

This
is the
String

then the result would be:

This  +------+
is the|This  |
String|is the|
      |String|
      +------+

I have thought of ways of doing this, but they seem too complicated and there might be an easier way. I was thinking of using for loops to go through each string line and printing the first one and then the second, but then that runs into the problem of an indexing error as with the example above. Is there a simple way to do this that i am not thinking of?

Here is the method that creates the underlying ASCII picture:

Picture Picture::create(std::vector<std::string> v){
    Picture c;  //default constructor called without parenthesis
    c.picList=v;
    c.result="";
    int max1=0;
    for(int i=0;i<v.size();i++){
        if(v.at(i).length()>max1){
           max1=v.at(i).length();
        }
        c.rows++;
        c.result+=v.at(i)+"\n";
    }
    c.maxLen=max1;
    return c;
}

Upvotes: 0

Views: 621

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 597941

Don't generate the complete picture as a single std::string, you need access to the individual std::string values that make up each std::vector. That way, you can run a single loop, where each iteration outputs the next l string padded to l.maxLen characters, then outputs the next r string, then outputs a line break. End the loop when both pictures have been exhausted.

For example:

#include <string>
#include <vector>

class Picture
{
private:
    std::vector<std::string> picList;
    std::size_t maxLen;
public:
    Picture();
    Picture(const std::vector<std::string> &v);

    static Picture create(const std::vector<std::string> &v);

    std::size_t getMaxRowLen() const;
    std::size_t getRows() const;
    std::string getRow(std::size_t index) const;

    // just in case you really need it
    std::string getResult() const;
};

#include <iostream>
#include <sstream>
#include <iomanip>

Picture Picture::create(const std::vector<std::string> &v)
{
    return Picture(v);
}

Picture::Picture()
    : maxLen(0)
{
}

Picture::Picture(const std::vector<std::string> &v)
    : picList(v), maxLen(0)
{
    for(std::vector<std::string>::const_iterator iter = picList.begin(); iter != picList.end(); ++iter) {
        if (iter->length() > maxLen) {
            maxLen = iter->length();
        }
    }
}

std::size_t Picture::getMaxRowLen() const
{
    return maxLen;
}

std::size_t Picture::getRows() const
{
    return picList.size();
}

std::string Picture::getRow(std::size_t index) const
{
    std::string row;
    if (index < picList.size()) {
        row = picList[index];
    }
    std::ostringstream oss;
    oss << std::setw(maxLen) << std::left << std::setfill(' ') << row;
    return oss.str();
}

std::string Picture::getResult() const
{
    std::ostringstream oss;
    for(std::vector<std::string>::const_iterator iter = picList.begin(); iter != picList.end(); ++iter) {
        oss << std::setw(maxLen) << std::left << std::setfill(' ') << *iter << "\n";
    }
    return oss.str();
}

void concatHz(const Picture &l, const Picture &r)
{
    std::size_t rows = std::max(l.getRows(), r.getRows());
    for (std::size_t i = 0; i < rows; ++i) {
        std::cout << l.getRow(i) << r.getRow(i) << "\n";
    }
}

Upvotes: 1

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145419

You're already using a vector of strings to represent screen contents.

Just store your two ASCII art images in such a vector, then output.

Alternatively you can use cursor positioning via e.g. ncurses library.

Upvotes: 0

Related Questions