g | x | w | all
Bytes Lang Time Link
nandef run_tournamentcontestants241205T032736ZEonema
nan241203T133842ZSpitemas
003Python241129T040850Ztsh
nan241129T152337ZThemooni
nan241129T114407ZThemooni
def run_tournament(contestants, games, play_game):
    winners = contestants[0:len(contestants)]
    upnext = winners
    # run several elimination rounds
    while True:
        # temp list of winners
        winners = []
        seconds = []
        # run games
        while len(upnext) > 0:
            games -= 1
            # choose size of game:
            if len(upnext) < 4:
                # all that are left
                n = len(upnext)
            elif len(upnext) % 4 > 0:
                # play games of 3 until it's divisible by 4
                n = 3
            else: 
                n = 4
            upnow = upnext[0:n]
            del upnext[0:n]
            # play game
            results = play_game(upnow)
            # record winner
            winners.append(results[0])
            seconds.append(results[1])
        # winners go in next round
        upnext = winners
        # if 4 or fewer winners, go to next stage
        if len(winners) <= 4:
            break
    # second stage: repeated games with finalists:
    finalists = winners + seconds[:(4-len(winners))]
    scores = { nm : 0 for nm in finalists }
    while games > 0:
        games -= 1
        results = play_game(finalists)
        for i in range(len(results)):
            scores[list(results)[i]] += 3-i
    # return winner
    return max(scores, key=scores.get)

Here's my best attempt:

import random

def run_tournament(contestants, games, play_game):
    contestants = [[x, 0, 0] for x in contestants]
    min_games_played = 0
    remove_per_round = min((len(contestants) - 4) / min(games - 2, games * 0.9), 3)
    to_remove = 0
    while games > 0:
        games -= 1
        options = [x for x in contestants if x[1] == min_games_played]
        if len(options) > 4:
            random.shuffle(options)
            options = options[:4]
        elif len(options) < 4:
            min_games_played += 1
            random.shuffle(contestants)
            options = options + [x for x in contestants if x[1] == min_games_played and x[0] not in options][:4 - len(options)]
        result = play_game([x[0] for x in options])
        for option in options:
            option[1] += 1
            option[2] += result.index(option[0])
        to_remove += remove_per_round
        while to_remove >= 0.99 and len(contestants) > 4:
            to_remove -= 1
            worst_score = max([x[2]/x[1] for x in contestants if x[1] > 0])
            for contestant in contestants:
                if contestant[1] == 0:
                    continue
                if contestant[2] / contestant[1] == worst_score:
                    contestants.remove(contestant)
                    break
    best_score = min([x[2]/x[1] for x in contestants if x[1] > 0])
    for contestant in contestants:
        if contestant[2] / contestant[1] == best_score:
            return contestant[0]
```

Python 3

A, B, C, D, E = 10000.0, 100.0, 1.003, 50.0, 0.95

def choose_player(players):
  name, score, win, lose = players
  return (lose, -win)

def record_result(win, lose):
  win[2] += 1
  lose[3] += 1
  p = 1 - 1 / (1 + C ** (lose[1] - win[1]))
  win[1] += p * B * E ** (win[2] + win[3])
  lose[1] -= p * B * E ** (lose[2] + lose[3])

def run_tournament(contestants, games, play_game):
  map = {c: [c, A, 0, 0] for c in contestants}
  scores = [map[c] for c in contestants]
  for i in range(games):
    players = sorted(scores, key=choose_player)[:4]
    names = [p[0] for p in players]
    result = play_game(names)
    for index, win in enumerate(result):
      for lose in result[:index:-1]:
        record_result(map[win], map[lose])
  final = sorted(scores, key=lambda s: -s[1])
  return final[0][0]

Try it online!

Bash

This is, short of always returning contestants[0], the worst algorithm possible. takes the first 4 contestants, runs a game with them. returns the winner of that game. use with helper.

read numcont
contestants=()
for i in $(seq 1 $numcont); do
    read cont
    contestants+=("$cont")
done
read numgames

echo "run"
echo 4
for i in $(seq 0 3); do
    echo "${contestants[$i]}"
done
results=()
for i in $(seq 0 3); do
    read res
    results+=("$res")
done
echo "ret"
echo "${results[0]}"
Ten weak players    : 14684    0.63590
Two groups          : 19462    0.78026
Huge pool           : 6031    0.78219
32 skilled players  : 8392    0.73068
Average             : 12142    0.73226

Other language helper

put the following code in a file named helper.py:

from subprocess import Popen, PIPE
import sys
from time import sleep

sleeptime = 0
def run_tournament(contestants, games, play_game):
    # contestants: an array of contestant names
    # games: a number - this is the maximum number of games you're allowed to play
    # play_game: a function which takes an array of contestants and returns the outcome of a game which they all play
    # returns a single string, expected to be the name of one of the competitors
    process = Popen([arg for arg in sys.argv[2:]], stdout=PIPE, stdin=PIPE, text=True, universal_newlines=True, bufsize=1)
    process.stdin.write(str(len(contestants)) + "\n")
    for c in contestants:
        process.stdin.write(c + "\n")
    process.stdin.write(str(games) + "\n")
    i=0
    while i<games:
        #sleep(sleeptime)
        line = process.stdout.readline().strip()
        if line == "run":
            #sleep(sleeptime)
            numplayers = int(process.stdout.readline())
            players = []
            for j in range(numplayers):
                #sleep(sleeptime)
                players.append(process.stdout.readline().strip())
            res = play_game(players)
            for p in res:
                process.stdin.write(p+"\n")
            i+=1
        elif line == "ret":
            #sleep(sleeptime)
            return process.stdout.readline().strip()
        else:
            raise ChildProcessError("Command not in [run, ret] recieved")
    raise ChildProcessError("No games are left, but never returned")

run using python3 main.py helper $(which <program>) [additional args passed to program...]

From the perspective of your program, the protocol looks like:

STDIN                                    STDOUT
                     init phase:
<number of contestants>
<name of contestant 1>
... repeat n times
<number of games>
                    ->goto loop
                     loop phase:
                                          run
                                          ->goto "run"
                                          (or)
                                          ret
                                          ->goto "ret"
                    "run" phase:
                                          <number of contestants in that game>
                                          <name of contestant 1>
                                          ...repeat n times
<name of winner>
...additional contestants, sorted
                    ->goto loop
                    "ret" phase:
                                          <name of overall winner>
             program is expected to terminate here.

Notes: