princemaple

princemaple

TLDR: https://minesweeper.fly.dev built with liveview and other recent tools.

Most relevant code at mine_sweeper/lib/mine_sweeper_web/live/session_live at main · princemaple/mine_sweeper · GitHub


Hi All,

My most familiar stack is building frontend with Angular and using phoenix as an API backend. I briefly tried liveview when it first came out. That was pre-heex, pre-component era. I’ve been wanting to try the shiny new stuff and stay up to date.

I could’ve chosen a different game if I simply wanted to build something interactive and realtime. I chose minesweeper because 1. it’s one of my favorite games, 2. it requires a lot of state keeping and inter-component communication (I initially thought each component would be a separate process) and 3. it requires quite a bit interaction (event handling). I thought it’s a good game to build to test all these things out.

Plus, there has been a couple other things on my listing waiting to be checked out.

  1. fly.io deployment
    (I’ve used the one-click to launch livebook. It’s great)
  2. phoenix with esbuild and tailwind
    (they are not new to me, I just haven’t built a phoenix app that uses them to build the assets)

So, I decided to build this minesweeper game with liveview, with the assets built with esbuild & tailwind, and deployed to fly.io


A few notes:

  1. as previously mentioned, I initially thought each component was a separate process. That wasn’t the case. So there isn’t really much “inter-component communication”. I built the game with GenServers, while liveview and components were solely used to render and interact.
  2. for in heex seems to update all or nothing. I thought it would be able to only update the ones with thier assigns changed. Easy workaround though, just check the new assigns with the assigns on socket.
  3. somewhat often, changes in assets, sometimes also in GenServers, don’t get reflected in the running app. Not sure if building on Window directly had something in it. I normally dev with docker and this is not an issue.

Overall everything went pretty smoothly.
GitHub - phoenixframework/esbuild: An installer for esbuild · GitHub and GitHub - phoenixframework/tailwind: An installer for tailwind · GitHub do a very good job getting me started, and provide very sensible docs and defaults. Deploying to fly.io was also easy, fly launch made it almost a no brainer. It generates a very good dockerfile and other relevant deployment related files. Heex is great to great to work with. Components do a good job separating small parts of the UI, encapsulating both their rendering and logic, allowing easy reuse.

I feel like I’ve got an OK understanding of latest liveview.
Things left to explore later: I did try out deploying to multiple regions on fly.io, which was easy, but I didn’t know how its routing works and whether you could reliably hit your closest server, so I reverted back to single server. Maybe a fun thing to do is to deploy a multi continent cluster and have the games shown globally. (oh, did I mention that you can enter others’ games and mess with help them)

Reviews and comments are welcome. Questions too!

Stay safe.

Showing Posts 1 to 10

LostKobrakai

LostKobrakai

You should be able to use stateful components within for and get granular updates.

princemaple

princemaple OP

:wink: Thanks. Yep, that’s what I did.

princemaple

princemaple OP

https://github.com/princemaple/mine_sweeper/blob/main/lib/mine_sweeper_web/live/session_live/cell_component.ex#L6-L9

^ This is my “workaround”. I hope it’s what you meant.

https://github.com/princemaple/mine_sweeper/blob/main/lib/mine_sweeper_web/live/session_live/show.html.heex#L22

^ I was hoping this would cause only individual cell gets the update call, but whenever the cache busting map gets any update, the whole for updates (i.e. every single cell component gets the update call)

qhwa

qhwa

Awesome project, congrats!

I had the same question before and ended up using the following approach with a CDN test tool to confirm that it was routed to the nearest region.

# config.exs
config :my_app, region: System.get_env("FLY_REGION", "unknown")

# my_plug.ex
conn |> put_resp_header("x-fly-region", Application.get_env(:region))

Anycast is amazing.

princemaple

princemaple OP

Thanks! :heart_eyes_cat:

josefrichter

josefrichter

I wonder if every field being a separate genserver isn’t an overkill. But I assume it’s only for education purposes.

Now I’d be interested in opposite extreme where each game is just a single genserver with list state and simple css grid and you could squeeze all that fun in 10 LOC :slightly_smiling_face:

princemaple

princemaple OP

Yes. It’s intentionally over-engineered :slight_smile:

Sebb

Sebb

I’d like to see that 10loc version ..

defmodule Minesweeper do
  def neighbours({x, y}) do
    [
      {x + 1, y - 1},
      {x + 1, y},
      {x + 1, y + 1},
      {x, y - 1},
      {x, y + 1},
      {x - 1, y - 1},
      {x - 1, y},
      {x - 1, y + 1}
    ]
    |> Enum.filter(fn {x, y} -> x in 0..8 and y in 0..8 end)
  end

  def numbers(mines) do
    Enum.flat_map(mines, &neighbours/1) |> Enum.frequencies()
  end

  # --- the view

  def cell(coord, numbers, mines) do
    if(coord in mines) do
      "M"
    else
      "#{Map.get(numbers, coord, " ")}"
    end
  end

  def print_board(numbers, mines) do
    for y <- 0..8 do
      for x <- 0..8 do
        cell({x,y}, numbers, mines)
      end
    end
  end
end
# @mines [{6,0}, {0,1}, {1,2}, {3,2}, {8,4}, {2,5}, {1,6}, {4,6}, {2,7}, {7,8}]
# Minesweeper.print_board(Minesweeper.numbers(@mines), @mines) |> IO.inspect()
[
  ["1", "1", " ", " ", " ", "1", "M", "1", " "],
  ["M", "2", "2", "1", "1", "1", "1", "1", " "],
  ["2", "M", "2", "M", "1", " ", " ", " ", " "],
  ["1", "1", "2", "1", "1", " ", " ", "1", "1"],
  [" ", "1", "1", "1", " ", " ", " ", "1", "M"],
  ["1", "2", "M", "2", "1", "1", " ", "1", "1"],
  ["1", "M", "3", "3", "M", "1", " ", " ", " "],
  ["1", "2", "M", "2", "1", "1", "1", "1", "1"],
  [" ", "1", "1", "1", " ", " ", "1", "M", "1"]
]
josefrichter

josefrichter

Brilliant work! I really like how you did the neighbours function with filter, that’s shrewd :slight_smile:

03juan

03juan

Late to the party but for funsies :smile:

def neighbours2({x, y} = orig) do
  for x_mod <- [1, 0, -1],
    y_mod <- [-1, 0, 1],
    x_new = x + x_mod,
    y_new = y + y_mod,
    x_new in 0..8 and y_new in 0..8 and {x_new, y_new} != orig do
      {x_new, y_new}
  end
end

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
AstonJ
Since we have deprecated our Erlang sections (as we have dedicated Erlang Forums now) let’s add this thread for those who’d like to post ...
New
maennchen
:warning: Security advisory: Decimal DoS vulnerability A vulnerability has been published for decimal where very large exponents can cau...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews