Islands
Learn how to create the Islands module.
We'll cover the following...
Represent islands
Let’s move on to the islands in the game.
Islands are more complex than coordinates or guesses. They come in five different shapes: :atoll,
:dot,
:l_shape,
:s_shape,
and :square
. Players can position them on the board, and their opponents try to guess their position.
Islands are made of groups of coordinates. This suggests that we can use a list to represent them.
Looking back at our list of actions, one of the things we need to do is determine whether or not an island is forested. In other words, we need to determine if all the coordinates of an island have been hit.
If we use a list to represent an island, we need to do two things:
- First, we need to mark coordinates as a hit.
- Then, whenever we need to see if the island is forested, we need to enumerate through the list.
To check for a win, we would have to enumerate through all the coordinates in all the islands. The total number of coordinates is small, so it’s not a really big deal. However, we can do better.
If we saved two lists—one for the initial list of coordinates, and another to which we add any coordinates that are hit during a guess—we can do a simple comparison of the two.
There’s a small problem with this, though. If we compare lists, the order of the elements matters.
[1, 2] == [2, 1]
Note: Running this in an IEx session displays
false
since the two lists are not interchangeable.
It’s doubtful that guesses will happen in the same order that the coordinates were added to an island. This would force us to sort the lists each time we made a comparison. Better yet, we can sort the initial coordinate list once and subsequently sort only the list of hits when we add a new one.
Fortunately, there’s a straightforward solution. If we use the MapSet
data structure to store the two lists, the order doesn’t matter. We can use the built-in MapSet.equal?/2
function to determine equality:
MapSet.equal?(MapSet.new([1, 2]), MapSet.new([2, 1]))
We can try running these commands in the terminal below:
We can wrap these two sets in a struct to package them as a single entity just as we did with coordinates and guesses.
Now we’re getting somewhere.
Create the Island
module
Let’s create a new Island
module at lib/islands_engine/island.ex
to capture what we’ve come up with so far:
defmodule IslandsEngine.Island doalias IslandsEngine.{Coordinate, Island}@enforce_keys [:coordinates, :hit_coordinates]defstruct [:coordinates, :hit_coordinates]def new(), do:%Island{coordinates: MapSet.new(), hit_coordinates: MapSet.new()}end
We could keep the new/0
function as is, but there’s ...