USA · Canada · Mexico · 11 June – 19 July 2026
Your Bracket Name is shown publicly on the leaderboard, along with your first name and last initial. Your last name, email, and phone number are kept private — phone is for admin verification only. One submission per email. Entries lock at the deadline.
Generate a complete bracket instantly. You can review and edit any pick before submitting.
Additional terms, conditions, eligibility requirements, and prizes may apply.
Supplemental stats and references for the tournament. For the full live standings, see the Home tab.
Showing the top 5 — see the Home tab for the full standings.
As of 6/2/2026. Men’s national teams in the 2026 World Cup. The left column ranks them within the field; the right column is each team’s actual FIFA world ranking. (Next official FIFA update: 11 June 2026.)
Outright title odds (American format), fixed at pre-tournament prices — a snapshot taken before kickoff that won’t change once play begins (BetMGM, late April 2026). “Win %” is the implied probability with the bookmaker margin removed, normalized to 100%.
When auditing your scores, look for green checkmarks to confirm you were awarded point(s) for the corresponding match.
Playoff note: if you predict the right winner with the right scoreline, +1 pt even if the wrong teams ended up in that bracket slot. Drawn playoff predictions require you to pick a penalty winner — no ties allowed.
Group stage: +1 for the correct result (win/draw/loss), and +1 more for the exact scoreline.
Knockout stage: points for each correct winner by round — 2 (R32), 3 (R16), 4 (QF), 5 (SF), 6 (Final) — plus +1 for the exact scoreline. Knockout scoring is by team identity: if you picked a team to win a round and it did, you earn the points no matter the opponent or bracket slot.
When you open an entry, each match shows green checkmarks that mirror the points awarded:
✓ — winner/result point awarded.
✓✓ — winner and exact-score point awarded (right winner with the right scoreline).
No checkmark means no points for that match. A perfect entry scores the 263 max shown above.
The William & Wall 2026 World Cup Challenge is a free promotional contest open to individuals who are at least 18 years of age. No purchase, engagement, referral, or business relationship with William & Wall is required to enter or win.
Participation is limited to one bracket per person. Duplicate or fraudulent entries may be disqualified at William & Wall’s sole discretion.
Brackets must be submitted prior to the start of the tournament. Once the tournament begins, bracket selections may not be modified.
Scoring will be determined exclusively by the official William & Wall World Cup Challenge scoring system. All scoring calculations, leaderboard rankings, tie-breakers, and contest results are final.
In the event that two or more entries are level on points, rankings are determined in the following order: (1) most total points; (2) a correct prediction of the World Cup champion, which applies only once the champion has been decided and is otherwise skipped; (3) most exact scores predicted correctly; (4) most bracket-stage points; (5) most group-stage points; and (6) the earliest submitted bracket. The complete scoring system and tiebreaker order are described on the Rules page.
Prizes will be awarded as follows: the first-place finisher will receive a $250 American Express Gift Card, the second-place finisher a $100 American Express Gift Card, and the third-place finisher a $50 American Express Gift Card. Each of the three winning entrants will also receive a Futstrikers Club match ball. All gift card prizes are non-transferable and may not be redeemed for cash.
William & Wall reserves the right to correct scoring errors, disqualify fraudulent entries, modify contest rules, suspend the contest, or cancel the contest if technical issues, data integrity concerns, or circumstances beyond its reasonable control affect the operation of the challenge.
Multiple Entries. William & Wall reserves the right, in its sole discretion, to disqualify any contestant who submits multiple entries, duplicate entries, or fraudulent entries, or who otherwise attempts to circumvent the official rules of the contest.
Verification of Winner Information. William & Wall reserves the right to verify the identity and contact information of any potential winner prior to awarding a prize. Failure to provide accurate and verifiable contact information may result in disqualification.
Eligibility. To be eligible to receive a prize, contestants must be legal residents physically residing within the contiguous United States. Residents of Alaska, Hawaii, U.S. territories, and international jurisdictions are not eligible to receive prizes unless otherwise approved by William & Wall in its sole discretion.
Prize Claim Deadline. Potential winners must respond to the prize notification and claim their prize within seven (7) calendar days of notification. Failure to respond within the required timeframe may result in forfeiture of the prize, and William & Wall reserves the right to select an alternate winner.
By participating, entrants agree to these Terms & Conditions and the decisions of William & Wall regarding contest administration and scoring.
Create a new Google Sheet
Go to sheets.google.com, create a blank spreadsheet, name it WC2026 Entries.
Open Apps Script
Extensions → Apps Script. Delete any existing code.
Paste this script
const ADMIN_PW = 'williamwall2026'; // CHANGE THIS
function doPost(e) {
try {
const data = JSON.parse(e.postData.contents);
const ss = SpreadsheetApp.getActiveSpreadsheet();
const action = data.action;
if (action === 'submit') {
// HARD BACKEND DEADLINE LOCK — June 10 2026 11:59 PM PT = June 11 2026 06:59 UTC
const DEADLINE = new Date('2026-06-11T06:59:00Z');
if (new Date() >= DEADLINE) {
return out({ok: false, msg: 'Bracket entry is closed. The deadline was June 10, 11:59 PM PT.'});
}
let sh = ss.getSheetByName('Entries') || ss.insertSheet('Entries');
if (sh.getLastRow() === 0) sh.appendRow(['Timestamp','Name','Email','Predictions','Score','Breakdown','BracketName','Phone','Industrious']);
const rows = sh.getDataRange().getValues();
for (let i = 1; i < rows.length; i++) {
if (rows[i][2].toLowerCase() === data.email.toLowerCase())
return out({ok: false, msg: 'This email has already submitted an entry.'});
}
// Calculate score against existing results so new entries score immediately
let initialScore = 0;
try {
const rs = ss.getSheetByName('Results');
if (rs && rs.getLastRow() > 0) {
const existingResults = JSON.parse(rs.getRange(1,1).getValue() || '{}');
if (Object.keys(existingResults.groups||{}).length > 0 || Object.keys(existingResults.bracket||{}).length > 0) {
initialScore = calcScore(data.predictions, existingResults);
}
}
} catch(err) {}
sh.appendRow([new Date().toISOString(), data.name, data.email, JSON.stringify(data.predictions), initialScore, '', data.bracketName || '', data.phone || '', data.industrious || '']);
return out({ok: true});
}
if (action === 'getLeaderboard') {
const sh = ss.getSheetByName('Entries');
if (!sh) return out({ok: true, entries: []});
const rows = sh.getDataRange().getValues().slice(1);
const entries = rows.map(r => ({
name: r[1],
email: r[2],
score: Number(r[4]) || 0,
predictions: JSON.parse(r[3] || '{}'),
submitted: r[0],
bracketName: r[6] || ''
})).sort((a, b) => b.score - a.score);
return out({ok: true, entries});
}
if (action === 'adminGetEntries') {
if (data.pw !== ADMIN_PW) return out({ok: false, msg: 'Wrong password'});
const sh = ss.getSheetByName('Entries');
if (!sh) return out({ok: true, entries: []});
const rows = sh.getDataRange().getValues().slice(1);
const entries = rows.map(r => ({
name: r[1],
email: r[2],
predictions: JSON.parse(r[3] || '{}'),
score: Number(r[4]) || 0,
submitted: r[0],
bracketName: r[6] || '',
phone: r[7] || '',
industrious: r[8] || ''
}));
return out({ok: true, entries});
}
if (action === 'saveResults') {
if (data.pw !== ADMIN_PW) return out({ok: false, msg: 'Wrong password'});
let rs = ss.getSheetByName('Results') || ss.insertSheet('Results');
rs.clearContents();
rs.appendRow([JSON.stringify(data.results)]);
rs.appendRow([JSON.stringify(data.slotOverrides || {})]);
rs.appendRow([new Date().toISOString()]); // row 3: last updated timestamp
const sh = ss.getSheetByName('Entries');
if (sh) {
const rows = sh.getDataRange().getValues();
// Merge slotOverrides into results so calcScore team-identity logic works
const resultsWithOvr = Object.assign({}, data.results, {
slotOverrides: data.slotOverrides || {}
});
for (let i = 1; i < rows.length; i++) {
const pred = JSON.parse(rows[i][3] || '{}');
// Skip empty entries
if (!pred || (!Object.keys(pred.groups||{}).length && !Object.keys(pred.bracket||{}).length)) continue;
const score = calcScore(pred, resultsWithOvr);
const breakdown = calcBreakdown(pred, resultsWithOvr);
sh.getRange(i + 1, 5).setValue(score);
sh.getRange(i + 1, 6).setValue(JSON.stringify(breakdown));
}
}
return out({ok: true, count: sh ? sh.getLastRow()-1 : 0});
}
if (action === 'getResults') {
const rs = ss.getSheetByName('Results');
if (!rs || rs.getLastRow() === 0) return out({ok: true, results: {}, slotOverrides: {}, lastUpdated: null});
const lastUpdated = rs.getLastRow() >= 3 ? rs.getRange(3, 1).getValue() : null;
const slotOvr = rs.getLastRow() >= 2 ? JSON.parse(rs.getRange(2, 1).getValue() || '{}') : {};
return out({ok: true,
results: JSON.parse(rs.getRange(1, 1).getValue() || '{}'),
slotOverrides: slotOvr,
lastUpdated: lastUpdated || null});
}
if (action === 'getAnnouncement') {
const cs = ss.getSheetByName('Config');
const msg = (cs && cs.getLastRow() > 0) ? cs.getRange(1, 1).getValue() : '';
return out({ok: true, announcement: msg || ''});
}
if (action === 'saveAnnouncement') {
if (data.pw !== ADMIN_PW) return out({ok: false, msg: 'Wrong password'});
const cs = ss.getSheetByName('Config') || ss.insertSheet('Config');
cs.getRange(1, 1).setValue(data.announcement || '');
return out({ok: true});
}
if (action === 'deleteEntry') {
if (data.pw !== ADMIN_PW) return out({ok: false, msg: 'Wrong password'});
const sh = ss.getSheetByName('Entries');
if (!sh) return out({ok: false, msg: 'No Entries sheet found'});
const rows = sh.getDataRange().getValues();
for (let i = 1; i < rows.length; i++) {
if (rows[i][2].toLowerCase() === data.email.toLowerCase()) {
sh.deleteRow(i + 1);
return out({ok: true, msg: 'Entry deleted'});
}
}
return out({ok: false, msg: 'Email not found: ' + data.email});
}
return out({ok: false, msg: 'Unknown action: ' + action});
} catch(err) {
return out({ok: false, msg: err.toString()});
}
}
function doGet() {
return out({ok: true, msg: 'WC2026 API running'});
}
function out(obj) {
return ContentService
.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}
function calcBreakdown(pred, real) {
// Uses team-identity comparison (same as calcScore) for accuracy
var items = [];
var rdpts = {r32: 2, r16: 3, qf: 4, sf: 5, fin: 6};
var ovr = real.slotOverrides || {};
// Group stage
var pg = pred.groups || {}, rg = real.groups || {};
Object.keys(rg).forEach(function(id) {
var p = pg[id], r = rg[id];
if (!p || r.h == null) return;
var pr = p.h > p.a ? 1 : p.h < p.a ? -1 : 0;
var rr = r.h > r.a ? 1 : r.h < r.a ? -1 : 0;
var result = pr === rr;
var exact = p.h === r.h && p.a === r.a;
if (result || exact) {
items.push({id: id, pred: p.h+'-'+p.a, real: r.h+'-'+r.a,
pts: (result ? 1 : 0) + (exact ? 1 : 0)});
}
});
// Bracket stage — ROUND-LEVEL team identity (same model as calcScore)
var realMap = gasBuildBracketWinnerMap(real.groups, real.bracket, ovr);
var predMap = gasBuildBracketWinnerMap(pred.groups, pred.bracket, {});
var realRW = gasBuildRoundWinners(realMap, real.bracket);
var predRW = gasBuildRoundWinners(predMap, pred.bracket);
['r32','r16','qf','sf','fin'].forEach(function(rnd) {
var realTeams = realRW[rnd], predTeams = predRW[rnd];
Object.keys(realTeams).forEach(function(tid) {
var ps = predTeams[tid];
if(!ps) return;
var rs = realTeams[tid];
var exact = ps.gf === rs.gf && ps.ga === rs.ga;
items.push({id: rnd+':'+tid, pred: ps.gf+'-'+ps.ga, real: rs.gf+'-'+rs.ga,
pts: (rdpts[rnd] || 0) + (exact ? 1 : 0)});
});
});
return items;
}
// ── BRACKET SCORING DATA ─────────────────────────────────────────────────────
// These mirror the frontend GROUPS, R32, and ADVANCEMENT constants exactly.
var GAS_GROUPS = {
A: [{id:"A1"},{id:"A2"},{id:"A3"},{id:"A4"}],
B: [{id:"B1"},{id:"B2"},{id:"B3"},{id:"B4"}],
C: [{id:"C1"},{id:"C2"},{id:"C3"},{id:"C4"}],
D: [{id:"D1"},{id:"D2"},{id:"D3"},{id:"D4"}],
E: [{id:"E1"},{id:"E2"},{id:"E3"},{id:"E4"}],
F: [{id:"F1"},{id:"F2"},{id:"F3"},{id:"F4"}],
G: [{id:"G1"},{id:"G2"},{id:"G3"},{id:"G4"}],
H: [{id:"H1"},{id:"H2"},{id:"H3"},{id:"H4"}],
I: [{id:"I1"},{id:"I2"},{id:"I3"},{id:"I4"}],
J: [{id:"J1"},{id:"J2"},{id:"J3"},{id:"J4"}],
K: [{id:"K1"},{id:"K2"},{id:"K3"},{id:"K4"}],
L: [{id:"L1"},{id:"L2"},{id:"L3"},{id:"L4"}],
};
var GAS_ANNEXC_SLOTS = ['A','B','D','E','G','I','K','L'];
var GAS_CLUSTER2SLOT = {'CEFHI':'A','EFGIJ':'B','BEFIJ':'D','ABCDF':'E','AEHIJ':'G','CDFGH':'I','DEIJL':'K','EHIJK':'L'};
var GAS_ANNEXC_RAW = `ABCDEFGH=HGBCAFDE
ABCDEFGI=CGBDAFEI
ABCDEFGJ=CGBDAFEJ
ABCDEFGK=CGBDAFEK
ABCDEFGL=CGBDAFLE
ABCDEFHI=HEBCAFDI
ABCDEFHJ=HJBCAFDE
ABCDEFHK=HEBCAFDK
ABCDEFHL=HFBCADLE
ABCDEFIJ=CJBDAFEI
ABCDEFIK=CEBDAFIK
ABCDEFIL=CEBDAFLI
ABCDEFJK=CJBDAFEK
ABCDEFJL=CJBDAFLE
ABCDEFKL=CEBDAFLK
ABCDEGHI=HGBCADEI
ABCDEGHJ=HGBCADEJ
ABCDEGHK=HGBCADEK
ABCDEGHL=HGBCADLE
ABCDEGIJ=EGBCADIJ
ABCDEGIK=EGBCADIK
ABCDEGIL=EGBCADLI
ABCDEGJK=EGBCADJK
ABCDEGJL=EGBCADLJ
ABCDEGKL=EGBCADLK
ABCDEHIJ=HJBCADEI
ABCDEHIK=HEBCADIK
ABCDEHIL=HEBCADLI
ABCDEHJK=HJBCADEK
ABCDEHJL=HJBCADLE
ABCDEHKL=HEBCADLK
ABCDEIJK=EJBCADIK
ABCDEIJL=EJBCADLI
ABCDEIKL=EIBCADLK
ABCDEJKL=EJBCADLK
ABCDFGHI=HGBCAFDI
ABCDFGHJ=HGBCAFDJ
ABCDFGHK=HGBCAFDK
ABCDFGHL=CGBDAFLH
ABCDFGIJ=CGBDAFIJ
ABCDFGIK=CGBDAFIK
ABCDFGIL=CGBDAFLI
ABCDFGJK=CGBDAFJK
ABCDFGJL=CGBDAFLJ
ABCDFGKL=CGBDAFLK
ABCDFHIJ=HJBCAFDI
ABCDFHIK=HFBCADIK
ABCDFHIL=HFBCADLI
ABCDFHJK=HJBCAFDK
ABCDFHJL=CJBDAFLH
ABCDFHKL=HFBCADLK
ABCDFIJK=CJBDAFIK
ABCDFIJL=CJBDAFLI
ABCDFIKL=CIBDAFLK
ABCDFJKL=CJBDAFLK
ABCDGHIJ=HGBCADIJ
ABCDGHIK=HGBCADIK
ABCDGHIL=HGBCADLI
ABCDGHJK=HGBCADJK
ABCDGHJL=HGBCADLJ
ABCDGHKL=HGBCADLK
ABCDGIJK=CJBDAGIK
ABCDGIJL=CJBDAGLI
ABCDGIKL=IGBCADLK
ABCDGJKL=CJBDAGLK
ABCDHIJK=HJBCADIK
ABCDHIJL=HJBCADLI
ABCDHIKL=HIBCADLK
ABCDHJKL=HJBCADLK
ABCDIJKL=IJBCADLK
ABCEFGHI=HGBCAFEI
ABCEFGHJ=HGBCAFEJ
ABCEFGHK=HGBCAFEK
ABCEFGHL=HGBCAFLE
ABCEFGIJ=EGBCAFIJ
ABCEFGIK=EGBCAFIK
ABCEFGIL=EGBCAFLI
ABCEFGJK=EGBCAFJK
ABCEFGJL=EGBCAFLJ
ABCEFGKL=EGBCAFLK
ABCEFHIJ=HJBCAFEI
ABCEFHIK=HEBCAFIK
ABCEFHIL=HEBCAFLI
ABCEFHJK=HJBCAFEK
ABCEFHJL=HJBCAFLE
ABCEFHKL=HEBCAFLK
ABCEFIJK=EJBCAFIK
ABCEFIJL=EJBCAFLI
ABCEFIKL=EIBCAFLK
ABCEFJKL=EJBCAFLK
ABCEGHIJ=HJBCAGEI
ABCEGHIK=EGBCAHIK
ABCEGHIL=EGBCAHLI
ABCEGHJK=HJBCAGEK
ABCEGHJL=HJBCAGLE
ABCEGHKL=EGBCAHLK
ABCEGIJK=EJBCAGIK
ABCEGIJL=EJBCAGLI
ABCEGIKL=EGBAICLK
ABCEGJKL=EJBCAGLK
ABCEHIJK=EJBCAHIK
ABCEHIJL=EJBCAHLI
ABCEHIKL=EIBCAHLK
ABCEHJKL=EJBCAHLK
ABCEIJKL=EJBAICLK
ABCFGHIJ=HGBCAFIJ
ABCFGHIK=HGBCAFIK
ABCFGHIL=HGBCAFLI
ABCFGHJK=HGBCAFJK
ABCFGHJL=HGBCAFLJ
ABCFGHKL=HGBCAFLK
ABCFGIJK=CJBFAGIK
ABCFGIJL=CJBFAGLI
ABCFGIKL=IGBCAFLK
ABCFGJKL=CJBFAGLK
ABCFHIJK=HJBCAFIK
ABCFHIJL=HJBCAFLI
ABCFHIKL=HIBCAFLK
ABCFHJKL=HJBCAFLK
ABCFIJKL=IJBCAFLK
ABCGHIJK=HJBCAGIK
ABCGHIJL=HJBCAGLI
ABCGHIKL=IGBCAHLK
ABCGHJKL=HJBCAGLK
ABCGIJKL=IJBCAGLK
ABCHIJKL=IJBCAHLK
ABDEFGHI=HGBDAFEI
ABDEFGHJ=HGBDAFEJ
ABDEFGHK=HGBDAFEK
ABDEFGHL=HGBDAFLE
ABDEFGIJ=EGBDAFIJ
ABDEFGIK=EGBDAFIK
ABDEFGIL=EGBDAFLI
ABDEFGJK=EGBDAFJK
ABDEFGJL=EGBDAFLJ
ABDEFGKL=EGBDAFLK
ABDEFHIJ=HJBDAFEI
ABDEFHIK=HEBDAFIK
ABDEFHIL=HEBDAFLI
ABDEFHJK=HJBDAFEK
ABDEFHJL=HJBDAFLE
ABDEFHKL=HEBDAFLK
ABDEFIJK=EJBDAFIK
ABDEFIJL=EJBDAFLI
ABDEFIKL=EIBDAFLK
ABDEFJKL=EJBDAFLK
ABDEGHIJ=HJBDAGEI
ABDEGHIK=EGBDAHIK
ABDEGHIL=EGBDAHLI
ABDEGHJK=HJBDAGEK
ABDEGHJL=HJBDAGLE
ABDEGHKL=EGBDAHLK
ABDEGIJK=EJBDAGIK
ABDEGIJL=EJBDAGLI
ABDEGIKL=EGBAIDLK
ABDEGJKL=EJBDAGLK
ABDEHIJK=EJBDAHIK
ABDEHIJL=EJBDAHLI
ABDEHIKL=EIBDAHLK
ABDEHJKL=EJBDAHLK
ABDEIJKL=EJBAIDLK
ABDFGHIJ=HGBDAFIJ
ABDFGHIK=HGBDAFIK
ABDFGHIL=HGBDAFLI
ABDFGHJK=HGBDAFJK
ABDFGHJL=HGBDAFLJ
ABDFGHKL=HGBDAFLK
ABDFGIJK=FJBDAGIK
ABDFGIJL=FJBDAGLI
ABDFGIKL=IGBDAFLK
ABDFGJKL=FJBDAGLK
ABDFHIJK=HJBDAFIK
ABDFHIJL=HJBDAFLI
ABDFHIKL=HIBDAFLK
ABDFHJKL=HJBDAFLK
ABDFIJKL=IJBDAFLK
ABDGHIJK=HJBDAGIK
ABDGHIJL=HJBDAGLI
ABDGHIKL=IGBDAHLK
ABDGHJKL=HJBDAGLK
ABDGIJKL=IJBDAGLK
ABDHIJKL=IJBDAHLK
ABEFGHIJ=HJBFAGEI
ABEFGHIK=EGBFAHIK
ABEFGHIL=EGBFAHLI
ABEFGHJK=HJBFAGEK
ABEFGHJL=HJBFAGLE
ABEFGHKL=EGBFAHLK
ABEFGIJK=EJBFAGIK
ABEFGIJL=EJBFAGLI
ABEFGIKL=EGBAIFLK
ABEFGJKL=EJBFAGLK
ABEFHIJK=EJBFAHIK
ABEFHIJL=EJBFAHLI
ABEFHIKL=EIBFAHLK
ABEFHJKL=EJBFAHLK
ABEFIJKL=EJBAIFLK
ABEGHIJK=EJBAHGIK
ABEGHIJL=EJBAHGLI
ABEGHIKL=EGBAIHLK
ABEGHJKL=EJBAHGLK
ABEGIJKL=EJBAIGLK
ABEHIJKL=EJBAIHLK
ABFGHIJK=HJBFAGIK
ABFGHIJL=HJBFAGLI
ABFGHIKL=HGBAIFLK
ABFGHJKL=HJBFAGLK
ABFGIJKL=IJBFAGLK
ABFHIJKL=HJBAIFLK
ABGHIJKL=HJBAIGLK
ACDEFGHI=HGECAFDI
ACDEFGHJ=HGJCAFDE
ACDEFGHK=HGECAFDK
ACDEFGHL=HGFCADLE
ACDEFGIJ=CGJDAFEI
ACDEFGIK=CGEDAFIK
ACDEFGIL=CGEDAFLI
ACDEFGJK=CGJDAFEK
ACDEFGJL=CGJDAFLE
ACDEFGKL=CGEDAFLK
ACDEFHIJ=HJECAFDI
ACDEFHIK=HEFCADIK
ACDEFHIL=HEFCADLI
ACDEFHJK=HJECAFDK
ACDEFHJL=HJFCADLE
ACDEFHKL=HEFCADLK
ACDEFIJK=CJEDAFIK
ACDEFIJL=CJEDAFLI
ACDEFIKL=CEIDAFLK
ACDEFJKL=CJEDAFLK
ACDEGHIJ=HGJCADEI
ACDEGHIK=HGECADIK
ACDEGHIL=HGECADLI
ACDEGHJK=HGJCADEK
ACDEGHJL=HGJCADLE
ACDEGHKL=HGECADLK
ACDEGIJK=EGJCADIK
ACDEGIJL=EGJCADLI
ACDEGIKL=EGICADLK
ACDEGJKL=EGJCADLK
ACDEHIJK=HJECADIK
ACDEHIJL=HJECADLI
ACDEHIKL=HEICADLK
ACDEHJKL=HJECADLK
ACDEIJKL=EJICADLK
ACDFGHIJ=HGJCAFDI
ACDFGHIK=HGFCADIK
ACDFGHIL=HGFCADLI
ACDFGHJK=HGJCAFDK
ACDFGHJL=CGJDAFLH
ACDFGHKL=HGFCADLK
ACDFGIJK=CGJDAFIK
ACDFGIJL=CGJDAFLI
ACDFGIKL=CGIDAFLK
ACDFGJKL=CGJDAFLK
ACDFHIJK=HJFCADIK
ACDFHIJL=HJFCADLI
ACDFHIKL=HFICADLK
ACDFHJKL=HJFCADLK
ACDFIJKL=CJIDAFLK
ACDGHIJK=HGJCADIK
ACDGHIJL=HGJCADLI
ACDGHIKL=HGICADLK
ACDGHJKL=HGJCADLK
ACDGIJKL=IGJCADLK
ACDHIJKL=HJICADLK
ACEFGHIJ=HGJCAFEI
ACEFGHIK=HGECAFIK
ACEFGHIL=HGECAFLI
ACEFGHJK=HGJCAFEK
ACEFGHJL=HGJCAFLE
ACEFGHKL=HGECAFLK
ACEFGIJK=EGJCAFIK
ACEFGIJL=EGJCAFLI
ACEFGIKL=EGICAFLK
ACEFGJKL=EGJCAFLK
ACEFHIJK=HJECAFIK
ACEFHIJL=HJECAFLI
ACEFHIKL=HEICAFLK
ACEFHJKL=HJECAFLK
ACEFIJKL=EJICAFLK
ACEGHIJK=EGJCAHIK
ACEGHIJL=EGJCAHLI
ACEGHIKL=EGICAHLK
ACEGHJKL=EGJCAHLK
ACEGIJKL=EJICAGLK
ACEHIJKL=EJICAHLK
ACFGHIJK=HGJCAFIK
ACFGHIJL=HGJCAFLI
ACFGHIKL=HGICAFLK
ACFGHJKL=HGJCAFLK
ACFGIJKL=IGJCAFLK
ACFHIJKL=HJICAFLK
ACGHIJKL=HJICAGLK
ADEFGHIJ=HGJDAFEI
ADEFGHIK=HGEDAFIK
ADEFGHIL=HGEDAFLI
ADEFGHJK=HGJDAFEK
ADEFGHJL=HGJDAFLE
ADEFGHKL=HGEDAFLK
ADEFGIJK=EGJDAFIK
ADEFGIJL=EGJDAFLI
ADEFGIKL=EGIDAFLK
ADEFGJKL=EGJDAFLK
ADEFHIJK=HJEDAFIK
ADEFHIJL=HJEDAFLI
ADEFHIKL=HEIDAFLK
ADEFHJKL=HJEDAFLK
ADEFIJKL=EJIDAFLK
ADEGHIJK=EGJDAHIK
ADEGHIJL=EGJDAHLI
ADEGHIKL=EGIDAHLK
ADEGHJKL=EGJDAHLK
ADEGIJKL=EJIDAGLK
ADEHIJKL=EJIDAHLK
ADFGHIJK=HGJDAFIK
ADFGHIJL=HGJDAFLI
ADFGHIKL=HGIDAFLK
ADFGHJKL=HGJDAFLK
ADFGIJKL=IGJDAFLK
ADFHIJKL=HJIDAFLK
ADGHIJKL=HJIDAGLK
AEFGHIJK=EGJFAHIK
AEFGHIJL=EGJFAHLI
AEFGHIKL=EGIFAHLK
AEFGHJKL=EGJFAHLK
AEFGIJKL=EJIFAGLK
AEFHIJKL=EJIFAHLK
AEGHIJKL=EJIAHGLK
AFGHIJKL=HJIFAGLK
BCDEFGHI=CGBDHFEI
BCDEFGHJ=HGBCJFDE
BCDEFGHK=CGBDHFEK
BCDEFGHL=CGBDHFLE
BCDEFGIJ=CGBDJFEI
BCDEFGIK=CGBDEFIK
BCDEFGIL=CGBDEFLI
BCDEFGJK=CGBDJFEK
BCDEFGJL=CGBDJFLE
BCDEFGKL=CGBDEFLK
BCDEFHIJ=CJBDHFEI
BCDEFHIK=CEBDHFIK
BCDEFHIL=CEBDHFLI
BCDEFHJK=CJBDHFEK
BCDEFHJL=CJBDHFLE
BCDEFHKL=CEBDHFLK
BCDEFIJK=CJBDEFIK
BCDEFIJL=CJBDEFLI
BCDEFIKL=CEBDIFLK
BCDEFJKL=CJBDEFLK
BCDEGHIJ=HGBCJDEI
BCDEGHIK=EGBCHDIK
BCDEGHIL=EGBCHDLI
BCDEGHJK=HGBCJDEK
BCDEGHJL=HGBCJDLE
BCDEGHKL=EGBCHDLK
BCDEGIJK=EGBCJDIK
BCDEGIJL=EGBCJDLI
BCDEGIKL=EGBCIDLK
BCDEGJKL=EGBCJDLK
BCDEHIJK=EJBCHDIK
BCDEHIJL=EJBCHDLI
BCDEHIKL=EIBCHDLK
BCDEHJKL=EJBCHDLK
BCDEIJKL=EJBCIDLK
BCDFGHIJ=HGBCJFDI
BCDFGHIK=CGBDHFIK
BCDFGHIL=CGBDHFLI
BCDFGHJK=HGBCJFDK
BCDFGHJL=CGBDHFLJ
BCDFGHKL=CGBDHFLK
BCDFGIJK=CGBDJFIK
BCDFGIJL=CGBDJFLI
BCDFGIKL=CGBDIFLK
BCDFGJKL=CGBDJFLK
BCDFHIJK=CJBDHFIK
BCDFHIJL=CJBDHFLI
BCDFHIKL=CIBDHFLK
BCDFHJKL=CJBDHFLK
BCDFIJKL=CJBDIFLK
BCDGHIJK=HGBCJDIK
BCDGHIJL=HGBCJDLI
BCDGHIKL=HGBCIDLK
BCDGHJKL=HGBCJDLK
BCDGIJKL=IGBCJDLK
BCDHIJKL=HJBCIDLK
BCEFGHIJ=HGBCJFEI
BCEFGHIK=EGBCHFIK
BCEFGHIL=EGBCHFLI
BCEFGHJK=HGBCJFEK
BCEFGHJL=HGBCJFLE
BCEFGHKL=EGBCHFLK
BCEFGIJK=EGBCJFIK
BCEFGIJL=EGBCJFLI
BCEFGIKL=EGBCIFLK
BCEFGJKL=EGBCJFLK
BCEFHIJK=EJBCHFIK
BCEFHIJL=EJBCHFLI
BCEFHIKL=EIBCHFLK
BCEFHJKL=EJBCHFLK
BCEFIJKL=EJBCIFLK
BCEGHIJK=EJBCHGIK
BCEGHIJL=EJBCHGLI
BCEGHIKL=EGBCIHLK
BCEGHJKL=EJBCHGLK
BCEGIJKL=EJBCIGLK
BCEHIJKL=EJBCIHLK
BCFGHIJK=HGBCJFIK
BCFGHIJL=HGBCJFLI
BCFGHIKL=HGBCIFLK
BCFGHJKL=HGBCJFLK
BCFGIJKL=IGBCJFLK
BCFHIJKL=HJBCIFLK
BCGHIJKL=HJBCIGLK
BDEFGHIJ=HGBDJFEI
BDEFGHIK=EGBDHFIK
BDEFGHIL=EGBDHFLI
BDEFGHJK=HGBDJFEK
BDEFGHJL=HGBDJFLE
BDEFGHKL=EGBDHFLK
BDEFGIJK=EGBDJFIK
BDEFGIJL=EGBDJFLI
BDEFGIKL=EGBDIFLK
BDEFGJKL=EGBDJFLK
BDEFHIJK=EJBDHFIK
BDEFHIJL=EJBDHFLI
BDEFHIKL=EIBDHFLK
BDEFHJKL=EJBDHFLK
BDEFIJKL=EJBDIFLK
BDEGHIJK=EJBDHGIK
BDEGHIJL=EJBDHGLI
BDEGHIKL=EGBDIHLK
BDEGHJKL=EJBDHGLK
BDEGIJKL=EJBDIGLK
BDEHIJKL=EJBDIHLK
BDFGHIJK=HGBDJFIK
BDFGHIJL=HGBDJFLI
BDFGHIKL=HGBDIFLK
BDFGHJKL=HGBDJFLK
BDFGIJKL=IGBDJFLK
BDFHIJKL=HJBDIFLK
BDGHIJKL=HJBDIGLK
BEFGHIJK=EJBFHGIK
BEFGHIJL=EJBFHGLI
BEFGHIKL=EGBFIHLK
BEFGHJKL=EJBFHGLK
BEFGIJKL=EJBFIGLK
BEFHIJKL=EJBFIHLK
BEGHIJKL=EJIBHGLK
BFGHIJKL=HJBFIGLK
CDEFGHIJ=CGJDHFEI
CDEFGHIK=CGEDHFIK
CDEFGHIL=CGEDHFLI
CDEFGHJK=CGJDHFEK
CDEFGHJL=CGJDHFLE
CDEFGHKL=CGEDHFLK
CDEFGIJK=CGEDJFIK
CDEFGIJL=CGEDJFLI
CDEFGIKL=CGEDIFLK
CDEFGJKL=CGEDJFLK
CDEFHIJK=CJEDHFIK
CDEFHIJL=CJEDHFLI
CDEFHIKL=CEIDHFLK
CDEFHJKL=CJEDHFLK
CDEFIJKL=CJEDIFLK
CDEGHIJK=EGJCHDIK
CDEGHIJL=EGJCHDLI
CDEGHIKL=EGICHDLK
CDEGHJKL=EGJCHDLK
CDEGIJKL=EGICJDLK
CDEHIJKL=EJICHDLK
CDFGHIJK=CGJDHFIK
CDFGHIJL=CGJDHFLI
CDFGHIKL=CGIDHFLK
CDFGHJKL=CGJDHFLK
CDFGIJKL=CGIDJFLK
CDFHIJKL=CJIDHFLK
CDGHIJKL=HGICJDLK
CEFGHIJK=EGJCHFIK
CEFGHIJL=EGJCHFLI
CEFGHIKL=EGICHFLK
CEFGHJKL=EGJCHFLK
CEFGIJKL=EGICJFLK
CEFHIJKL=EJICHFLK
CEGHIJKL=EJICHGLK
CFGHIJKL=HGICJFLK
DEFGHIJK=EGJDHFIK
DEFGHIJL=EGJDHFLI
DEFGHIKL=EGIDHFLK
DEFGHJKL=EGJDHFLK
DEFGIJKL=EGIDJFLK
DEFHIJKL=EJIDHFLK
DEGHIJKL=EJIDHGLK
DFGHIJKL=HGIDJFLK
EFGHIJKL=EJIFHGLK`;
var _gasAnnexC = null;
function gasAnnexCTable(){
if(_gasAnnexC) return _gasAnnexC;
var t = {};
GAS_ANNEXC_RAW.trim().split('\n').forEach(function(line){
var p = line.split('=');
if(p.length === 2) t[p[0]] = p[1];
});
_gasAnnexC = t;
return t;
}
function gasAnnexCFromThirds(thirds){
var ranked = (thirds || []).filter(function(x){ return x && x.team; });
if(ranked.length < 8) return null;
var qual = ranked.slice(0,8).map(function(x){ return x.group; });
var key = qual.slice().sort().join('');
if(key.length !== 8) return null;
var row = gasAnnexCTable()[key];
if(!row || row.length !== 8) return null;
var map = {};
for(var i=0;i<GAS_ANNEXC_SLOTS.length;i++) map[GAS_ANNEXC_SLOTS[i]] = row[i];
return map;
}
var GAS_R32 = [
{id:"p_r32_0", home:"1E", away:"3ABCDF"},
{id:"p_r32_1", home:"1I", away:"3CDFGH"},
{id:"p_r32_2", home:"2A", away:"2B"},
{id:"p_r32_3", home:"1F", away:"2C"},
{id:"p_r32_4", home:"2K", away:"2L"},
{id:"p_r32_5", home:"1H", away:"2J"},
{id:"p_r32_6", home:"1D", away:"3BEFIJ"},
{id:"p_r32_7", home:"1G", away:"3AEHIJ"},
{id:"p_r32_8", home:"1C", away:"2F"},
{id:"p_r32_9", home:"2E", away:"2I"},
{id:"p_r32_10", home:"1A", away:"3CEFHI"},
{id:"p_r32_11", home:"1L", away:"3EHIJK"},
{id:"p_r32_12", home:"1J", away:"2H"},
{id:"p_r32_13", home:"2D", away:"2G"},
{id:"p_r32_14", home:"1B", away:"3EFGIJ"},
{id:"p_r32_15", home:"1K", away:"3DEIJL"},
];
var GAS_ADVANCEMENT = {
// R32 → R16 (left: pairs 0+1→0, 2+3→1, 4+5→2, 6+7→3; right: 8+9→4, 10+11→5, 12+13→6, 14+15→7)
'p_r32_0': {next:'p_r16_0',slot:'home'},
'p_r32_1': {next:'p_r16_0',slot:'away'},
'p_r32_2': {next:'p_r16_1',slot:'home'},
'p_r32_3': {next:'p_r16_1',slot:'away'},
'p_r32_4': {next:'p_r16_2',slot:'home'},
'p_r32_5': {next:'p_r16_2',slot:'away'},
'p_r32_6': {next:'p_r16_3',slot:'home'},
'p_r32_7': {next:'p_r16_3',slot:'away'},
'p_r32_8': {next:'p_r16_4',slot:'home'},
'p_r32_9': {next:'p_r16_4',slot:'away'},
'p_r32_10': {next:'p_r16_5',slot:'home'},
'p_r32_11': {next:'p_r16_5',slot:'away'},
'p_r32_12': {next:'p_r16_6',slot:'home'},
'p_r32_13': {next:'p_r16_6',slot:'away'},
'p_r32_14': {next:'p_r16_7',slot:'home'},
'p_r32_15': {next:'p_r16_7',slot:'away'},
// R16 → QF
'p_r16_0': {next:'p_qf_0',slot:'home'},
'p_r16_1': {next:'p_qf_0',slot:'away'},
'p_r16_2': {next:'p_qf_1',slot:'home'},
'p_r16_3': {next:'p_qf_1',slot:'away'},
'p_r16_4': {next:'p_qf_2',slot:'home'},
'p_r16_5': {next:'p_qf_2',slot:'away'},
'p_r16_6': {next:'p_qf_3',slot:'home'},
'p_r16_7': {next:'p_qf_3',slot:'away'},
// QF → SF
'p_qf_0': {next:'p_sf_0',slot:'home'},
'p_qf_1': {next:'p_sf_0',slot:'away'},
'p_qf_2': {next:'p_sf_1',slot:'home'},
'p_qf_3': {next:'p_sf_1',slot:'away'},
// SF → Final
'p_sf_0': {next:'p_fin_0',slot:'home'},
'p_sf_1': {next:'p_fin_0',slot:'away'},
};
// Build a map of which team (by id) occupies each bracket slot and who won.
// groups: groups results object, bracket: bracket results object, ovr: slot overrides
function gasBuildBracketWinnerMap(groups, bracket, ovr) {
ovr = ovr || {};
var gScores = groups || {};
var hasG = Object.keys(gScores).length > 0;
// Compute simple standings: for each group, rank teams by points/gd/gf
var standings = {};
if(hasG) {
Object.keys(GAS_GROUPS).forEach(function(g) {
var teams = GAS_GROUPS[g];
var stats = {};
teams.forEach(function(t) { stats[t.id] = {id:t.id, pts:0, gd:0, gf:0, mp:0}; });
// Tally group results
Object.keys(gScores).forEach(function(mid) {
var parts = mid.split('_'); // g_A_0_1
if(parts[1] !== g) return;
var r = gScores[mid];
if(!r || r.h == null) return;
var i = parseInt(parts[2]), j = parseInt(parts[3]);
var ti = teams[i] && teams[i].id, tj = teams[j] && teams[j].id;
if(!ti || !tj) return;
stats[ti].mp++; stats[tj].mp++;
stats[ti].gf += r.h; stats[ti].gd += (r.h - r.a);
stats[tj].gf += r.a; stats[tj].gd += (r.a - r.h);
if(r.h > r.a) { stats[ti].pts += 3; }
else if(r.h < r.a) { stats[tj].pts += 3; }
else { stats[ti].pts += 1; stats[tj].pts += 1; }
});
var sorted = Object.values(stats).sort(function(a,b) {
if(b.pts !== a.pts) return b.pts - a.pts;
if(b.gd !== a.gd) return b.gd - a.gd;
return b.gf - a.gf;
});
standings[g] = sorted;
});
}
// All thirds sorted for 3rd-place slot resolution
var thirds = [];
Object.keys(standings).forEach(function(g) {
if(standings[g][2]) thirds.push({group: g, team: standings[g][2]});
});
thirds.sort(function(a,b) {
var ta=a.team, tb=b.team;
if(tb.pts !== ta.pts) return tb.pts - ta.pts;
if(tb.gd !== ta.gd) return tb.gd - ta.gd;
return tb.gf - ta.gf;
});
// FIFA Annex C assignment for the 8 reserved third-place R32 slots (or null).
var annexMap = gasAnnexCFromThirds(thirds);
// Resolve a slot code to a team id
// NOTE: mp >= 3 check removed — scoring must work mid-tournament.
function resolveSlot(code, usedSet) {
if(!code) return null;
var rank = code[0], grps = code.slice(1);
if(rank === '1') {
var g1 = standings[grps]; return (g1 && g1[0]) ? g1[0].id : null;
}
if(rank === '2') {
var g2 = standings[grps]; return (g2 && g2[1]) ? g2[1].id : null;
}
if(rank === '3') {
// Official Annex C path: cluster -> reserved slot -> FIFA-assigned group.
var slotKey = GAS_CLUSTER2SLOT[grps];
if(slotKey){
if(annexMap && annexMap[slotKey]){
var ag = annexMap[slotKey];
var ast = standings[ag];
return (ast && ast[2]) ? ast[2].id : null;
}
return null;
}
for(var k=0; k<thirds.length; k++) {
var x = thirds[k];
if(grps.indexOf(x.group) !== -1 && x.team && !usedSet[x.team.id]) {
usedSet[x.team.id] = true;
return x.team.id;
}
}
return null;
}
return null;
}
var teamMap = {};
var used3rd = {};
// Seed R32
GAS_R32.forEach(function(m) {
var hId = (ovr[m.home] && ovr[m.home].id) || resolveSlot(m.home, used3rd);
var aId = (ovr[m.away] && ovr[m.away].id) || resolveSlot(m.away, used3rd);
if(ovr[m.home] && hId) used3rd[hId] = true;
if(ovr[m.away] && aId) used3rd[aId] = true;
var r = (bracket || {})[m.id];
var winnerId = null;
if(r && r.h != null && r.a != null) {
var side = r.h > r.a ? 'home' : r.h < r.a ? 'away' : (r.pen || null);
winnerId = side === 'home' ? hId : side === 'away' ? aId : null;
}
teamMap[m.id] = {homeId: hId, awayId: aId, winnerId: winnerId};
});
// Propagate through later rounds
var rounds = [{id:'r16',count:8},{id:'qf',count:4},{id:'sf',count:2},{id:'fin',count:1}];
rounds.forEach(function(rnd) {
for(var i=0; i<rnd.count; i++) {
var id = 'p_' + rnd.id + '_' + i;
var hId2 = null, aId2 = null;
Object.keys(GAS_ADVANCEMENT).forEach(function(src) {
var adv = GAS_ADVANCEMENT[src];
if(adv.next === id) {
var srcE = teamMap[src];
if(srcE && srcE.winnerId) {
if(adv.slot === 'home') hId2 = srcE.winnerId;
else aId2 = srcE.winnerId;
}
}
});
var r2 = (bracket || {})[id];
var wId2 = null;
if(r2 && r2.h != null && r2.a != null) {
var side2 = r2.h > r2.a ? 'home' : r2.h < r2.a ? 'away' : (r2.pen || null);
wId2 = side2 === 'home' ? hId2 : side2 === 'away' ? aId2 : null;
}
teamMap[id] = {homeId: hId2, awayId: aId2, winnerId: wId2};
}
});
return teamMap;
}
// Per-round winners keyed by TEAM IDENTITY, with the scoreline from the winner's
// perspective (gf = goals for winner, ga = goals against). Mirrors the frontend
// buildRoundWinners — makes knockout scoring slot/side independent + override-safe.
function gasBuildRoundWinners(winnerMap, bracketScores) {
var out = {r32:{}, r16:{}, qf:{}, sf:{}, fin:{}};
var bs = bracketScores || {};
Object.keys(bs).forEach(function(id) {
var sc = bs[id];
if(!sc || sc.h == null || sc.a == null) return;
var rnd = id.split('_')[1];
if(!out[rnd]) return;
var entry = winnerMap[id];
var wid = entry && entry.winnerId;
if(!wid) return;
var gf, ga;
if(sc.h === sc.a) { gf = sc.h; ga = sc.a; }
else if(wid === entry.homeId) { gf = sc.h; ga = sc.a; }
else { gf = sc.a; ga = sc.h; }
if(!out[rnd][wid]) out[rnd][wid] = {gf:gf, ga:ga, slot:id};
});
return out;
}
function calcScore(pred, real) {
var ovr = real.slotOverrides || {};
var pts = 0;
var rdpts = {r32:2, r16:3, qf:4, sf:5, fin:6};
// Group stage
var pg = pred.groups || {}, rg = real.groups || {};
Object.keys(rg).forEach(function(id) {
var p = pg[id], r = rg[id];
if(!p || !r || r.h == null) return;
var pr = p.h > p.a ? 1 : p.h < p.a ? -1 : 0;
var rr = r.h > r.a ? 1 : r.h < r.a ? -1 : 0;
if(pr === rr) pts++;
if(p.h === r.h && p.a === r.a) pts++;
});
// Bracket: compare team identities
var realMap = gasBuildBracketWinnerMap(real.groups, real.bracket, ovr);
var predMap = gasBuildBracketWinnerMap(pred.groups, pred.bracket, {});
var realRW = gasBuildRoundWinners(realMap, real.bracket);
var predRW = gasBuildRoundWinners(predMap, pred.bracket);
// ROUND-LEVEL: a user scores a round when a team they picked to win that round
// actually won that round, regardless of slot/opponent. Exact bonus compares the
// winner-relative scoreline, so it is side-independent and override-safe.
['r32','r16','qf','sf','fin'].forEach(function(rnd) {
var realTeams = realRW[rnd], predTeams = predRW[rnd];
Object.keys(realTeams).forEach(function(tid) {
var ps = predTeams[tid];
if(!ps) return;
pts += (rdpts[rnd] || 0);
var rs = realTeams[tid];
if(ps.gf === rs.gf && ps.ga === rs.ga) pts += 1;
});
});
return pts;
}
Deploy as web app
Deploy → New deployment → Web app. Execute as: Me. Access: Anyone. Copy the URL.
Configure in Admin
Go to Admin tab, log in, paste your URL in Settings. Save.
Embed in Squarespace
Add a Code Block:
<iframe src="YOUR_FILE_URL" width="100%" height="900" frameborder="0" style="border:none;border-radius:12px"></iframe>