4 stars based on
I remember one of my first weeks as an Engineer at Twilio, I tried to send Unicode chess pieces to my phone. I was disappointed to see the characters not come through to the handset. Perhaps just as bad, when sending chess pieces to Twilio from my phone, they were sent to my TwiML endpoint incorrectly encoded.
Option 160 ascii requirement for sending messages internationally is to support the characters of the languages of those countries. Learning about character encoding and SMS network protocols proved to be an extremely educational and interesting task. This turned out to option 160 ascii oversimplified in two ways: The maximum actually comes from the fact that you can encode 7-bit characters into bytes.
Certain characters in GSM This means they take 2 characters 14 bits to encode. In short, an SMS of all escape option 160 ascii can only have 80 characters, instead of Perhaps more devastating is that a message that was truncated at exactly won't fit into a single SMS if it has a single one of these characters.
But, the bad news is that very few of these encodings actually matter. It depends on the carrier network of the handset, but option 160 ascii phones especially internationally will receive messages in either GSM or UCS-2 character encoding.
This means that even though, for example, SMPP 3. There are two main differences between these encodings:.
These differences turn out not to matter in practice, because due to the lack of support for the UCS-2 encoding, in modern programming languages smartphones tend to just decode UCS-2 messages as Option 160 ascii Big Endian. This is good news, because it means in practice we can send non-BMP characters, such as Emoji characters, over SMS, despite the fact that the spec doesn't strictly allow it.
The drawback of UTF messages is that since each character is option 160 ascii or 4 bytes, we can have a maximum of 70 fit into a byte SMS message. This is even true if only one character isn't in GSM, since the encoding applies to every character in the message.
Note that if we're only sending Emoji or other non-BMP characters, then the limitation is actually This is ignoring combining characters e. Once we knew what was possible, it was clear our API had some limitations, so it was time to start correcting these issues. Most of the bugs fell into just a few categories. To avoid our mistakes, the following concepts are important to keep in kind:. If you're on MySQL 5.
The latter does not have support for non-BMP characters as it has a maximum of 3 bytes per character. In general, do not confuse "strings" and "bytes. Moves are made using the Long Algebraic Notation e.
To send a chessboard to a phone, there's basically two challenges: There's a few tricky things about displaying chessboards using only text. When I was searching for Unicode codepoints that would make good empty black and white squares, I was option 160 ascii to find characters as close to the width of the chess piece characters as possible. In general, phones do not use fixed-width fonts. Worse, since phones use different fonts, it may prove difficult or impossible to find a black and white square character that will make the board align nicely across all handsets.
In fact, in many fonts, the chess pieces themselves don't even have the same width! Of course, all this assumes the phone's font even has the characters for the chess pieces. Luckily, iPhone, Android, and Windows Phone all use fonts with chess pieces.
For other phones, we'll have to fall back to alphabetical characters. After some trial and error, I found Unicode shaded block characters and fixed-width whitespace characters that worked pretty well on my iPhone's Helevetica Neue font. Since we can't tell what kind of phone we're sending the SMS to, it's up to option 160 ascii end option 160 ascii to change their "settings" for which option 160 ascii it uses to render to board. But in general, due to all these problems, rendering a board is very much "best effort.
Since I was using whitespace characters for the white squares, I ran into a problem that if the top left square was empty the top left happens to be a white square, when you're playing as white the first character in the message was whitespace. It turned out that our API actually strips leading whitespace, option 160 ascii so it was stripping my square!
Option 160 ascii this is the most literal "corner case" in the history of software. I changed the API to only strip the "standard" types of whitespace, under the assumption that anyone who is using special whitespace characters is probably doing so on purpose.
If you recall from the character encoding background section, we're allowed bytes in an SMS message. Thus, in each message we can send 70 characters. A chessboard is 8 by 8, so 64 of our characters are used by the board itself. We need to split the ranks so we need 7 newlines to do that one after each rank except the last. We need option 160 ascii too many characters, so close!
The solution for fitting the board is to omit the final whitespace on the ranks which have an empty white space on the end. This works until each of those 4 ranks have a piece sitting option 160 ascii them. For those positions, I haven't come up with a workaround, and the board will just be sent in two messages. I knew that the requirements of ChesSMS would expose me to several features of Erlang that I hadn't gotten to play with yet, and I knew that for a service as mission critical as Chess over SMS, no other system could give me the reliability and scalability that I needed.
Well, actually despite not having great reasons to choose Erlang, it did end up being an excellent and fun choice, as I will explain without getting too detailed on the architecture. Developing a chess engine was outside of the scope of this project. Luckily, there's dozens of great open source chess engines, and two main protocols for communicating between engines and interfaces. UCI is a much simpler interface, but it puts more of the complexity on the UI side.
I option 160 ascii to implement UCI because of its stateless design and simpler command list. A Port is an executable program that your program forks and can send and receive messages to as if it was another Erlang actor. This made it extremely simple to command chess engines from Erlang. Since I option 160 ascii to give the engine a few seconds to decide on a move, I spawn 8 engines by default, it's of course configurable and add them to a common resource pool, which manages my pool of engines.
I'm currently using the Option 160 ascii chess engine, but in theory, any UCI engine should plug in and work. Implementing the chessboard state and updating the board on moves was a surprisingly good fit for Erlang. The pattern matching of Erlang in particular made parts of the code very readable that would have otherwise option 160 ascii nasty. Each chess game is running as an Erlang "process" not an operating system process inside of the Erlang VM. I use the mnesia database to store a mapping of Players to Pids process IDs.
Then, it sends the move as a message to the process since we're in Erlang, the process could be running locally or on another Erlang node without changes to the code. If the move is valid, the process option 160 ascii the changes to its local state, asks the chess engine pool for a response move, serializes the chessboard, and sends it back to the actor that returns TwiML.
Or, you can fork the source on Github.