All SolutionsAll Solutions
🏆
FIFA World Cup 2026
Week 23, 2026
WON'T WORK (MUST chng goal to goals in RND16) | devilssnare | Python Solutions
# Mr. Draw6 discovered that this solution will not work unless we change goal to goals in Round 16 only. In other words, all singular instances of goal must be converted to goals, but only in Round 16. Mr. Draw6 is a wizard
from itertools import combinations
groups = [
["Mexico", "South Africa", "Korea Republic", "Czechia"],
["Canada", "Bosnia and Herzegovina", "Qatar", "Switzerland"],
["Brazil", "Morocco", "Haiti", "Scotland"],
["USA", "Paraguay", "Australia", "Türkiye"],
["Germany", "Curaçao", "Côte d'Ivoire", "Ecuador"],
["Netherlands", "Japan", "Sweden", "Tunisia"],
["Belgium", "Egypt", "IR Iran", "New Zealand"],
["Spain", "Cabo Verde", "Saudi Arabia", "Uruguay"],
["France", "Senegal", "Iraq", "Norway"],
["Argentina", "Algeria", "Austria", "Jordan"],
["Portugal", "Congo DR", "Uzbekistan", "Colombia"],
["England", "Croatia", "Ghana", "Panama"]
]
ratings = {
"France": 1877.32,
"Spain": 1876.4,
"Argentina": 1874.81,
"England": 1825.97,
"Portugal": 1763.83,
"Brazil": 1762.66,
"Netherlands": 1757.87,
"Morocco": 1755.87,
"Belgium": 1734.71,
"Germany": 1731.3,
"Croatia": 1717.07,
"Colombia": 1695.99,
"Senegal": 1686.41,
"Mexico": 1684.13,
"USA": 1675.7,
"Uruguay": 1673.07,
"Japan": 1661.58,
"Switzerland": 1650.75,
"IR Iran": 1616.04,
"Türkiye": 1601.99,
"Austria": 1597.4,
"Ecuador": 1596.48,
"Korea Republic": 1589.65,
"Australia": 1578.66,
"Egypt": 1565.56,
"Algeria": 1564.26,
"Canada": 1560.62,
"Norway": 1555.6,
"Panama": 1539.14,
"Côte d'Ivoire": 1532.98,
"Sweden": 1510.11,
"Paraguay": 1503.5,
"Czechia": 1503.04,
"Scotland": 1499.92,
"Tunisia": 1479.1,
"Congo DR": 1478.35,
"Uzbekistan": 1461.21,
"Qatar": 1452.37,
"Iraq": 1447.77,
"South Africa": 1428.38,
"Saudi Arabia": 1419.73,
"Jordan": 1390.1,
"Bosnia and Herzegovina": 1385.77,
"Cabo Verde": 1369.29,
"Ghana": 1345.23,
"Curaçao": 1293.08,
"Haiti": 1291.71,
"New Zealand": 1281.57
}
round_32_slots = [
"1E", "?", "1I", "?", "2A", "2B", "1F", "2C",
"2K", "2L", "1H", "2J", "1D", "?", "1G", "?",
"1C", "2F", "2E", "2I", "1A", "?", "1L", "?",
"1J", "2H", "2D", "2G", "1B", "?", "1K", "?"
]
third_place_rules = {
"ACDEGIJL": ["E", "G", "J", "C", "A", "D", "L", "I"]
}
def get_goal_margin(rating_gap):
if rating_gap >= 500:
return 3
if rating_gap >= 250:
return 2
if rating_gap >= 100:
return 1
return 0
def play_game(first_team, second_team, knock_out_game=False):
rating_gap = abs(ratings[first_team] - ratings[second_team])
goal_margin = get_goal_margin(rating_gap)
if goal_margin == 0:
if knock_out_game:
if ratings[first_team] > ratings[second_team]:
return first_team, second_team, "penalties"
return second_team, first_team, "penalties"
return None, None, "draw"
if ratings[first_team] > ratings[second_team]:
return first_team, second_team, goal_margin
return second_team, first_team, goal_margin
def write_game_line(first_team, second_team, knock_out_game=False):
winner, loser, result = play_game(first_team, second_team, knock_out_game)
if result == "draw":
return f"{first_team} drew with {second_team}", None
if result == "penalties":
return f"{winner} beat {loser} on penalties", winner
if result == 1:
return f"{winner} beat {loser} by 1 goal", winner
return f"{winner} beat {loser} by {result} goals", winner
def run_tournament():
group_letters = "ABCDEFGHIJKL"
lines = []
group_standings = {}
third_place_list = []
for group_letter, group_teams in zip(group_letters, groups):
team_stats = {}
for team in group_teams:
team_stats[team] = {
"points": 0,
"goal_difference": 0
}
lines.append(f"--- Group {group_letter} Matches ---")
for first_team, second_team in combinations(group_teams, 2):
match_line, _ = write_game_line(first_team, second_team)
lines.append(match_line)
winner, loser, result = play_game(first_team, second_team)
if result == "draw":
team_stats[first_team]["points"] += 1
team_stats[second_team]["points"] += 1
else:
team_stats[winner]["points"] += 3
team_stats[winner]["goal_difference"] += result
team_stats[loser]["goal_difference"] -= result
final_table = sorted(
group_teams,
key=lambda team: (
-team_stats[team]["points"],
-team_stats[team]["goal_difference"],
-ratings[team]
)
)
group_standings[group_letter] = final_table
lines.append("")
lines.append(f"--- Group {group_letter} Table ---")
for place, team in enumerate(final_table, 1):
points = team_stats[team]["points"]
goal_difference = team_stats[team]["goal_difference"]
lines.append(f"{place}. {team} {points} {goal_difference}")
lines.append("")
third_team = final_table[2]
third_place_list.append({
"group": group_letter,
"team": third_team,
"points": team_stats[third_team]["points"],
"goal_difference": team_stats[third_team]["goal_difference"],
"rating": ratings[third_team]
})
third_place_list.sort(
key=lambda team: (
-team["points"],
-team["goal_difference"],
-team["rating"]
)
)
best_third_placed_teams = third_place_list[:8]
eliminated_third_placed_teams = third_place_list[8:]
lines.append("--- Third Place Qualifiers ---")
for place, team in enumerate(best_third_placed_teams, 1):
lines.append(
f"{place}. {team['team']} {team['points']} {team['goal_difference']}"
)
lines.append("--- Third Place Eliminations ---")
for place, team in enumerate(eliminated_third_placed_teams, 9):
lines.append(
f"{place}. {team['team']} {team['points']} {team['goal_difference']}"
)
third_place_key = "".join(sorted(team["group"] for team in best_third_placed_teams))
if third_place_key not in third_place_rules:
raise ValueError(f"No third-place rule found for {third_place_key}")
group_winners_that_face_third = ["A", "B", "D", "E", "G", "I", "K", "L"]
third_place_order = third_place_rules[third_place_key]
third_team_for_winner = dict(zip(group_winners_that_face_third, third_place_order))
team_places = {}
for group_letter in group_letters:
table = group_standings[group_letter]
team_places[f"1{group_letter}"] = table[0]
team_places[f"2{group_letter}"] = table[1]
team_places[f"3{group_letter}"] = table[2]
current_bracket = []
for slot_number, slot in enumerate(round_32_slots):
if slot != "?":
current_bracket.append(team_places[slot])
else:
previous_slot = round_32_slots[slot_number - 1]
winner_group = previous_slot[1]
third_group = third_team_for_winner[winner_group]
current_bracket.append(team_places[f"3{third_group}"])
round_names = [
"Round of 32",
"Round of 16",
"Quarter Final",
"Semi Final",
"Final"
]
for round_name in round_names:
lines.append("")
lines.append(f"--- {round_name} ---")
winners = []
for game_number in range(1, len(current_bracket) // 2 + 1):
first_team = current_bracket[(game_number - 1) * 2]
second_team = current_bracket[(game_number - 1) * 2 + 1]
match_line, winner = write_game_line(
first_team,
second_team,
knock_out_game=True
)
lines.append(f"{game_number}. {match_line}")
winners.append(winner)
current_bracket = winners
return "\n".join(lines)
if __name__ == "__main__":
result = run_tournament()
print(result)
Events, groups, teams, matches etc. | greenya | Odin Solutions
package main
import "core:encoding/json"
import "core:fmt"
import "core:slice"
INPUT_TYPE :: "fifa" // "fifa", "uefa"
INPUT_GROUPS_JSON := #load("groups_" + INPUT_TYPE + ".json")
INPUT_RANKINGS_JSON := #load("rankings_" + INPUT_TYPE + ".json")
INPUT_QUALIFIERS_JSON := #load("qualifiers.json") // The third place qualifiers table
INPUT_KNOCKOUT_32_JSON := #load("knockout_32.json") // The matches played in Knockout stage with 32 teams
when INPUT_TYPE == "fifa" do input_ruler := Input_Match_Ruler { 100, 250, 500 }
else when INPUT_TYPE == "uefa" do input_ruler := Input_Match_Ruler { 20, 40, 80 }
else do #panic("input_ruler is undefined for `" + INPUT_TYPE + "`")
main :: proc () {
input_groups: Input_Groups
json.unmarshal(INPUT_GROUPS_JSON, &input_groups)
input_rankings: Input_Rankings
json.unmarshal(INPUT_RANKINGS_JSON, &input_rankings)
input_qualifiers: Input_Qualifiers
json.unmarshal(INPUT_QUALIFIERS_JSON, &input_qualifiers)
input_knockout_32: Input_Knockout_32
json.unmarshal(INPUT_KNOCKOUT_32_JSON, &input_knockout_32)
fmt.ensuref(len(input_knockout_32) == 32, "Expecting 32 teams (16 pairs) in knockout_32, got %i", len(input_knockout_32))
fmt.ensuref(len(input_groups) == 12, "Expecting 12 groups, got %i", len(input_groups))
for group, i in input_groups {
fmt.ensuref(len(group) == 4, "Expecting 4 teams, got %i in group #%i", len(group), i)
for team in group do fmt.ensuref(team in input_rankings, "Missing ranking for team `%s`", team)
}
event: Event
event_init(&event, input_groups, input_rankings, input_ruler)
event_do_groups(&event)
event_do_third_place_qualifiers_and_eliminations(&event)
event_do_knockout_32(&event, input_qualifiers, input_knockout_32)
event_do_knockout_bracket(&event, from=event.knockout.teams_16[:], to=event.knockout.teams_8[:])
event_do_knockout_bracket(&event, from=event.knockout.teams_8[:], to=event.knockout.teams_4[:])
event_do_knockout_bracket(&event, from=event.knockout.teams_4[:], to=event.knockout.teams_2[:])
event_do_knockout_bracket(&event, from=event.knockout.teams_2[:], to=event.knockout.teams_1[:])
}
Input_Groups :: [] [] string
Input_Rankings :: map [string] f32
Input_Qualifiers :: map [string] [] string
Input_Knockout_32 :: [] string
Input_Match_Ruler :: [3] f32 // 0..<[0] draw/penalties, [0]..<[1] 1 goal, [1]..<[2] 2 goals, [2]+ 3 goals
Event :: struct {
teams : [48] Event_Team,
groups : [12] Event_Group,
ruler : Input_Match_Ruler,
knockout: struct {
teams_32: [32] ^Event_Team, // Round of 32: [0..23] 12 winners and 12 runnings, [24..31] top 8 3rd places
teams_16: [16] ^Event_Team, // Round of 16
teams_8 : [8] ^Event_Team, // Quarter Final
teams_4 : [4] ^Event_Team, // Semi Final
teams_2 : [2] ^Event_Team, // Final
teams_1 : [1] ^Event_Team, // Champion
},
}
Event_Group :: struct {
name : byte,
teams : [4] ^Event_Team,
}
Event_Team :: struct {
name : string,
group : ^Event_Group,
points : int,
goals : int,
ranking : f32,
}
event_init :: proc (e: ^Event, input_groups: Input_Groups, input_rankings: Input_Rankings, input_ruler: Input_Match_Ruler) {
e^ = {}
e.ruler = input_ruler
for group, i in input_groups {
e.groups[i].name = 'A' + byte(i)
for team, j in group {
fmt.ensuref(team in input_rankings, "Missing ranking for team `%s`", team)
e.teams[i*4+j] = {
name = team,
group = &e.groups[i],
ranking = input_rankings[team],
}
e.groups[i].teams[j] = &e.teams[i*4+j]
}
}
}
event_do_groups :: proc (e: ^Event) {
for &group in e.groups {
fmt.printfln("--- Group %c Matches ---", group.name)
for i:=0; i<4; i+=1 do for j:=i+1; j<4; j+=1 {
event_teams_match(group.teams[i], group.teams[j], e.ruler, draw_allowed=true)
}
fmt.println()
event_teams_sort(group.teams[:])
fmt.printfln("--- Group %c Table ---", group.name)
for t, i in group.teams {
fmt.printfln("%i. %s %i %i", i+1, t.name, t.points, t.goals)
}
fmt.println()
}
}
event_do_third_place_qualifiers_and_eliminations :: proc (e: ^Event) {
third_place_teams: [12] ^Event_Team
for group, i in e.groups {
e.knockout.teams_32[i*2+0] = group.teams[0] // group winner
e.knockout.teams_32[i*2+1] = group.teams[1] // group runner
third_place_teams[i] = group.teams[2] // third place candidate
}
event_teams_sort(third_place_teams[:])
for team, i in third_place_teams {
if i < 8 do e.knockout.teams_32[12*2+i] = team
if i == 0 do fmt.println("--- Third Place Qualifiers ---")
if i == 8 do fmt.println("--- Third Place Eliminations ---")
fmt.printfln("%i. %s %i %i", i+1, team.name, team.points, team.goals)
}
fmt.println()
}
event_do_knockout_32 :: proc (e: ^Event, input_qualifiers: Input_Qualifiers, input_knockout_32: Input_Knockout_32) {
fmt.println("--- Round of 32 ---")
q_row := event_qualifiers_row(e, input_qualifiers)
for &winner, i in e.knockout.teams_16 {
pair: [2] ^Event_Team
for &team, j in pair {
group_name: byte
team_pos: int
key := input_knockout_32[i*2+j]
if key == "?" {
assert(1 == j) // The "?" can only be the second in a pair
assert(1 == event_team_group_pos(pair[0])) // and 1st team must be a winner, e.g. 1E not 2E
group_name = q_row[pair[0].group.name-'A']
team_pos = 3
} else {
group_name = key[1]
team_pos = int(key[0]-'0')
}
team = event_team_in_group(e.knockout.teams_32[:], group_name, team_pos)
}
fmt.printf("%i. ", i+1)
winner = event_teams_match(pair[0], pair[1], e.ruler, draw_allowed=false)
}
fmt.println()
}
event_do_knockout_bracket :: proc (e: ^Event, from, to: [] ^Event_Team) {
assert(len(from) == 2 * len(to))
switch len(from) {
case 16 : fmt.println("--- Round of 16 ---")
case 8 : fmt.println("--- Quarter Final ---")
case 4 : fmt.println("--- Semi Final ---")
case 2 : fmt.println("--- Final ---")
case : panic("Unexpected bracket size")
}
for &winner, i in to {
fmt.printf("%i. ", i+1)
winner = event_teams_match(from[i*2+0], from[i*2+1], e.ruler, draw_allowed=false)
}
fmt.println()
}
event_qualifiers_row :: proc (e: ^Event, input_qualifiers: Input_Qualifiers) -> [12] byte {
q_key: [8] byte
for &b, i in q_key do b = e.knockout.teams_32[i+24].group.name
slice.sort(q_key[:])
q_key_str := string(q_key[:])
fmt.ensuref(q_key_str in input_qualifiers, "Missing qualifier key `%s`", q_key_str)
q: [8] byte
for s, i in input_qualifiers[q_key_str] do q[i] = s[0]
// 1A 1B 1C 1D 1E 1F 1G 1H 1I 1J 1K 1L
return { q[0], q[1], 0, q[2], q[3], 0, q[4], 0, q[5], 0, q[6], q[7] }
}
event_teams_match :: proc (team1, team2: ^Event_Team, ruler: Input_Match_Ruler, draw_allowed := true) -> (winner: ^Event_Team) {
ranking_diff := team1.ranking - team2.ranking
ranking_diff_abs := abs(ranking_diff)
if ranking_diff_abs < ruler[0] && draw_allowed {
fmt.printfln("%s drew with %s", team1.name, team2.name)
team1.points += 1
team2.points += 1
return
}
goals: int
beat_order: [2] ^Event_Team = ranking_diff > 0 ? { team1, team2 } : { team2, team1 }
beat_order[0].points += 3
switch {
case ranking_diff_abs < ruler[0]:
fmt.printfln("%s beat %s on penalties", beat_order[0].name, beat_order[1].name)
// ignore goals counter for penalties
case ranking_diff_abs < ruler[1]:
fmt.printfln("%s beat %s by 1 goal", beat_order[0].name, beat_order[1].name)
goals = 1
case ranking_diff_abs < ruler[2]:
fmt.printfln("%s beat %s by 2 goals", beat_order[0].name, beat_order[1].name)
goals = 2
case:
fmt.printfln("%s beat %s by 3 goals", beat_order[0].name, beat_order[1].name)
goals = 3
}
beat_order[0].goals += goals
beat_order[1].goals -= goals
return beat_order[0]
}
event_teams_sort :: proc (teams: [] ^Event_Team) {
slice.sort_by(teams[:], less = proc (t1, t2: ^Event_Team) -> bool {
switch {
case t1.points != t2.points : return t1.points > t2.points
case t1.goals != t2.goals : return t1.goals > t2.goals
case : return t1.ranking > t2.ranking
}
})
}
event_team_in_group :: proc (teams: [] ^Event_Team, group_name: byte, team_pos: int) -> ^Event_Team {
Args :: struct { group_name: byte, team_pos: int }
context.user_ptr = &Args { group_name, team_pos }
i, ok := slice.linear_search_proc(teams, proc (t: ^Event_Team) -> bool {
args := cast (^Args) context.user_ptr
return t.group.name == args.group_name && event_team_group_pos(t) == args.team_pos
})
assert(ok)
return teams[i]
}
event_team_group_pos :: proc (team: ^Event_Team) -> int {
i, ok := slice.linear_search(team.group.teams[:], team)
assert(ok)
return 1 + i
}