I’ve been doing some of the Facebook Engineering Puzzles recently, and in a previous blog post I described how to solve the problem User Bin Crash.
The problem User Bin Crash would be considered a batch problem. Such problem requires a program that takes some input, and produces some output. All the judge does is feed your program the input and check its output.
Thrift problems are a bit different. Such a problem would be an interactive problem, where the judge program has to interact with your program.
In the facebook puzzles, Simon Says, Rush Hour, Battleship, and Dinosaur island are interactive problems. All of the rest of the problems are batch.
Interactive problems are submitted in a different way from regular problems, as well. You, the programmer, are required to make a Thrift program, and instead of sending it to run on their server, you run your program on your own computer. The program connects to the facebook servers via Thrift. A successful program will return a special code which can be used to claim credit for a problem.
Because of the nature of interactive problems, they are somewhat difficult to set up. Thrift itself is rather new and its documentation lacking. When making my first Thrift submission, I found a few difficulties. No adequate tutorial exists on this topic, so this post may be of some use to future puzzlers.
Prerequisites
Simon Says is, after all, a simple test problem to help you get set up with Thrift.
This tutorial is relevant most if you are using the Java programming language, and are using Windows with Cygwin. If you’re using a different language, or a different platform, parts of this document may not apply to you.
Cygwin is required because the thrift compiler itself does not run natively on windows. Only the base cygwin is necessary to run the thrift compiler.
Step 1: Setting up the Thrift compiler
The official Thrift package comes only with the source code, and no linux nor cygwin binaries. As building anything from source is a tricky and error-prone process, we’re not going to compile Thrift from source (even though the official documentation recommends us to do so).
I wasn’t able to compile Thrift from source, but I found someone else’s cygwin Thrift binaries. I’ll put a link to it:
To run this in Cygwin, extract thrift.exe to /cygwin/bin/
.
This Thrift binary is of version 0.20, which is not backwards compatible with 0.10. The Thrift wiki provides cygwin binaries to 0.10, which isn’t very useful for us since the code generated by 0.10 can’t be used to solve Facebook problems.
Anyways, this compiler will likely be obsolete soon, and 0.3x will likely break backwards compatability again.
The Thrift compiler compiles your thrift source into source code into a language of your choice. The outputted source code contains much of the code handling networking, protocols, etc.
To run the thrift compiler, navigate to the directory containing simonsays.thrift
(while in cygwin), and run,
thrift --gen java simonsays.thrift
You should now have a directory called gen-java
. At this point we just need the stuff in gen-java
, and we don’t need the thrift compiler anymore. We can also switch back from the cygwin shell.
Part 2: Setting up the Java libraries
To build and run a Thrift Java program, we need to link a few libraries. The first library is the Java thrift library, which I’ve named thrift.jar
.
Another dependency is SLF4J, a logging framework required by the Thrift libraries. I’m not sure why it really needs this library, but we need this to compile the code. I’ve named this library slf4j.jar
.
Here’s a download link to the two jar files:
Now we’re ready to begin coding. In a new directory, place the two jar files and the gen-java folder; create your source file in this folder as well.
Part 3: Coding the problem
The problem itself is very simple. On each round, you receive a list of colors via startTurn()
, and send the colors back one by one in order using chooseTurn()
. When you’re done, call endTurn()
(which also tells you if there’s more rounds).
In the beginning, call registerClient()
with your facebook email address; at the end, call winGame()
to receive the special password.
Here’s my implementation (simonsays.java):
import org.apache.thrift.*; import org.apache.thrift.transport.*; import org.apache.thrift.protocol.*; import java.util.*; public class simonsays{ public static void main(String[] args) throws Throwable { // Set up the thrift connection to the Facebook servers TTransport transport = new TSocket("thriftpuzzle.facebook.com", 9030); TProtocol protocol = new TBinaryProtocol(transport); SimonSays.Client client = new SimonSays.Client(protocol); transport.open(); // Register client client.registerClient("your.email@gmail.com"); boolean done = false; while(!done){ // Retrieve color list List<Color> listColors = client.startTurn(); // Some debug information System.out.println(listColors.size()); // Play back colors list for(Color color : listColors){ client.chooseColor(color); } // If we're done, endTurn() will return true. done = client.endTurn(); } String pwd = client.winGame(); System.out.println(pwd); } }
Compiling the code:
javac -cp .;./thrift.jar;./slf4j.jar;./gen-java simonsays.java
Running the code:
java -cp .;./thrift.jar;./slf4j.jar;./gen-java simonsays
If you did everything correctly, the program should output the numbers 1 to 31 and finally a line like this:
simonsays(8d96b611989c0d38b0c47703a37466c5)
Part 4: Submitting the code
Be sure to replace my email with your own email if you wish to receive credit for the problem.
From the email you provided in registerClient()
, send an email to puzzles@facebook.com
, with the subject as the line outputted by the program.
If you want, you can also attach your source code, but that’s not needed. We’re done!
Awesome, I was having a bear of a time getting the win32 code generator working, only to find out I was using 0.1 which did not work.
LikeLike
Hello I’ve got an error 😦
javac -cp .;./thrift.jar;./slf4j.jar;./gen-java simonsays.java
.\gen-java\SimonSays.java:29: cannot find symbol
symbol : class TTransport
location: class SimonSays
TTransport transport = new TSocket(“thriftpuzzle.facebook.com”, 9030);
^
.\gen-java\SimonSays.java:29: cannot find symbol
symbol : class TSocket
location: class SimonSays
TTransport transport = new TSocket(“thriftpuzzle.facebook.com”, 9030);
^
Note: .\gen-java\SimonSays.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: .\gen-java\SimonSays.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
2 errors
How do I fix it please help. Thanks.
LikeLike
I think the problem is you forgot to import org.apache.thrift.transport.
If that’s not the problem, then it’s definitely in the thrift.jar file: maybe try redownloading it or compiling it from source if that doesn’t work.
Cheers.
LikeLike
would anyone be able to put the javathrift.zip (189 kb) file online somewhere so i could download it? thanks
LikeLike
Ahhh crap, I never anticipated drop.io to go down permanently and without warning, and I don’t have backups.. :S
LikeLike
I got the simonsays_client.java file like you wrote in the root dir then i got gen-java which olds the Color.java and SimonSays.java made from the thrift file
Now when i run javac simonsays_client.java i get 4 errors
simonsays_client.java:13: package SimonSays does not exist
SimonSays.Client client = new SimonSays.Client(protocol);
^
simonsays_client.java:13: package SimonSays does not exist
SimonSays.Client client = new SimonSays.Client(protocol);
^
simonsays_client.java:22: cannot find symbol
symbol : class Color
location: class simonsays_client
List listColors = client.startTurn();
^
simonsays_client.java:26: cannot find symbol
symbol : class Color
location: class simonsays_client
for (Color color : listColors)
Any ideas why or how i can fix this?
LikeLike