From c190be6a06b81d4928dadb12661f232395b0b66e Mon Sep 17 00:00:00 2001 From: LoseGameng Date: Thu, 15 May 2025 14:39:33 +0300 Subject: [PATCH 001/628] added the version display on the main screen --- .../templates/root/landing.html.heex | 3 +++ .../lib/codebattle_web/views/root_view.ex | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/services/app/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex b/services/app/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex index 3fc7f2717..6dc0e6e45 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex +++ b/services/app/apps/codebattle/lib/codebattle_web/templates/root/landing.html.heex @@ -387,6 +387,9 @@ CasperMosh

+

+ Version: <%= app_short_version() %> +

diff --git a/services/app/apps/codebattle/lib/codebattle_web/views/root_view.ex b/services/app/apps/codebattle/lib/codebattle_web/views/root_view.ex index 88bcd454f..574cf8c9c 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/views/root_view.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/views/root_view.ex @@ -5,6 +5,7 @@ defmodule CodebattleWeb.RootView do alias Codebattle.Feedback + @app_version Application.compile_env(:codebattle, :app_version) def csrf_token do Plug.CSRFProtection.get_csrf_token() end @@ -20,6 +21,20 @@ defmodule CodebattleWeb.RootView do Enum.map(Feedback.get_all(), &item/1) end + def app_short_version do + case @app_version do + "" -> "undefined" + version -> String.slice(version, 0, 7) + end + end + + def github_commit_link do + case @app_version do + "" -> "/" + version -> "https://github.com/hexlet-codebattle/codebattle/commit/#{version}" + end + end + defp item(%{title: title, description: description, pubDate: pub_date, link: link, guid: guid}) do """ From 0aa7a8bafd8c35c3cd62fa3dd072da1f3787a401 Mon Sep 17 00:00:00 2001 From: LoseGameng Date: Thu, 15 May 2025 15:16:05 +0300 Subject: [PATCH 002/628] remove black bar on right side in mobile view (iPad mini emulation) --- .../app/apps/codebattle/assets/css/style.scss | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/services/app/apps/codebattle/assets/css/style.scss b/services/app/apps/codebattle/assets/css/style.scss index b3194afc7..bba943639 100644 --- a/services/app/apps/codebattle/assets/css/style.scss +++ b/services/app/apps/codebattle/assets/css/style.scss @@ -774,6 +774,33 @@ main { width: 250px; min-width: 250px; } +@media screen and (min-width: $md) { + .main-nav { + padding-left: clamp(0.25rem, 1vw, 0.5rem); + padding-right: clamp(0.25rem, 1vw, 0.5rem); + } + + .main-nav .btn { + padding: clamp(0.2rem, 0.5vw, 0.5rem) clamp(0.4rem, 1vw, 0.75rem); + font-size: clamp(0.75rem, 1vw, 0.875rem); + } + + .main-nav img[src*="shields.io"] { + max-width: 100%; + width: clamp(60px, 10vw, 80px); + height: auto; + } + + .navbar-brand img { + max-height: clamp(28px, 5vw, 36px); + height: auto; + width: auto; + } + + .navbar-brand span { + font-size: clamp(13px, 1.5vw, 18px); + } +} @media (max-width: $xl) { .cb-heading { From 284a8190894b715357cd7b96aecbbbc5a39608ef Mon Sep 17 00:00:00 2001 From: GfxMod Date: Tue, 27 May 2025 23:15:35 +0300 Subject: [PATCH 003/628] Use mutable collections and remove explicit type declaration for default values (Kotlin) - Changed `listOf` to `mutableListOf` and `mapOf` to `mutableMapOf` for default array and hash values to allow mutation. - Removed explicit type declaration (`val ans: `) in favor of type inference with `var`. --- services/app/apps/runner/lib/runner/languages.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/app/apps/runner/lib/runner/languages.ex b/services/app/apps/runner/lib/runner/languages.ex index f22b86609..2b79b5f98 100644 --- a/services/app/apps/runner/lib/runner/languages.ex +++ b/services/app/apps/runner/lib/runner/languages.ex @@ -327,7 +327,7 @@ defmodule Runner.Languages do import kotlin.collections.* fun solution(<%= arguments %>):<%= expected %> { - val ans: <%= expected %> = <%= default_value %> + var ans = <%= default_value %> return ans } // <%= comment %> @@ -337,9 +337,9 @@ defmodule Runner.Languages do "integer" => "0", "float" => "0.1", "string" => "\"value\"", - "array" => "listOf(<%= value %>)", + "array" => "mutableListOf(<%= value %>)", "boolean" => "true", - "hash" => "mapOf(\"key\" to <%= value %>)" + "hash" => "mutableMapOf(\"key\" to <%= value %>)" }, expected_template: " <%= type %>", types: %{ From cf8364211c2cf5e1bb5c2a65f33d9467aef1eb2a Mon Sep 17 00:00:00 2001 From: vtm Date: Tue, 27 May 2025 23:03:53 +0200 Subject: [PATCH 004/628] Improve tournament performance --- .../lib/codebattle/tournament/server.ex | 88 +++++-- .../codebattle/tournament/strategy/base.ex | 215 +++++++++++------- .../test/runner/solution_generator_test.exs | 2 +- 3 files changed, 209 insertions(+), 96 deletions(-) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/server.ex b/services/app/apps/codebattle/lib/codebattle/tournament/server.ex index bf2fda7e7..2f63a4a3a 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/server.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/server.ex @@ -11,6 +11,7 @@ defmodule Codebattle.Tournament.Server do require Logger @type tournament_id :: pos_integer() + @tournament_info_table :tournament_info_cache @waiting_room_timeout_ms to_timeout(second: 1) # API def start_link(tournament_id) do @@ -26,7 +27,15 @@ defmodule Codebattle.Tournament.Server do end def get_tournament_info(id) do - GenServer.call(server_name(id), :get_tournament_info) + # Try to get from ETS cache first + case :ets.lookup(@tournament_info_table, id) do + [{^id, tournament_info}] -> + tournament_info + + [] -> + # Fall back to GenServer call if not in cache + GenServer.call(server_name(id), :get_tournament_info, 20_000) + end catch :exit, {:noproc, _} -> nil @@ -37,7 +46,7 @@ defmodule Codebattle.Tournament.Server do end def get_tournament(id) do - GenServer.call(server_name(id), :get_tournament) + GenServer.call(server_name(id), :get_tournament, 20_000) catch :exit, {:noproc, _} -> nil @@ -60,7 +69,8 @@ defmodule Codebattle.Tournament.Server do def finish_round_after(tournament_id, round_position, timeout_in_seconds) do GenServer.call( server_name(tournament_id), - {:finish_round_after, round_position, timeout_in_seconds} + {:finish_round_after, round_position, timeout_in_seconds}, + 30_000 ) catch :exit, reason -> @@ -82,7 +92,7 @@ defmodule Codebattle.Tournament.Server do end def handle_event(tournament_id, event_type, params) do - GenServer.call(server_name(tournament_id), {:fire_event, event_type, params}) + GenServer.call(server_name(tournament_id), {:fire_event, event_type, params}, 20_000) catch :exit, reason -> Logger.error("Error to send tournament update: #{inspect(reason)}") @@ -91,6 +101,11 @@ defmodule Codebattle.Tournament.Server do # SERVER def init(tournament_id) do + # Create tournament_info_cache table if it doesn't exist + if :ets.whereis(@tournament_info_table) == :undefined do + :ets.new(@tournament_info_table, [:named_table, :set, :public, read_concurrency: true]) + end + players_table = Tournament.Players.create_table(tournament_id) matches_table = Tournament.Matches.create_table(tournament_id) tasks_table = Tournament.Tasks.create_table(tournament_id) @@ -138,6 +153,23 @@ defmodule Codebattle.Tournament.Server do end def handle_call({:update, new_tournament}, _from, state) do + # Update the tournament_info cache when tournament is updated + tournament_info = + Map.drop(new_tournament, [ + :__struct__, + :__meta__, + :creator, + :event, + :matches, + :players, + :waiting_room_state, + :stats, + :played_pair_ids, + :round_tasks + ]) + + :ets.insert(@tournament_info_table, {new_tournament.id, tournament_info}) + broadcast_tournament_update(new_tournament) {:reply, :ok, %{state | tournament: new_tournament}} end @@ -167,19 +199,24 @@ defmodule Codebattle.Tournament.Server do end def handle_call(:get_tournament_info, _from, state) do - {:reply, - Map.drop(state.tournament, [ - :__struct__, - :__meta__, - :creator, - :event, - :matches, - :players, - :waiting_room_state, - :stats, - :played_pair_ids, - :round_tasks - ]), state} + tournament_info = + Map.drop(state.tournament, [ + :__struct__, + :__meta__, + :creator, + :event, + :matches, + :players, + :waiting_room_state, + :stats, + :played_pair_ids, + :round_tasks + ]) + + # Update the cache + :ets.insert(@tournament_info_table, {state.tournament.id, tournament_info}) + + {:reply, tournament_info, state} end def handle_call({:fire_event, event_type, params}, _from, %{tournament: tournament} = state) do @@ -192,6 +229,23 @@ defmodule Codebattle.Tournament.Server do apply(module, event_type, [tournament, params]) end + # Update the tournament_info cache when firing events + tournament_info = + Map.drop(new_tournament, [ + :__struct__, + :__meta__, + :creator, + :event, + :matches, + :players, + :waiting_room_state, + :stats, + :played_pair_ids, + :round_tasks + ]) + + :ets.insert(@tournament_info_table, {new_tournament.id, tournament_info}) + # TODO: rethink broadcasting during applying event, maybe put inside tournament module broadcast_tournament_event_by_type(event_type, params, new_tournament) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex index 2212cf366..d0b02d6e9 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex @@ -577,19 +577,33 @@ defmodule Codebattle.Tournament.Base do end defp start_round(tournament, round_params \\ %{}) do + # Perform initial updates in a single operation + tournament = + update_struct(tournament, %{ + break_state: "off", + last_round_started_at: NaiveDateTime.utc_now(:second), + match_timeout_seconds: Map.get(round_params, :timeout_seconds, tournament.match_timeout_seconds) + }) + + # Build and save round first - this is a critical operation + tournament = build_and_save_round!(tournament) + + # Perform these operations in sequence as they depend on each other + tournament = + tournament + |> maybe_preload_tasks() + |> maybe_set_round_task_ids() + |> maybe_start_round_timer() + |> maybe_activate_players() + + # Build matches - this is the most time-consuming part + tournament = build_round_matches(tournament, round_params) + + # Save to database + tournament = db_save!(tournament) + + # These operations can be done after the critical path tournament - |> update_struct(%{ - break_state: "off", - last_round_started_at: NaiveDateTime.utc_now(:second), - match_timeout_seconds: Map.get(round_params, :timeout_seconds, tournament.match_timeout_seconds) - }) - |> build_and_save_round!() - |> maybe_preload_tasks() - |> maybe_set_round_task_ids() - |> maybe_start_round_timer() - |> maybe_activate_players() - |> build_round_matches(round_params) - |> db_save!() |> maybe_start_waiting_room() |> broadcast_round_created() end @@ -648,40 +662,51 @@ defmodule Codebattle.Tournament.Base do defp bulk_create_round_games_and_matches(batch, tournament, task, timeout_seconds) do reset_task_ids = tournament.task_provider == "task_pack_per_round" - batch - |> Enum.map(fn - # TODO: skip bots game - # {[p1 = %{is_bot: true}, p2 = %{is_bot: true}], match_id} -> - # Tournament.Matches.put_match(tournament, %Tournament.Match{ - # id: match_id, - # state: "canceled", - # round_id: tournament.current_round_id, - # round_position: tournament.current_round_position, - # player_ids: Enum.sort([p1.id, p2.id]) - # }) - - {[p1, p2] = players, match_id} -> - %{ - players: players, - ref: match_id, - round_id: tournament.current_round_id, - state: "playing", - task: task, - waiting_room_name: tournament.waiting_room_name, - timeout_seconds: timeout_seconds, - tournament_id: tournament.id, - type: game_type(), - use_chat: tournament.use_chat, - use_timer: tournament.use_timer - } - |> maybe_set_free_task(tournament, p1) - |> maybe_add_award(tournament) - end) - |> Game.Context.bulk_create_games() - |> Enum.zip(batch) - |> Enum.each(fn {game, {players, _match_id}} -> - build_and_run_match(tournament, players, game, reset_task_ids) - end) + # Prepare game creation parameters in a single pass + game_params = + Enum.map(batch, fn + {[p1, p2] = players, match_id} -> + base_params = %{ + players: players, + ref: match_id, + round_id: tournament.current_round_id, + state: "playing", + task: task, + waiting_room_name: tournament.waiting_room_name, + timeout_seconds: timeout_seconds, + tournament_id: tournament.id, + type: game_type(), + use_chat: tournament.use_chat, + use_timer: tournament.use_timer + } + + # Apply transformations + params = + base_params + |> maybe_set_free_task(tournament, p1) + |> maybe_add_award(tournament) + + {params, players, match_id} + end) + + # Extract just the game parameters for bulk creation + game_creation_params = Enum.map(game_params, fn {params, _players, _match_id} -> params end) + + # Create games in bulk + created_games = Game.Context.bulk_create_games(game_creation_params) + + # Process matches in parallel using Task.async_stream with controlled concurrency + created_games + |> Enum.zip(game_params) + |> Task.async_stream( + fn {game, {_params, players, _match_id}} -> + build_and_run_match(tournament, players, game, reset_task_ids) + end, + max_concurrency: System.schedulers_online(), + ordered: false, + timeout: 30_000 + ) + |> Stream.run() end defp create_rematch_game(tournament, players, ref) do @@ -1026,43 +1051,77 @@ defmodule Codebattle.Tournament.Base do matches_to_finish = get_matches(tournament, "playing") finished_at = DateTime.utc_now(:second) - Enum.each( - matches_to_finish, - fn match -> - duration_sec = NaiveDateTime.diff(finished_at, match.started_at) - - player_results = improve_player_results(tournament, match, duration_sec) - Game.Context.trigger_timeout(match.game_id) + # Early return if no matches to finish + if matches_to_finish == [] do + tournament + else + # Process matches in parallel with Task.async_stream + match_results = + matches_to_finish + |> Task.async_stream( + fn match -> + duration_sec = NaiveDateTime.diff(finished_at, match.started_at) + + # Get player results and trigger timeout + player_results = improve_player_results(tournament, match, duration_sec) + Game.Context.trigger_timeout(match.game_id) + + # Create new match with timeout state + new_match = %{ + match + | state: "timeout", + player_results: player_results, + duration_sec: duration_sec, + finished_at: finished_at + } + + # Return match and player data for batch processing + {new_match, player_results} + end, + max_concurrency: System.schedulers_online() * 2, + timeout: 10_000 + ) + |> Enum.to_list() - new_match = %{ - match - | state: "timeout", - player_results: player_results, - duration_sec: duration_sec, - finished_at: finished_at - } + # Batch update matches and collect player updates + player_updates = + Enum.reduce(match_results, %{}, fn {:ok, {new_match, player_results}}, acc -> + # Update match in tournament + Tournament.Matches.put_match(tournament, new_match) - Tournament.Matches.put_match(tournament, new_match) + # Broadcast match update + Codebattle.PubSub.broadcast("tournament:match:upserted", %{ + tournament: tournament, + match: new_match + }) - Codebattle.PubSub.broadcast("tournament:match:upserted", %{ - tournament: tournament, - match: new_match - }) + # Collect player updates + Enum.reduce(player_results, acc, fn {player_id, result}, player_acc -> + player_score = result.score + player_lang = result.lang - player_results - |> Map.keys() - |> Enum.each(fn player_id -> - player = Tournament.Players.get_player(tournament, player_id) - - player && - Tournament.Players.put_player(tournament, %{ - player - | score: player.score + player_results[player_id].score, - lang: player_results[player_id].lang - }) + # credo:disable-for-next-line Credo.Check.Refactor.Nesting + Map.update(player_acc, player_id, %{score: player_score, lang: player_lang}, fn existing -> + %{score: existing.score + player_score, lang: player_lang} + end) + end) end) - end - ) + + # Batch update player scores + Enum.each(player_updates, fn {player_id, updates} -> + player = Tournament.Players.get_player(tournament, player_id) + + if player do + Tournament.Players.put_player(tournament, %{ + player + | score: player.score + updates.score, + lang: updates.lang + }) + end + end) + + tournament + end end defp improve_player_results(tournament, match, duration_sec) do diff --git a/services/app/apps/runner/test/runner/solution_generator_test.exs b/services/app/apps/runner/test/runner/solution_generator_test.exs index 41a953274..ae645128d 100644 --- a/services/app/apps/runner/test/runner/solution_generator_test.exs +++ b/services/app/apps/runner/test/runner/solution_generator_test.exs @@ -141,7 +141,7 @@ defmodule Runner.SolutionGeneratorTest do import kotlin.collections.* fun solution(a: Int, text: String, b: Double, c: Boolean, nested_hash_of_string: Map, nested_array_of_string: List, nested_array_of_array_of_strings: List>): List { - val ans: List = listOf("value") + var ans = mutableListOf("value") return ans } // use stdout to debug From 3ceca56520263ca07f8ff3764ee3acf635875dad Mon Sep 17 00:00:00 2001 From: vtm Date: Thu, 29 May 2025 11:49:29 +0200 Subject: [PATCH 005/628] Fix tournament --- .../codebattle/lib/codebattle/game/context.ex | 2 +- .../codebattle/lib/codebattle/game/engine.ex | 51 +- .../tournament/global_supervisor.ex | 6 + .../lib/codebattle/tournament/server.ex | 3 - .../codebattle/tournament/strategy/base.ex | 132 +--- .../codebattle/tournament/strategy/swiss.ex | 10 +- .../tournament/tournament_result.ex | 10 +- .../codebattle_web/channels/game_channel.ex | 1 + .../live/components/tournament/create_form.ex | 4 +- .../test/codebattle/game/context_test.exs | 2 +- .../tournament/tournament_result_test.exs | 581 +++--------------- .../arena_clan_95_percentile_test.exs | 6 +- .../tournament/arena_clan_test.exs | 6 +- 13 files changed, 173 insertions(+), 641 deletions(-) diff --git a/services/app/apps/codebattle/lib/codebattle/game/context.ex b/services/app/apps/codebattle/lib/codebattle/game/context.ex index 78423bb60..92555ddd4 100644 --- a/services/app/apps/codebattle/lib/codebattle/game/context.ex +++ b/services/app/apps/codebattle/lib/codebattle/game/context.ex @@ -231,7 +231,7 @@ defmodule Codebattle.Game.Context do end end - @spec trigger_timeout(game_id) :: :ok + @spec trigger_timeout(game_id) :: {:ok, Game.t()} def trigger_timeout(game_id) do game_id |> get_game!() |> Engine.trigger_timeout() end diff --git a/services/app/apps/codebattle/lib/codebattle/game/engine.ex b/services/app/apps/codebattle/lib/codebattle/game/engine.ex index df26edb3c..dbf58aee2 100644 --- a/services/app/apps/codebattle/lib/codebattle/game/engine.ex +++ b/services/app/apps/codebattle/lib/codebattle/game/engine.ex @@ -356,10 +356,12 @@ defmodule Codebattle.Game.Engine do |> Repo.update!() end + @spec update_game!(Game.t()) :: Game.t() + @spec update_game!(Game.t(), map()) :: Game.t() def update_game!(%Game{} = game) do case Repo.get(Game, game.id) do nil -> - :ok + game game -> game @@ -371,7 +373,7 @@ defmodule Codebattle.Game.Engine do def update_game!(%Game{} = game, params) do case Repo.get(Game, game.id) do nil -> - :ok + game game -> game @@ -386,37 +388,40 @@ defmodule Codebattle.Game.Engine do def trigger_timeout(%Game{state: "game_over"} = game) do terminate_game_after(game, 1) + {:ok, game} end def trigger_timeout(%Game{} = game) do Logger.debug("Trigger timeout for game: #{game.id}") {:ok, {old_game_state, new_game}} = fire_transition(game.id, :timeout, %{}) - case {old_game_state, new_game.state} do - {old_state, "timeout"} - when old_state in ["waiting_opponent", "playing"] -> - Codebattle.PubSub.broadcast("game:finished", %{game: new_game}) - - update_game!(new_game, %{ - state: get_state(new_game), - players: get_game_players(new_game), - duration_sec: new_game.duration_sec, - finishes_at: new_game.finishes_at - }) + new_game = + case {old_game_state, new_game.state} do + {old_state, "timeout"} + when old_state in ["waiting_opponent", "playing"] -> + Codebattle.PubSub.broadcast("game:finished", %{game: new_game}) + + update_game!(new_game, %{ + state: get_state(new_game), + players: get_game_players(new_game), + duration_sec: new_game.duration_sec, + finishes_at: new_game.finishes_at + }) - if game.tournament_id do - terminate_game_after(game, 1) - else - terminate_game_after(game, 15) - end + if game.tournament_id do + terminate_game_after(game, 1) + else + terminate_game_after(game, 15) + end - store_playbook_async(game) + store_playbook_async(game) + new_game - _ -> - :noop - end + _ -> + new_game + end - :ok + {:ok, new_game} end defp maybe_fire_playing_game_side_effects(%{state: "playing"} = game) do diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/global_supervisor.ex b/services/app/apps/codebattle/lib/codebattle/tournament/global_supervisor.ex index c18c14212..3c9ab9b7a 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/global_supervisor.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/global_supervisor.ex @@ -6,12 +6,18 @@ defmodule Codebattle.Tournament.GlobalSupervisor do require Logger + @tournament_info_table :tournament_info_cache + def start_link(_) do Supervisor.start_link(__MODULE__, [], name: __MODULE__) end @impl true def init(_) do + if :ets.whereis(@tournament_info_table) == :undefined do + :ets.new(@tournament_info_table, [:named_table, :set, :public, read_concurrency: true]) + end + Supervisor.init([], strategy: :one_for_one) end diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/server.ex b/services/app/apps/codebattle/lib/codebattle/tournament/server.ex index 2f63a4a3a..e6d3e0cfd 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/server.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/server.ex @@ -102,9 +102,6 @@ defmodule Codebattle.Tournament.Server do # SERVER def init(tournament_id) do # Create tournament_info_cache table if it doesn't exist - if :ets.whereis(@tournament_info_table) == :undefined do - :ets.new(@tournament_info_table, [:named_table, :set, :public, read_concurrency: true]) - end players_table = Tournament.Players.create_table(tournament_id) matches_table = Tournament.Matches.create_table(tournament_id) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex index d0b02d6e9..ce4a844b8 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex @@ -391,21 +391,6 @@ defmodule Codebattle.Tournament.Base do match = get_match(tournament, params.ref) winner_id = pick_game_winner_id(match.player_ids, params.player_results) - player_results = - Map.new(params.player_results, fn {player_id, result} -> - {player_id, - Map.put( - result, - :score, - get_score( - tournament.score_strategy, - match.level, - result.result_percent, - params.duration_sec - ) - )} - end) - params.player_results |> Map.keys() |> Enum.each(fn player_id -> @@ -414,20 +399,13 @@ defmodule Codebattle.Tournament.Base do if player do player = %{ player - | score: player.score + player_results[player_id].score, - lang: params.player_results[player_id].lang, + | lang: params.player_results[player_id].lang, wins_count: player.wins_count + - if(player_results[player_id].result == "won", do: 1, else: 0) + if(params.player_results[player_id].result == "won", do: 1, else: 0) } Tournament.Players.put_player(tournament, player) - - Tournament.Ranking.update_player_result( - tournament, - player, - player_results[player_id].score - ) end end) @@ -436,7 +414,7 @@ defmodule Codebattle.Tournament.Base do | state: params.game_state, winner_id: winner_id, duration_sec: params.duration_sec, - player_results: player_results, + player_results: params.player_results, finished_at: DateTime.utc_now(:second) } @@ -861,7 +839,6 @@ defmodule Codebattle.Tournament.Base do |> maybe_finish_waiting_room() |> set_stats() |> set_winner_ids() - # |> db_save!() |> maybe_save_event_results() |> db_save!(:with_ets) |> broadcast_tournament_finished() @@ -1056,37 +1033,22 @@ defmodule Codebattle.Tournament.Base do tournament else # Process matches in parallel with Task.async_stream - match_results = - matches_to_finish - |> Task.async_stream( - fn match -> - duration_sec = NaiveDateTime.diff(finished_at, match.started_at) - - # Get player results and trigger timeout - player_results = improve_player_results(tournament, match, duration_sec) - Game.Context.trigger_timeout(match.game_id) - - # Create new match with timeout state - new_match = %{ - match - | state: "timeout", - player_results: player_results, - duration_sec: duration_sec, - finished_at: finished_at - } - - # Return match and player data for batch processing - {new_match, player_results} - end, - max_concurrency: System.schedulers_online() * 2, - timeout: 10_000 - ) - |> Enum.to_list() + matches_to_finish + |> Task.async_stream( + fn match -> + # trigger game timeout and set player results + {:ok, game} = Game.Context.trigger_timeout(match.game_id) + + # Create new match with timeout state + new_match = %{ + match + | state: "timeout", + player_results: Game.Helpers.get_player_results(game), + duration_sec: game.duration_sec, + finished_at: finished_at + } - # Batch update matches and collect player updates - player_updates = - Enum.reduce(match_results, %{}, fn {:ok, {new_match, player_results}}, acc -> - # Update match in tournament + # Return match and player data for batch processing Tournament.Matches.put_match(tournament, new_match) # Broadcast match update @@ -1094,61 +1056,17 @@ defmodule Codebattle.Tournament.Base do tournament: tournament, match: new_match }) - - # Collect player updates - Enum.reduce(player_results, acc, fn {player_id, result}, player_acc -> - player_score = result.score - player_lang = result.lang - - # credo:disable-for-next-line Credo.Check.Refactor.Nesting - Map.update(player_acc, player_id, %{score: player_score, lang: player_lang}, fn existing -> - %{score: existing.score + player_score, lang: player_lang} - end) - end) - end) - - # Batch update player scores - Enum.each(player_updates, fn {player_id, updates} -> - player = Tournament.Players.get_player(tournament, player_id) - - if player do - Tournament.Players.put_player(tournament, %{ - player - | score: player.score + updates.score, - lang: updates.lang - }) - end - end) + end, + max_concurrency: System.schedulers_online() * 2, + timeout: 10_000 + ) + |> Stream.run() tournament end end - defp improve_player_results(tournament, match, duration_sec) do - case Game.Context.fetch_game(match.game_id) do - {:ok, %{is_live: true} = game} -> - game - |> Game.Helpers.get_player_results() - |> Map.new(fn {player_id, result} -> - {player_id, - Map.put( - result, - :score, - get_score( - tournament.score_strategy, - match.level, - result.result_percent, - duration_sec - ) - )} - end) - - {:error, _reason} -> - %{} - end - end - - defp maybe_add_award(game_params, tournament) do + defp maybe_add_award(game_params, %{type: "show"} = tournament) do tournament.meta |> Map.get(:rounds_config) |> case do @@ -1168,6 +1086,8 @@ defmodule Codebattle.Tournament.Base do end end + defp maybe_add_award(game_params, _tournament), do: game_params + defp maybe_set_free_task(game_params, %Tournament{type: "show", task_strategy: "sequential"} = tournament, player) do task_id = Enum.at(tournament.round_task_ids, Enum.count(player.task_ids)) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/swiss.ex b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/swiss.ex index 090d8cfe4..f26c7f3c3 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/swiss.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/swiss.ex @@ -20,10 +20,14 @@ defmodule Codebattle.Tournament.Swiss do def reset_meta(meta), do: meta @impl Tournament.Base - def finish_round_after_match?(%{current_round_position: current_round_position} = tournament) do - matches = get_round_matches(tournament, current_round_position) + def finish_round_after_match?(tournament) do + if tournament.players_count < 128 do + matches = get_round_matches(tournament, tournament.current_round_position) - Enum.all?(matches, &(&1.state != "playing")) + Enum.all?(matches, &(&1.state != "playing")) + else + false + end end @impl Tournament.Base diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/tournament_result.ex b/services/app/apps/codebattle/lib/codebattle/tournament/tournament_result.ex index c591231fb..28d10830e 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/tournament_result.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/tournament_result.ex @@ -64,10 +64,10 @@ defmodule Codebattle.Tournament.TournamentResult do task_id, count(*), case - when level = 'elementary' THEN 30.0 + when level = 'elementary' THEN 50.0 when level = 'easy' THEN 100.0 - when level = 'medium' THEN 300.0 - when level = 'hard' THEN 1000.0 + when level = 'medium' THEN 150.0 + when level = 'hard' THEN 200.0 end AS base_score, array_agg(duration_sec), max(duration_sec) as max_duration, @@ -226,8 +226,8 @@ defmodule Codebattle.Tournament.TournamentResult do }, where: r.tournament_id == ^tournament.id, group_by: [r.user_id, r.user_name, c.id], - order_by: [asc_nulls_first: sum(r.score)], - windows: [overall_partition: [order_by: [asc_nulls_first: sum(r.score), asc: sum(r.duration_sec)]]] + order_by: [desc: sum(r.score)], + windows: [overall_partition: [order_by: [desc_nulls_last: sum(r.score), asc: sum(r.duration_sec)]]] ) Repo.all(query) diff --git a/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex b/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex index 3fc39d10f..c9ff17573 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex @@ -25,6 +25,7 @@ defmodule CodebattleWeb.GameChannel do active_game_id = Tournament.Helpers.get_active_game_id(tournament, user_id) + # TODO: think about active_game_id {user_id, active_game_id} else {nil, nil} diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/create_form.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/create_form.ex index 312b9da8a..4c8b31220 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/create_form.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/create_form.ex @@ -264,9 +264,7 @@ defmodule CodebattleWeb.Live.Tournament.CreateFormComponent do
<%= label(f, :rounds_limit) %> - <%= select(f, :rounds_limit, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 137, 200], - class: "custom-select" - ) %> + <%= select(f, :rounds_limit, Enum.to_list(1..42), class: "custom-select") %> <%= error_tag(f, :rounds_limit) %>
diff --git a/services/app/apps/codebattle/test/codebattle/game/context_test.exs b/services/app/apps/codebattle/test/codebattle/game/context_test.exs index 91bb95522..db6e15caf 100644 --- a/services/app/apps/codebattle/test/codebattle/game/context_test.exs +++ b/services/app/apps/codebattle/test/codebattle/game/context_test.exs @@ -27,7 +27,7 @@ defmodule Codebattle.Game.ContextTest do game_topic = "game:#{game_id}" Codebattle.PubSub.subscribe(game_topic) - :ok = Game.Context.trigger_timeout(game_id) + {:ok, _new_game} = Game.Context.trigger_timeout(game_id) assert_received %Message{ event: "game:finished", diff --git a/services/app/apps/codebattle/test/codebattle/tournament/tournament_result_test.exs b/services/app/apps/codebattle/test/codebattle/tournament/tournament_result_test.exs index c2c51b895..50024aef0 100644 --- a/services/app/apps/codebattle/test/codebattle/tournament/tournament_result_test.exs +++ b/services/app/apps/codebattle/test/codebattle/tournament/tournament_result_test.exs @@ -34,7 +34,7 @@ defmodule Codebattle.Tournament.TournamenResultTest do user71 = insert(:user, name: "u71", clan_id: clan7.id) user81 = insert(:user, name: "u81", clan_id: clan8.id) - tournament = insert(:tournament, type: "arena", ranking_type: "by_player_95th_percentile") + tournament = insert(:tournament, type: "swiss", ranking_type: "by_player_95th_percentile", use_clan: false) insert_game(task4, tournament, user11, user21, 100, 100.0, 70.0) insert_game(task4, tournament, user12, user22, 200, 100.0, 60.0) @@ -62,261 +62,68 @@ defmodule Codebattle.Tournament.TournamenResultTest do insert_game(task2, tournament, user53, user71, 20, 100.0, 40.0) insert_game(task1, tournament, user11, user21, 100, 100.0, 10.0) - insert_game(task1, tournament, user71, user81, 10, 80.0, 10.0) + insert_game(task1, tournament, user71, user81, 10, 80.0, 5.0) TournamentResult.upsert_results(tournament) assert [ - %{ - user_name: "u11", - user_id: _, - clan_id: _, - wins_count: 4, - clan_name: "c1", - total_score: 1430, - total_duration_sec: 310, - clan_rank: 1 - }, - %{ - user_name: "u12", - user_id: _, - clan_id: _, - wins_count: 3, - clan_name: "c1", - total_score: 1321, - total_duration_sec: 332, - clan_rank: 1 - }, - %{ - user_name: "u13", - user_id: _, - clan_id: _, - wins_count: 3, - clan_name: "c1", - total_score: 1139, - total_duration_sec: 554, - clan_rank: 1 - }, - %{ - user_name: "u14", - user_id: _, - clan_id: _, - wins_count: 2, - clan_name: "c1", - total_score: 898, - total_duration_sec: 760, - clan_rank: 1 - }, - %{ - user_name: "u15", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c1", - total_score: 536, - total_duration_sec: 800, - clan_rank: 1 - }, - %{ - user_name: "u21", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 1063, - total_duration_sec: 310, - clan_rank: 2 - }, - %{ - user_name: "u22", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 868, - total_duration_sec: 332, - clan_rank: 2 - }, - %{ - user_name: "u23", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 634, - total_duration_sec: 554, - clan_rank: 2 - }, - %{ - user_name: "u24", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 405, - total_duration_sec: 760, - clan_rank: 2 - }, - %{ - user_name: "u25", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c2", - total_score: 161, - total_duration_sec: 800, - clan_rank: 2 - }, - %{ - user_name: "u31", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 195, - total_duration_sec: 180, - clan_rank: 3 - }, - %{ - user_name: "u32", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 166, - total_duration_sec: 200, - clan_rank: 3 - }, - %{ - user_name: "u33", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 137, - total_duration_sec: 220, - clan_rank: 3 - }, - %{ - user_name: "u34", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 108, - total_duration_sec: 240, - clan_rank: 3 - }, - %{ - user_name: "u35", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c3", - total_score: 90, - total_duration_sec: 260, - clan_rank: 3 - }, - %{ - user_name: "u41", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c4", - total_score: 98, - total_duration_sec: 180, - clan_rank: 4 - }, - %{ - user_name: "u42", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c4", - total_score: 66, - total_duration_sec: 200, - clan_rank: 4 - }, - %{ - user_name: "u43", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c4", - total_score: 41, - total_duration_sec: 220, - clan_rank: 4 - }, - %{ - user_name: "u44", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c4", - total_score: 22, - total_duration_sec: 240, - clan_rank: 4 - }, - %{ - user_name: "u51", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c5", - total_score: 57, - total_duration_sec: 16, - clan_rank: 5 - }, - %{ - user_name: "u52", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c5", - total_score: 42, - total_duration_sec: 18, - clan_rank: 5 - }, - %{ - user_name: "u53", - user_id: _, - clan_id: _, - wins_count: 1, - clan_name: "c5", - total_score: 30, - total_duration_sec: 20, - clan_rank: 5 - }, - %{ - user_name: "u61", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c6", - total_score: 34, - total_duration_sec: 16, - clan_rank: 6 - }, - %{ - user_name: "u62", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c6", - total_score: 21, - total_duration_sec: 18, - clan_rank: 6 - }, - %{ - user_name: "u71", - user_id: _, - clan_id: _, - wins_count: 0, - clan_name: "c7", - total_score: 45, - total_duration_sec: 290, - clan_rank: 7 - } + %{id: _, name: "u11", score: 500, clan: "c1", clan_id: _, place: 1}, + %{id: _, name: "u12", score: 419, clan: "c1", clan_id: _, place: 2}, + %{id: _, name: "u21", score: 370, clan: "c2", clan_id: _, place: 3}, + %{id: _, name: "u13", score: 363, clan: "c1", clan_id: _, place: 4}, + %{id: _, name: "u22", score: 298, clan: "c2", clan_id: _, place: 5}, + %{id: _, name: "u14", score: 247, clan: "c1", clan_id: _, place: 6}, + %{id: _, name: "u23", score: 221, clan: "c2", clan_id: _, place: 7}, + %{id: _, name: "u24", score: 121, clan: "c2", clan_id: _, place: 8}, + %{id: _, name: "u15", score: 107, clan: "c1", clan_id: _, place: 9}, + %{id: _, name: "u31", score: 98, clan: "c3", clan_id: _, place: 10}, + %{id: _, name: "u32", score: 83, clan: "c3", clan_id: _, place: 11}, + %{id: _, name: "u16", score: 79, clan: "c1", clan_id: _, place: 12}, + %{id: _, name: "u33", score: 68, clan: "c3", clan_id: _, place: 13}, + %{id: _, name: "u17", score: 60, clan: "c1", clan_id: _, place: 14}, + %{id: _, name: "u51", score: 57, clan: "c5", clan_id: _, place: 15}, + %{id: _, name: "u71", score: 56, clan: "c7", clan_id: _, place: 16}, + %{id: _, name: "u34", score: 54, clan: "c3", clan_id: _, place: 17}, + %{id: _, name: "u41", score: 49, clan: "c4", clan_id: _, place: 18}, + %{id: _, name: "u35", score: 45, clan: "c3", clan_id: _, place: 19}, + %{id: _, name: "u52", score: 42, clan: "c5", clan_id: _, place: 20}, + %{id: _, name: "u61", score: 34, clan: "c6", clan_id: _, place: 21}, + %{id: _, name: "u42", score: 33, clan: "c4", clan_id: _, place: 22}, + %{id: _, name: "u25", score: 32, clan: "c2", clan_id: _, place: 23}, + %{id: _, name: "u53", score: 30, clan: "c5", clan_id: _, place: 24}, + %{id: _, name: "u62", score: 21, clan: "c6", clan_id: _, place: 25}, + %{id: _, name: "u43", score: 20, clan: "c4", clan_id: _, place: 26}, + %{id: _, name: "u26", score: 16, clan: "c2", clan_id: _, place: 27}, + %{id: _, name: "u44", score: 11, clan: "c4", clan_id: _, place: 28}, + %{id: _, name: "u81", score: 8, clan: "c8", clan_id: _, place: 29} + ] = TournamentResult.get_user_ranking(tournament) + + assert [ + %{clan_rank: 1, total_duration_sec: 310, total_score: 500, user_name: "u11", wins_count: 4}, + %{clan_rank: 1, total_duration_sec: 332, total_score: 419, user_name: "u12", wins_count: 3}, + %{clan_rank: 1, total_duration_sec: 554, total_score: 363, user_name: "u13", wins_count: 3}, + %{clan_rank: 1, total_duration_sec: 760, total_score: 247, user_name: "u14", wins_count: 2}, + %{clan_rank: 1, total_duration_sec: 800, total_score: 107, user_name: "u15", wins_count: 1}, + %{clan_rank: 2, total_duration_sec: 310, total_score: 370, user_name: "u21", wins_count: 0}, + %{clan_rank: 2, total_duration_sec: 332, total_score: 298, user_name: "u22", wins_count: 0}, + %{clan_rank: 2, total_duration_sec: 554, total_score: 221, user_name: "u23", wins_count: 0}, + %{clan_rank: 2, total_duration_sec: 760, total_score: 121, user_name: "u24", wins_count: 0}, + %{clan_rank: 2, total_duration_sec: 800, total_score: 32, user_name: "u25", wins_count: 0}, + %{clan_rank: 3, total_duration_sec: 180, total_score: 98, user_name: "u31", wins_count: 1}, + %{clan_rank: 3, total_duration_sec: 200, total_score: 83, user_name: "u32", wins_count: 1}, + %{clan_rank: 3, total_duration_sec: 220, total_score: 68, user_name: "u33", wins_count: 1}, + %{clan_rank: 3, total_duration_sec: 240, total_score: 54, user_name: "u34", wins_count: 1}, + %{clan_rank: 3, total_duration_sec: 260, total_score: 45, user_name: "u35", wins_count: 1}, + %{clan_rank: 4, total_duration_sec: 16, total_score: 57, user_name: "u51", wins_count: 1}, + %{clan_rank: 4, total_duration_sec: 18, total_score: 42, user_name: "u52", wins_count: 1}, + %{clan_rank: 4, total_duration_sec: 20, total_score: 30, user_name: "u53", wins_count: 1}, + %{clan_rank: 5, total_duration_sec: 180, total_score: 49, user_name: "u41", wins_count: 0}, + %{clan_rank: 5, total_duration_sec: 200, total_score: 33, user_name: "u42", wins_count: 0}, + %{clan_rank: 5, total_duration_sec: 220, total_score: 20, user_name: "u43", wins_count: 0}, + %{clan_rank: 5, total_duration_sec: 240, total_score: 11, user_name: "u44", wins_count: 0}, + %{clan_rank: 6, total_duration_sec: 290, total_score: 56, user_name: "u71", wins_count: 0}, + %{clan_rank: 7, total_duration_sec: 16, total_score: 34, user_name: "u61", wins_count: 0}, + %{clan_rank: 7, total_duration_sec: 18, total_score: 21, user_name: "u62", wins_count: 0} ] = TournamentResult.get_top_users_by_clan_ranking(tournament) assert [ @@ -375,181 +182,39 @@ defmodule Codebattle.Tournament.TournamenResultTest do ] == TournamentResult.get_tasks_ranking(tournament) assert [ - %{clan_name: "c1", game_id: _, score: 1000, user_id: _, user_name: "u11"}, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 951, - user_id: _, - user_name: "u12" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 813, - user_id: _, - user_name: "u13" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 674, - user_id: _, - user_name: "u14" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 536, - user_id: _, - user_name: "u15" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 397, - user_id: _, - user_name: "u16" - }, - %{ - clan_id: _, - clan_name: "c1", - game_id: _, - score: 300, - user_id: _, - user_name: "u17" - } + %{clan_name: "c1", game_id: _, score: 200, user_id: _, user_name: "u11"}, + %{clan_name: "c1", game_id: _, score: 190, user_id: _, user_name: "u12"}, + %{clan_name: "c1", game_id: _, score: 163, user_id: _, user_name: "u13"}, + %{clan_name: "c1", game_id: _, score: 135, user_id: _, user_name: "u14"}, + %{clan_name: "c1", game_id: _, score: 107, user_id: _, user_name: "u15"}, + %{clan_name: "c1", game_id: _, score: 79, user_id: _, user_name: "u16"}, + %{clan_name: "c1", game_id: _, score: 60, user_id: _, user_name: "u17"} ] = TournamentResult.get_top_user_by_task_ranking(tournament, task4.id) assert [ - %{ - user_name: "u11", - user_id: _, - score: 300, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u12", - user_id: _, - score: 282, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u13", - user_id: _, - score: 253, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u14", - user_id: _, - score: 224, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u31", - user_id: _, - score: 195, - clan_id: _, - clan_name: "c3", - game_id: _ - }, - %{ - user_name: "u32", - user_id: _, - score: 166, - clan_id: _, - clan_name: "c3", - game_id: _ - }, - %{ - user_name: "u33", - user_id: _, - score: 137, - clan_id: _, - clan_name: "c3", - game_id: _ - }, - %{ - user_name: "u34", - user_id: _, - score: 108, - clan_id: _, - clan_name: "c3", - game_id: _ - }, - %{user_name: "u35", user_id: _, score: 90, clan_id: _, clan_name: "c3", game_id: _} + %{user_name: "u11", score: 150, clan_id: _, clan_name: "c1", game_id: _}, + %{user_name: "u12", score: 141, clan_id: _, clan_name: "c1", game_id: _}, + %{user_name: "u13", score: 127, clan_id: _, clan_name: "c1", game_id: _}, + %{user_name: "u14", score: 112, clan_id: _, clan_name: "c1", game_id: _}, + %{user_name: "u31", score: 98, clan_id: _, clan_name: "c3", game_id: _}, + %{user_name: "u32", score: 83, clan_id: _, clan_name: "c3", game_id: _}, + %{user_name: "u33", score: 68, clan_id: _, clan_name: "c3", game_id: _}, + %{user_name: "u34", score: 54, clan_id: _, clan_name: "c3", game_id: _}, + %{user_name: "u35", user_id: _, score: 45, clan_id: _, clan_name: "c3", game_id: _} ] = TournamentResult.get_top_user_by_task_ranking(tournament, task3.id) assert [ - %{ - user_name: "u11", - user_id: _, - score: 100, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u12", - user_id: _, - score: 88, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u13", - user_id: _, - score: 73, - clan_id: _, - clan_name: "c1", - game_id: _ - }, - %{ - user_name: "u51", - user_id: _, - score: 57, - clan_id: _, - clan_name: "c5", - game_id: _ - }, - %{ - user_name: "u52", - user_id: _, - score: 42, - clan_id: _, - clan_name: "c5", - game_id: _ - }, - %{user_name: "u53", user_id: _, score: 30, clan_id: _, clan_name: "c5", game_id: _} + %{user_name: "u11", score: 100, clan_id: _, clan_name: "c1", game_id: _}, + %{user_name: "u12", score: 88, clan_id: _, clan_name: "c1", game_id: _}, + %{user_name: "u13", score: 73, clan_id: _, clan_name: "c1", game_id: _}, + %{user_name: "u51", score: 57, clan_id: _, clan_name: "c5", game_id: _}, + %{user_name: "u52", score: 42, clan_id: _, clan_name: "c5", game_id: _}, + %{user_name: "u53", score: 30, clan_id: _, clan_name: "c5", game_id: _} ] = TournamentResult.get_top_user_by_task_ranking(tournament, task2.id) assert [ - %{ - user_name: "u11", - user_id: _, - score: 30, - clan_id: _, - clan_name: "c1", - game_id: _, - clan_long_name: "l1" - } - ] = - TournamentResult.get_top_user_by_task_ranking(tournament, task1.id) + %{user_name: "u11", user_id: _, score: 50, clan_id: _, clan_name: "c1", game_id: _, clan_long_name: "l1"} + ] = TournamentResult.get_top_user_by_task_ranking(tournament, task1.id) assert [%{start: 100, end: 100, wins_count: 0}] == TournamentResult.get_task_duration_distribution(tournament, task1.id) @@ -612,78 +277,14 @@ defmodule Codebattle.Tournament.TournamenResultTest do ] == TournamentResult.get_task_duration_distribution(tournament, task4.id) assert [ - %{ - clan_id: _, - clan_long_name: "l1", - clan_name: "c1", - performance: 860, - player_count: 7, - radius: 7, - total_score: 6021 - }, - %{ - clan_id: _, - clan_long_name: "l2", - clan_name: "c2", - performance: 535, - player_count: 6, - radius: 6, - total_score: 3210 - }, - %{ - clan_id: _, - clan_long_name: "l3", - clan_name: "c3", - performance: 139, - player_count: 5, - radius: 5, - total_score: 696 - }, - %{ - clan_id: _, - clan_long_name: "l4", - clan_name: "c4", - performance: 56, - player_count: 4, - radius: 4, - total_score: 227 - }, - %{ - clan_id: _, - clan_long_name: "l5", - clan_name: "c5", - performance: 43, - player_count: 3, - radius: 3, - total_score: 129 - }, - %{ - clan_id: _, - clan_long_name: "l6", - clan_name: "c6", - performance: 27, - player_count: 2, - radius: 2, - total_score: 55 - }, - %{ - clan_id: _, - clan_long_name: "l7", - clan_name: "c7", - performance: 45, - player_count: 1, - radius: 1, - total_score: 45 - }, - %{ - clan_id: _, - clan_long_name: "l8", - clan_name: "c8", - performance: 33, - player_count: 1, - radius: 1, - total_score: 33 - } + %{clan_name: "c1", performance: 253, player_count: 7, radius: 7, total_score: 1775}, + %{clan_name: "c2", performance: 176, player_count: 6, radius: 6, total_score: 1058}, + %{clan_name: "c3", performance: 69, player_count: 5, radius: 5, total_score: 348}, + %{clan_name: "c5", performance: 43, player_count: 3, radius: 3, total_score: 129}, + %{radius: 4, total_score: 113, clan_name: "c4", performance: 28, player_count: 4}, + %{radius: 1, total_score: 56, clan_name: "c7", performance: 56, player_count: 1}, + %{clan_name: "c6", performance: 27, player_count: 2, radius: 2, total_score: 55}, + %{clan_name: "c8", performance: 8, player_count: 1, radius: 1, total_score: 8} ] = TournamentResult.get_clans_bubble_distribution(tournament) end diff --git a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_95_percentile_test.exs b/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_95_percentile_test.exs index fc6cfb947..9432dbce7 100644 --- a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_95_percentile_test.exs +++ b/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_95_percentile_test.exs @@ -278,7 +278,7 @@ defmodule CodebattleWeb.Integration.Tournament.ArenaClan95PercentileTest do id: ^u1_id, state: "matchmaking_active", task_ids: [^t1_id], - score: 3, + score: 0, place: 0, wins_count: 1 } @@ -298,7 +298,7 @@ defmodule CodebattleWeb.Integration.Tournament.ArenaClan95PercentileTest do id: ^u1_id, state: "matchmaking_active", task_ids: [^t1_id], - score: 3, + score: 0, place: 0, wins_count: 1 } @@ -312,7 +312,7 @@ defmodule CodebattleWeb.Integration.Tournament.ArenaClan95PercentileTest do current_player: %{ state: "matchmaking_active", task_ids: [^t1_id], - score: 1, + score: 0, place: 0, wins_count: 0 } diff --git a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_test.exs b/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_test.exs index a491e9836..a93f235bb 100644 --- a/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_test.exs +++ b/services/app/apps/codebattle/test/codebattle_web/integration/tournament/arena_clan_test.exs @@ -272,7 +272,7 @@ defmodule CodebattleWeb.Integration.Tournament.ArenaClanTest do id: ^u1_id, state: "matchmaking_active", task_ids: [^t1_id], - score: 3, + score: 0, place: 0, wins_count: 1 } @@ -292,7 +292,7 @@ defmodule CodebattleWeb.Integration.Tournament.ArenaClanTest do id: ^u1_id, state: "matchmaking_active", task_ids: [^t1_id], - score: 3, + score: 0, place: 0, wins_count: 1 } @@ -306,7 +306,7 @@ defmodule CodebattleWeb.Integration.Tournament.ArenaClanTest do current_player: %{ state: "matchmaking_active", task_ids: [^t1_id], - score: 1, + score: 0, place: 0, wins_count: 0 } From 7ededa48ed10aae4f51031f8e64be3eec436ed48 Mon Sep 17 00:00:00 2001 From: vtm Date: Thu, 29 May 2025 12:18:03 +0200 Subject: [PATCH 006/628] Improve active_game_id --- .../lib/codebattle/tournament/helpers.ex | 16 ++++++++++------ .../lib/codebattle/tournament/strategy/base.ex | 12 +----------- .../lib/codebattle_web/channels/game_channel.ex | 1 - 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex b/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex index 54cfc6f76..cc87784b3 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex @@ -239,12 +239,16 @@ defmodule Codebattle.Tournament.Helpers do # end def get_active_game_id(tournament, player_id) do - tournament - |> get_matches("playing") - |> Enum.find(fn match -> player_id in match.player_ids end) - |> case do - nil -> nil - match -> match.game_id + player = get_player(tournament, player_id) + match_id = List.last(player.matches_ids) + + if match_id do + tournament + |> get_match(match_id) + |> case do + %{state: "playing"} -> match_id + _ -> nil + end end end diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex index ce4a844b8..14b5688f7 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex @@ -35,13 +35,6 @@ defmodule Codebattle.Tournament.Base do require Logger - @custom_round_tiemouts_in_sec %{ - "elementary" => 5 * 60, - "easy" => 6 * 60, - "medium" => 10 * 60, - "hard" => 25 * 60 - } - def add_player(tournament, player) do tournament_player = Tournament.Player.new!(player) Tournament.Players.put_player(tournament, tournament_player) @@ -967,11 +960,8 @@ defmodule Codebattle.Tournament.Base do end end - defp get_custom_round_timeout_seconds(tournament, nil), do: get_round_timeout_seconds(tournament) - defp get_custom_round_timeout_seconds(tournament, task) do - Map.get(@custom_round_tiemouts_in_sec, task.level) || - get_round_timeout_seconds(tournament) + (task && task.time_to_solve_sec) || get_round_timeout_seconds(tournament) end defp seconds_to_end_round(tournament) do diff --git a/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex b/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex index c9ff17573..3fc39d10f 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex @@ -25,7 +25,6 @@ defmodule CodebattleWeb.GameChannel do active_game_id = Tournament.Helpers.get_active_game_id(tournament, user_id) - # TODO: think about active_game_id {user_id, active_game_id} else {nil, nil} From 3e7276f1a2abd237a29c6ca90b751f557b065035 Mon Sep 17 00:00:00 2001 From: ReDBrother Date: Thu, 29 May 2025 19:16:16 +0300 Subject: [PATCH 007/628] fixes --- .../pages/tournament/PlayersRankingPanel.jsx | 153 +++++++++--------- .../lib/codebattle/bot/playbook_player.ex | 4 + .../tournament/ranking/by_player.ex | 2 +- 3 files changed, 83 insertions(+), 76 deletions(-) diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayersRankingPanel.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayersRankingPanel.jsx index 542049dda..c0cd72aef 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayersRankingPanel.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayersRankingPanel.jsx @@ -28,6 +28,8 @@ const tableDataCellClassName = cn( const PlayersRankingPanel = ({ playersCount, ranking }) => { const currentUserClanId = useSelector(currentUserClanIdSelector); + const rankingItems = ranking?.entries || []; + return (
@@ -37,85 +39,86 @@ const PlayersRankingPanel = ({ playersCount, ranking }) => { .

) : ( -
-
- {i18next.t('Ranking')} -
-
- - - - - - - - - - - {ranking?.entries?.map(item => ( - - {item.place > 3 ? ( - <> - + rankingItems.length !== 0 && ( +
+
+ {i18next.t('Ranking')} +
+
+
- {i18next.t('User')} - - {i18next.t('Clan')} - - {i18next.t('Score')} - - {i18next.t('Place')} -
+ + + + + + + + + + {rankingItems.map(item => ( + + {item.place > 3 ? ( + <> + + + + + ) : ( - - - ) : ( - - )} - - - + + + - - - - - ))} - -
+ {i18next.t('User')} + + {i18next.t('Clan')} + + {i18next.t('Score')} + + {i18next.t('Place')} +
-
+
- {item?.name.slice(0, 11) + (item?.name.length > 11 ? '...' : '')} - - -
+ {item?.name.slice(0, 11) + (item?.name.length > 11 ? '...' : '')} +
+
+
+ {item?.clan?.slice(0, 11) + (item?.clan?.length > 11 ? '...' : '')} +
+
{item.score} - {item?.clan?.slice(0, 11) + (item?.clan?.length > 11 ? '...' : '')} - - {item.score} - {item.place} -
+ {item.place} + + + + ))} + + +
-
- )} + ))}
diff --git a/services/app/apps/codebattle/lib/codebattle/bot/playbook_player.ex b/services/app/apps/codebattle/lib/codebattle/bot/playbook_player.ex index ffc153565..dee4f28d2 100644 --- a/services/app/apps/codebattle/lib/codebattle/bot/playbook_player.ex +++ b/services/app/apps/codebattle/lib/codebattle/bot/playbook_player.ex @@ -174,6 +174,10 @@ defmodule Codebattle.Bot.PlaybookPlayer do round(k / (player_rating + b)) end + defp get_bot_time_ms(_, _) do + 1000 * 120 + end + def stringify_keys(list) when is_list(list) do Enum.map(list, &stringify_keys/1) end diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/ranking/by_player.ex b/services/app/apps/codebattle/lib/codebattle/tournament/ranking/by_player.ex index a2ed98b98..d00302768 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/ranking/by_player.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/ranking/by_player.ex @@ -13,7 +13,7 @@ defmodule Codebattle.Tournament.Ranking.ByPlayer do end def get_nearest_page_by_player(_tournament, _player) do - [] + %{ entries: [] } end def get_page(_tournament, _page, page_size) do From e9590ed8b2f607db260fdbd76abc5f1d542c5927 Mon Sep 17 00:00:00 2001 From: ReDBrother Date: Thu, 29 May 2025 19:47:44 +0300 Subject: [PATCH 008/628] fixes --- .../codebattle/lib/codebattle/tournament/ranking/by_player.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/ranking/by_player.ex b/services/app/apps/codebattle/lib/codebattle/tournament/ranking/by_player.ex index d00302768..aabfc17cb 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/ranking/by_player.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/ranking/by_player.ex @@ -13,7 +13,7 @@ defmodule Codebattle.Tournament.Ranking.ByPlayer do end def get_nearest_page_by_player(_tournament, _player) do - %{ entries: [] } + %{entries: []} end def get_page(_tournament, _page, page_size) do From 3289c7bc232767945242dceb7804b64f2cc4a65d Mon Sep 17 00:00:00 2001 From: ReDBrother Date: Thu, 29 May 2025 20:06:45 +0300 Subject: [PATCH 009/628] fixe matchmaking --- .../app/apps/codebattle/lib/codebattle/tournament/helpers.ex | 4 ++++ .../codebattle/lib/codebattle/tournament/strategy/swiss.ex | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex b/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex index cc87784b3..ae81b07fb 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex @@ -14,6 +14,8 @@ defmodule Codebattle.Tournament.Helpers do def get_players(tournament, ids), do: Tournament.Players.get_players(tournament, ids) + def get_unbanned_players(tournament), do: tournament |> get_players() |> Enum.filter(&unbanned_player?(&1)) + def get_tasks(%{tasks_table: nil} = _tournament), do: [] def get_tasks(tournament), do: Tournament.Tasks.get_tasks(tournament) @@ -349,4 +351,6 @@ defmodule Codebattle.Tournament.Helpers do end def get_players_total_games_count(_tournament, player), do: Enum.count(player.matches_ids) + + defp unbanned_player?(player), do: player.state != "banned" end diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/swiss.ex b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/swiss.ex index f26c7f3c3..954a67299 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/swiss.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/swiss.ex @@ -82,7 +82,7 @@ defmodule Codebattle.Tournament.Swiss do player_pairs = tournament - |> get_players() + |> get_unbanned_players() |> Enum.sort_by(& &1.id) |> Enum.chunk_every(2) @@ -102,7 +102,7 @@ defmodule Codebattle.Tournament.Swiss do sorted_players = tournament - |> get_players() + |> get_unbanned_players() |> Enum.filter(&(&1.id > 0)) |> Enum.sort_by(& &1.score, :desc) From f838cad6dab0e7839fd260a73cd2f0bfa17c01a1 Mon Sep 17 00:00:00 2001 From: ReDBrother Date: Fri, 30 May 2025 09:58:48 +0300 Subject: [PATCH 010/628] fixe matchmaking --- .../lib/codebattle/tournament/helpers.ex | 18 +++++++++++------- .../codebattle_web/channels/game_channel.ex | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex b/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex index ae81b07fb..120ec2e29 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex @@ -242,14 +242,17 @@ defmodule Codebattle.Tournament.Helpers do def get_active_game_id(tournament, player_id) do player = get_player(tournament, player_id) - match_id = List.last(player.matches_ids) - if match_id do - tournament - |> get_match(match_id) - |> case do - %{state: "playing"} -> match_id - _ -> nil + if player do + match_id = List.last(player.matches_ids) + + if match_id do + tournament + |> get_match(match_id) + |> case do + %{state: "playing"} -> match_id + _ -> nil + end end end end @@ -350,6 +353,7 @@ defmodule Codebattle.Tournament.Helpers do t |> Tournament.Tasks.get_task_ids() |> Enum.count() end + def get_players_total_games_count(_tournament, nil), do: 0 def get_players_total_games_count(_tournament, player), do: Enum.count(player.matches_ids) defp unbanned_player?(player), do: player.state != "banned" diff --git a/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex b/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex index 3fc39d10f..d5bae6649 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/channels/game_channel.ex @@ -43,6 +43,8 @@ defmodule CodebattleWeb.GameChannel do %{entries: ranking} end) + banned? = current_player.state == 'banned' + {:ok, %{ active_game_id: active_game_id, @@ -63,6 +65,7 @@ defmodule CodebattleWeb.GameChannel do }, assign(socket, tournament_id: game.tournament_id, + banned?: banned?, game_id: game_id, follow_id: follow_id )} @@ -70,7 +73,7 @@ defmodule CodebattleWeb.GameChannel do {:ok, %{ game: GameView.render_game(game, score) - }, assign(socket, game_id: game_id, tournament_id: nil, follow_id: nil)} + }, assign(socket, game_id: game_id, tournament_id: nil, follow_id: nil, banned?: false)} end rescue e -> @@ -320,11 +323,23 @@ defmodule CodebattleWeb.GameChannel do end def handle_info(%{event: "user:banned", payload: %{player: player}}, socket) do + user_id = socket.assigns.current_user.id + + if (user_id == player.id) do + socket = assign(socket, banned?: true) + end + push(socket, "user:banned", %{user_id: player.id}) {:noreply, socket} end def handle_info(%{event: "user:unbanned", payload: %{player: player}}, socket) do + user_id = socket.assigns.current_user.id + + if (user_id == player.id) do + socket = assign(socket, banned?: false) + end + push(socket, "user:unbanned", %{user_id: player.id}) {:noreply, socket} end From 434295a14e859c144334e144d9ffe4d7224c5cdc Mon Sep 17 00:00:00 2001 From: vtm Date: Fri, 30 May 2025 09:04:03 +0200 Subject: [PATCH 011/628] add fixes --- .../js/widgets/pages/game/EditorToolbar.jsx | 4 - .../pages/game/TournamentStatisticsModal.jsx | 3 - .../pages/game/TournamentUserGameScore.jsx | 35 ----- .../pages/tournament/PlayerStatsPanel.jsx | 6 - .../pages/tournament/StatisticsCard.jsx | 16 ++- .../pages/tournament/TournamentPlace.jsx | 4 +- .../pages/tournament/UsersMatchList.jsx | 11 -- .../assets/js/widgets/selectors/index.js | 1 + .../js/widgets/utils/useMatchesStatistics.js | 15 +-- .../codebattle/lib/codebattle/game/context.ex | 8 ++ .../codebattle/lib/codebattle/game/engine.ex | 10 +- .../lib/codebattle/tournament/helpers.ex | 20 +-- .../codebattle/tournament/strategy/base.ex | 124 ++++++++---------- .../codebattle/tournament/strategy/swiss.ex | 10 +- .../codebattle_web/channels/game_channel.ex | 1 + .../codebattle_web/channels/main_channel.ex | 6 +- .../channels/tournament_admin_channel.ex | 2 +- 17 files changed, 110 insertions(+), 166 deletions(-) delete mode 100644 services/app/apps/codebattle/assets/js/widgets/pages/game/TournamentUserGameScore.jsx diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/game/EditorToolbar.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/game/EditorToolbar.jsx index 99e51caf3..ba90620ce 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/game/EditorToolbar.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/game/EditorToolbar.jsx @@ -11,7 +11,6 @@ import GameActionButtons from './GameActionButtons'; import GameBanPlayerButton from './GameBanPlayerButton'; import GameReportButton from './GameReportButton'; import GameResultIcon from './GameResultIcon'; -import TournamentUserGameScore from './TournamentUserGameScore'; import UserGameScore from './UserGameScore'; import VimModeButton from './VimModeButton'; @@ -80,9 +79,6 @@ const EditorToolbar = ({ {mode === GameRoomModes.standard && ( )} - {mode === GameRoomModes.tournament && ( - - )}
diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/game/TournamentStatisticsModal.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/game/TournamentStatisticsModal.jsx index 3657798a5..60e451950 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/game/TournamentStatisticsModal.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/game/TournamentStatisticsModal.jsx @@ -74,7 +74,6 @@ const TournamentStatisticsModal = NiceModal.create(() => {
{firstPlayer?.name} - {player.score} {player.winMatches.length} {Math.ceil(player.avgTests)} @@ -87,14 +86,12 @@ const TournamentStatisticsModal = NiceModal.create(() => {
Player - Score Wins AVG Tests AVG Solving speed
{secondPlayer?.name} - {opponent.score} {opponent.winMatches.length} {Math.ceil(opponent.avgTests)} diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/game/TournamentUserGameScore.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/game/TournamentUserGameScore.jsx deleted file mode 100644 index 57a5d663a..000000000 --- a/services/app/apps/codebattle/assets/js/widgets/pages/game/TournamentUserGameScore.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useMemo, memo } from 'react'; - -import cn from 'classnames'; -import { useSelector } from 'react-redux'; - -import { tournamentSelector } from '@/selectors'; -import useMatchesStatistics from '@/utils/useMatchesStatistics'; - -function TournamentUserGameScore({ userId }) { - const { type, matches, currentRoundPosition } = useSelector(tournamentSelector); - const roundMatches = useMemo(() => ( - Object.values(matches || {}).filter(match => match.roundPosition === currentRoundPosition) - ), [matches, currentRoundPosition]); - - const [player, opponent] = useMatchesStatistics(userId, roundMatches); - - if (type !== 'swiss' || roundMatches.length === 0) { - return null; - } - - const scoreResultClass = cn('ml-2', { - 'cb-game-score-won': player.score > opponent.score, - 'cb-game-score-lost': player.score < opponent.score, - 'cb-game-score-draw': player.score === opponent.score, - }); - - return ( -
- Score: - {player.score} -
- ); -} - -export default memo(TournamentUserGameScore); diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayerStatsPanel.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayerStatsPanel.jsx index 24addfb79..00770aad9 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayerStatsPanel.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayerStatsPanel.jsx @@ -115,9 +115,6 @@ function PlayerStatsPanel({ )}
- - -