tags:

views:

1169

answers:

3

I'm developing a card playing game and would like to print out the symbol for hearts, diamonds, spades and clubs. My target platform will be Linux.

In Windows, I know how to print out these symbols. For example, to print out a heart (in ASCII) I wrote...

// in Windows, print a ASCII Heart

#include <iostream>

using std::cout;
using std::endl;

int main()
{
 char foo = '\3';
 cout << heart << endl;
 system ( "PAUSE" );
 return 0;
}

However, as I alluded to, a heart symbol won't be printed in Linux. Is there a standard library that can be used to print out a symbol for hearts, diamonds, spades and clubs in both Linux and Windows? What I have been researching so far is looking at Unicode since it is my understanding this is universal.

Thanks for any assistance provided.

+1  A: 

It's not a question of the library, it's a question of the codepage of the font you're using.

If the font used for the terminal you're running on doesn't have hearts and diamonds in it's current code page, no library will help you -- you'd have to use graphics.

For further reading, I'd try to find it maybe in Unicode Tables -- however, unicode terminals are rare... And even if you have a Unicode font, there's no guarantee that it will have the card-images in it.

Bottom line: it all depends on the font, and there's no guaranteed portable way to achieve it without suppling your own gylphs.

Kornel Kisielewicz
This is my first time hearing about 'Code page'. I am now going to read about this. Thanks a lot.
different
The code page doesn't play into it. The vast majority of code pages leave ASCII intact at the first 128 characters and only redefine characters above that. Also control characters shouldn't be assumed to be printable anyway.
Joey
Unicode *is* a portable way of achieving this – on systems supporting Unicode at least (do you know operating systems that don't?). You can specifically output a character that represents a heart. Glyph support in fonts may spoil this but that doesn't affect the fact that a heart came out. However, when using control characters like the OP does, you have absolutely no guarantee or portability.
Joey
"You can specifically output a character that represents a heart." -- sure, but what's the point if there's no gylph for it in the users font?
Kornel Kisielewicz
Code pages aren't particularly standardized, which means you'd have the same portability issues. Unicode is standard, and does have suit symbols. It may not work on any given platform, unfortunately, but it's the best place to start.
David Thornley
Kornel: Unicode is about information representation. Font support is actually a side-quest there. First and foremost it's about representing content. And there you have a character that says *“Hey, I'm a filled heart shape”* instead of a character that says *“Hey, I'm a control character to end a text, but I happen to have a glyph if you're nice to me. On some systems I might appear as a filled heart”.* Besides, the suit symbols are present in most widespread fonts nowadays. The OS should have no problem finding a suitable one.
Joey
Yes, the font thing is a red herring. No matter what I set the font to in gnome-terminal, the heart displays just fine. (Presumably, if gtk+ sees the program trying to show a glyph that the font doesn't have, it goes and finds a font that does have it.)
Jason Orendorff
@Jason -- tell that to Windows... no matter what I do, I can't set my terminal to respect unicode...
Kornel Kisielewicz
The Windows console's Unicode support is sort of a disaster, yes. But that's not really a font problem. It's mainly the unfortunate legacy of DOS. The console uses the "OEM code page", typically IBM437, a character set that lacks most Unicode characters. (Ooh-- but if you call `SetConsoleOutputCP(65001)`, and your command prompt window is using a normal font, not a raster font, you might get UTF-8 output to display, according to http://msdn.microsoft.com/en-us/library/ms686036%28VS.85%29.aspx .)
Jason Orendorff
Kornel: You did change your console font to a non-raster font, right? Because I have no issues with Unicode here, using either Lucida Console or Consolas ...
Joey
+10  A: 

If you want a portable way, then you should use the Unicode code points (which have defined glyphs associated to them):

♠ U+2660 Black Spade Suit
♡ U+2661 White Heart Suit
♢ U+2662 White Diamond Suit
♣ U+2663 Black Club Suit
♤ U+2664 White Spade Suit
♥ U+2665 Black Heart Suit
♦ U+2666 Black Diamond Suit
♧ U+2667 White Club Suit

Remember that everything below character 32 in ASCII is a control character. They have a meaning associated with them and you don't have a guarantee of getting a glyph or a behavior there (even though most control characters to have glyphs, although they were never intended to be printable). Still, it's not a safe bet.

However, using Unicode needs proper font and encoding support which may or may not be a problem on UNIX-likes.

On Windows at least some of the above code points map to the ASCII control character glyphs you're outputting if the console is set to raster fonts (and therefore not supporting Unicode or anything else than the currently set OEM code page). This only applies to the black variants since the white ones have no equivalent.

Joey
"♠ U+2660 Black Space Suit" is one of the funnier typos I've seen in a while.
Jerry Coffin
@Jerry: [urgh, I hate that @], fixed :-). I'm running low on caffeine, I think :-). And I type »space« more often than »spade«, so my fingers went ahead without consulting with my eyes whether it's correct :-)
Joey
@Johannes Rössel: How did you 'type' the symbols in your answer??
Lazer
@eskay: Character map and copy/paste. If I know the code point in advance, I simply do `[char]2662` in PowerShell and copy from there. Or I use an instance of RichEdit (Word, various other programs) and type the code point value and hit Alt+X/Alt+C.
Joey
+4  A: 

On Linux, you can almost always write UTF-8 to stdout and Unicode characters will be displayed beautifully.

#include <iostream>

const char heart[] = "\xe2\x99\xa5";

int main() {
    std::cout << heart << '\n';
    return 0;
}

You can find UTF-8 encodings of Unicode characters on sites like fileformat.info (search that page for "UTF-8 (hex)").

Another way is to use wide characters. You first need to call setlocale to set things up. Then just use wchar_t instead of char and wcout instead of cout.

#include <iostream>
#include <clocale>

const wchar_t heart[] = L"\u2665";

int main() {
    setlocale(LC_ALL, "");
    std::wcout << heart << L'\n';
    return 0;
}
Jason Orendorff
Do any of the experts have issue with this? I'm thinking I might find it useful in future.
James Morris
`setlocale` + `wcout` is definitely the most standard thing to do. The main annoyance is that apart from the standard library, libraries tend to want you to pass `char` strings, not `wchar_t`. So you have to write functions to convert back and forth, and you have to call them as appropriate. It ends up feeling kind of bureaucratic. :-\
Jason Orendorff
+1: this is a much more expanded answer than the accepted one
Kornel Kisielewicz
Oh darn, out of votes for today :/
Kornel Kisielewicz
+1 for actually telling the OP how to use Unicode properly. I don't do much C/C++ so I remembered that I was supposed to use an `L""` string literal but not much else. The first suggestion of blindly using UTF-8 almost qualifies for a downvote, though [imho]. The wide-character APIs should handle conversion for you while you'd blindly assume the locale to use UTF-8.
Joey
*"suggestion of blindly using UTF-8 almost qualifies for a downvote, though"* That's fair. In some sense almost every program that doesn't call `setlocale` and use wide characters, and `localeconv` to display numbers, is broken.
Jason Orendorff