Putting It All Together

Let's wrap up all the game elements we've built so far.

The <Board> component will render the <Canvas> representing the puzzle board shape, along with the <Palette> we just built. The <Board> will also manage the state of the game based on user interactions. It will be a stateful component that knows how to receive events and update the game’s state in response to a user selecting, moving, and placing pentominoes.

Rendering the Board component

Before we dive into the code for our component, let’s take a look at how GameLive will render it. We start by updating the aliases and mount/3 function in GameLive like this:

Press + to interact
defmodule PentoWeb.Pento.GameLive do
use Surface.LiveView
alias PentoWeb.Pento.{Board, Title}
def mount(%{"puzzle" => puzzle}, _session, socket) do
{:ok, assign(socket, puzzle: puzzle)}
end

We match the puzzle name in params and store it in the socket. We’ll need it to render the <Board> component with the correct puzzle board shape and palette of pentomino shapes. Then, we update the render/1 function to call on the <Board> component. It should call on the component with a puzzle prop set equal to the @puzzle assignment and an id prop set equal to board:

Press + to interact
def render(assigns) do
~H"""
<section class="container">
<Title message="Welcome to Pento!" />
<Board puzzle="{{ @puzzle }}" id="game" />
</section>
"""
end

Our new code is simple and elegant. The GameLive LiveView takes some info from the params and renders two components. Next, we used the <Board> on line 5 to display elements of ...