Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display cut conversion rates #416

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion app/controllers/tournaments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class TournamentsController < ApplicationController
show edit update destroy
upload_to_abr save_json cut qr registration timer
close_registration open_registration lock_player_registrations unlock_player_registrations
id_and_faction_data
id_and_faction_data cut_conversion_rates
]

def index
Expand Down Expand Up @@ -223,6 +223,12 @@ def unlock_player_registrations
redirect_back(fallback_location: tournament_rounds_path(@tournament))
end

def cut_conversion_rates
authorize @tournament, :show?

render json: @tournament.cut_conversion_rates_data
end

def id_and_faction_data
authorize @tournament, :show?

Expand Down
46 changes: 46 additions & 0 deletions app/models/tournament.rb
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,52 @@ def self.registration_consent_notice
'decklists, they may be shared with participants or made public.'
end

def cut_conversion_rates_data
sql = ActiveRecord::Base.sanitize_sql([
'SELECT * FROM cut_conversion_rates WHERE tournament_id = ?', id
])
rows = ActiveRecord::Base.connection.exec_query(sql).to_a
results = {
factions: {
corp: {},
runner: {}
},
identities: {
corp: {},
runner: {}
}
}

rows.each do |row|
side = row['side'].to_sym

# Make a place for factions
unless results[:factions][side].key?(row['faction'])
results[:factions][side][row['faction']] =
{ num_swiss_players: 0, num_cut_players: 0,
cut_conversion_percentage: 0.0 }
end

results[:factions][side][row['faction']][:num_swiss_players] += row['num_swiss_players'].to_i
results[:factions][side][row['faction']][:num_cut_players] += row['num_cut_players'].to_i

# Identities are already unique, so just insert them into results.
results[:identities][side][row['identity']] = {
faction: row['faction'],
num_swiss_players: row['num_swiss_players'].to_i,
num_cut_players: row['num_cut_players'].to_i,
cut_conversion_percentage: row['cut_conversion_percentage'].to_f
}
end
results[:factions].each_key do |side|
results[:factions][side].each do |faction, data|
results[:factions][side][faction][:cut_conversion_percentage] =
(data[:num_cut_players].to_f / data[:num_swiss_players]) * 100
end
end
results
end

private

def default_date
Expand Down
124 changes: 123 additions & 1 deletion app/views/tournaments/_player_counts.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,40 @@
th Players
tbody

h3 Elimination Cut Conversion Rates
.row
.col-md-6
table.table id="cut_corp_faction_conversion_rate"
thead
tr
th Corp Factions
th Players
tbody

.col-md-6
table.table id="cut_runner_faction_conversion_rate"
thead
tr
th Runner Factions
th Players
tbody

.row
.col-md-6
table.table id="cut_corp_ids_conversion_rate"
thead
tr
th Corp
th Players
tbody

.col-md-6
table.table id="cut_runner_ids_conversion_rate"
thead
tr
th Runner
th Players
tbody

javascript:
function drawPieChart(element, series, labels, colors=null) {
Expand Down Expand Up @@ -160,6 +194,94 @@
});
}

function populateFactionCutRows(data, side) {
factions = [];
for (faction in data) {
factions.push({
name: faction,
num_swiss_players: data[faction].num_swiss_players,
num_cut_players: data[faction].num_cut_players,
cut_conversion_percentage: data[faction].cut_conversion_percentage,
});
}
factions.sort((a, b) => {
if (b.cut_conversion_percentage !== a.cut_conversion_percentage) {
return b.cut_conversion_percentage - a.cut_conversion_percentage; // Descending order by cut_conversion_percentage
} else {
return b.num_cut_players - a.num_cut_players; // Descending order by num_cut_players
}
});

console.table(factions);

let tableId = `cut_${side}_faction_conversion_rate`;
const tableBody = document.querySelector(`#${tableId} tbody`);
factions.forEach((faction) => {
const row = document.createElement("tr");

const idCell = document.createElement("td");
idCell.innerHTML = `<div class="div ${faction.name}"><i class="fa icon icon-${faction.name == 'Unspecified' ? 'interrupt' : faction.name}"></i> ${displayFaction(faction.name)}</div>`;
row.appendChild(idCell);

const countCell = document.createElement("td");
countCell.innerHTML = `${faction.num_cut_players} / ${faction.num_swiss_players} (${faction.cut_conversion_percentage.toFixed(1)}%)`;
row.appendChild(countCell);

tableBody.appendChild(row);
});
}

function populateIdentityCutRows(data, side) {
ids = [];
for (id in data) {
ids.push({
name: id,
faction: data[id].faction,
num_swiss_players: data[id].num_swiss_players,
num_cut_players: data[id].num_cut_players,
cut_conversion_percentage: data[id].cut_conversion_percentage,
});
}
ids.sort((a, b) => {
if (b.cut_conversion_percentage !== a.cut_conversion_percentage) {
return b.cut_conversion_percentage - a.cut_conversion_percentage; // Descending order by cut_conversion_percentage
} else {
return b.num_cut_players - a.num_cut_players; // Descending order by num_cut_players
}
});

console.table(ids);

let tableId = `cut_${side}_ids_conversion_rate`;
const tableBody = document.querySelector(`#${tableId} tbody`);
ids.forEach((id) => {
const row = document.createElement("tr");

const idCell = document.createElement("td");
idCell.innerHTML = `<div class="div ${id.faction}"><i class="fa icon icon-${id.faction == 'Unspecified' ? 'interrupt' : id.faction}"></i> ${id.name}</div>`;
row.appendChild(idCell);

const countCell = document.createElement("td");
countCell.innerHTML = `${id.num_cut_players} / ${id.num_swiss_players} (${id.cut_conversion_percentage.toFixed(1)}%)`;
row.appendChild(countCell);

tableBody.appendChild(row);
});
}

if (#{@tournament.stages.size} > 1) {
fetch('/tournaments/#{@tournament.id}/cut_conversion_rates')
.then(response => response.json())
.then(data => {
populateFactionCutRows(data.factions.corp, 'corp');
populateFactionCutRows(data.factions.runner, 'runner');

populateIdentityCutRows(data.identities.corp, 'corp');
populateIdentityCutRows(data.identities.runner, 'runner');
})
.catch(error => console.error('Error fetching cut conversion rate data:', error));
}

fetch('/tournaments/#{@tournament.id}/id_and_faction_data')
.then(response => response.json())
.then(data => {
Expand Down Expand Up @@ -199,4 +321,4 @@

}
})
.catch(error => console.error('Error:', error));
.catch(error => console.error('Error fetching ID and faction data:', error));
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
post :upload_to_abr, on: :member
get :save_json, on: :member
get :id_and_faction_data, on: :member
get :cut_conversion_rates, on: :member
post :cut, on: :member
get :qr, on: :member
get :registration, on: :member
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class UpdateCutConversionRatesToVersion2 < ActiveRecord::Migration[7.2]
def change
update_view :cut_conversion_rates, version: 2, revert_to_version: 1
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class UpdateCutConversionRatesToVersion3 < ActiveRecord::Migration[7.2]
def change
update_view :cut_conversion_rates, version: 3, revert_to_version: 2
end
end
9 changes: 5 additions & 4 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.2].define(version: 2025_02_17_212451) do
ActiveRecord::Schema[7.2].define(version: 2025_02_18_061330) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

Expand Down Expand Up @@ -276,7 +276,7 @@
FROM (((stages s_1
JOIN registrations r ON ((s_1.id = r.stage_id)))
JOIN players p ON ((r.player_id = p.id)))
JOIN identities id ON ((p.runner_identity_ref_id = id.id)))
LEFT JOIN identities id ON ((p.runner_identity_ref_id = id.id)))
), combined AS (
SELECT corps.tournament_id,
corps.stage_number,
Expand Down Expand Up @@ -318,12 +318,13 @@
)
SELECT s.tournament_id,
s.side,
s.faction,
s.identity,
sum(s.num_players) AS num_swiss_players,
sum(COALESCE(c.num_players, (0)::bigint)) AS num_cut_players,
((sum(COALESCE(c.num_players, (0)::bigint)) / sum(s.num_players)) * (100)::numeric) AS cut_conversion_percentage
FROM (swiss s
LEFT JOIN cut c USING (tournament_id, side, identity))
GROUP BY s.tournament_id, s.side, s.identity;
LEFT JOIN cut c USING (tournament_id, side, identity, faction))
GROUP BY s.tournament_id, s.faction, s.side, s.identity;
SQL
end
78 changes: 78 additions & 0 deletions db/views/cut_conversion_rates_v02.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
WITH corps AS (
SELECT s.tournament_id,
s.number AS stage_number,
s.id AS stage_id,
'corp' AS side,
COALESCE(id.name, 'Unspecified') as identity,
COALESCE(id.faction, 'Unspecified') as faction
FROM stages s
JOIN registrations r ON s.id = r.stage_id
JOIN players p ON r.player_id = p.id
LEFT JOIN identities AS id ON p.corp_identity_ref_id = id.id
),
runners AS (
SELECT s.tournament_id,
s.number AS stage_number,
s.id AS stage_id,
'runner' AS side,
COALESCE(id.name, 'Unspecified') as identity,
COALESCE(id.faction, 'Unspecified') as faction
FROM stages s
JOIN registrations r ON s.id = r.stage_id
JOIN players p ON r.player_id = p.id
JOIN identities AS id ON p.runner_identity_ref_id = id.id
),
combined AS (
SELECT *
FROM corps
UNION ALL
SELECT *
FROM runners
),
swiss AS (
SELECT tournament_id,
stage_id,
stage_number,
side,
identity,
faction,
COUNT(*) AS num_players
FROM combined
WHERE stage_number = 1
GROUP BY 1,
2,
3,
4,
5,
6
),
cut AS (
SELECT
tournament_id,
stage_id,
stage_number,
side,
identity,
faction,
COUNT(*) AS num_players
FROM combined
WHERE stage_number = 2
GROUP BY
tournament_id,
stage_id,
stage_number,
side,
identity,
faction
)
SELECT
s.tournament_id,
s.side,
s.faction,
s.identity,
SUM(s.num_players) AS num_swiss_players,
SUM(COALESCE(c.num_players, 0)) AS num_cut_players,
(SUM(COALESCE(c.num_players, 0)) / SUM(s.num_players)) * 100 AS cut_conversion_percentage
FROM swiss s
LEFT JOIN cut c USING (tournament_id, side, identity, faction)
GROUP BY s.tournament_id, s.faction, s.side, s.identity;
Loading