From 8d8a3ab3a5b7615f79577596697b048efc424d33 Mon Sep 17 00:00:00 2001 From: Joshua Higgins Date: Tue, 18 Nov 2025 17:24:55 -0500 Subject: [PATCH] fix: example client bug fixes & handle ping/pongs on server --- README.md | 15 +++++++++++++- example_client.py | 50 ++++++++++++++++++++++++++--------------------- src/main.rs | 8 ++++---- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ac4a4f7..7fe4b65 100644 --- a/README.md +++ b/README.md @@ -1 +1,14 @@ -# Connect4 Moderator - Server \ No newline at end of file +# 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). \ No newline at end of file diff --git a/example_client.py b/example_client.py index dedac88..5c8cb5e 100644 --- a/example_client.py +++ b/example_client.py @@ -7,13 +7,7 @@ class Slot(Enum): RED = 1 BLUE = 2 -# Global board state (6 columns x 5 rows) -board = [[Slot.NONE] * 5 for _ in range(6)] - -our_color = None -opponent_color = None - -def calculate_move(opponent_move): +def calculate_move(opponent_move, board, our_color, opponent_color): if opponent_move is not None: print(f"Opponent played column {opponent_move}") # TODO: Implement your move calculation logic here instead @@ -21,25 +15,30 @@ def calculate_move(opponent_move): return int(input("Column: ")) 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 + print(f"Received message: {message}") match message[0]: - case 'CONNECT:ACK': + case 'CONNECT': await socket.send('READY') - case 'GAMESTART': # Game has started - if message[1] == '1': - our_color = Slot.RED - opponent_color = Slot.BLUE - col = calculate_move(None) # calculate_move is some arbitrary function you have created to figure out the next move - await socket.send(f'PLAY:{col}') # Send your move to the sever - else: - our_color = Slot.BLUE - opponent_color = Slot.RED + case 'GAME': + if message[1] == 'START': + if message[2] == '1': + our_color = Slot.RED + opponent_color = Slot.BLUE + col = calculate_move(None, board, our_color, opponent_color) # calculate_move is some arbitrary function you have created to figure out the next move + await socket.send(f'PLAY:{col}') # Send your move to the sever + else: + our_color = Slot.BLUE + opponent_color = Slot.RED 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 case 'WIN' | 'LOSS' | 'DRAW' | 'TERMINATED': # Game has ended @@ -47,11 +46,18 @@ async def gameloop (socket): board = [[Slot.NONE] * 5 for _ in range(6)] our_color = None opponent_color = None + await socket.send('READY') + + case 'KICK': + print("You have been kicked from the game") + break case 'ERROR': - print(f"Error: {':'.join(message[1:])}") - exit() - + print(f"{message[0]}: {':'.join(message[1:])}") + break + + await socket.close() + async def join_server(username): async with websockets.connect(f'wss://connect4.abunchofknowitalls.com') as socket: # Establish websocket connection await socket.send(f'CONNECT:{username}') diff --git a/src/main.rs b/src/main.rs index 9e2dcc7..f2e5ffe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -379,13 +379,13 @@ async fn handle_connection( info!("Client {} disconnected", addr); break; } - Ok(_) => { - let _ = send(&tx, "ERROR:UNKNOWN"); - } + Ok(Message::Ping(b)) => { let _ = tx.send(Message::Pong(b)); } + Ok(Message::Binary(_)) => { let _ = send(&tx, "ERROR:UNKNOWN"); } + Ok(_) => { info!("Received pong/frame? Something fishy is happening") }, Err(e) => { error!("WebSocket error for {}: {}", addr, e); break; - } + }, } }