For the past few months I've been messing around with implementing my own version of a well-known board game. After much experimentation I've arrived on a few key points that describe my system:
- The game state is centralized and serializable. The server can be interrupted at any time, but simply by pulling the state from storage, a player could resume their game exactly where it stopped
- Game rules are simply a function of the state
(state, ...args) => newState
- Clients interact and modify the state through actions, described by a rule which modifies the state accordingly (see point above), and a values function
(state, player) => args[]
, which, given the current state and the player, returns the valid values (if any) for that particular type of action. This is used to inform the client of their valid actions and also as a validator for incoming actions - The player chooses one of the possible actions, sends it to the server in the form
{type, args}
, which validates the action against the possible values for that particular action type and executes the corresponding rule, returning the new state back to the player
I haven't managed to find any well-known pattern which could give me some insight on how to best go about implementing this. I'm not trying to shoehorn something here for the sake of it, just trying to get a sense of a general guideline and other similar cases in real-life that I could learn from.
In some sense, this works much like a state machine, with some kind of Command paattern and an RPC system to mediate between client/server that triggers the state changes.
I'm trying to go for a functional approach here, so no mutations of objects, and all effects depend solely on the game state. Also, I'm developing this in JavaScript, but I don't think that matters much.