RPS Twisted Server
v 3 - Dec 8
#!/usr/bin/env python
"""
PROGRAM: Rock Paper Scissors... Twisted. - Server version 3.
FUNCTION: Receives client connections on port 64800. Client
submits a valid move (see Protocol Messages below), and once
program receives two moves, returns reslts.
ACCEPTED PROTOCOL MESSAGES:
Server to Client:
"CONNECTED" - Inital connection made; awaiting your move.
"REPEAT" - Did not receive valid message.
"WIN" - Valid results.
"LOSE"
"DRAW"
Client to server:
"REPEAT" - Did not understand message.
"ROCK" - Valid moves.
"PAPER"
"SCISSORS"
"""
port = 64800
from twisted.internet import protocol, reactor
from twisted.protocols import basic
CR = "\x0D"
LF = "\x0A"
EOL = CR + LF
machine = {
"REPEAT" : (lambda self: self.sendMessage(self.lastSentMessage)),
"ROCK" : (lambda self: self.doMove("ROCK")),
"PAPER" : (lambda self: self.doMove("PAPER")),
"SCISSORS": (lambda self: self.doMove("SCISSORS")),
}
class rpsProtocol(basic.LineReceiver):
def __init__(self):
self.lastSentMessage = ""
def sendMessage(self, message):
self.lastSentMessage = message
self.transport.write(message + EOL)
def connectionMade(self):
self.ipAddress = self.transport.getPeer()
print "Connection established with %s" % self.ipAddress
self.sendMessage("CONNECTED")
def connectionLost(self, reason):
print "Connection lost from %s" % self.ipAddress
def lineReceived(self, line):
"""Do the right thing when a line is received from the client."""
if machine.has_key(line):
machine[line](self)
else:
self.sendMessage("REPEAT")
def doMove(self, move):
"""Either adds player and move to self.factory.playerWhoMoved
or sends user' move and other player & their move to judgeMoves."""
if self.factory.playerWhoMoved:
player2 = self.factory.playerWhoMoved.pop()
self.judgeMoves(move, player2)
else:
self.factory.playerWhoMoved.append([self,move])
def judgeMoves(self, player1move, player2):
"""This function judges possible results, putting results into a list of two integers,
with player1 as [0] and player2 [1], and sends results to both players.
Note: Player 2 gets passed as a list: [0] is player's protocol, [1] his-or-her move."""
possibleResults = {
"ROCK/PAPER" : [0,1],
"PAPER/SCISSORS" : [0,1],
"SCISSORS/ROCK" : [0,1],
"ROCK/ROCK" : [0,0],
"SCISSORS/SCISSORS" : [0,0],
"PAPER/PAPER" : [0,0],
"PAPER/ROCK" : [1,0],
"SCISSORS/PAPER" : [1,0],
"ROCK/SCISSORS" : [1,0]
}
moves = player1move + '/' + player2[1]
results = possibleResults[moves]
print "Player 1: %s, Player 2: %s." % (player1move, player2[1]),
# A '1' is a win, '0' is a loss or draw.
if results[0]:
player2[0].sendMessage("LOSE")
self.sendMessage("WIN")
print "Player 1 wins."
elif results[1]:
player2[0].sendMessage("WIN")
self.sendMessage("LOSE")
print "Player 2 wins."
else:
player2[0].sendMessage("DRAW")
self.sendMessage("DRAW")
print "Draw."
class rpsFactory(protocol.ServerFactory):
protocol = rpsProtocol
def __init__(self):
self.playerWhoMoved = []
print "-- starting rps server --"
reactor.listenTCP(port, rpsFactory())
reactor.run()
v 2 - Dec 1 in Jim's office
#!/usr/bin/env python
"""
Dec 1 in Jim's office,
continuing work on RPC server.
*** This is incomplete ***
version 2
"""
port = 64800
from twisted.internet import protocol, reactor
from twisted.protocols import basic
CR = "\x0D"
LF = "\x0A"
EOL = CR + LF
machine = {
"REPEAT" : (lambda self: self.sendMessage(self.lastSentMessage)),
"ROCK" : (lambda self: self.doMove("ROCK")),
"PAPER" : (lambda self: self.doMove("PAPER")),
"SCISSORS": (lambda self: self.doMove("SCISSORS")),
}
class rpsProtocol(basic.LineReceiver):
def __init__(self):
self.lastSentMessage = ""
def sendMessage(self, message):
self.lastSentMessage = message
self.transport.write(message + EOL)
def connectionMade(self):
self.ipAddress = self.transport.getPeer()
print "Connection established with %s" % self.ipAddress
self.factory.registerClient(self)
self.sendMessage("CONNECTED")
def connectionLost(self, reason):
self.factory.deleteClient(self)
print "Connection lost from %s" % self.ipAddress
def lineReceived(self, line):
"""Do the right thing when a line is received from the client."""
if machine.has_key(line):
machine[line](self)
else:
self.sendMessage("REPEAT")
# print "server got line '%s' from %s" % (line, self.ipAddress)
# self.transport.write("You said '%s'.\r\n" % (line))
class rpsFactory(protocol.ServerFactory):
protocol = rpsProtocol
def __init__(self):
self.playersWaiting = [] # [client1, client2, ...]
self.playerWhoMoved = ''
self.playersMove = ''
def registerPlayer(self, player):
if self.playersWaiting:
self.pairsPlaying.append((self.playersWaiting.pop(), player))
else:
self.waitingPlayers.append(client)
def moveMade(self, player, move):
# if someone else has made a move, pair 'em up,
opponent = playing
player.sendMessage("WIN")
def deletePlayer(self):
self.clientList.remove(self)
print "-- starting rps server --"
reactor.listenTCP(port, rpsFactory())
reactor.run()
v. 1.1 - Dec 1
- The """ commented out area in my factory was my earlier attempt at recording the address of each client as the connection was made. When run, this method would display the following upon each client's connection:
{0: <twisted.internet.address._ServerFactoryIPv4Address object at 0xb6e3f0>}
{0: <twisted.internet.address._ServerFactoryIPv4Address object at 0xb6e690>}
- So it would tell me where in the hardware memory I could find what I was looking for.
- Instead I added the code "print self.transport.getPeer()" in the Protocol Process section (launched for each client's connection), which prints the Socket Type, Address, and Port #. Much easier.
- For the final class I will hopefully get this working, recording all client connections, playing their games, etc.
#!/usr/bin/env python
"""
In tutorial with Jim M on Nov 3, exploring examples at
http://twistedmatrix.com/projects/core/documentation/howto/tutorial/intro.html
"""
port = 64800
from twisted.internet import protocol, reactor
from twisted.protocols import basic
class rpsProtocol(basic.LineReceiver):
def connectionMade(self):
print "Connection established."
print self.transport.getPeer()
self.transport.write("CONNECTED")
def connectionLost(self, reason):
print "Connection lost."
def lineReceived(self, line):
"""Do something when a line is received from the client."""
print "server got line '%s'" % (line)
self.transport.write("You said '%s'.\r\n" % (line))
class rpsFactory(protocol.ServerFactory):
protocol = rpsProtocol
def __init__(self):
self.numClients = 0
self.clientList = {}
"""
def buildProtocol(self, addr):
self.clientList[self.numClients] = addr
print self.clientList
"""
print "-- starting rps server --"
reactor.listenTCP(port, rpsFactory())
reactor.run()
v. 1 - Nov 10
Not quite an update on your code, trying to figure out how
twisted processes work and then
twisted deferreds. Then I can begin adapting my
RPS Server Finite State Machine into the twisted server framework.
#!/usr/bin/env python
"""
In tutorial with Jim M on Nov 3, exploring examples at
http://twistedmatrix.com/projects/core/documentation/howto/tutorial/intro.html
"""
port = 64800
from twisted.internet import protocol, reactor
from twisted.protocols import basic
class rpsProtocol(basic.LineReceiver):
def connectionMade(self):
print "Connection established."
def connectionLost(self, reason):
print "Connection lost."
def lineReceived(self, line):
"""Do something when a line is received from the client."""
print "server got line '%s'" % (line)
self.transport.write("You said '%s'.\r\n" % (line))
class rpsFactory(protocol.ServerFactory):
protocol = rpsProtocol
print "-- starting rps server --"
reactor.listenTCP(port, rpsFactory())
reactor.run()