fix: example client bug fixes & handle ping/pongs on server

This commit is contained in:
2025-11-18 17:24:55 -05:00
Unverified
parent 45c6000bc4
commit 8d8a3ab3a5
3 changed files with 46 additions and 27 deletions

View File

@@ -1 +1,14 @@
# Connect4 Moderator - Server # Connect4 Moderator - Server
A WebSocket server for the Connect4 Moderator.
An example client can be found in the [`example_client.py`](https://github.com/joshuafhiggins/connect4-moderator-server/blob/main/example_client.py) file.
In order to run the example you need:
- Python 3
- `pip install websockets`
- `pip install pip-system-certs`
To run the example, run `python example_client.py`.
The visual client for observing games/tournaments as well as managing games can be found at [`connect4-moderator-observer`](https://github.com/joshuafhiggins/connect4-moderator-observer).

View File

@@ -7,13 +7,7 @@ class Slot(Enum):
RED = 1 RED = 1
BLUE = 2 BLUE = 2
# Global board state (6 columns x 5 rows) def calculate_move(opponent_move, board, our_color, opponent_color):
board = [[Slot.NONE] * 5 for _ in range(6)]
our_color = None
opponent_color = None
def calculate_move(opponent_move):
if opponent_move is not None: if opponent_move is not None:
print(f"Opponent played column {opponent_move}") print(f"Opponent played column {opponent_move}")
# TODO: Implement your move calculation logic here instead # TODO: Implement your move calculation logic here instead
@@ -21,25 +15,30 @@ def calculate_move(opponent_move):
return int(input("Column: ")) return int(input("Column: "))
async def gameloop (socket): async def gameloop (socket):
while socket.open: # While game is active, continually anticipate messages board = [[Slot.NONE] * 5 for _ in range(6)]
our_color = Slot.NONE
opponent_color = Slot.NONE
while True: # While game is active, continually anticipate messages
message = (await socket.recv()).split(':') # Receive message from server message = (await socket.recv()).split(':') # Receive message from server
print(f"Received message: {message}")
match message[0]: match message[0]:
case 'CONNECT:ACK': case 'CONNECT':
await socket.send('READY') await socket.send('READY')
case 'GAMESTART': # Game has started case 'GAME':
if message[1] == '1': if message[1] == 'START':
our_color = Slot.RED if message[2] == '1':
opponent_color = Slot.BLUE our_color = Slot.RED
col = calculate_move(None) # calculate_move is some arbitrary function you have created to figure out the next move opponent_color = Slot.BLUE
await socket.send(f'PLAY:{col}') # Send your move to the sever col = calculate_move(None, board, our_color, opponent_color) # calculate_move is some arbitrary function you have created to figure out the next move
else: await socket.send(f'PLAY:{col}') # Send your move to the sever
our_color = Slot.BLUE else:
opponent_color = Slot.RED our_color = Slot.BLUE
opponent_color = Slot.RED
case 'OPPONENT': # Opponent has gone; calculate next move case 'OPPONENT': # Opponent has gone; calculate next move
col = calculate_move(message[1]) # Give your function your opponent's move col = calculate_move(message[1], board, our_color, opponent_color) # Give your function your opponent's move
await socket.send(f'PLAY:{col}') # Send your move to the sever await socket.send(f'PLAY:{col}') # Send your move to the sever
case 'WIN' | 'LOSS' | 'DRAW' | 'TERMINATED': # Game has ended case 'WIN' | 'LOSS' | 'DRAW' | 'TERMINATED': # Game has ended
@@ -47,11 +46,18 @@ async def gameloop (socket):
board = [[Slot.NONE] * 5 for _ in range(6)] board = [[Slot.NONE] * 5 for _ in range(6)]
our_color = None our_color = None
opponent_color = None opponent_color = None
await socket.send('READY')
case 'KICK':
print("You have been kicked from the game")
break
case 'ERROR': case 'ERROR':
print(f"Error: {':'.join(message[1:])}") print(f"{message[0]}: {':'.join(message[1:])}")
exit() break
await socket.close()
async def join_server(username): async def join_server(username):
async with websockets.connect(f'wss://connect4.abunchofknowitalls.com') as socket: # Establish websocket connection async with websockets.connect(f'wss://connect4.abunchofknowitalls.com') as socket: # Establish websocket connection
await socket.send(f'CONNECT:{username}') await socket.send(f'CONNECT:{username}')

View File

@@ -379,13 +379,13 @@ async fn handle_connection(
info!("Client {} disconnected", addr); info!("Client {} disconnected", addr);
break; break;
} }
Ok(_) => { Ok(Message::Ping(b)) => { let _ = tx.send(Message::Pong(b)); }
let _ = send(&tx, "ERROR:UNKNOWN"); Ok(Message::Binary(_)) => { let _ = send(&tx, "ERROR:UNKNOWN"); }
} Ok(_) => { info!("Received pong/frame? Something fishy is happening") },
Err(e) => { Err(e) => {
error!("WebSocket error for {}: {}", addr, e); error!("WebSocket error for {}: {}", addr, e);
break; break;
} },
} }
} }