From the code example you provided, you seem to have understood that socket communication allows you to send and receive messages. Okay. But you insist on trying to run a function remotely (or associate a function with a TCP / IP client), and that is not so trivial . Sockets can be used to do this? Of course, but you will need to implement a "remote call" feature manually. If that is your intention, look for libraries that already do this sort of thing (RPC, Remote Procedure Call, or Remote Procedure Call), since reinventing the wheel is nonsense. Some examples can be found this SOen link .
On the other hand, games do not usually call remote procedures. They usually communicate between the server and the player (s) the game state . So your problem is actually how to represent the state of the game so that it can be transmitted via sockets.
The most common is serialize / deserialize an object that represents the state of the game , and use the bytes representing that state in the communication. Python has a lot of options for serialization, just take a look around ( link suggestion ). But in your case, as it is trivial, my suggestion is to convert the array of parts of the board into a string. Easy, fast and inspectable! (just print the result of save
, for example).
So I made an example class that represents the game board:
import numpy as np
from random import *
class GameState:
"""
Classe que representa o estado do jogo.
"""
# -------------------------------------------------
def __init__(self):
"""
Construtor. Initializa o tabuleiro 3x3 vazio.
"""
self.board = [[''] * 3 for n in range(3)]
# -------------------------------------------------
def save(self):
"""
Salva os dados do tabuleiro para uma string.
Gera uma string com as peças do tabuleiro separadas por
ponto-e-vírgula (';'), de forma que o estado do jogo possa
ser comunicado via socket.
Retorno
----------
data: str
String de texto com os dados do tabuleiro separados por
ponto-e-vírgula (';'), prontos para serem comunicados.
"""
return ';'.join([';'.join(x) for x in self.board])
# -------------------------------------------------
def restore(self, data):
"""
Restaura os dados do tabuleiro a partir de uma string.
Lê uma string com as peças do tabuleiro separadas por
ponto-e-vírgula (';'), de forma que o estado do jogo possa ser
comunicado via socket.
Parâmetros
----------
data: str
String de texto com os dados do tabuleiro separados por um
ponto-e-vírgula (';'), prontos para serem atualizados neste
objeto.
"""
self.board = np.reshape(data.split(';'), (3,3)).tolist()
# -------------------------------------------------
def print(self):
"""
Imprime o tabuleiro em um formato visual.
"""
print("+---+---+---+")
for row in self.board:
print('|{}|{}|{}|'.format(row[0].center(3, ' '), row[1].center(3, ' '), row[2].center(3, ' ')))
print("+---+---+---+")
# -------------------------------------------------
def move(self, row, col, piece):
"""
Faz uma jogada no tabuleiro, nas posições dadas.
Parâmetros
----------
row: int
Número da linha no tabuleiro, no intervalo [0,2].
col: int
Número da coluna no tabuleiro, no intervalo [0,2].
piece: str
Letra com o símbolo jogado, entre as opções 'o' e 'x'.
"""
# Valida os parâmetros de entrada
if row < 0 or row > 2:
raise RuntimeError('Número de linha inválido: {}'.format(row))
if col < 0 or col > 2:
raise RuntimeError('Número de coluna inválido: {}'.format(col))
piece = piece.lower()
if piece != 'x' and piece != 'o':
raise RuntimeError('Peça inválida: {}'.format(piece))
# Verifica se a posição jogada está vazia
if self.board[row][col] != '':
raise RuntimeError('Posição do tabuleiro já preenchida: {}x{}'.format(row, col))
# Faz a jogada
self.board[row][col] = piece
# -------------------------------------------------
def moveRandom(self, piece):
"""
Faz uma jogada aleatória no tabuleiro, em uma das posições vazias.
Parâmetros
----------
piece: str
Letra com o símbolo jogado, entre as opções 'o' e 'x'.
"""
# Cria uma lista com as posições vazias
options = []
for row in range(3):
for col in range(3):
if self.board[row][col] == '':
options.append((row, col))
# Faz uma permutação aleatória nessa lista
shuffle(options)
# Faz a jogada na primeira posição da lista
if len(options) > 0:
row = options[0][0]
col = options[0][1]
self.move(row, col, piece)
The code is documented, but the cat's leap is in the save
and restore
methods that respectively generate a string for you to send via socket and restores the tray from a string received via socket. So you can use this to "assemble" your game more or less this way:
Server:
import socket
from gamestate import GameState
# Cria o socket TCP/IP
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Faz o bind no endereco e porta
server_address = ('localhost', 5000)
sock.bind(server_address)
# Fica ouvindo por conexoes
sock.listen(1)
while True:
print('Aguardando a conexao do jogador')
connection, client_address = sock.accept()
try:
print('Jogador chegou! :)')
# Cria um tabuleiro de jogo vazio
board = GameState()
# Faz uma jogada aleatoria
board.moveRandom('o')
print('Eu joguei:')
board.print()
# Envia o tabuleiro para o jogador
connection.sendall(board.save().encode('utf-8'))
# Processa em loop
while True:
# Recebe a jogada do jogador
data = connection.recv(1024)
# Checa se a conexao do jogador foi terminada
if not data:
print('Jogador se foi. :(')
break
# Converte para string e restaura no tabuleiro
board.restore(data.decode('utf-8'))
print('O jogador jogou:')
board.print()
# Faz outra jogada aleatoria
board.moveRandom('o')
print('Eu joguei:')
board.print()
# Envia o tabuleiro para o jogador
connection.sendall(board.save().encode('utf-8'))
finally:
# Clean up the connection
connection.close()
Client:
import socket
import sys
from gamestate import GameState
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port where the server is listening
server_address = ('localhost', 5000)
print('Conectando ao servidor {} na porta {}'.format(server_address[0], server_address[1]))
sock.connect(server_address)
# Cria um tabuleiro de jogo vazio
board = GameState()
try:
while True:
# Recebe a jogada do servidor
data = sock.recv(1024)
board.restore(data.decode('utf-8'))
print('O servidor jogou:')
board.print()
print('Faça a sua jogada:')
print('------------------')
nok = True
while nok:
row = int(input('Digite a linha:'))
col = int(input('Digite a coluna:'))
nok = False
try:
board.move(row, col, 'x')
except:
nok = True
print('Linha ou coluna inválida. Tente novamente.')
# Envia o tabuleiro para o servidor
sock.sendall(board.save().encode('utf-8'))
finally:
print('Encerrando o cliente')
sock.close()
Test session result:
No servidor:
-----------------------------
Aguardando a conexao do jogador
Jogador chegou! :)
Eu joguei:
+---+---+---+
| o | | |
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
O jogador jogou:
+---+---+---+
| o | | |
+---+---+---+
| | | x |
+---+---+---+
| | | |
+---+---+---+
Eu joguei:
+---+---+---+
| o | o | |
+---+---+---+
| | | x |
+---+---+---+
| | | |
+---+---+---+
No cliente:
------------------
Conectando ao servidor localhost na porta 5000
O servidor jogou:
+---+---+---+
| o | | |
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
Faça a sua jogada:
------------------
Digite a linha:1
Digite a coluna:2
O servidor jogou:
+---+---+---+
| o | o | |
+---+---+---+
| | | x |
+---+---+---+
| | | |
+---+---+---+
Faça a sua jogada:
------------------
Digite a linha: