Skip to content

Commit

Permalink
feat: add gameplay test
Browse files Browse the repository at this point in the history
  • Loading branch information
dennyabrain committed Sep 18, 2024
1 parent d653083 commit c97ca64
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 130 deletions.
2 changes: 1 addition & 1 deletion lib/viral_spiral/room/engine_config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule ViralSpiral.Game.EngineConfig do
@moduledoc """
Global configuration for the game engine.
Unlike its room specific counterpart `ViralSpiral.Room.RoomConfig`, this configuration is global to every game room created on this server. These configuration are loaded at compile time and don't change throughout the runtime of the engine.
Unlike its room specific counterpart `ViralSpiral.Room.State.Room`, this configuration is global to every game room created on this server. These configuration are loaded at compile time and don't change throughout the runtime of the engine.
An imagined usecase of this module is to support spinning up varied instances of viral spiral with different characteristics. For instance,
- Spinning up a server where only communities from :yellow and :red are available for gameplay.
Expand Down
46 changes: 0 additions & 46 deletions lib/viral_spiral/room/room_config.ex

This file was deleted.

6 changes: 3 additions & 3 deletions lib/viral_spiral/room/state/player.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule ViralSpiral.Room.State.Player do
}
"""
alias ViralSpiral.Room
alias ViralSpiral.Room.RoomConfig
alias ViralSpiral.Room.State.Room
alias ViralSpiral.Room.State.Player.ActiveCardDoesNotExist
alias ViralSpiral.Room.State.Player.DuplicateActiveCardException
alias ViralSpiral.Room.State.Player
Expand Down Expand Up @@ -39,8 +39,8 @@ defmodule ViralSpiral.Room.State.Player do
active_cards: list(String.t())
}

@spec new(RoomConfig.t()) :: t()
def new(%RoomConfig{} = room_config) do
@spec new(Room.t()) :: t()
def new(%Room{} = room_config) do
identity = Enum.shuffle(room_config.communities) |> Enum.at(0)

bias_list = Enum.filter(room_config.communities, &(&1 != identity))
Expand Down
153 changes: 134 additions & 19 deletions lib/viral_spiral/room/state/room.ex
Original file line number Diff line number Diff line change
@@ -1,33 +1,73 @@
defmodule ViralSpiral.Room.State.Room do
@moduledoc """
## Example
Room specific configuration for every game.
"""
alias ViralSpiral.Bias
alias ViralSpiral.Affinity
alias ViralSpiral.Room.State.Room
alias ViralSpiral.Game.EngineConfig

defstruct chaos_countdown: 10,
id: "",
name: "",
defstruct affinities: [],
communities: [],
chaos_counter: nil,
volatality: :medium,
id: nil,
name: nil,
state: :uninitialized

@all_states [:uninitialized, :waiting_for_players, :running, :paused]

@type states :: :uninitialized | :waiting_for_players | :running | :paused
@type t :: %__MODULE__{
chaos_countdown: integer(),
affinities: list(Affinity.target()),
communities: list(Bias.target()),
chaos_counter: integer(),
volatality: EngineConfig.volatility(),
id: String.t(),
name: String.t(),
state: states()
}

@doc """
Create a new Room with default values.
"""
@spec new() :: t()
def new(player_count) do
engine_config = %EngineConfig{}

affinities = engine_config.affinities
total_affinities = length(affinities)

two_affinities =
Stream.repeatedly(fn -> :rand.uniform(total_affinities - 1) end)
|> Stream.dedup()
|> Enum.take(2)

room_affinities = Enum.map(two_affinities, &Enum.at(affinities, &1))

communities = engine_config.communities

room_communities =
case player_count do
x when x <= 3 -> Enum.shuffle(communities) |> Enum.take(2)
_ -> communities
end

%Room{
id: UXID.generate!(prefix: "room", size: :small),
state: :uninitialized,
affinities: room_affinities,
communities: room_communities,
chaos_counter: engine_config.chaos_counter,
volatality: engine_config.volatility
}
end

def new() do
engine_config = %EngineConfig{}

%Room{
id: UXID.generate!(prefix: "room", size: :small),
state: :uninitialized
name: name(),
state: :uninitialized,
chaos_counter: engine_config.chaos_counter,
volatality: engine_config.volatility
}
end

Expand All @@ -40,7 +80,86 @@ defmodule ViralSpiral.Room.State.Room do
"""
@spec countdown(t()) :: t()
def countdown(%Room{} = room) do
%{room | chaos_countdown: room.chaos_countdown - 1}
%{room | chaos_counter: room.chaos_counter - 1}
end

def name() do
adjectives = [
"ambitious",
"basic",
"careful",
"dark",
"eager",
"fab",
"glib",
"happy",
"inept",
"jolly",
"keen",
"lavish",
"magic",
"neat",
"official",
"perfect",
"quack",
"rare",
"sassy",
"tall",
"velvet",
"weak"
]

nouns = [
"apple",
"ball",
"cat",
"dog",
"eel",
"fish",
"goat",
"hen",
"island",
"joker",
"lion",
"monk",
"nose",
"oven",
"parrot",
"queen",
"rat",
"sun",
"tower",
"umbrella",
"venus",
"water",
"zebra"
]

Enum.random(adjectives) <> "-" <> Enum.random(nouns)
end

def start(%Room{} = room, player_count) do
engine_config = %EngineConfig{}

affinities = engine_config.affinities
total_affinities = length(affinities)

two_affinities =
Stream.repeatedly(fn -> :rand.uniform(total_affinities - 1) end)
|> Stream.dedup()
|> Enum.take(2)

room_affinities = Enum.map(two_affinities, &Enum.at(affinities, &1))

communities = engine_config.communities

room_communities =
case player_count do
x when x <= 3 -> Enum.shuffle(communities) |> Enum.take(2)
_ -> communities
end

%{room | affinities: room_affinities, communities: room_communities, state: :running}
end
end

Expand All @@ -53,14 +172,10 @@ defimpl ViralSpiral.Room.State.Change, for: ViralSpiral.Room.State.Room do
"""
@spec apply_change(Room.t(), State.t(), keyword()) :: Room.t()
def apply_change(%Room{} = score, _global_state, opts) do
opts = Keyword.validate!(opts, offset: 0)

case opts[:offset] do
x when is_integer(x) ->
Map.put(score, :chaos_countdown, score.chaos_countdown + opts[:offset])
opts = Keyword.validate!(opts, type: nil, offset: 0)

y when is_bitstring(y) ->
Map.put(score, :chaos_countdown, score.chaos_countdown)
case opts[:type] do
:chaos_coutdown -> Map.put(score, :chaos_couter, score.chaos_counter + opts[:offset])
end
end
end
29 changes: 21 additions & 8 deletions lib/viral_spiral/room/state/root.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule ViralSpiral.Room.State.Root do
When a round begins, we also start a Turn. Within each Round there's a turn that includes everyone except the person who started the turn.
"""

alias ViralSpiral.Room.RoomConfig
alias ViralSpiral.Room.State.Room
alias ViralSpiral.Room.State.Turn
alias ViralSpiral.Canon.Deck
alias ViralSpiral.Room.State.Round
Expand All @@ -18,22 +18,37 @@ defmodule ViralSpiral.Room.State.Root do
alias ViralSpiral.Room.State.Root
alias ViralSpiral.Room.State.Change

defstruct room_config: nil,
room: nil,
defstruct room: nil,
players: [],
round: nil,
turn: nil,
deck: nil

@type t :: %__MODULE__{
room_config: RoomConfig.t(),
room: Room.t(),
players: list(Player.t()),
round: Round.t()
# turn: Turn.t(),
round: Round.t(),
turn: Turn.t()
# deck: Deck.t()
}

def new(%Room{} = room, player_names) when is_list(player_names) do
players =
player_names
|> Enum.map(fn player_name -> Player.new(room) |> Player.set_name(player_name) end)
|> Enum.reduce(%{}, fn player, acc -> Map.put(acc, player.id, player) end)

round = Round.new(players)
turn = Turn.new(round)

%Root{
room: room,
players: players,
round: round,
turn: turn
}
end

def set_round(%Root{} = game, round) do
%{game | round: round}
end
Expand All @@ -46,8 +61,6 @@ defmodule ViralSpiral.Room.State.Root do
# list({:ok, message :: String.t()} | {:error, reason :: String.t()})
def apply_changes(state, changes) do
Enum.reduce(changes, state, fn change, state ->
# require IEx
# IEx.pry()
data = get_target(state, elem(change, 0))
change_inst = elem(change, 1)
new_value = apply_change(data, state, change_inst)
Expand Down
8 changes: 7 additions & 1 deletion lib/viral_spiral/room/state/round.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ defmodule ViralSpiral.Room.State.Round do

@type change_opts :: [type: :next]

@typedoc "Description of which player to skip and in which round"
@type skip :: %{
player: String.t(),
round: :current | :next
}

@type t :: %__MODULE__{
order: list(String.t()),
count: integer(),
current: integer(),
skip: boolean()
skip: skip() | nil
}

@doc """
Expand Down
17 changes: 8 additions & 9 deletions test/support/fixtures.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule Fixtures do
alias ViralSpiral.Room.RoomConfig
alias ViralSpiral.Room.State.Room
alias ViralSpiral.Room.State.Player
alias ViralSpiral.Deck.Card
alias ViralSpiral.Room.State.Turn
Expand All @@ -10,13 +10,13 @@ defmodule Fixtures do
alias ViralSpiral.Room.State.Root

def initialized_game() do
room_config = RoomConfig.new(4)
room = Room.new(4)

player_list = [
Player.new(room_config) |> Player.set_name("adhiraj"),
Player.new(room_config) |> Player.set_name("aman"),
Player.new(room_config) |> Player.set_name("krys"),
Player.new(room_config) |> Player.set_name("farah")
Player.new(room) |> Player.set_name("adhiraj"),
Player.new(room) |> Player.set_name("aman"),
Player.new(room) |> Player.set_name("krys"),
Player.new(room) |> Player.set_name("farah")
]

players = Enum.reduce(player_list, %{}, fn player, acc -> Map.put(acc, player.id, player) end)
Expand All @@ -25,16 +25,15 @@ defmodule Fixtures do
turn = Turn.new(round)

%Root{
room_config: room_config,
room: Room.new(),
room: room,
players: players,
round: round,
turn: turn
}
end

def players() do
room_config = %RoomConfig{}
room_config = %Room{}

player_list = [
Player.new(room_config) |> Player.set_name("adhiraj"),
Expand Down
Loading

0 comments on commit c97ca64

Please sign in to comment.