Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chess symbols aren't displaying in command prompt

Tags:

c

unicode

chess

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:

symbols from 192 to 217 are changed

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:

failed attempt to display a chess board

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

chess symbols in terminal

I'll do the coding part somehow, but how do I make those symbols to show correctly in the terminal?

like image 963
VasyaDryashkaba Avatar asked Nov 22 '25 13:11

VasyaDryashkaba


2 Answers

You have a text encoding mismatch

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.

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.

... and use the Terminal colour codes

For colours, use the ANSI colour escape codes - the answer to this question gives a good summary of how these work.

like image 55
KrisW Avatar answered Nov 25 '25 02:11

KrisW


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.

  • The source file encoding might not be what the compiler thinks it is.
  • The execution character set the compiler is targeting may not be appropriate.
  • The C run-time library's locale setting may be interfering when executing the printf. The default is the "C" locale, but we don't know whether that's the current setting.
  • The C run-time implementation may be trying to convert to wide characters or it may be letting Windows do the conversion. If it is calling an ANSI API, is it specifying the correct code page or is it letting Windows infer it?
  • The code page of the terminal may or may not be correct.
  • The remapping of the glyphs may or may not be correct.
  • Font linking and/or font fallback may be interfering in the font selection?

You want to control the encoding from end-to-end.

  1. 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.

  2. 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.

  3. 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.

  4. 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:

    1. 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.)

    2. You may also want to set the input code page to CP_UTF8.

    3. 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);
      
like image 38
Adrian McCarthy Avatar answered Nov 25 '25 03:11

Adrian McCarthy