#OTP Advice – Turn-based (board) game.

38 messages · Page 1 of 1 (latest)

old pecan
#

Hello, I'm implementing a game like Checkers or Chess in Erlang at the moment. Currently, most of the game logic is finished and tested.

I've been excited to get the OTP stuff hooked up, but I'm hitting a conceptual wall. I'm planning on using Cowboy for the web stuff, which I've played with before, but trying to figure out where to start with organizing code into supervisors and such for the game and players is a bit overwhelming.

I'm reading through "Designing Elixir Systems with OTP" right now, but any advice on how to conceptualize this / get started with OTP proper would be appreciated. Thanks

#

A theoretical user story would be "User opens website, clicks 'new game' button, waits for a different player to join. Another use joins, users play game turn by turn, game ends." The trouble in my mind is how I should go about starting to fit the OTP processes together.

shy yarrow
#

you can most certainly try and do this all from scratch if you want, and it's probably a really good learning exercise, but there are already a lot of libraries and frameworks out there that will handle the details for you. For example, I would just use Phoenix for the web stuff, rather than trying to use cowboy directly. If you want to learn how they did the supervision structure etc, then maybe reading the Phoenix source code is a good place to look.

old pecan
shy yarrow
#

Phoenix really is more of a library, e.g. it's nothing like rails

#

If you really insist, then try using plug + plug_cowboy

#

but you're really just going to end up reinventing the wheel

old pecan
#

I found the basics of Cowboy straightforward when I tried it a few months ago.

I suppose my main issue is just figuring out a good starting point for jumping into OTP. I'm comfortable with Erlang and I understand the concepts of the OTP, but I haven't played with it (the OTP) too much as of yet.

In this game project, I have this idea that each user will have a process talking to them and serving them the webpage. The two player's processes will somehow register themselves with a shared "game" process, which implements the game logic and handles communication between them. In this theoretical framework, I anticipate the main issues being in the conceptualizing and gluing these processes together, less so the serving webpages / implementing REST, etc.

#

I don't mind reinventing the wheel, since this is mostly a learning exercise in any case 😄

shy yarrow
#

How does the second player know when the first player has taken their turn?

old pecan
#

Something like this:

Player 1's webpage (1A) sends a move to the user's handling process (1B). That process is focused on serving pages, so it sends the move to the game logic process (P). If the move is valid, the game process updates the board and sends those updated boards to the users' serving processes (1B, 2B), which serves the updated boards to the webpages (1A, 2A)

shy yarrow
#

It makes sense conceptually, but HTTP is request/response based. To "push" an updated page to the other player you will need websockets, not regular HTTP requests.

#

so you will need a JavaScript client that opens a persistent websocket connection that will give you bidirectional communication.

#

Each websocket connection will be represented by a server-side process like you said, and they can each register with the shared game process.

#

You have the general idea of how this should be built, but all of this has already been solved with Phoenix LiveView and PubSub. It does exactly what you describe.

#

I really don't want to discourage you from learning and doing things yourself from scratch, but it took literally years for Phoenix LiveView to be developed

#

At least maybe looking at those other projects should serve as inspiration for how to build what you want even if you don't want to use them

tame walrus
#

I would strongly recommend Phoenix here, as @shy yarrow said, it's lightweight and the channel abstraction is what you're looking for

#

Also, I've built a turn based game in elixir and live view, and the gen_statem module was great for representing different game states

old pecan
#

I suppose I don't really see what Phoenix would add for me here. Using Erlang and Cowboy, conceptually, seems to be a good level of abstraction for me here. What am I really gaining by jumping up a level to Phoenix, besides not having to write some boilerplate?

tame walrus
#

Websockets and channels

#

And the well tested Phoenix.js lib.

#

But if you're doing this in erlang, maybe that's too much

#

And presence and pubsub

#

There's a lot that it gives you out of the box. The easy part is cowboy

#

If you ever want this to run on more than one machine, Phoenix is a big plus

shy yarrow
#

I guess I missed the fact that you were using erlang and not elixir, sorry about that 😅. Elixir's ecosystem really does have solutions for all of this already, but I'm not familiar with whether or not erlang has equivalents

tame walrus
#

To my knowledge, erlang doesn't have a phoenix-like solution. There are some web frameworks, but nothing like channels

shy yarrow
#

@old pecan you're really going to need something like channels built on top of websockets, otherwise the best you'll have is something like polling, where the player who's turn it isn't will have to continue to check every few seconds by making http requests over and over.

old pecan
#

If I really wanted an abstraction, I'd be happy to jump over to Elixir

old pecan
shy yarrow
#

yes, that's a good architecture, but you're leaving out the browser<->server connection in your design.

#

or rather, you just never actually mentioned websockets, I think it's important to understand that part of it more

old pecan
#

I suppose I haven't put a lot of thought into it. I'm only sending a few bytes here and there, so I imagine there are a few solutions that could work on the client side. In that regard, I'm more worried about working with Javascript's event loop

#

The board state is represented as 128 bits, so there's not a lot of data! I wouldn't mind just polling if I have to

#

It's a board game so I could just poll every second or so, too. Luckily I don't have that first-person shooter timing requirement 😆

shy yarrow
#

sure, it's just not as "elegant" 😅