How can I condense this printf that uses ANSI colors?

Viewed 106

I am programming a game of Tetris to be played in the terminal. Of course, it wouldn't be Tetris without fancy colors! Unfortunately, to print pretty colors, the code must look ugly. There are "ANSI escape sequences" I have used to create colors, and the title screen of my program looks like this. However, to create this beautiful screen, I want to make the code look as neat as possible.

So far I have devised two ways of condensing this code: definitions and strings. Here is the version of the code that uses definitions:

#define TEXT_ADMIN "\e[31m"
#define TEXT_ORANGE "\e[38;5;202m"
#define TEXT_BROWN "\e[38;5;130m"
#define TEXT_YELLOW "\e[93m"
#define TEXT_PUKE "\e[33m"
#define TEXT_LIME "\e[92m"
#define TEXT_GREEN "\e[32m"
#define TEXT_AQUA "\e[96m"
#define TEXT_SKY "\e[94m"
#define TEXT_MAGENTA "\e[35m"
#define COLOR_RESET "\e[0m"

#include <stdio.h>

int main()
{
    char space[]="        ";

    printf(
    "%s"TEXT_ADMIN"████████╗"TEXT_ORANGE"███████"TEXT_BROWN"╗"TEXT_YELLOW"████████"TEXT_PUKE"╗"TEXT_LIME"██████"TEXT_GREEN"╗"TEXT_AQUA" ██"TEXT_SKY"╗"TEXT_MAGENTA"███████╗"COLOR_RESET"\n"
    "%s"TEXT_ADMIN"╚══██╔══╝"TEXT_ORANGE"██"TEXT_BROWN"╔════╝"TEXT_PUKE"╚══"TEXT_YELLOW"██"TEXT_PUKE"╔══╝"TEXT_LIME"██"TEXT_GREEN"╔══"TEXT_LIME"██"TEXT_LIME"╗"TEXT_AQUA"██"TEXT_SKY"║"TEXT_MAGENTA"██╔════╝"COLOR_RESET"\n"
    "%s"TEXT_ADMIN"   ██║   "TEXT_ORANGE"█████"TEXT_BROWN"╗     "TEXT_YELLOW"██"TEXT_PUKE"║   "TEXT_LIME"██████"TEXT_GREEN"╔╝"TEXT_AQUA"██"TEXT_SKY"║"TEXT_MAGENTA"███████╗"COLOR_RESET"\n"
    "%s"TEXT_ADMIN"   ██║   "TEXT_ORANGE"██"TEXT_BROWN"╔══╝     "TEXT_YELLOW"██"TEXT_PUKE"║   "TEXT_LIME"██"TEXT_GREEN"╔══"TEXT_LIME"██"TEXT_GREEN"╗"TEXT_AQUA"██"TEXT_SKY"║"TEXT_MAGENTA"╚════██║"COLOR_RESET"\n"
    "%s"TEXT_ADMIN"   ██║   "TEXT_ORANGE"███████"TEXT_BROWN"╗   "TEXT_YELLOW"██"TEXT_PUKE"║   "TEXT_LIME"██"TEXT_GREEN"║  "TEXT_LIME"██"TEXT_GREEN"║"TEXT_AQUA"██"TEXT_SKY"║"TEXT_MAGENTA"███████║"COLOR_RESET"\n"
    "%s"TEXT_ADMIN"   ╚═╝   "TEXT_BROWN"╚══════╝   "TEXT_PUKE"╚═╝   "TEXT_GREEN"╚═╝  ╚═╝"TEXT_SKY"╚═╝"TEXT_MAGENTA"╚══════╝"COLOR_RESET"\n\n"
    "%s             PRESS ANY KEY TO BEGIN\n\n",
    space,space,space,space,space,space,space);

}//TETRIS = 6 lines, text = 1 line, 8 lines total including space.

(An ugly monstrosity requiring much horizontal scrolling)

And here is the version which uses strings:

#include <stdio.h>

int main()
{
    char admin[]="\e[31m";
    char orange[]="\e[38;5;202m";
    char brown[]="\e[38;5;130m";
    char yellow[]="\e[93m";
    char puke[]="\e[33m";
    char lime[]="\e[92m";
    char green[]="\e[32m";
    char aqua[]="\e[96m";
    char sky[]="\e[94m";
    char magenta[]="\e[35m";
    char reset[]="\e[0m";
    char space[]="        ";

    printf(
    "%s%s████████╗%s███████%s╗%s████████%s╗%s██████%s╗%s ██%s╗%s███████╗%s\n"
    "%s%s╚══██╔══╝%s██%s╔════╝%s╚══%s██%s╔══╝%s██%s╔══%s██%s╗%s██%s║%s██╔════╝%s\n"
    "%s%s   ██║   %s█████%s╗     %s██%s║   %s██████%s╔╝%s██%s║%s███████╗%s\n"
    "%s%s   ██║   %s██%s╔══╝     %s██%s║   %s██%s╔══%s██%s╗%s██%s║%s╚════██║%s\n"
    "%s%s   ██║   %s███████%s╗   %s██%s║   %s██%s║  %s██%s║%s██%s║%s███████║%s\n"
    "%s%s   ╚═╝   %s╚══════╝   %s╚═╝   %s╚═╝  ╚═╝%s╚═╝%s╚══════╝%s\n\n"
    
    "%s             PRESS ANY KEY TO BEGIN\n\n",
    space,admin,orange,brown,yellow,puke,lime,green,sky,blue,magenta,reset,
    space,admin,orange,brown,puke,yellow,puke,lime,green,lime,green,sky,blue,magenta,reset,
    space,admin,orange,brown,yellow,puke,lime,green,sky,blue,magenta,reset,
    space,admin,orange,brown,yellow,puke,lime,green,lime,green,sky,blue,magenta,reset,
    space,admin,orange,brown,yellow,puke,lime,green,lime,green,sky,blue,magenta,reset,
    space,admin,brown,puke,green,blue,magenta,reset,
    space);

}//TETRIS = 6 lines, text = 1 line, 8 lines total including space.

As you can see, the string method looks somewhat cleaner, even though it uses more lines and memory, but even this method is quite long. Have I condensed this bit of code as much as I can? Is it even worth it to condense this? Thanks for your input!

1 Answers

I ended up with:

// colors.h
#define COLOR_ADMIN   "\033[31m"
#define COLOR_ORANGE  "\033[38;5;202m"
#define COLOR_BROWN   "\033[38;5;130m"
#define COLOR_YELLOW  "\033[93m"
#define COLOR_PUKE    "\033[33m"
#define COLOR_LIME    "\033[92m"
#define COLOR_GREEN   "\033[32m"
#define COLOR_AQUA    "\033[96m"
#define COLOR_SKY     "\033[94m"
#define COLOR_MAGENTA "\033[35m"
#define COLOR_RESET   "\033[0m"

// welcometext.c
#include "colors.h"

#define PRE "        "
#define T COLOR_ADMIN
#define E COLOR_ORANGE
#define e COLOR_BROWN
#define T2 COLOR_YELLOW
#define t2 COLOR_PUKE
#define RC COLOR_GREEN
#define rc COLOR_AQUA
#define I COLOR_SKY
#define i COLOR_AQUA
#define S COLOR_MAGENTA
#define POST COLOR_RESET"\n"

const char welcomestring[] = 
    PRE T "████████╗"   E "███████"e "╗"  T2"███"  "█████"t2"╗"   RC"██████"rc"╗ "          I"██"i"╗"  S"███████╗" POST
    PRE T "╚══██╔══╝"   E "██"e "╔════╝"  t2"╚══"T2"██"t2"╔══╝"   RC"██"rc"╔══"RC"██"rc"╗"  I"██"i"║"  S"██╔════╝" POST
    PRE T "   ██║   "   E "█████"e "╗  "    "   "T2"██"t2"║   "   RC"██████"rc"╔╝"          I"██"i"║"  S"███████╗" POST
    PRE T "   ██║   "   E "██"e "╔══╝  "    "   "T2"██"t2"║   "   RC"██"rc"╔══"RC"██"rc"╗"  I"██"i"║"  S"╚════██║" POST
    PRE T "   ██║   "   E "███████"e "╗"    "   "T2"██"t2"║   "   RC"██"rc"║  "RC"██"rc"║"  I"██"i"║"  S"███████║" POST
    PRE T "   ╚═╝   "   e "╚══════"  "╝"    "   "t2"╚═"  "╝   "   rc"╚═╝  ╚═╝"              i"╚═" "╝"  S"╚══════╝" POST
    "\n"
    PRE  "             PRESS ANY KEY TO BEGIN\n"
    "\n"
    ;

//  welcometext.h
extern const char welcomestring[];

// main.c
#include <stdio.h>
int main() {
    printf("%s\n", welcomestring);
}

Note that L"string", u"string" and U"string" have meaning in C, and R"string" is interpreted by GCC as a raw string literal, so I renamed it RC. It would be good to pick unique names for defines, to name these single letters something more unique, or add more spaces.

Related