Skip to content

Commit

Permalink
refactor out game scoring logic to the context so it can be used ever…
Browse files Browse the repository at this point in the history
…ywhere in the frontend
  • Loading branch information
tobyirvine committed Jun 13, 2024
1 parent e84c799 commit 28d9edb
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 41 deletions.
44 changes: 44 additions & 0 deletions lib/copi/cornucopia.ex
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,48 @@ defmodule Copi.Cornucopia do
def change_card(%Card{} = card, attrs \\ %{}) do
Card.changeset(card, attrs)
end

def highest_scoring_cards_in_game(game) do
Enum.reduce(game.players, [], fn player, cards -> (player.dealt_cards |> played_cards) ++ cards end) # Combine all played cards from all players
|> lead_suit_cards # Filter to just the lead suit cards
|> scoring_cards(Enum.count(game.players)) # Filter to just the cards that scored
|> Enum.group_by(fn card -> card.played_in_round end) # Convert to map where {round, [scoring_cards]}
|> Enum.flat_map(fn {_, cards} -> highest_card(cards) end) # Back to a list of just the highest scoring card in each round
end

def highest_scoring_cards_for_player(player, game) do
highest_scoring_cards_in_game(game)
|> Enum.filter(fn dealt_card -> dealt_card.player_id == player.id end)
end

def highest_scoring_card_in_round(game, round) do
highest_scoring_cards_in_game(game)
|> Enum.find(fn dealt_card -> dealt_card.played_in_round == round end)
end

defp highest_card(cards) do
card_order = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "JokerB", "JokerA"]

Enum.group_by(cards, fn dealt_card -> Enum.find_index(card_order, fn value -> value == dealt_card.card.value end) end)
|> Enum.max_by(fn {index, _cards} -> index end)
|> elem(1)
end

def unplayed_cards(cards) do
Enum.filter(cards, fn card -> card.played_in_round == nil end)
end

def played_cards(cards) do
Enum.filter(cards, fn card -> card.played_in_round != nil end)
end

def scoring_cards(cards, number_of_players) do
Enum.filter(cards, fn card -> card.played_in_round != nil && Enum.count(card.votes) > (number_of_players - 1) / 2 end)
end

def lead_suit_cards(cards) do
Enum.group_by(cards, fn card -> card.played_in_round end) # Convert to map where {round, [played_cards]}
|> Map.new(fn {round, played_cards} -> {round, Enum.sort_by(played_cards, &(&1.updated_at))} end) # Sort played cards in rounds by when played
|> Enum.flat_map(fn {_round, ordered_played_cards} -> Enum.filter(ordered_played_cards, fn card -> card.card.category == List.first(ordered_played_cards).card.category or card.card.value in ["JokerA", "JokerB"] or String.upcase(card.card.category) == "CORNUCOPIA" end) end) # Back to a list of just the lead suit cards in each round (plus jokers and trump cards)
end
end
45 changes: 4 additions & 41 deletions lib/copi_web/components/game_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ defmodule CopiWeb.GameComponents do
</thead>
<tbody id="players" class="divide-y divide-gray-200 bg-white">
<%= for {player, _index} <- Enum.with_index(@game.players) do %>
<% score = player.dealt_cards |> scoring_cards(Enum.count(@game.players)) |> Enum.count %>
<% highest_card_bonus = player |> highest_scoring_cards(@game) |> Enum.count %>
<% score = player.dealt_cards |> Copi.Cornucopia.scoring_cards(Enum.count(@game.players)) |> Enum.count %>
<% highest_card_bonus = player |> Copi.Cornucopia.highest_scoring_cards_for_player(@game) |> Enum.count %>
<tr>
<td class="whitespace-nowrap py-5 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6"><%= player.name %></td>
<td class="text-right whitespace-nowrap px-3 py-3.5 text-sm text-gray-500"><%= player.dealt_cards |> unplayed_cards |> Enum.count %></td>
<td class="text-right whitespace-nowrap px-3 py-4 text-sm text-gray-500"><%= player.dealt_cards |> played_cards |> Enum.count %></td>
<td class="text-right whitespace-nowrap px-3 py-3.5 text-sm text-gray-500"><%= player.dealt_cards |> Copi.Cornucopia.unplayed_cards |> Enum.count %></td>
<td class="text-right whitespace-nowrap px-3 py-4 text-sm text-gray-500"><%= player.dealt_cards |> Copi.Cornucopia.played_cards |> Enum.count %></td>
<td class="text-right whitespace-nowrap px-3 py-4 text-sm text-gray-500"><%= score %></td>
<td class="text-right whitespace-nowrap px-3 py-4 text-sm text-gray-500"><%= highest_card_bonus %></td>
<td class="text-right whitespace-nowrap px-3 py-4 text-sm text-gray-500"><strong><%= score + highest_card_bonus %></strong></td>
Expand All @@ -47,41 +47,4 @@ defmodule CopiWeb.GameComponents do
</div>
"""
end

defp highest_scoring_cards(player, game) do

Enum.reduce(game.players, [], fn player, cards -> (player.dealt_cards |> played_cards) ++ cards end) # Combine all played cards from all players
|> lead_suit_cards # Filter to just the lead suit cards
|> scoring_cards(Enum.count(game.players)) # Filter to just the cards that scored
|> Enum.group_by(fn card -> card.played_in_round end) # Convert to map where {round, [scoring_cards]}
|> Enum.flat_map(fn {_, cards} -> highest_scoring_cards(cards) end) # Back to a list of just the highest scoring card in each round
|> Enum.filter(fn dealt_card -> dealt_card.player_id == player.id end) # Filter out just the highest scoring cards for the player provided

end

defp highest_scoring_cards(cards) do
card_order = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "JokerB", "JokerA"]

Enum.group_by(cards, fn dealt_card -> Enum.find_index(card_order, fn value -> value == dealt_card.card.value end) end)
|> Enum.max_by(fn {index, _cards} -> index end)
|> elem(1)
end

defp unplayed_cards(cards) do
Enum.filter(cards, fn card -> card.played_in_round == nil end)
end

defp played_cards(cards) do
Enum.filter(cards, fn card -> card.played_in_round != nil end)
end

defp scoring_cards(cards, number_of_players) do
Enum.filter(cards, fn card -> card.played_in_round != nil && Enum.count(card.votes) > (number_of_players - 1) / 2 end)
end

defp lead_suit_cards(cards) do
Enum.group_by(cards, fn card -> card.played_in_round end) # Convert to map where {round, [played_cards]}
|> Map.new(fn {round, played_cards} -> {round, Enum.sort_by(played_cards, &(&1.updated_at))} end) # Sort played cards in rounds by when played
|> Enum.flat_map(fn {_round, ordered_played_cards} -> Enum.filter(ordered_played_cards, fn card -> card.card.category == List.first(ordered_played_cards).card.category or card.card.value in ["JokerA", "JokerB"] or String.upcase(card.card.category) == "CORNUCOPIA" end) end) # Back to a list of just the lead suit cards in each round (plus jokers and trump cards)
end
end

0 comments on commit 28d9edb

Please sign in to comment.