0

I am looking for a way to output the elements of a structure I have defined in a Yahtzee program I'm trying to make.

My structure is:

struct card_cell
{
    std::string name;
    int points;
    int state;
}

I want to print it in the format:

    name1    name2    name3...
    points1  points2  points3...
    state1   state2   state3...

across the screen like so.

The different types of structures are stored in a std::vector<card_cell>, so I can do this by just iterating through the members of the vector and outputting the names, then points, then states in turn.

However, I have enough card_cells in the vector that when I print it all this way, the entries begin making new lines by themselves, and mucking up the formatting:

    name1    name2    name3...
    nameN...
    points1  points2  points3...
    pointsN...
    state1   state2   state3...
    stateN...

I want to be able to declare something like const int CELLS_PER_LINE = 6; and when my iteration prints that number of name's, it will halt, start a new line and print the next 6 points values. When it finally reaches the end of the states, it will form a new line and start printing the next set of names where it left off.

I could brute force and hard-code this, yes, but I was wondering if anyone had an idea of how to do this in a cuter way?

Thanks!

Niall
  • 30,036
  • 10
  • 99
  • 142

3 Answers3

0

First you may want to know how wide the terminal is, so that you can make sure not to overflow it. For that we can use ioctl() with TIOCGWINSZ as shown here: https://stackoverflow.com/a/8529354/4323

Then, we can use the std::ostream::tellp() to know how many characters we have written so far: http://www.cplusplus.com/reference/ostream/ostream/tellp/

Putting it all together, my plan would be to get the window width, print one column, check how wide it is (or maybe you already know), and make a good guess about whether the next column will be too wide or not. If you're near the end of the line, just defer printing of that column until after you've printed all the rows for the columns so far.

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
0

Here's something to try:

void printCells(std::vector<card_cell> const& cells)
{
   // Compute the number of screens you would need to write
   // the cells.
   int numScreens = (cells.size()+CELLS_PER_LINE-1)/CELLS_PER_LINE;

   // Iterators to iterate over all the cells.
   std::vector<card_cell>::const_iterator iter = cells.begin();
   std::vector<card_cell>::const_iterator end = cells.end();

   // Loop over the number of screens needed.
   for ( int i = 0; i != numScreens; ++i )
   {
      // While printing the cells in a screen we have to make sure that:
      // 1. We don't print more than CELLS_PER_LINE.
      // 2. We stop when we are at the end of the cells.

      int count = 0;
      std::vector<card_cell>::const_iterator iter2 = iter;

      // Iterate over the cells for the names and print the names.
      for ( ;
            iter2 != end && count != CELLS_PER_LINE;
            ++iter2, ++count )
      {
         // Figure out how much width to use for each name.
         // Hard coded to 10 here.
         std::cout << std::setw(10) << iter2->name;
      }
      std::cout << std::endl; 

      // Iterate over the cells for the points and print the points.
      for ( count = 0, iter2 = iter;
            iter2 != end && count != CELLS_PER_LINE;
            ++iter2, ++count )
      {
         // Figure out how much width to use for each point.
         // Hard coded to 10 here.
         std::cout << std::setw(10) << iter2->points;
      }
      std::cout << std::endl; 

      // Iterate over the cells for the states and print the states.
      for ( count = 0, iter2 = iter;
            iter2 != end && count != CELLS_PER_LINE;
            ++iter2, ++count )
      {
         // Figure out how much width to use for each state.
         // Hard coded to 10 here.
         std::cout << std::setw(10) << iter2->state;
      }
      std::cout << std::endl; 
      std::cout << std::endl; 

      iter = iter2;
   }
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

I assume that your screen is enough long.

  • Firstly, get the longest length of the first column and memorize it. Do the same for the next CELLS_PER_LINE - 1 elements.
  • Secondly, print the first CELLS_PER_LINE elements's name. If the length of some item is less than longest length you memorized, fill with blank. Then print points, state following the above rule.

Now you have pretty-printed the first CELLS_PER_LINE elements. Output a newline and do the same.

For example,

John Alice Tim

10.000000 9.98 8.1

good bad good

the longest length of first column is lengthof("10.000000") = 9 that you should memorize.

the second column one is lengthof("Alice") = 5.

and third column one is lengthof("good") = 4.

Then pretty-print them...

John______Alice_Time

10.000000_9.98__8.1

good______bad___good

Here `_' means blank.

Community
  • 1
  • 1
Youmu
  • 78
  • 4