
As the title suggests, I'm relatively new to elixir. I've read books and I've done some projects here and there. I've dedicated this year to getting my hands into elixir, and boy am I being radicalized lol. I love elixir, erlang/otp, the community, and the advancements. I actually just finished watching Chris McCord's 2025 keynote, inspired by a recent post about the DurableServer, good stuff. Anyway, onto the actual post.
Long story short, to try and test out elixir + wasm (using popcorn), I've decided implement the game Snake. I've also decided to do it with no coding agents. The first phase was to just create a genserver for something to use in iex, just to get the logic down. (Small aside: I tried to make a full TUI version of it, but elixir doesn't seem to have great TUI libs/support. I'm using iTerm2 if that helps.)
A part of the snake implementation is the logic to place the food pellet, this is the logic. The constraints are only that the pellet needs to be on the grid and it cannot land on the snake.
def move_food(%__MODULE__{grid_height: height, grid_width: width} = state) do
new_food_spt =
Enum.reduce_while(1..(height * width), nil, fn _, _ ->
spt = %{x: Enum.random(0..width-1), y: Enum.random(0..height-1), direction: nil}
if spt_full?(state, spt.x, spt.y) do
{:cont, nil}
else
{:halt, spt}
end
end)
if new_food_spt == nil do
raise "No space for food?"
end
%{state | snake_food: new_food_spt}
end
defp spt_full?(%__MODULE__{snake_head: head, snake_tail: tail}, x, y)
when x >= 0 and y >= 0 do
[head | tail] |> Enum.any?(fn spt -> spt.x == x and spt.y == y end)
end
spt is short for snake point, it's different from just a point as it also has a direction. In my head it reads as "spot."
This is the implementation I went with. As I'm new to elixir, I'm unsure if this is a good way to go about it. I know that this is a super small thing, and I don't need to have it hyper optimized, I'm mainly asking to see other implementations or any thoughts.
The idea here is to randomly generate a point, then check to see if the spot is already taken, if it is check again. Do this area-of-the-grid times.
I know this is super simple, but it feels wrong somehow to use reduce like this. Also, since the random point generator is random, it could technically try the same, taken, spot(s) for each iteration which would be a false representation. I just feel that it's ... so unlikely ... until you've properly "snaked" and have filled up the board lol. Should I add a "seen" situation within the reduce fn? Any thoughts? Implementations? Admonishments?