This project is a tic-tac-toe game able to be played simultaneously by any number of connected players, all updating in real-time. It's a way for me to learn a bit about the Elixir/Phoenix/LiveView stack and the BEAM, as an alternative to SPA frontends and stateless application servers.
- While you can enter a username through the form on the left (which will show up in the user list for all users), this will be lost on refresh.
- A single game state is shared between all users.
I initialized this project with mix phx.new massively_multiplayer_ttt --live --no-ecto
to create a Phoenix LiveView app without a database backend. From there, as can be seen in my Application
module, I have the following processes running under the root supervisor:
Endpoint
, which spawns theGameLive
processes that serve the UI and handle input.Telemetry
andPubSub
, provided out of the box by Phoenix.GameServer
, which maintains the tic-tac-toe game state.GameLive
processes call it to submit moves or game resets;GameServer
then broadcasts over pubsub to update the game state for all clients.UsernameServer
, which maintains a map ofGameLive
view process IDs to usernames, holding the list of all currently connected users, broadcasting username additions/changes/removals over pubsub.
The Game
module encapsulates all tic-tac-toe game logic. The Live EEx template describes the UI (with a bit of CSS), while GameLive
handles input and responds to messages coming from the pubsub system.
- Install Elixir.
- Install the Hex package manager by running
mix local.hex
. - Install Node.js.
- If on linux, install
inotify-tools
. - At the root of this repo, run
mix setup
to install and compile all dependencies.
- Start the Phoenix server with
mix phx.server
. - The application should now be available at
localhost:4000
in your browser.
There are several improvements/opportunities I deliberately haven't pursued with this project, largely to keep the scope manageable:
- Persisting data beyond the server; I didn't want to bother with database access for this. Admittedly, this has made managing usernames more difficult, especially persisting them across browser refreshes.
- A mobile-friendly UI; I did the minimum necessary to create a usable UI for desktops.
- Notifications for erroneous moves; Phoenix's built-in flash messages only work on redirects; they don't work especially well with LiveView. I didn't want to spend the time necessary to integrate a JS library for notifications.
- Preserving session state (i.e. usernames) through refreshes. This is tricky without a database backend; I tried saving a session key client-side, getting it with JS hooks, and using that to manage state in the
UsernameServer
. However, I couldn't get everything synchronizing correctly.
I've been eyeing Erlang/Elixir for a long while, interested by its performance, reliability, and unique approach to structuring and maintaining applications. I then watched Chris McCord's video, Build a real-time Twitter clone in 15 minutes with LiveView and Phoenix 1.5, which really piqued my interest and inspired me to start this project. I've also worked through some of The Pragmatic Studio's Phoenix LiveView course to help build my understanding.