Skip to content

Commit ee18bb4

Browse files
committed
Improve
1 parent d55e86b commit ee18bb4

15 files changed

Lines changed: 988 additions & 197 deletions

File tree

apps/codebattle/assets/js/widgets/pages/groupTournament/GroupTournamentPage.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ function GroupTournamentPage({
4747
useGroupBattleRun(data);
4848

4949
const isAdmin = useSelector(selectors.currentUserIsAdminSelector);
50+
const currentUserId = useSelector(selectors.currentUserIdSelector);
5051

5152
const requestInviteUpdates = () => {
5253
requestInviteUpdate()(dispatch);
@@ -113,6 +114,7 @@ function GroupTournamentPage({
113114
leaderboard={data?.leaderboard}
114115
roundsCount={data?.groupTournament?.roundsCount}
115116
currentRoundPosition={data?.groupTournament?.currentRoundPosition}
117+
currentUserId={currentUserId}
116118
/>
117119
</div>
118120
</div>

apps/codebattle/assets/js/widgets/pages/groupTournament/Leaderboard.jsx

Lines changed: 304 additions & 105 deletions
Large diffs are not rendered by default.

apps/codebattle/assets/js/widgets/pages/groupTournament/MainPanel.jsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ function MainPanel({
1212
roundsCount,
1313
currentRoundPosition,
1414
status,
15+
currentUserId,
1516
}) {
1617
const [openJson, setOpenJson] = useState(null); // "history" | "summary" | null
1718
const [activeTab, setActiveTab] = useState("run"); // "run" | "leaderboard"
@@ -23,11 +24,12 @@ function MainPanel({
2324
const summary = run?.result?.summary;
2425
const hasHistory = history != null;
2526
const hasSummary = summary != null;
27+
// Show the leaderboard tab for every multi-player tournament regardless of
28+
// round count or how far along the tournament is — players want to see
29+
// current standings even before round 1 is over, and single-round
30+
// tournaments still benefit from the slice/seed views.
2631
const hasLeaderboard =
27-
Array.isArray(leaderboard) &&
28-
leaderboard.length > 0 &&
29-
Number.isInteger(roundsCount) &&
30-
roundsCount > 1;
32+
Array.isArray(leaderboard) && leaderboard.length > 0 && Number.isInteger(roundsCount);
3133

3234
const tabBtnClass = (active) =>
3335
`btn btn-sm px-3 mr-2 text-white shadow-none border-0 rounded-0 ${
@@ -84,6 +86,7 @@ function MainPanel({
8486
roundsCount={roundsCount}
8587
currentRoundPosition={currentRoundPosition}
8688
isFinished={status === "finished"}
89+
currentUserId={currentUserId}
8790
/>
8891
</div>
8992
</>

apps/codebattle/assets/js/widgets/slices/groupTournament.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ const groupTournament = createSlice({
7373
state.langSlug = payload;
7474
},
7575
setData: (state, { payload }) => {
76-
state.data = payload;
76+
// Merge so a later-arriving REST snapshot can't wipe fields that only
77+
// the channel push includes (notably `leaderboard`). Both sources race
78+
// on initial page load.
79+
state.data = { ...(state.data || {}), ...(payload || {}) };
7780
},
7881
setActiveRunIdFromServer: (state, { payload }) => {
7982
state.activeRunIdFromServer = payload;

apps/codebattle/lib/codebattle/group_task/context.ex

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -525,17 +525,23 @@ defmodule Codebattle.GroupTask.Context do
525525

526526
round_position = tournament.current_round_position
527527

528+
# Dense-rank humans only: when a slice is bot-filled, the runner ranks
529+
# bots inline (e.g. a bot may take #1), leaving gaps in the surviving
530+
# human places. Strip the bots first, then re-number 1..N by their raw
531+
# rank so partial slices score and display contiguously.
528532
runs
529533
|> Enum.map(fn run ->
530534
user_id = run.user_group_tournament && run.user_group_tournament.user_id
531-
place = extract_place_for_user(_user_ranking(run), user_id)
532-
{user_id, place, run.id}
535+
raw_place = extract_place_for_user(_user_ranking(run), user_id)
536+
{user_id, raw_place, run.id}
533537
end)
534538
|> Enum.filter(fn {user_id, place, _} -> is_integer(user_id) and is_integer(place) end)
535-
|> Enum.each(fn {user_id, place, run_id} ->
536-
round_points = Scoring.round_points(tournament.scoring_strategy, slice_index, place, opts)
537-
bump_player_score(tournament.id, user_id, round_points, place)
538-
record_round_score(tournament.id, user_id, run_id, round_position, slice_index, place, round_points)
539+
|> Enum.sort_by(fn {_uid, place, _rid} -> place end)
540+
|> Enum.with_index(1)
541+
|> Enum.each(fn {{user_id, _raw_place, run_id}, dense_place} ->
542+
round_points = Scoring.round_points(tournament.scoring_strategy, slice_index, dense_place, opts)
543+
bump_player_score(tournament.id, user_id, round_points, dense_place)
544+
record_round_score(tournament.id, user_id, run_id, round_position, slice_index, dense_place, round_points)
539545
end)
540546
end
541547

apps/codebattle/lib/codebattle/group_tournament/context.ex

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -620,49 +620,49 @@ defmodule Codebattle.GroupTournament.Context do
620620
|> Enum.group_by(& &1.user_id)
621621

622622
players
623-
|> Enum.map(fn player ->
624-
rounds =
625-
round_scores
626-
|> Map.get(player.user_id, [])
627-
|> Map.new(fn rs ->
628-
{rs.round_position,
629-
%{
630-
slice_index: rs.slice_index,
631-
place: rs.place,
632-
score: rs.score
633-
}}
634-
end)
635-
636-
# Synthesise R1 from the seeding pass so the UI can show the seed score
637-
# in the R1 column. Seeding runs solo-against-bots, so there's no
638-
# cross-player place; we still surface the score (and the initial slice
639-
# the player landed in) without touching total_score.
640-
rounds =
641-
if is_integer(player.seed_score) and not Map.has_key?(rounds, 1) do
642-
Map.put(rounds, 1, %{
643-
slice_index: player.slice_index,
644-
place: nil,
645-
score: player.seed_score
646-
})
647-
else
648-
rounds
649-
end
623+
|> Enum.map(&build_leaderboard_entry(&1, round_scores))
624+
|> Enum.sort_by(fn entry ->
625+
{-(entry.total_score || 0), -(entry.seed_score || 0), entry.user_id}
626+
end)
627+
end
650628

651-
%{
652-
user_id: player.user_id,
653-
name: player.user && player.user.name,
654-
avatar_url: player.user && Map.get(player.user, :avatar_url),
655-
clan: player.user && Map.get(player.user, :clan),
656-
clan_id: player.user && Map.get(player.user, :clan_id),
657-
state: player.state,
629+
defp build_leaderboard_entry(player, round_scores) do
630+
rounds =
631+
round_scores
632+
|> Map.get(player.user_id, [])
633+
|> Map.new(fn rs ->
634+
{rs.round_position, %{slice_index: rs.slice_index, place: rs.place, score: rs.score}}
635+
end)
636+
|> maybe_put_seed_round(player)
637+
638+
%{
639+
user_id: player.user_id,
640+
name: player.user && player.user.name,
641+
avatar_url: player.user && Map.get(player.user, :avatar_url),
642+
clan: player.user && Map.get(player.user, :clan),
643+
clan_id: player.user && Map.get(player.user, :clan_id),
644+
state: player.state,
645+
slice_index: player.slice_index,
646+
total_score: player.total_score || 0,
647+
seed_score: player.seed_score,
648+
last_round_place: player.last_round_place,
649+
rounds: rounds
650+
}
651+
end
652+
653+
# Synthesise R1 from the seeding pass so the UI can show the seed score in
654+
# the R1 column. Seeding runs solo-against-bots, so there's no cross-player
655+
# place; we surface score and initial slice without touching total_score.
656+
defp maybe_put_seed_round(rounds, player) do
657+
if is_integer(player.seed_score) and not Map.has_key?(rounds, 1) do
658+
Map.put(rounds, 1, %{
658659
slice_index: player.slice_index,
659-
total_score: player.total_score || 0,
660-
seed_score: player.seed_score,
661-
last_round_place: player.last_round_place,
662-
rounds: rounds
663-
}
664-
end)
665-
|> Enum.sort_by(fn entry -> {-(entry.total_score || 0), entry.user_id} end)
660+
place: nil,
661+
score: player.seed_score
662+
})
663+
else
664+
rounds
665+
end
666666
end
667667

668668
def serialize_run(run) do

apps/codebattle/lib/codebattle/group_tournament/group_tournament.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ defmodule Codebattle.GroupTournament do
166166

167167
def states, do: @states
168168
def types, do: @types
169+
def slice_strategies, do: @slice_strategies
169170
def scoring_strategies, do: @scoring_strategies
170171
def movement_strategies, do: @movement_strategies
171172

0 commit comments

Comments
 (0)