defmodule Hexalixir.Game do use GenServer alias Hexalixir.Grid # Client API def start_link(_opts) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) end def click_tile(coords) do GenServer.call(__MODULE__, {:click_tile, coords}) end def save_color(color, slot) do GenServer.call(__MODULE__, {:save_color, color, slot}) end def use_saved_color(coords, slot) do GenServer.call(__MODULE__, {:use_saved_color, coords, slot}) end # Server Callbacks @impl true def init(:ok) do {:ok, %{ grid: Grid.new(), saved_colors: %{1 => {nil, 6}, 2 => {nil, 6}} }} end @impl true def handle_call({:click_tile, coords}, _from, state) do if Map.get(state.grid, coords) do {:reply, {:error, :tile_already_colored}, state} else new_grid = color_tiles([coords | Grid.get_adjacent_coords(coords)], state.grid) new_state = %{state | grid: new_grid} {:reply, {:ok, new_grid, Grid.check_win(new_grid)}, new_state} end end @impl true def handle_call({:save_color, color, slot}, _from, state) do new_state = put_in(state.saved_colors[slot], {color, 6}) {:reply, :ok, new_state} end @impl true def handle_call({:use_saved_color, coords, slot}, _from, state) do case state.saved_colors[slot] do {nil, _} -> {:reply, {:error, :no_color_saved}, state} {color, 0} -> {:reply, {:error, :no_uses_left}, state} {color, uses} -> if Map.get(state.grid, coords) do {:reply, {:error, :tile_already_colored}, state} else new_grid = Map.put(state.grid, coords, color) new_state = %{state | grid: new_grid, saved_colors: Map.put(state.saved_colors, slot, {color, uses - 1}) } {:reply, {:ok, new_grid, Grid.check_win(new_grid)}, new_state} end end end # Private Functions defp color_tiles(coords, grid) do Enum.reduce(coords, grid, fn coord, acc -> if Map.get(acc, coord) do acc else Map.put(acc, coord, Grid.random_color()) end end) end end