Cricket Tournament Scorer Tool
Cricket Tournament Scorer Tool
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cricket Scorer</title>
<script src="[Link]
<link href="[Link]
family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
}
.hidden {
display: none;
}
.ball {
width: 30px;
height: 30px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
margin: 2px;
font-weight: bold;
color: white;
}
.ball-0 { background-color: #4A5568; }
.ball-1 { background-color: #38A169; }
.ball-2 { background-color: #3182CE; }
.ball-3 { background-color: #805AD5; }
.ball-4 { background-color: #D69E2E; }
.ball-6 { background-color: #DD6B20; }
.ball-w { background-color: #E53E3E; }
.ball-wd, .ball-nb { background-color: #718096; }
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 50;
overflow-y: auto;
}
.modal-content {
background-color: white;
padding: 2rem;
border-radius: 0.5rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
max-width: 90%;
width: 400px;
}
@media print {
body > #app > *:not(#scorecardModal) {
display: none !important;
}
#scorecardModal {
visibility: visible !important;
display: block !important;
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: auto !important;
background: white !important;
z-index: 9999 !important;
overflow: visible !important;
}
#scorecardModal .modal-content {
width: 100% !important;
max-width: 100% !important;
box-shadow: none !important;
border: none !important;
padding: 0 !important;
margin: 0 !important;
}
.no-print {
display: none !important;
}
}
</style>
</head>
<body class="bg-gray-100 text-gray-800">
</div>
<script>
// App State
let state = {};
let nextPlayerContext = {};
let lastCompletedMatchState = {};
const defaultSquads = {
'NILGIRI': { name: 'Nilgiri', players: [Link]({ length: 15 }, (_,
i) => `Player ${i + 1}`) },
'HIMALAYA': { name: 'Himalaya', players: [Link]({ length: 15 }, (_,
i) => `Player ${i + 1}`) },
'ARAVALI': { name: 'Aravali', players: [Link]({ length: 15 }, (_,
i) => `Player ${i + 1}`) },
'SHIWALIK': { name: 'Shiwalik', players: [Link]({ length: 15 }, (_,
i) => `Player ${i + 1}`) }
};
const FIXTURES = [
{ teamA: 'NILGIRI', teamB: 'HIMALAYA' },
{ teamA: 'ARAVALI', teamB: 'SHIWALIK' },
{ teamA: 'NILGIRI', teamB: 'ARAVALI' },
{ teamA: 'HIMALAYA', teamB: 'SHIWALIK' },
{ teamA: 'NILGIRI', teamB: 'SHIWALIK' },
{ teamA: 'ARAVALI', teamB: 'HIMALAYA' }
];
const initialPointsTable = {
'NILGIRI': { p: 0, w: 0, l: 0, pts: 0, nrr: 0, runsScored: 0,
oversFaced: 0, runsConceded: 0, oversBowled: 0 },
'HIMALAYA': { p: 0, w: 0, l: 0, pts: 0, nrr: 0, runsScored: 0,
oversFaced: 0, oversBowled: 0, runsConceded: 0, },
'ARAVALI': { p: 0, w: 0, l: 0, pts: 0, nrr: 0, runsScored: 0,
oversFaced: 0, oversBowled: 0, runsConceded: 0, },
'SHIWALIK': { p: 0, w: 0, l: 0, pts: 0, nrr: 0, runsScored: 0,
oversFaced: 0, oversBowled: 0, runsConceded: 0, }
};
// UI Elements
const mainScreen = [Link]('mainScreen');
const adminScreen = [Link]('adminScreen');
const recordsScreen = [Link]('recordsScreen');
const matchSetupScreen = [Link]('matchSetupScreen');
const scoringScreen = [Link]('scoringScreen');
// Functions
function navigate(screen) {
[Link]('hidden');
[Link]('hidden');
[Link]('hidden');
[Link]('hidden');
[Link]('hidden');
[Link](screen).[Link]('hidden');
}
function loadSquads() {
const savedSquads = [Link]('cricketSquads');
squads = savedSquads ? [Link](savedSquads) :
[Link]([Link](defaultSquads));
}
function initializeApp() {
loadSquads();
populateFixtures();
updatePointsTableUI();
[Link]('customMatchBtn').addEventListener('click', ()
=> setupMatch());
[Link]('adminPanelBtn').addEventListener('click',
showAdminPanel);
[Link]('recordsBtn').addEventListener('click',
showRecordsScreen);
[Link]('saveSquadsBtn').addEventListener('click',
saveSquads);
[Link]('#backToMainFromAdminBtn,
#backToMainFromRecordsBtn').forEach(btn => [Link]('click', () =>
navigate('mainScreen')));
[Link]('tossBtn').addEventListener('click',
conductToss);
[Link]('.run-btn').forEach(btn =>
[Link]('click', (e) => addRuns(parseInt([Link]))));
[Link]('wdBtn').addEventListener('click',
openWideModal);
[Link]('.wide-run-btn').forEach(btn =>
[Link]('click', (e) => addWide(parseInt([Link]))));
[Link]('cancelWideBtn').addEventListener('click', ()
=> [Link]('wideRunsModal').[Link]('hidden'));
[Link]('nbBtn').addEventListener('click', addNoBall);
[Link]('wicketBtn').addEventListener('click',
openWicketModal);
[Link]('cancelWicketBtn').addEventListener('click', ()
=> [Link]('wicketModal').[Link]('hidden'));
[Link]('.wicket-type-btn').forEach(btn =>
[Link]('click', (e) => handleWicket([Link])));
[Link]('startPlayBtn').addEventListener('click',
startPlay);
[Link]('endInningsBtn').addEventListener('click',
endInnings);
[Link]('backToHomeBtn').addEventListener('click',
resetAndGoHome);
[Link]('viewScorecardBtn').addEventListener('click',
showFullScorecard);
[Link]('printScorecardBtn').addEventListener('click',
() => [Link]());
[Link]('closeScorecardBtn').addEventListener('click',
() => [Link]('scorecardModal').[Link]('hidden'));
[Link]('undoBtn').addEventListener('click',
undoLastAction);
[Link]('confirmNextPlayerBtn').addEventListener('click',
confirmNextPlayer);
navigate('mainScreen');
}
function showAdminPanel() {
const editor = [Link]('squadsEditor');
[Link] = '';
[Link](squads).forEach(teamKey => {
const team = squads[teamKey];
let inputs = '';
[Link]((player, index) => {
inputs += `
<div class="flex items-center mb-2">
<label class="w-8 text-right mr-2 font-semibold">$
{index + 1}.</label>
<input type="text" value="${player}" class="squad-input
w-full p-1 border rounded" data-team="${teamKey}" data-player-index="${index}">
</div>
`;
});
const teamForm = `
<div class="bg-gray-50 p-4 rounded-lg">
<h3 class="text-xl font-bold mb-4 text-center">$
{[Link]}</h3>
${inputs}
</div>
`;
[Link] += teamForm;
});
navigate('adminScreen');
}
function saveSquads() {
[Link]('.squad-input').forEach(input => {
const { team, playerIndex } = [Link];
squads[team].players[playerIndex] = [Link];
});
[Link]('cricketSquads', [Link](squads));
function populateFixtures() {
const fixturesContainer = [Link]('fixtures');
[Link] = '';
[Link]((fixture, index) => {
const btn = [Link]('button');
[Link] = 'w-full bg-blue-600 hover:bg-blue-700 text-white
font-bold py-2 px-4 rounded-lg mb-2 transition duration-300';
[Link] = `${squads[[Link]].name} vs $
{squads[[Link]].name}`;
[Link]('click', () => setupMatch([Link],
[Link]));
[Link](btn);
});
}
[Link](squads).forEach(key => {
[Link] += `<option value="${key}">$
{squads[key].name}</option>`;
[Link] += `<option value="${key}">$
{squads[key].name}</option>`;
});
navigate('matchSetupScreen');
}
function conductToss() {
const teamA = [Link]('teamA').value;
const teamB = [Link]('teamB').value;
const maxOvers = parseInt([Link]('matchType').value);
[Link]('.toss-winner-btn').forEach(btn => {
[Link] = () => selectTossWinner([Link]);
});
[Link]('hidden');
}
function selectTossWinner(winnerKey) {
[Link] = winnerKey;
[Link]('tossWinnerModal').[Link]('hidden');
[Link]('batBtn').onclick = () => {
[Link] = [Link];
[Link] = [Link] === [Link] ?
[Link] : [Link];
[Link]('hidden');
openPlayingXIModal();
};
[Link]('bowlBtn').onclick = () => {
[Link] = [Link];
[Link] = [Link] === [Link] ?
[Link] : [Link];
[Link]('hidden');
openPlayingXIModal();
};
}
function openPlayingXIModal() {
const modal = [Link]('playingXIModal');
const teamA_Container = [Link]('teamA_XI_Selection');
const teamB_Container = [Link]('teamB_XI_Selection');
[Link]('.xi-checkbox').forEach(cb =>
[Link]('change', handleXISelectionChange));
[Link]('proceedToMatchBtn').addEventListener('click',
proceedToMatch);
[Link]('hidden');
}
function handleXISelectionChange() {
const selectedA = [Link]('.xi-checkbox[data-
team="A"]:checked').length;
const selectedB = [Link]('.xi-checkbox[data-
team="B"]:checked').length;
[Link]('teamACount').textContent = `Selected: $
{selectedA}/11`;
[Link]('teamBCount').textContent = `Selected: $
{selectedB}/11`;
function proceedToMatch() {
// Set playing status instead of replacing the array
[Link](p => [Link] = false);
[Link](p => [Link] = false);
[Link]('.xi-checkbox[data-
team="A"]:checked').forEach(checkbox => {
const playerName = [Link];
const playerObj = [Link](p => [Link] ===
playerName);
if (playerObj) [Link] = true;
});
[Link]('.xi-checkbox[data-
team="B"]:checked').forEach(checkbox => {
const playerName = [Link];
const playerObj = [Link](p => [Link] ===
playerName);
if (playerObj) [Link] = true;
});
[Link]('playingXIModal').[Link]('hidden');
openPlayerSelectionModal();
}
function openPlayerSelectionModal() {
const modal = [Link]('playerSelectionModal');
const battingTeamKey = [Link] === 1 ?
[Link] : [Link];
const bowlingTeamKey = [Link] === 1 ?
[Link] : [Link];
const battingTeam = [Link] === battingTeamKey ? [Link] :
[Link];
const bowlingTeam = [Link] === bowlingTeamKey ? [Link] :
[Link];
[Link]('strikerLabel').textContent = `Striker ($
{[Link]}):`;
[Link]('nonStrikerLabel').textContent = `Non-Striker
(${[Link]}):`;
[Link]('bowlerLabel').textContent = `Bowler ($
{[Link]}):`;
[Link]('hidden');
}
function startPlay() {
const strikerId = [Link]('strikerSelect').value;
const nonStrikerId = [Link]('nonStrikerSelect').value;
const bowlerId = [Link]('bowlerSelect').value;
const innings = {
battingTeam: battingTeamKey,
bowlingTeam: bowlingTeamKey,
score: 0,
wickets: 0,
overs: 0,
balls: 0,
extras: { wides: 0, noballs: 0 },
currentOver: [],
striker: strikerId,
nonStriker: nonStrikerId,
bowler: bowlerId,
bowlerStats: {} // Keyed by player ID
};
[Link][[Link] - 1] = innings;
[Link]('playerSelectionModal').[Link]('hidden');
navigate('scoringScreen');
updateScoreboard();
}
function saveState() {
[Link]([Link]([Link](state)));
}
function undoLastAction() {
if ([Link] > 0) {
state = [Link]();
updateScoreboard();
} else {
const undoBtn = [Link]('undoBtn');
[Link] = 'Nothing to Undo';
setTimeout(() => { [Link] = 'Undo'; }, 1500);
}
}
function addRuns(runs) {
saveState();
const inn = [Link][[Link] - 1];
const battingTeam = [Link] === [Link] ? [Link] :
[Link];
[Link] += runs;
if ([Link][[Link]-1] !== 'Nb') {
[Link]++;
}
[Link](runs);
if (![Link][[Link]]) [Link][[Link]] =
{ overs: 0, balls: 0, runs: 0, wickets: 0 };
[Link][[Link]].runs += runs;
if (runs % 2 !== 0) {
[[Link], [Link]] = [[Link], [Link]];
}
checkOverEnd();
updateScoreboard();
checkChaseEnd();
}
function openWideModal() {
[Link]('wideRunsModal').[Link]('hidden');
}
function addWide(extraRuns) {
saveState();
const inn = [Link][[Link] - 1];
const totalRunsFromWide = 1 + extraRuns;
[Link] += totalRunsFromWide;
[Link]++;
[Link](extraRuns > 0 ? `Wd+${extraRuns}` : 'Wd');
if (![Link][[Link]]) [Link][[Link]] =
{ overs: 0, balls: 0, runs: 0, wickets: 0 };
[Link][[Link]].runs += totalRunsFromWide;
if (extraRuns % 2 !== 0) {
[[Link], [Link]] = [[Link], [Link]];
}
[Link]('wideRunsModal').[Link]('hidden');
updateScoreboard();
checkChaseEnd();
}
function addNoBall() {
saveState();
const inn = [Link][[Link] - 1];
[Link]++;
[Link]++;
[Link]('Nb');
if (![Link][[Link]]) [Link][[Link]] =
{ overs: 0, balls: 0, runs: 0, wickets: 0 };
[Link][[Link]].runs++;
updateScoreboard();
checkChaseEnd();
}
function openWicketModal() {
const modal = [Link]('wicketModal');
const runOutBatsmanSelect = [Link]('runOutBatsman');
const inn = [Link][[Link] - 1];
const battingTeam = [Link] === [Link] ? [Link] :
[Link];
[Link] = `
<option value="${[Link]}">${[Link]} (Striker)</option>
<option value="${[Link]}">${[Link]} (Non-
Striker)</option>
`;
[Link]('runOutOptions').[Link]('hidden');
[Link]('hidden');
}
function handleWicket(type) {
saveState();
const inn = [Link][[Link] - 1];
const battingTeam = [Link] === [Link] ? [Link] :
[Link];
[Link]++;
if (type !== 'Run Out' && type !== 'Caught') { // Caught is also a
valid delivery
[Link]++;
}
[Link]('W');
if (![Link][[Link]]) [Link][[Link]] =
{ overs: 0, balls: 0, runs: 0, wickets: 0 };
if(type !== 'Run Out') {
[Link][[Link]].wickets++;
}
let outBatsmanId;
if (type === 'Run Out') {
outBatsmanId = [Link]('runOutBatsman').value;
} else {
outBatsmanId = [Link];
}
checkOverEnd();
updateScoreboard();
}
function confirmNextPlayer() {
const selectedId = [Link]('nextPlayerSelect').value;
const inn = [Link][[Link] - 1];
if(!selectedId) {
[Link]('nextPlayerModal').[Link]('hidden');
return;
}
[Link]('nextPlayerModal').[Link]('hidden');
updateScoreboard();
}
function checkOverEnd() {
const inn = [Link][[Link] - 1];
if ([Link] === 6) {
[Link]++;
[Link] = 0;
[Link] = [];
[[Link], [Link]] = [[Link], [Link]];
function checkChaseEnd() {
if ([Link] !== 2) return;
const inn1 = [Link][0];
const inn2 = [Link][1];
if ([Link] > [Link]) {
setTimeout(() => {
if
([Link]('matchSummaryModal').[Link]('hidden')) {
calculateResult();
}
}, 100);
}
}
function endInnings() {
if ([Link] === 1) {
[Link] = 2;
openPlayerSelectionModal();
} else {
calculateResult();
}
}
function calculateResult() {
const inn1 = [Link][0];
const inn2 = [Link][1];
let resultText = '';
pointsTable[loser].runsScored += [Link];
pointsTable[loser].oversFaced += [Link] +
([Link] / 6);
pointsTable[loser].runsConceded += [Link];
pointsTable[loser].oversBowled += [Link] +
([Link] / 6);
updateNRR();
[Link]('pointsTable', [Link](pointsTable));
}
lastCompletedMatchState = [Link]([Link](state));
[Link](lastCompletedMatchState);
[Link]('allMatchData', [Link](allMatchData));
updatePointsTableUI();
[Link]('matchResultText').textContent = resultText;
[Link]('matchSummaryModal').[Link]('hidden');
}
function showFullScorecard() {
const match = lastCompletedMatchState;
const content = [Link]('fullScorecardContent');
[Link] = '';
[Link](p => {
const sr = [Link] > 0 ? (([Link] / [Link]) *
100).toFixed(2) : '0.00';
battingRows += `
<tr class="border-b">
<td class="py-1 px-2">${[Link]}</td>
<td class="py-1 px-2 text-sm text-gray-600">${[Link] ?
[Link] : 'not out'}</td>
<td class="py-1 px-2 text-right
font-bold">${[Link]}</td>
<td class="py-1 px-2 text-right">${[Link]}</td>
<td class="py-1 px-2 text-right">${[Link]}</td>
<td class="py-1 px-2 text-right">${[Link]}</td>
<td class="py-1 px-2 text-right">${sr}</td>
</tr>
`;
});
if (p && stats) {
const oversDecimal = [Link] + ([Link] / 6);
const econ = oversDecimal > 0 ? ([Link] /
oversDecimal).toFixed(2) : '0.00';
bowlingRows += `
<tr class="border-b">
<td class="py-1 px-2">${[Link]}</td>
<td class="py-1 px-2 text-right">${[Link]}.$
{[Link]}</td>
<td class="py-1 px-2 text-right">${[Link]}</td>
<td class="py-1 px-2 text-right">$
{[Link]}</td>
<td class="py-1 px-2 text-right">${econ}</td>
</tr>
`;
}
});
const scorecardHTML = `
<div>
<h3 class="font-bold text-lg mb-1">${[Link]} - $
{[Link]}/${[Link]} (${[Link]}.${[Link]} Overs)</h3>
<div class="overflow-x-auto">
<table class="min-w-full text-sm">
<thead class="bg-gray-100"><tr>
<th class="py-1 px-2
text-left">Batsman</th><th></th>
<th class="py-1 px-2 text-right">R</th><th
class="py-1 px-2 text-right">B</th>
<th class="py-1 px-2 text-right">4s</th><th
class="py-1 px-2 text-right">6s</th>
<th class="py-1 px-2 text-right">SR</th>
</tr></thead>
<tbody>${battingRows}</tbody>
</table>
<h4 class="font-semibold mt-4 mb-1">Bowling</h4>
<table class="min-w-full text-sm">
<thead class="bg-gray-100"><tr>
<th class="py-1 px-2 text-left">Bowler</th>
<th class="py-1 px-2 text-right">O</th><th
class="py-1 px-2 text-right">R</th>
<th class="py-1 px-2 text-right">W</th><th
class="py-1 px-2 text-right">Econ</th>
</tr></thead>
<tbody>${bowlingRows}</tbody>
</table>
</div>
</div>
`;
[Link] += scorecardHTML;
});
[Link]('scorecardModal').[Link]('hidden');
}
function showRecordsScreen() {
const playerStats = {};
[Link](match => {
[[Link], [Link]].forEach(team => {
[Link](p => [Link]).forEach(player => {
if (!playerStats[[Link]]) {
playerStats[[Link]] = { name: [Link], team:
[Link], totalRuns: 0, totalBalls: 0, totalWickets: 0, totalRunsConceded: 0,
totalBallsBowled: 0 };
}
playerStats[[Link]].totalRuns += [Link];
playerStats[[Link]].totalBalls += [Link];
});
});
// Most Runs
const sortedRuns = [...statsArray].sort((a, b) => [Link] -
[Link]);
[Link]('mostRunsBody').innerHTML = [Link](0,
5).map(p => `<tr><td class="py-1 px-2">${[Link]} <span class="text-xs text-gray-
500">${[Link]}</span></td><td class="py-1 px-2 text-right font-bold">$
{[Link]}</td></tr>`).join('');
// Most Wickets
const sortedWickets = [...statsArray].sort((a, b) => [Link] -
[Link]);
[Link]('mostWicketsBody').innerHTML =
[Link](0, 5).map(p => `<tr><td class="py-1 px-2">${[Link]} <span
class="text-xs text-gray-500">${[Link]}</span></td><td class="py-1 px-2 text-right
font-bold">${[Link]}</td></tr>`).join('');
// Best Economy
const sortedEcon = [...statsArray].filter(p => [Link] >=
12).sort((a, b) => ([Link] / ([Link] / 6)) -
([Link] / ([Link] / 6)));
[Link]('bestEconomyBody').innerHTML =
[Link](0, 5).map(p => {
const econ = [Link] > 0 ? ([Link] /
([Link]/6)).toFixed(2) : '0.00';
return `<tr><td class="py-1 px-2">${[Link]} <span class="text-xs
text-gray-500">${[Link]}</span></td><td class="py-1 px-2 text-right font-bold">$
{econ}</td></tr>`;
}).join('');
navigate('recordsScreen');
}
function updateNRR() {
[Link](pointsTable).forEach(teamKey => {
const teamData = pointsTable[teamKey];
if ([Link] > 0 && [Link] > 0) {
const runRateFor = [Link] / [Link];
const runRateAgainst = [Link] /
[Link];
[Link] = (runRateFor - runRateAgainst).toFixed(2);
}
});
}
function resetAndGoHome() {
state = {};
history = [];
lastCompletedMatchState = {};
[Link]('matchSummaryModal').[Link]('hidden');
navigate('mainScreen');
}
function updateScoreboard() {
if (![Link] || ![Link][[Link] - 1] ||
[Link]([Link][[Link]-1]).length === 0) return;
[Link]('scoringTeamName').textContent =
[Link];
[Link]('totalRuns').textContent = [Link];
[Link]('totalWickets').textContent = [Link];
const oversCompleted = `${[Link]}.${[Link]}`;
[Link]('overs').textContent = oversCompleted;
const totalBalls = [Link] * 6 + [Link];
[Link]('crr').textContent = totalBalls > 0 ?
([Link] / totalBalls * 6).toFixed(2) : '0.00';
if ([Link] === 2) {
[Link]('targetContainer').[Link]('hidden');
const targetScore = [Link][0].score + 1;
[Link]('target').textContent = targetScore;
[Link]('targetContainer').[Link]('hidden');
}
// This Over
[Link]('thisOver').innerHTML =
[Link](ball => {
let ballContent = ball;
let ballClass = '';
if (typeof ball === 'number') {
ballClass = `ball-${ball}`;
} else if (typeof ball === 'string') {
if ([Link]().startsWith('wd')) {
ballClass = 'ball-wd';
} else if ([Link]() === 'nb') {
ballClass = 'ball-nb';
} else if ([Link]() === 'w') {
ballClass = 'ball-w';
}
}
return `<div class="ball ${ballClass}">${ballContent}</div>`;
}).join('');
updateLiveScorecardPreview();
}
function updateLiveScorecardPreview() {
const previewContainer =
[Link]('liveScorecardPreview');
if (![Link] || ![Link][[Link] - 1] ||
[Link]([Link][[Link] - 1]).length === 0) {
[Link] = '';
return;
}
battingRows += `
<tr class="${rowClass}">
<td class="py-1 px-2">${[Link]} ${indicator}</td>
${dismissalInfo}
<td class="py-1 px-2 text-right">${[Link]}</td>
<td class="py-1 px-2 text-right">${[Link]}</td>
</tr>
`;
});
const previewHTML = `
<div>
<h4 class="font-bold text-lg mb-1">${[Link]}
Batting</h4>
<div class="overflow-x-auto">
<table class="min-w-full text-sm">
<thead class="bg-gray-100"><tr>
<th class="py-1 px-2 text-left">Batsman</th>
<th class="py-1 px-2 text-left"></th>
<th class="py-1 px-2 text-right">R</th>
<th class="py-1 px-2 text-right">B</th>
</tr></thead>
<tbody>${battingRows}</tbody>
</table>
</div>
</div>
<div>
<h4 class="font-semibold mt-4 mb-1">${[Link]}
Bowling</h4>
<div class="overflow-x-auto">
<table class="min-w-full text-sm">
<thead class="bg-gray-100"><tr>
<th class="py-1 px-2 text-left">Bowler</th>
<th class="py-1 px-2 text-right">O</th><th
class="py-1 px-2 text-right">R</th>
<th class="py-1 px-2 text-right">W</th>
</tr></thead>
<tbody>${bowlingRows}</tbody>
</table>
</div>
</div>
`;
[Link] = previewHTML;
}
function updatePointsTableUI() {
const tableBody = [Link]('pointsTableBody');
[Link] = '';
const sortedTeams = [Link](pointsTable).sort(([,a], [,b]) => {
if([Link] !== [Link]) return [Link] - [Link];
return [Link] - [Link];
});
</script>
</body>
</html>