Facebook puzzles – solutions (battleship + simon says w/ thrift)

A year ago i was looking for a job, Facebook was a valid choice. but before they would contact you, you would have to solve their puzzles. These puzzles have various difficulties, and i managed to solve quite a few, i am publishing some of my solutions here so that people can understand a little bit about thrift.

 

the first one is Simon says (the easiest) and it is only there to get you going with the networking protocol of thrift.

#!/usr/bin/env python
import sys
from random import randrange
sys.path.append('../gen-py')

import SimonSays 
from ttypes import *
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

# Make socket
transport = TSocket.TSocket('thriftpuzzle.facebook.com', 9030)  
#transport = TSocket.TSocket('localhost', 9090)

# Buffering is critical. Raw sockets are very slow
transport = TTransport.TBufferedTransport(transport)

# Wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)

# Create a client to use the protocol encoder
client = SimonSays.Client(protocol)

# Connect!
transport.open()

#Player one or two (two is run via command line) 
if len(sys.argv) <= 1:
    emailAddress = 'blah@gmail.com'
    gameID = client.registerClient(emailAddress)
    print 'gameID =', gameID
else:
    joinstatus = False
    emailAddress = 'blah2@gmail.com'    
    try:
        gameID = int(sys.argv[1])
        print gameID,'from command argument'
        joinstatus = client.join(gameID, emailAddress)
    except DuplicateEmailException:
        print "bad email"

    if joinstatus == False:
        print "Failed to join game: " + str(gameID)
        sys.exit(1)

endT = False
while endT==False:
    listC = client.startTurn()
    print 'list',listC
    for color in listC:
        print 'c',color
        res = client.chooseColor(color)
        print res
    endT = client.endTurn()
print client.winGame() 
# Close!
transport.close()

The second one is a little harder, it was the classic battleship game. if you look around the web hard enough you will find all the best tactics to win 🙂

import sys
from random import randrange
sys.path.append('../gen-py')

import Battleship2
#from battleship2 import Battleship2
from ttypes import *
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

class Player:
    attackPattern = []
    attackNextCellIndex = 0
    attackPatternLength = 0
    emailAddress = ''
    hitLocations = {}
    state = 0 #0 is search,  1 is try to sink via stack
    hitStack = []
    roundRobin = [(0,-1),(0,1),(-1,0),(1,0)]
    currentRobin = roundRobin[:]
    
    def __init__(self,client,emailAddress):
        self.client = client
        self.placePieces()
        self.emailAddress = emailAddress
        print 'finished placing', emailAddress   
        self.createPattern()
        
    def placePieces(self):
        for piece in xrange(1, 6):
            while not self.client.placePiece(piece, 
                         Coordinate(randrange(10), randrange(10)), bool(randrange(2))):
                pass  
    
    def createPattern(self): 
        for i in range(0,10):
            for j in range(0,10):
                if (j % 2 ==0):
                    if (i % 2 ==0):
                        self.attackPattern.append((i,j))
                else:
                    if (i % 2 ==1):
                        self.attackPattern.append((i,j))
        print self.attackPattern
        self.attackPatternLength = len(self.attackPattern)
    
    def changeStateHit(self):        
        self.state = 1 
        
    def changeStateSearch(self):       
        self.state = 0    
    
    def resetRobin(self):
        self.currentRobin = self.roundRobin[:] 
                    
    def addHitStack(self,result,x,y):
        if result==6:
            self.hitStack.append((x,y))
            self.changeStateHit()   
            
    def attackCell(self,x,y):
        result =  self.client.attack(Coordinate(x,y))
        if result in [1,2,3,4]:
            print 'sunk ship=>',result
        return result
        
    def attackNext(self):
        print self.attackNextCellIndex,'my turn, i am gonna kill this guy'
        x,y = self.attackPattern[self.attackNextCellIndex]
        if self.attackNextCellIndex0:
                    "get next most probable cell (for now its the first)"
                    (a,b) = self.currentRobin.pop()
                    "if cell between bounds of grid"
                    if a+x>=0 and a+x<=9 and b+y>=0 and b+y<=9:
                        result = self.attackCell(x+a,y+b)
#                        if result==6:
#                            self.resetRobin()
                        self.addHitStack(result, x+a, y+b)
                        foundNextCell = True
        "may need to put code that knows orientation of ship "
        "if there are two shots next to each other"            
                 
    def hitNext(self):
        "keep searchin"
        if self.state==0: 
            self.attackNext()                    
        else:
            "attack known areas"
            self.attackFirstInStack()
        

# Make socket
transport = TSocket.TSocket('thriftpuzzle.facebook.com', 9031)  
#transport = TSocket.TSocket('localhost', 9090)

# Buffering is critical. Raw sockets are very slow
transport = TTransport.TBufferedTransport(transport)

# Wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)

# Create a client to use the protocol encoder
client = Battleship2.Client(protocol)

# Connect!
transport.open()

    
#Player one or two (two is run via command line) 
if len(sys.argv) <= 1:
    emailAddress = 'blah@gmail.com'
    gameID = client.registerClient(emailAddress)
    print 'gameID =', gameID
else:
    joinstatus = False
    emailAddress = 'blah2@gmail.com'    
    try:
        gameID = int(sys.argv[1])
        print gameID,'from command argument'
        joinstatus = client.join(gameID, emailAddress)
    except DuplicateEmailException:
        print "bad email"

    if joinstatus == False:
        print "Failed to join game: " + str(gameID)
        sys.exit(1)
      
#create a player
player = Player(client,emailAddress)            

totalMoves = 0
while totalMoves<1000:
    totalMoves+=1
    try:
        isTurn = client.isMyTurn()
    except GameOverException:
        break
    if isTurn:    
        player.hitNext()
        print client.winGame() 
# Close!
transport.close()