Curious about coloring output text

I'm wondering if anyone can help me make my program a little more portable. It works on my computer (Mac OS X) and works the way I want it, but it is reliant upon my terminal settings. If I use a different terminal scheme, the text is different colors than what I intended. The way that I wrote the code, this is not a surprise, but I'd like it to have the same colors no matter what.

Here's the part where I define the colors I use. I just put them in a string before I add the text I want to be that color.
1
2
3
const string WHITE = "\033[37m";
const string RED = "\033[35m";
const string CYAN = "\033[34m";


I'll also include the entire program if you'd like to play around with it. It quizzes the user on the placement of elements in the periodic table. You need a text file with the elements listed, which you can download at http://pastebin.com/Qi5EMAUS then update filename on line 11. I'm relatively new at programming, so any tips would be appreciated!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <stdexcept>
using namespace std;

const string filename = "elements.txt";

//the following are UBUNTU/LINUX ONLY terminal color codes.
const string WHITE = "\033[37m";
const string RED = "\033[35m";
const string CYAN = "\033[34m";

class Elements{
public:
    vector<string> symbols;
    vector<string> names;
    void genElements(Elements &elements);
};

void printTable(vector<string> correct);
void pause();

int main()
{
    int num, i, j, right = 0;
    double grade, ans;
    vector<string> correct;
    string sym, elm, temp;
    vector<int> skipped;
    vector<int> numsUsed;
    string answer;
    bool done = false;
    
    Elements elements;
    elements.genElements(elements);
    
    correct.resize(118);
    numsUsed.resize(118);
    for (i = 1; i <= 118; i++){
        temp = to_string(i);
        correct[i-1] = WHITE + temp + WHITE;
        numsUsed[i-1] = i;
    }

    srand(time(0));
    for (i = 0; i < 118; i++){
        /* randomizes element list */
        num = (rand() % 118);
        j = numsUsed[i];
        numsUsed[i] = numsUsed[num];
        numsUsed[num] = j;
    }

    /* quiz user */
    //first time through
    for (i = 0; i < numsUsed.size(); i++){
        num = numsUsed[i];
        cout << string(50, '\n');
        printTable(correct);
        sym = elements.symbols[num - 1];
        elm = elements.names[num - 1];
        cout << "enter the atomic number of " << elm << " (" << sym << ")\n";
        cout << "(enter 0 to skip)\n";
        ans = -1;
        do{
            cin >> answer;
            try {
                ans = stod(answer);
            } catch (const invalid_argument& ai) { }
            if (ans < 0 || ans > 118){
                cerr << "error: must be a number between 0 and 118" << endl;
            }
        } while (ans < 0 || ans > 118);
        if (ans == 0){
            skipped.push_back(num);
        }else if (ans == num){
            right++;
            correct[num - 1] = CYAN + sym + WHITE;
        }else{
            cout << "incorrect, " << elm << " has the atomic number " << num << endl;
            correct[num - 1] = RED + sym + WHITE;
            pause();
        }
       //deal with skipped elements
       if (i == numsUsed.size() - 1){
          while (!skipped.empty()){
             numsUsed.clear();
             numsUsed = skipped;
             for (i = 0; i < numsUsed.size(); i++){
                /* randomizes element list */
                num = (rand() % numsUsed.size());
                j = numsUsed[i];
                numsUsed[i] = numsUsed[num];
                numsUsed[num] = j;
             }
             skipped.clear();
          }
          i = 0; //reset counter
       }
    }
    cout << string(50, '\n');
    printTable(correct);
    /* output grade */
    grade = (right/118.0)*100;
    printf("You got %.2f", grade);
    cout << "% correct!\n";
    
    return 0;
}


void Elements::genElements(Elements &elements){
    int num;
    ifstream text;
    string sym, elm;
    
    text.open(filename.c_str());
    if (text.fail()){ cerr << "failed to open file" << endl; exit(1);}

    elements.symbols.resize(118);
    elements.names.resize(118);
    while (text >> sym >> elm >> num){
        elements.symbols[num-1] = sym;
        elements.names[num-1] = elm;
    }
    text.close();
}

void printTable(vector<string> correct){//sorry for the mess
    int i;
    string row, row7, row8;
    string row1space;
    string row2space;
    string row4space;
    string row8space;
    
    row = " --- ---     --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---";
    row7 = " --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---";
    row8 = "             --- --- --- --- --- --- --- --- --- --- --- --- --- ---        ";
    row1space = "                                                                   ";
    row2space = "                                           ";
    row4space = "   ";
    row8space = "         ";
    
    //row 1
    printf(" ---                                                                     ---\n");
    printf("|%13s|%s|%13s|\n", correct[0].c_str(), row1space.c_str(), correct[1].c_str());
    
    //row 2
    printf(" --- --- %s --- --- --- --- --- ---\n", row2space.c_str());
    printf("|%13s|%13s|%s", correct[2].c_str(), correct[3].c_str(), row2space.c_str());
    for (i = 4; i < 10; i++){
        printf("|%13s", correct[i].c_str());
    }
    printf("|\n");
    
    //row 3
    printf(" --- --- %s --- --- --- --- --- ---\n", row2space.c_str());
    printf("|%13s|%13s|%s", correct[10].c_str(), correct[11].c_str(), row2space.c_str());
    for (i = 12; i < 18; i++){
        printf("|%13s", correct[i].c_str());
    }
    printf("|\n");
    
    //row 4
    printf("%s\n", row.c_str());
    printf("|%13s|%13s|%s", correct[18].c_str(), correct[19].c_str(), row4space.c_str());
    for (i = 20; i < 36; i++){
        printf("|%13s", correct[i].c_str());
    }
    printf("|\n");
    
    //row 5
    printf("%s\n", row.c_str());
    printf("|%13s|%13s|%s", correct[36].c_str(), correct[37].c_str(), row4space.c_str());
    for (i = 38; i < 54; i++){
        printf("|%13s", correct[i].c_str());
    }
    printf("|\n");
    
    //row 6
    printf("%s\n", row7.c_str());
    printf("|%13s|%13s| * ", correct[54].c_str(), correct[55].c_str());
    for (i = 70; i < 86; i++){
        printf("|%13s", correct[i].c_str());
    }
    printf("|\n");
    
    //row 7
    printf("%s\n", row7.c_str());
    printf("|%13s|%13s| # ", correct[86].c_str(), correct[87].c_str());
    for (i = 102; i < 118; i++){
        printf("|%13s", correct[i].c_str());
    }
    printf("|\n%s\n", row7.c_str());
    
    //row 8
    printf("%s\n", row8.c_str());
    printf("%s * ", row8space.c_str());
    for (i = 56; i < 70; i++){
        printf("|%13s", correct[i].c_str());
    }
    printf("|\n");
    
    //row 8
    printf("%s\n", row8.c_str());
    printf("%s # ", row8space.c_str());
    for (i = 88; i < 102; i++){
        printf("|%13s", correct[i].c_str());
    }
    printf("|\n%s\n", row8.c_str());
}

void pause(){
    cin.clear();
    cout << "press any key to continue" << endl;
    cin.ignore();
    cin.get();
}
Last edited on
The phrase "console application" is mutually exclusive with the word "portable".
If you want a portable console application it's (ironically) easier in general to not use the console. What I mean by this is you would have a better time creating your own console using a graphics api (such as sdl or sfml) so you can actually have consistent portable control over what's displayed and how.
Dwarf Fortress does this for example.
I am interested though how colors and setting cursor position and passwords etc. are handled in SSH...
Perhaps using the curses (or ncurses?) library
Thanks guys. I'll look into that graphics api you talked about, Lachlan. Seems like that's exactly what I need.
Topic archived. No new replies allowed.