I had the idea to try and make a simple version of the Apples to Apples game and set it up as a webapp. My initial idea is that each game instance will essentially be a chat room. Multiple players (up to some arbitrary but small limit) connect to the game instance via websockets.
Each player will have some state that consists of a score and current cards.
The game will have Players, Cards, Topics, and Rounds. Each Round will have a Judge and a Winner.
cards: Vec<(Card, Player)>
type Card = String;
type Topic = String;
Each round of play consists of all but one player submitting a card. The excepted player is the Judge for that round. Once all players have submitted a card (by checking
Round::cards.len() and that
Round::cards has only a single submission from each player), the Judge picks a winner. Once a winner is chosen the round is over and the next player in sequence becomes the Judge.
Before getting into the nuts and bolts of the websockets and so on, does this overall structure make sense? What organization would offer easier gameplay logic/algorithms?
I wish I could be of more help, but I'm pretty new to Rust. The overall structure looks good, but I get the feeling that your vectors for the
players field in
Round will probably need to be some sort of smart pointer like
RefCell or something like that. I haven't had a real opportunity to use smart pointers in practice yet. Same with the
Player field in the tuple for the
References might be the way to go so that you only have a single instance of each unique player in memory. If you don't reference players, then you'll have to make copies of these instances for each round.
For example: round 1 starts. If we go the copy route, then we'll need to copy/clone all participating players into that round. This might be fine, but if the player is allowed to change their screen name or other attributes at any time throughout the game, then the player instance will get updated in the
Game struct, but not in the
Round struct. If you want this exact behavior, then you're all set. If you don't, then smart pointers or even storing the IDs of each player could be easier too. If
Round only stores each participating player's ID, then you could provide a method like
get_player_by_id(id: u32) -> &Player, on the
Game struct to look up players.
Definitely a good point to not copy the whole
Player to the
Round but access it by ID. Thanks.
If you want users to have persistent identities -- usernames, win statistics, stuff like that -- I would recommend separating user data (stuff that follows a person from game to game) from player data (stuff that is only relevant to a game, such as hand and score). This also lets you do stuff like play multiple games at once as the same user.
That's good advice. This is intended only for a small group of friends, though. I'm not planning to keep stats or have persistent storage at all really.
I'd suggest avoiding
type and instead use a struct for player and card. It allows the compiler to give you a but more help in catching bugs, and also can ease refactoring later if you decide to change the representation of those types.
I imagined that the persistent data would live in a database of some sort for the long-term data such as storing password hashes, and records between the player table and the games tables (assuming relational databases here). Then, when the user is actively using the service (playing the game in this case), their data would be loaded into memory which is where the
Game struct comes in handy. The indefinite long-term stuff that's rarely modified could stored directly into the database which would be submitted directly by the server-side Rust binary.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.