Skip to content

Commit

Permalink
Add ets to tournaments
Browse files Browse the repository at this point in the history
  • Loading branch information
vtm9 committed Nov 28, 2023
1 parent 946c182 commit 445a037
Show file tree
Hide file tree
Showing 14 changed files with 378 additions and 239 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import axios from 'axios';
import Gon from 'gon';
import { camelizeKeys } from 'humps';
import compact from 'lodash/compact';

import socket from '../../socket';
import TournamentStates from '../config/tournament';
Expand All @@ -25,10 +26,15 @@ const initTournamentChannel = dispatch => {

dispatch(actions.setTournamentData({
...data.tournament,
matches: {},
players: {},
channel: { online: true },
playersPageNumber: 1,
playersPageSize: 20,
}));

dispatch(actions.updateTournamentPlayers(compact(data.players)));
dispatch(actions.updateTournamentMatches(data.matches));
};

channel
Expand Down Expand Up @@ -100,7 +106,7 @@ export const connectToTournament = () => dispatch => {
dispatch(actions.removeTournamentPlayer(data));
};

const handleMatchCreated = response => {
const handleMatchUpserted = response => {
const data = camelizeKeys(response);

dispatch(actions.updateTournamentMatches([data.match]));
Expand All @@ -122,7 +128,7 @@ export const connectToTournament = () => dispatch => {
channel.on('tournament:start', handleTournamentStart),
channel.on('tournament:player:joined', handlePlayerJoined),
channel.on('tournament:player:left', handlePlayerLeft),
channel.on('tournament:match:created', handleMatchCreated),
channel.on('tournament:match:upserted', handleMatchUpserted),
channel.on('tournament:restarted', handleTournamentRestarted),
];

Expand All @@ -137,7 +143,7 @@ export const connectToTournament = () => dispatch => {
oldChannel.off('tournament:start', refs[5]);
oldChannel.off('tournament:player:joined', refs[6]);
oldChannel.off('tournament:player:left', refs[7]);
oldChannel.off('tournament:match:created', refs[8]);
oldChannel.off('tournament:match:upserted', refs[8]);
oldChannel.off('tournament:restarted', refs[9]);
};

Expand Down
6 changes: 3 additions & 3 deletions services/app/apps/codebattle/lib/codebattle/pub_sub/events.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ defmodule Codebattle.PubSub.Events do
def get_messages("tournament:round_finished", params) do
players =
params.tournament
|> Tournament.Helpers.get_players()
|> Tournament.Helpers.get_top_players()
|> Enum.map(&Map.take(&1, [:id, :place, :score]))

[
Expand Down Expand Up @@ -129,11 +129,11 @@ defmodule Codebattle.PubSub.Events do
]
end

def get_messages("tournament:match:created", params) do
def get_messages("tournament:match:upserted", params) do
Enum.map(params.match.player_ids, fn player_id ->
%Message{
topic: "tournament:#{params.tournament_id}:player:#{player_id}",
event: "tournament:match:created",
event: "tournament:match:upserted",
payload: %{match: params.match}
}
end)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,15 @@ defmodule Codebattle.Tournament.Context do
import Ecto.Changeset

@type tournament_id :: pos_integer() | String.t()
@type user :: %{id: pos_integer() | String.t(), name: String.t()}

@states_from_restore ["waiting_participants"]
@max_alive_tournaments 7

@spec get_tournament_for_user(tournament_id(), user()) :: Tournament.t() | map()
def get_tournament_for_user(tournament_id, user) do
case Tournament.Server.get_tournament_for_user(tournament_id, user) do
nil ->
get_from_db!(tournament_id)

tournament_info ->
tournament_info
@spec get_tournament_info(tournament_id()) :: Tournament.t() | map()
def get_tournament_info(tournament_id) do
case Tournament.Server.get_tournament_info(tournament_id) do
nil -> get_from_db!(tournament_id)
tournament_info -> tournament_info
end
end

Expand Down
116 changes: 84 additions & 32 deletions services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex
Original file line number Diff line number Diff line change
@@ -1,21 +1,86 @@
defmodule Codebattle.Tournament.Helpers do
alias Codebattle.User
alias Codebattle.Tournament

def get_player(tournament, id), do: Map.get(tournament.players, to_id(id))
def get_players(tournament), do: tournament.players |> Map.values()
def get_players(tournament, ids), do: Enum.map(ids, &get_player(tournament, &1))
def get_match(tournament, id), do: Map.get(tournament.matches, to_id(id))
def get_matches(tournament), do: tournament.matches |> Map.values()
def get_matches(tournament, range = %Range{}), do: Enum.map(range, &get_match(tournament, &1))
def get_player(tournament = %{players_table: nil}, id),
do: Map.get(tournament.players, id)

def get_matches(tournament, state) when is_binary(state) do
tournament |> get_matches() |> Enum.filter(&(&1.state == state))
def get_player(tournament, id), do: Tournament.Players.get_player(tournament, id)

def get_players(tournament = %{players_table: nil}), do: tournament.players |> Map.values()
def get_players(tournament), do: Tournament.Players.get_players(tournament)

def get_players(tournament = %{players_table: nil}, ids),
do: Enum.map(ids, &get_player(tournament, &1))

def get_players(tournament, ids), do: Tournament.Players.get_players(tournament, ids)

def players_count(tournament = %{players_table: nil}) do
tournament |> get_players() |> Enum.count()
end

def get_matches_by_ids(tournament, matches_ids) do
Enum.map(matches_ids, &get_match(tournament, &1))
def players_count(tournament) do
Tournament.Players.count(tournament)
end

def get_paginated_players(tournament = %{players_table: nil}, _page_num, _page_size) do
# return all players, cause we don't want to paginate if tournament finished
get_players(tournament)
end

def get_paginated_players(tournament, page_num, page_size) do
start_index = (page_num - 1) * page_size
end_index = start_index + page_size - 1

tournament
|> get_players()
|> Enum.sort_by(& &1.place)
|> Enum.slice(start_index..end_index)
end

def get_top_players(tournament = %{players_table: nil}, _page_num, _page_size) do
# return all players, cause we don't want to paginate if tournament finished
get_players(tournament)
end

# only for waiting_participants, cause all players have score = 0
# we don't care about ordering
def get_top_players(tournament = %{type: type, top_player_ids: []})
when type in ["swiss", "ladder", "stairway"] do
tournament |> get_players() |> Enum.take(30)
end

# we don't want to cut plaeyrs for team/individual tournaments for players
def get_top_players(tournament = %{top_player_ids: []}) do
get_players(tournament)
end

def get_top_players(tournament = %{top_player_ids: ids}) do
get_players(tournament, ids)
end

def players_count(tournament, team_id) do
tournament |> get_team_players(team_id) |> Enum.count()
end

def get_match(tournament = %{matches_table: nil}, id),
do: Map.get(tournament.matches, id)

def get_match(tournament, id), do: Tournament.Matches.get_match(tournament, id)

def get_matches(tournament = %{matches_table: nil}), do: tournament.matches |> Map.values()
def get_matches(tournament), do: Tournament.Matches.get_matches(tournament)

def get_matches(tournament = %{matches_table: nil}, ids) when is_list(ids),
do: Enum.map(ids, &get_match(tournament, &1))

def get_matches(tournament = %{matches_table: nil}, state) when is_binary(state) do
tournament |> get_matches() |> Enum.filter(&(&1.state == state))
end

def get_matches(tournament, ids_or_state),
do: Tournament.Matches.get_matches(tournament, ids_or_state)

def get_matches_by_players(tournament, player_ids) do
matches_ids =
tournament
Expand All @@ -24,7 +89,7 @@ defmodule Codebattle.Tournament.Helpers do
|> Enum.flat_map(& &1.matches_ids)
|> Enum.uniq()

get_matches_by_ids(tournament, matches_ids)
get_matches(tournament, matches_ids)
end

def get_round_matches(tournament) do
Expand All @@ -34,9 +99,11 @@ defmodule Codebattle.Tournament.Helpers do
|> Enum.chunk_by(& &1.round)
end

def matches_count(t), do: Tournament.Matches.count(t)

def get_current_round_matches(tournament) do
tournament
|> get_matches
|> get_matches()
|> Enum.filter(&(&1.round == tournament.current_round))
end

Expand All @@ -46,29 +113,14 @@ defmodule Codebattle.Tournament.Helpers do

def get_current_round_playing_matches(tournament) do
tournament
|> get_matches
|> get_matches()
|> Enum.filter(&(&1.round == tournament.current_round and &1.state == "playing"))
end

def get_first_match(tournament),
do: tournament.matches |> Map.get(to_id(0))

def is_match_player?(match, player_id), do: Enum.any?(match.player_ids, &(&1 == player_id))

def get_player_ids(tournament), do: tournament |> get_players |> Enum.map(& &1.id)

def players_count(tournament) do
tournament |> get_players() |> Enum.count()
end

def players_count(tournament, team_id) do
tournament |> get_team_players(team_id) |> Enum.count()
end

def matches_count(tournament) do
tournament |> get_matches() |> Enum.count()
end

def can_be_started?(tournament = %{state: "waiting_participants"}) do
players_count(tournament) > 0
end
Expand Down Expand Up @@ -100,15 +152,15 @@ defmodule Codebattle.Tournament.Helpers do
def in_break?(tournament), do: tournament.break_state == "on"

def is_player?(tournament, player_id) do
tournament.players
|> Map.get(to_id(player_id))
tournament
|> get_player(player_id)
|> Kernel.!()
|> Kernel.!()
end

def is_player?(tournament, player_id, team_id) do
tournament.players
|> Map.get(to_id(player_id))
tournament
|> get_player(player_id)
|> case do
%{team_id: ^team_id} -> true
_ -> false
Expand Down
51 changes: 51 additions & 0 deletions services/app/apps/codebattle/lib/codebattle/tournament/matches.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
defmodule Codebattle.Tournament.Matches do
def create_table do
:ets.new(:t_matches, [:set, :public, {:write_concurrency, true}, {:read_concurrency, true}])
end

def put_match(tournament, match) do
:ets.insert(tournament.matches_table, {match.id, match.state, match})
end

def get_match(tournament, match_id) do
:ets.lookup_element(tournament.matches_table, match_id, 3)
rescue
_e ->
nil
end

def get_matches(tournament) do
:ets.select(tournament.matches_table, [{{:"$1", :"$2", :"$3"}, [], [:"$3"]}])
end

def get_matches(tournament, matches_ids) when is_list(matches_ids) do
Enum.map(matches_ids, fn match_id ->
get_match(tournament, match_id)
end)
end

def get_matches(tournament, state) when is_binary(state) do
:ets.select(tournament.matches_table, [{{:"$1", state, :"$3"}, [], [:"$3"]}])
end

def count(tournament) do
:ets.select_count(tournament.matches_table, [{:_, [], [true]}])
end
end

alias Codebattle.Tournament.Matches, as: M
table = M.create_table()
t = %{matches_table: table}

M.put_match(t, %{id: 1, game_id: 1, state: "canceled", player_ids: [1, 2]})
M.put_match(t, %{id: 2, game_id: 2, state: "canceled", player_ids: [3, 4]})
M.put_match(t, %{id: 3, game_id: 3, state: "game_over", player_ids: [1, 2]})
M.put_match(t, %{id: 4, game_id: 4, state: "timeout", player_ids: [3, 4]})
M.put_match(t, %{id: 5, game_id: 5, state: "playing", player_ids: [1, 2]})
M.put_match(t, %{id: 6, game_id: 6, state: "playing", player_ids: [3, 4]})

M.get_match(t, 1)
M.get_matches(t)
M.get_matches(t, [2, 3])
M.get_matches(t, "playing")
M.get_matches(t, "canceled")
30 changes: 30 additions & 0 deletions services/app/apps/codebattle/lib/codebattle/tournament/players.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule Codebattle.Tournament.Players do
def create_table do
:ets.new(:t_players, [:set, :public, {:write_concurrency, true}, {:read_concurrency, true}])
end

def count(tournament) do
:ets.select_count(tournament.players_table, [{:_, [], [true]}])
end

def put_player(tournament, player) do
:ets.insert(tournament.players_table, {player.id, player})
end

def get_player(tournament, player_id) do
:ets.lookup_element(tournament.players_table, player_id, 2)
rescue
_e ->
nil
end

def get_players(tournament) do
:ets.select(tournament.players_table, [{{:"$1", :"$2"}, [], [:"$2"]}])
end

def get_players(tournament, player_ids) do
Enum.map(player_ids, fn player_id ->
get_player(tournament, player_id)
end)
end
end
Loading

0 comments on commit 445a037

Please sign in to comment.