r/learnpython • • 2d ago

Multiplayer tetris using sockets

I have a college assignment to make a multiplayer tetris game (2 players) using TCP sockets, client and server and all that. The idea is the server doing most of the stuff, chosing new pieces, handling the translation of position of the pieces, with the clients being responsible for most the rendering/display part and getting the inputs(I think so at least, that's what I'm trying to do), but I'm having a hard time with it.

I can't seem to think of a way to have the client call to the server to send a new piece to the clients, and if I don't know how to do even that then I don't know how to do anything else (making the back and forth for controlling the pieces, both for the player of the client and the preview of the game of the player 2, and all the rest), tho I hope if I can understand how to do one thing I would be able to make the others, but I really don't even know how to do this.

I know I need to use threads on this, tho I don't really know how to do it, I'm still fairly green on python too so, if anyone could give some help in any way with this it would be much appreciated.

3 Upvotes

11 comments sorted by

3

u/Calm_Exchange_989 2d ago

Keep the server authoritative: it owns the board and piece RNG, and broadcasts state after every tick or input. Clients only send inputs and render; don’t make the client ask for the next piece. Use newline-delimited JSON so each side can read complete messages without guessing packet boundaries.

1

u/DRowe_ 12h ago

okay but if the client is not asking for anything, how would the server know when to send a new piece to the client?

1

u/Calm_Exchange_989 11h ago

The server doesn't wait to be asked. It runs the clock: on each tick it applies gravity, and when the piece can't move down it locks it into the board, spawns the next one, and sends the updated state to both clients. The client just renders the last state it received. If your server only moves when recv() returns, add a game loop/timer so it moves on its own.

1

u/DRowe_ 11h ago

So the server should be the one that knows when a piece can't move down anymore, and that could be used as a way of sending a new piece to the clients, tho I would still need a queue for the pieces with that idea since one client could be asking for pieces more then the other if he's playing quicker, does that make sense?

1

u/Calm_Exchange_989 11h ago

Yes, that's exactly the trigger. But the clients don't ask: each player has their own board and next-piece queue, and the server pops from that queue when their piece locks. A faster player just advances their own board faster, so the queue you need is for upcoming pieces.

1

u/DRowe_ 11h ago

In the case of the game I'm making both players have the same sequence of pieces

1

u/Calm_Exchange_989 8h ago

Then keep one sequence on the server and give each board its own cursor into it. Don't share a single consumed queue: if the faster player pops from it, the slower player's next piece changes. Each lock advances only that player's cursor, so both boards see the same sequence at their own pace

1

u/Boybay_Garid 1d ago

100% this, TCP being a stream instead of discrete packets trips everyone up on their first socket project tbh

1

u/socal_nerdtastic 2d ago

There's tons of tutorials and examples out there for this, including 2 in the official python docs:

https://docs.python.org/3/library/socket.html#example
https://docs.python.org/3/howto/sockets.html

This isn't really a place for people to write personalized tutorials for you. You can use google or AI for that, or just talk to your professor. This sub works best if you post the code you have so far, complete errors you may be getting, and ask a very specific question about your code.

1

u/timrprobocom 2d ago

The client will be time driven. When a piece reaches the bottom, the client does a request/response (like AJAX) to get the next piece.

1

u/FerricDonkey 2d ago

You will need to create a language for them to communicate. Suggest (length) + json: the json you send might be {"message_type": "new_piece", "piece_id": 3} then the bytes you send should be two bytes containing the length of that message (look up struct.pack), followed by the bytes of that message.

This language allows your read loop to look like:

# aggressively pseudo code
while True:
    json_size = read_bytes(2)  # convert to int
    payload_bytes = read_bytes(json_size)
    process_message(json.loads(payload_bytes)) 

For saying "here's the next piece", your code can have a list of all possible pieces (the same on client and server). Piece id can be the index into that list. Come up with other ways to represent the other types of communication using json.