Use typedstruct
This commit is contained in:
parent
b5cc41e9f4
commit
45f271aa3d
5 changed files with 58 additions and 81 deletions
|
@ -1,29 +1,26 @@
|
|||
defmodule ExSpeedGame.Game.ButtonInput do
|
||||
use GenServer
|
||||
import ExSpeedGame.Utils.TypedStruct
|
||||
|
||||
alias ExSpeedGame.Game.Types
|
||||
|
||||
defmodule Options do
|
||||
@type t :: %__MODULE__{
|
||||
pins: Types.pins(),
|
||||
debounce_delay: integer(),
|
||||
name: GenServer.name()
|
||||
}
|
||||
@enforce_keys [:pins, :debounce_delay, :name]
|
||||
defstruct [:pins, :debounce_delay, :name]
|
||||
deftypedstruct(%{
|
||||
pins: Types.pins(),
|
||||
debounce_delay: integer(),
|
||||
name: GenServer.name()
|
||||
})
|
||||
end
|
||||
|
||||
defmodule State do
|
||||
@type t :: %__MODULE__{
|
||||
pins: Types.pins(),
|
||||
debounce_delay: integer(),
|
||||
listener: pid() | nil,
|
||||
pin_refs: [reference()],
|
||||
pin_timers: %{optional(Types.pin()) => reference()},
|
||||
active: boolean()
|
||||
}
|
||||
|
||||
@enforce_keys [:pins, :debounce_delay]
|
||||
defstruct [:pins, :debounce_delay, :listener, pin_refs: [], pin_timers: %{}, active: false]
|
||||
deftypedstruct(%{
|
||||
pins: Types.pins(),
|
||||
debounce_delay: integer(),
|
||||
listener: {pid() | nil, nil},
|
||||
pin_refs: {[reference()], []},
|
||||
pin_timers: {%{optional(Types.pin()) => reference()}, %{}},
|
||||
active: {boolean(), false}
|
||||
})
|
||||
end
|
||||
|
||||
defmodule InputError do
|
||||
|
@ -53,24 +50,20 @@ defmodule ExSpeedGame.Game.ButtonInput do
|
|||
|
||||
# Acquire
|
||||
|
||||
@spec handle_call(:acquire, GenServer.from(), %State{active: false}) :: {:reply, :ok, State.t()}
|
||||
def handle_call(:acquire, {from, _}, %State{active: false} = state) do
|
||||
{:reply, :ok, %State{state | listener: from, active: true}}
|
||||
end
|
||||
|
||||
@spec handle_call(:acquire, any, %State{active: true}) :: no_return()
|
||||
def handle_call(:acquire, _from, %State{active: true, listener: l}) do
|
||||
raise InputError, message: "ButtonInput already acquired to #{l}"
|
||||
end
|
||||
|
||||
# Release
|
||||
|
||||
@spec handle_call(:release, any, %State{active: true}) :: {:reply, :ok, State.t()}
|
||||
def handle_call(:release, _from, %State{active: true} = state) do
|
||||
{:reply, :ok, %State{state | listener: nil, active: false}}
|
||||
end
|
||||
|
||||
@spec handle_call(:release, any, %State{active: false}) :: {:reply, :ok, State.t()}
|
||||
def handle_call(:release, _from, %State{active: false} = state) do
|
||||
{:reply, :ok, state}
|
||||
end
|
||||
|
@ -78,8 +71,6 @@ defmodule ExSpeedGame.Game.ButtonInput do
|
|||
@impl true
|
||||
def handle_info(msg, state)
|
||||
|
||||
@spec handle_info({:circuits_gpio, Types.pin(), integer(), 0 | 1}, %State{active: true}) ::
|
||||
{:noreply, State.t()}
|
||||
def handle_info({:circuits_gpio, pin, _time, value}, %State{active: true} = state) do
|
||||
timer_ref = Map.get(state.pin_timers, pin)
|
||||
|
||||
|
@ -101,7 +92,6 @@ defmodule ExSpeedGame.Game.ButtonInput do
|
|||
{:noreply, %State{state | pin_timers: pin_timers}}
|
||||
end
|
||||
|
||||
@spec handle_info({:debounce, Types.pin()}, %State{active: true}) :: {:noreply, State.t()}
|
||||
def handle_info({:debounce, pin}, %State{active: true} = state) do
|
||||
send(state.listener, {:input, pin})
|
||||
|
||||
|
@ -110,7 +100,6 @@ defmodule ExSpeedGame.Game.ButtonInput do
|
|||
end
|
||||
|
||||
# Discard all other messages
|
||||
@spec handle_info(any, %State{active: false}) :: {:noreply, State.t()}
|
||||
def handle_info(_msg, %State{active: false} = state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
defmodule ExSpeedGame.Game.Lights do
|
||||
use GenServer
|
||||
use Bitwise, only_operators: true
|
||||
import ExSpeedGame.Utils.TypedStruct
|
||||
|
||||
alias ExSpeedGame.Game.Types
|
||||
|
||||
@type values :: {boolean(), boolean(), boolean(), boolean()}
|
||||
|
||||
defmodule Options do
|
||||
@type t :: %__MODULE__{
|
||||
light_pins: Types.led_pins(),
|
||||
name: GenServer.name()
|
||||
}
|
||||
@enforce_keys [:light_pins, :name]
|
||||
defstruct [:light_pins, :name]
|
||||
deftypedstruct(%{
|
||||
light_pins: Types.led_pins(),
|
||||
name: GenServer.name()
|
||||
})
|
||||
end
|
||||
|
||||
defmodule State do
|
||||
@type t :: %__MODULE__{
|
||||
lights: {Types.pin(), Types.pin(), Types.pin(), Types.pin()},
|
||||
references: [reference()]
|
||||
}
|
||||
defstruct [:lights, :references]
|
||||
deftypedstruct(%{
|
||||
lights: {Types.pin(), Types.pin(), Types.pin(), Types.pin()},
|
||||
references: [reference()]
|
||||
})
|
||||
end
|
||||
|
||||
### SERVER INTERFACE
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule ExSpeedGame.Game.Menu do
|
||||
use GenServer
|
||||
require Logger
|
||||
import ExSpeedGame.Utils.TypedStruct
|
||||
|
||||
alias ExSpeedGame.Game.{Types, ButtonInput, ShowIP, Lights}
|
||||
|
||||
|
@ -27,24 +28,20 @@ defmodule ExSpeedGame.Game.Menu do
|
|||
@menu_size :erlang.tuple_size(@menu)
|
||||
|
||||
defmodule Options do
|
||||
@type t :: %__MODULE__{
|
||||
name: GenServer.name()
|
||||
}
|
||||
@enforce_keys [:name]
|
||||
defstruct [:name]
|
||||
deftypedstruct(%{
|
||||
name: GenServer.name()
|
||||
})
|
||||
end
|
||||
|
||||
defmodule State do
|
||||
@type mode :: :menu | :ingame
|
||||
@type t :: %__MODULE__{
|
||||
index: integer(),
|
||||
button_pins: Types.pins(),
|
||||
mode: mode(),
|
||||
game: pid(),
|
||||
game_ref: reference()
|
||||
}
|
||||
@enforce_keys [:button_pins]
|
||||
defstruct [:button_pins, :game, :game_ref, index: 0, mode: :menu]
|
||||
deftypedstruct(%{
|
||||
index: {integer(), 0},
|
||||
button_pins: Types.pins(),
|
||||
mode: {mode(), :menu},
|
||||
game: {pid() | nil, nil},
|
||||
game_ref: {reference() | nil, nil}
|
||||
})
|
||||
end
|
||||
|
||||
@spec start_link(Options.t()) :: :ignore | {:error, any} | {:ok, pid}
|
||||
|
@ -68,7 +65,6 @@ defmodule ExSpeedGame.Game.Menu do
|
|||
@impl true
|
||||
def handle_info(msg, state)
|
||||
|
||||
@spec handle_info({:input, Types.pin()}, State.t()) :: {:noreply, State.t()}
|
||||
def handle_info(
|
||||
{:input, btn_pin},
|
||||
%State{index: index, button_pins: {pin1, _, _, pin4}, mode: :menu} = state
|
||||
|
@ -90,7 +86,6 @@ defmodule ExSpeedGame.Game.Menu do
|
|||
{:noreply, new_state}
|
||||
end
|
||||
|
||||
@spec handle_info({:input, Types.pin()}, State.t()) :: {:noreply, State.t()}
|
||||
def handle_info({:input, _pin}, %State{index: index, mode: :menu} = state) do
|
||||
ButtonInput.release(ButtonInput)
|
||||
|
||||
|
@ -106,7 +101,6 @@ defmodule ExSpeedGame.Game.Menu do
|
|||
{:noreply, new_state}
|
||||
end
|
||||
|
||||
@spec handle_info({:DOWN, reference(), :process, any, any}, State.t()) :: {:noreply, State.t()}
|
||||
def handle_info(
|
||||
{:DOWN, ref, :process, _, reason},
|
||||
%State{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule ExSpeedGame.Game.Modes.Speed do
|
||||
use GenServer, restart: :temporary
|
||||
require Logger
|
||||
import ExSpeedGame.Utils.TypedStruct
|
||||
|
||||
alias ExSpeedGame.Game.{Types, Lights, ButtonInput, Randomiser}
|
||||
alias ExSpeedGame.PubSub
|
||||
|
@ -8,25 +9,21 @@ defmodule ExSpeedGame.Game.Modes.Speed do
|
|||
@max_queue Application.get_env(:ex_speed_game, :max_queue)
|
||||
|
||||
defmodule Options do
|
||||
@type t :: %__MODULE__{
|
||||
initial_score: integer(),
|
||||
initial_delay: integer()
|
||||
}
|
||||
@enforce_keys [:initial_score, :initial_delay]
|
||||
defstruct [:initial_score, :initial_delay]
|
||||
deftypedstruct(%{
|
||||
initial_score: integer(),
|
||||
initial_delay: integer()
|
||||
})
|
||||
end
|
||||
|
||||
defmodule State do
|
||||
@type t :: %__MODULE__{
|
||||
score: integer(),
|
||||
delay: float(),
|
||||
queue: :queue.queue(Types.pin()),
|
||||
queue_len: integer(),
|
||||
previous: Types.choice(),
|
||||
active: boolean()
|
||||
}
|
||||
@enforce_keys [:score, :delay]
|
||||
defstruct [:score, :delay, queue: :queue.new(), queue_len: 0, previous: nil, active: true]
|
||||
deftypedstruct(%{
|
||||
score: integer(),
|
||||
delay: float(),
|
||||
queue: {:queue.queue(Types.pin()), :queue.new()},
|
||||
queue_len: {integer(), 0},
|
||||
previous: {Types.choice() | nil, nil},
|
||||
active: {boolean(), true}
|
||||
})
|
||||
end
|
||||
|
||||
@spec start_link(Options.t()) :: :ignore | {:error, any} | {:ok, pid}
|
||||
|
@ -38,7 +35,7 @@ defmodule ExSpeedGame.Game.Modes.Speed do
|
|||
end
|
||||
|
||||
@impl true
|
||||
@spec init(map()) :: {:ok, State.t()}
|
||||
@spec init(%{initial_score: integer(), initial_delay: float()}) :: {:ok, State.t()}
|
||||
def init(%{initial_score: score, initial_delay: delay}) do
|
||||
ButtonInput.acquire(ButtonInput)
|
||||
Lights.clear(Lights)
|
||||
|
@ -52,7 +49,8 @@ defmodule ExSpeedGame.Game.Modes.Speed do
|
|||
# Tick handling
|
||||
|
||||
@impl true
|
||||
@spec handle_info(:tick, State.t()) :: {:noreply, State.t()}
|
||||
def handle_info(msg, state)
|
||||
|
||||
def handle_info(:tick, %State{queue_len: queue_len, active: true} = state)
|
||||
when queue_len >= @max_queue do
|
||||
end_game(state)
|
||||
|
@ -79,19 +77,16 @@ defmodule ExSpeedGame.Game.Modes.Speed do
|
|||
end
|
||||
|
||||
@impl true
|
||||
@spec handle_info(:tick, %State{active: false}) :: {:noreply, State.t()}
|
||||
def handle_info(:tick, %State{active: false} = state), do: {:noreply, state}
|
||||
|
||||
# Input handling
|
||||
|
||||
@impl true
|
||||
@spec handle_info({:input, any()}, %State{active: false}) :: {:stop, :normal, State.t()}
|
||||
def handle_info({:input, _}, %State{active: false} = state) do
|
||||
{:stop, :normal, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
@spec handle_info({:input, Types.pin()}, %State{active: true}) :: {:noreply, :normal, State.t()}
|
||||
def handle_info({:input, pin}, %State{active: true} = state) do
|
||||
choice = ButtonInput.get_choice(pin, Application.get_env(:ex_speed_game, :button_pins))
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
defmodule ExSpeedGame.Game.ShowIP do
|
||||
use GenServer, restart: :temporary
|
||||
import ExSpeedGame.Utils.TypedStruct
|
||||
|
||||
require Logger
|
||||
|
||||
defmodule State do
|
||||
@type t :: %__MODULE__{
|
||||
ip: String.t(),
|
||||
index: integer()
|
||||
}
|
||||
@enforce_keys [:ip]
|
||||
defstruct [:ip, index: 0]
|
||||
deftypedstruct(%{
|
||||
ip: String.t(),
|
||||
index: {integer(), 0}
|
||||
})
|
||||
end
|
||||
|
||||
@spec start_link(any) :: :ignore | {:error, any} | {:ok, pid}
|
||||
|
|
Loading…
Reference in a new issue