< Back to Code Samples
################################################################################
# Aaron Hill #
# T3 Implementation #
################################################################################
# Bring in the killer socket bunnies
from socket import *
from sys import stdout
##### Configuration ####################
VERSION = "1.0"
PORT = 8000
#### Non-editable constants ###############
SOCK = socket(family=AF_INET, type=SOCK_STREAM)
OPPONENT = "none"
ALPHA_TO_NUM = {"A":"0 0", "B":"0 1", "C":"0 2", "D":"1 0", "E":"1 1", "F":"1 2",
"G":"2 0", "H":"2 1", "I":"2 2"}
NUM_TO_ALPHA = {"0 0":"A", "0 1":"B", "0 2":"C", "1 0":"D", "1 1":"E", "1 2":"F",
"2 0":"G", "2 1":"H", "2 2":"I"}
BOARD = {"A":" ", "B":" ", "C":" ", "D":" ", "E":" ", "F":" ", "G":" ", "H":" ", "I":" "}
WINS = [ ["A","B","C"], ["D","E","F"], ["G","H","I"],["A","D","G"],["B","E","H"],
["C","F","I"],["A","E","I"],["C","E","G"] ]
GAMEOVER_MSG = {"UWIN":"You win!", "IWIN":"Opponent wins :(","DRAW":"It's a draw."}
# Opponent is always displayed as "O" and local player is always displayed as "X".
MY_SYMBOL = "X"
OPP_SYMBOL = "O"
"""
A || B || C
==========
D || E || F
==========
G || H || I
"""
### universal quit function ###################
def die(reason = 'No reason given.'):
SOCK.send("Closing connection: " + reason)
SOCK.close()
print("Connection terminated:" + reason)
quit()
def isEmpty(cell):
print (cell)
print(BOARD[cell])
if BOARD[cell] == " ":
return 1
else:
return 0
def checkForWin(symbol):
victory = 1
for winCondition in WINS:
for cell in winCondition:
victory = 1
if BOARD[cell] != symbol:
victory = 0
if victory == 1:
return victory
return 0
def isGameOver():
if checkForWin(MY_SYMBOL):
return "IWIN"
if checkForWin(OPP_SYMBOL):
return "UWIN"
cellCount = 0
for cell in BOARD:
if (cell != ""):
cellCount = cellCount + 1
if cellCount == 9:
return "DRAW"
return 0
# player makes move
def place(choice, symbol):
if isEmpty(choice):
BOARD[choice] = symbol
return "OK"
else:
return "-ERR MOVE"
def printState():
cellCount = 0
for cell in "ABCDEFGHI":
output = ''
if isEmpty(cell):
output = output + cell
else:
output = output + BOARD[cell]
cellCount = cellCount + 1
if cellCount % 3 == 0 and cellCount % 9 != 0:
output = output + "\n=======\n"
elif cellCount % 9 != 0:
output = output + " || "
stdout.write(output)
stdout.flush()
##### Player Class #####################
""" This class is used to simplify the send() and recv()
functions. Rather than having to do separate cases for
either every single time, we'll just make sure the methods
are standardized. Plus it'll just make the code look cleaner """
class player():
def __init__(self,choice):
self.choice = choice
self.response = '';
if self.choice == 'c':
ip = raw_input("Enter the IP of your opponent:");
SOCK.connect((ip, PORT))
else:
hostname = gethostname()
ip = gethostbyname(hostname)
SOCK.bind((ip,PORT))
SOCK.listen(1)
self.conn, self.addr = SOCK.accept()
def send(self, msg =''):
if self.choice == 'c':
return SOCK.send(msg)
else:
return self.conn.send(msg)
def recv(self, bytes = 512):
if self.choice == 'c':
return SOCK.recv(bytes).split(' ',1)
else:
return self.conn.recv(bytes).split(' ',1)
def connect(self):
if self.choice == 'c':
self.send("HELO T3 v" + VERSION)
resp = self.recv()
if (resp[0].upper() == "+OK"):
# resp[1] contains the version string, if supplied
print("Connection established. (" + resp[1] + ")")
else:
die(resp[1])
else:
# we're listening, get our local IP
resp = self.recv()
if (resp[0].upper() == "HELO"):
#resp[1] contains version string, for comparisons
print("Connection established.")
self.send("+OK T3 v" + VERSION)
else:
self.send("-ERR Improper use of T3 protocol. Connection Closed.")
#die("Foreign host not using T3 protocol.")
def exchange_names(self, myName):
correct = 0
if (self.choice == 'c'):
while (correct == 0):
self.send("NAME " + myName)
resp = self.recv()
if (resp[0] == "+OK"): # name is correct
correct = 1
correct = 0
while (correct == 0):
resp = self.recv()
if (resp[0] == "NAME"):
opponent = resp[1]
self.send("+OK " + opponent)
correct = 1
else:
self.send("-ERR Expecting NAME but received: " +
resp[0] + " " + resp[1])
else: #listener
while (correct == 0):
resp = self.recv()
if (resp[0] == "NAME"):
opponent = resp[1]
self.send("+OK " + opponent)
correct = 1
else:
# ("Inappropriate response for NAME.")
self.send("-ERR Expecting NAME but received: " +
resp[0] + " " + resp[1])
correct = 0
while (correct == 0):
self.send("NAME " + myName)
resp = self.recv()
if (resp[0] == "+OK"): #name is correct
correct = 1
return opponent
def resetGame(self):
for cell in BOARD:
BOARD[cell] = ""
def doRound(self):
# CONNECTOR BLOCK #
if self.choice == 'c':
# Sends the move over
cell = raw_input("Pick your square:").upper()
while not isEmpty(cell):
print("Sorry, that cell is occupied, please try again.\n")
cell = raw_input("Pick your square:")
self.send("MOVE " + ALPHA_TO_NUM[cell])
resp = self.recv()
while resp[0].upper() != "ACK" and resp[1] != ALPHA_TO_NUM[cell]:
self.send("MOVE " + ALPHA_TO_NUM[cell])
resp = self.recv()
place('X',cell)
# Receives the opponent's move
resp = self.recv()
cell = NUM_TO_ALPHA[resp[1]]
while not isEmpty(cell):
self.send("-ERR Invalid Move")
resp = self.recv()
cell = NUM_TO_ALPHA[resp[1]]
self.send("ACK " + resp[1])
place('O',cell)
# LISTENER BLOCK #
else:
# Foreign move
resp = self.recv()
print(resp[0] + " " + resp[1])
cell = NUM_TO_ALPHA[resp[1]]
while not isEmpty(cell):
self.send("-ERR Invalid Move")
resp = self.recv()
cell = NUM_TO_ALPHA[resp[1]]
self.send("ACK " + resp[1])
place('X',cell)
# Local move
cell = raw_input("Pick your square:").upper()
while not isEmpty(cell):
print("Sorry, that cell is occupied, please try again.\n")
cell = raw_input("Pick your square:")
self.send("MOVE " + ALPHA_TO_NUM[cell])
resp = self.recv()
while resp[0].upper() != "ACK" and resp[1] != ALPHA_TO_NUM[cell]:
self.send("MOVE " + ALPHA_TO_NUM[cell])
resp = self.recv()
place('O',cell)
#####################################
# traffic police
#def handle(packet):
# result = {
# 'a': lambda x: x * 5,
# 'b': lambda x: x + 7,
# 'c': lambda x: x - 2
# }[packet.upper()](x)
def main ():
# determine if user is Connecting or Listening
print "TIC TAC TOE ONLINE"
choice = ""
while choice.lower() != 'l' and choice.lower() != 'c':
print "Are you [L]istening or [C]onnecting?"
choice = raw_input(">").lower()
game = player(choice)
# establish the connection or wait for the connection
game.connect()
# ... And now for something completely different.
# The connection has been established, get the name now
myName = raw_input("Enter your name:")
OPPONENT = game.exchange_names(myName)
print ("[X]: " + myName)
print ("[O]:" + OPPONENT)
# determine who goes first
gameOver = 0
while not gameOver:
printState()
game.doRound()
gameOver = isGameOver()
game.send(gameOver)
resp = game.recv()
print(GAMEOVER_MSG[resp[0]])
if __name__ == "__main__":
main()