I'm trying to make a 2-player Chess game in C that would work simply in terminal. I had a lot of problems with fonts, so I just found a good looking (most importantly - monospaced) font and just added Chess symbols to LucidaConsole font using FontForge.
I changed symbols from 192 to 217 that I knew for sure I wouldn't need in the game:

I've made an array of strings:
char board[64][4] = {
"È","Ö","É","Ó","Æ","Õ","Ê","Ô",
"×","Ë","×","Ë","×","Ë","×","Ë",
"Ø","Ù","Ø","Ù","Ø","Ù","Ø","Ù",
"Ù","Ø","Ù","Ø","Ù","Ø","Ù","Ø",
"Ø","Ù","Ø","Ù","Ø","Ù","Ø","Ù",
"Ù","Ø","Ù","Ø","Ù","Ø","Ù","Ø",
"Å","Ñ","Å","Ñ","Å","Ñ","Å","Ñ",
"Î","Ä","Ï","Á","Ì","Ã","Ð","Â"
};
for(int i = 0; i < 64; i++) {
printf("%s", board[i]);
if( (i+1) % 8 == 0 ) {
printf("\n");
}
}
Then in the terminal, I was expecting it to look like a normal Chess board, but instead this is what I've got:

Also, I can actually write them by hand using codes from Alt+0192 to Alt+0217:

I'll do the coding part somehow, but how do I make those symbols to show correctly in the terminal?
Your terminal is set up to expect KOI8-R text encoding (one byte per character), but the bytes that your application is outputting represent UTF-8 encoded text, and for the characters you are using, each character is encoded as two bytes.
Text encoding is “out-of-band” information: both sides of the communication must agree on it beforehand. If they don’t agree (as has happened here) you get nonsense as output. This is why you should avoid having to deal with text encoding wherever possible, and the way to do that is to use Unicode.
Good news: your terminal supports Unicode, so why not let it handle rendering for you? Unicode has chess symbols already defined at codepoints U+2654 to U+265F. You will need to encode the chesspiece codepoints as UTF-8, or you can just cut and paste from this into your code:
"♔","♕","♖","♗","♘","♙", // WHITE k q r b k p
"♚","♛","♜","♝","♞","♟︎" // BLACK k q r b k p
You will also need to configure your terminal to use UTF-8 encoding (Look for a setting called “Text Encoding”).
Hacking a font is a terrible idea, by the way. I means nobody but you (on your system) can use the program, and you can’t use that terminal to display text properly either.
For colours, use the ANSI colour escape codes - the answer to this question gives a good summary of how these work.
It's true that this is an encoding problem and that the solution is to use Unicode. But we don't have enough information to pinpoint exactly where the encoding mismatch—or mismatches—are.
You want to control the encoding from end-to-end.
Make sure the source file is UTF-8 encoded. In Posix-land, this is probably a given. But on Windows it's not. In your IDE or editor, there should be a way to select the encoding when saving the file.
You'll likely have the option to save it with or without "the signature". (The signature is the Unicode byte-order-mark encoded as UTF-8.) Using a signature is widely discouraged, even by the Unicode consortium, but it can be helpful in Windows. Take your pick.
Tell the compiler that your source is UTF-8 encoded. You also want to tell it that to use UTF-8 for the execution character set. In current versions of MSVC, there's a /UTF-8 command line option for this. I'm sure all the other compilers have a comparable settings.
Make sure the C run-time library's locale is the C locale. That's the default. Make sure you don't change it and that you're not using another library that might be changing it.
It's now possible to write text mode applications for Windows much like you'd do it for a Posix environment: using UTF-8 (and terminal escape sequences) through standard IO. Because there are a lot of older programs that don't work that way, Windows requires that you opt in:
Call SetConsoleOutputCP(CP_UTF8) to tell the terminal you'll be sending text in UTF-8. (I restore the original code page when the program ends.)
You may also want to set the input code page to CP_UTF8.
If you want to use terminal escape sequences (which let you control color), you opt in for "virtual terminal processing" like this:
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
GetConsoleMode(hOut, &mode);
SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With