0

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.

  • I think you should separate, your interrupt-able / resume question from the main question your asking about architecting your game, gamedev.stackexchange.com might be appropriate. – esoterik Jun 18 '18 at 21:41
  • I might split the question as you suggest. Regarding the gamedev, in this case is a game, but I think this could apply to other kinds of applications as well so I decided to ask here – Thiatt Jun 18 '18 at 21:44
  • 3
    "I haven't managed to find any well-known pattern which could give me some insight on how to best go about implementing this" - why do you need a "pattern" for implementing this? Why don't you just try it out, and when you run into an obstacle, come back and ask? Currently, without any clear problem statement, I don't see an answerable question in your question. – Doc Brown Jun 19 '18 at 2:30
  • 3
1

It looks to me like you have already found several patterns here:

The game state is centralized and serializable...

Sounds like a client-server model.

Game rules are simply a function of the state (state, ...args) => newState

Sounds like a state machine.

Clients interact and modify the state through actions...

Sounds like event dispatching on one end and event handling on the other.

These are all well-known patterns used in writing games and other types of code.

1

I haven't managed to find any well-known pattern which could give me some insight on how to best go about implementing this

What do you need one for? Is the code tightly coupled? What would a pattern solve compared for your current code? If you don't know the problem, you can't know which pattern to use. If you don't have such problems with your current code, it gets even better because you clearly don't need to solve anything.

I'm not trying to shoehorn something here for the sake of it

It actually sounds like you are. You are looking at a set of solutions without having a well-defined problem that such patterns could solve.

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.

Again this is the same thing. You are looking at the solutions you have implemented, while seemingly not having figured out what problems you were trying to solve by using them.

Patterns are not building blocks. You don't need to use a well-known pattern like the command pattern. If you notice your code is becoming tightly coupled, you are constantly touching multiple places classes for a small change etc, while your problem description sounds somewhat like mentioned here ("Need to issue requests to objects without knowing anything about the operation being requested or the receiver of the request."), then yes, you can consider using that pattern to loosen the coupling.

But in order to make that decision, you need a well-defined problem and if you end up picking a (more well-known) pattern such as the command pattern (although you do not have to pick any of those), you should make sure that it actually forms a solution to whatever problem you were trying to solve.

just trying to get a sense of a general guideline

It's hard to make a guideline for solutions. It's not obligated to use solution y for problem x nor should it be a guideline to make use of solution z in some place in your code. Your solution works and if you are not having problems with, for example, making changes, you probably do not need to apply any pattern like command, strategy or whatever.

The only guidelines you can make regarding patterns is that you should not try to incorporate them in every application, you should not try to apply a pattern without knowing the problem to solve and you should not look at the popular and well-known patterns as the only solutions to software engineering.

Adhere to principles of SOLID design instead. You might end up needing patterns like the strategy pattern and command pattern to achieve that, perhaps you will not, but following those principles well will make your code end up in a good state, regardless.

  • I'm not looking for patterns to "apply". I'm also not looking for solutions. As I said in my post, but maybe not clearly enough. I'm looking to draw/find parallels/inspiration between my own application and well-known patterns that might be related, and/or real applications. And although my current solution could work, if I'm reinventing the wheel without knowing/realizing it, I could benefit from the experience and mistakes of others when doing similar things. – Thiatt Jun 19 '18 at 11:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.