PyLeague Academy

Learn to
code
a winning team.

This isn't about memorizing the whole engine. It's about understanding the three decisions your team makes and tuning them until they win matches. We take you from the template that already plays to your first win against a real opponent.

Where to start

Your path, from zero to competing

You don't need to write a team from scratch. The short path is this: start from something that already works and improve it methodically, measuring every change.

01

Copy the template

It already plays competitively: it passes, shoots to the corners and presses loose balls. It's your starting point, not a blank page.

$ cp -r equipos/plantilla equipos/miequipo
02

Change one thing

Touch only the tactics, or only the player. One change at a time is the only way to know what helps and what hurts.

03

Measure with sparring

Pit it against several opponents over many seeds and watch win-rate and stats. That way a lucky match won't fool you.

$ python sparring.py --team equipos/miequipo
04

Compete

Upload your team to the platform and take on leagues with an ELO ranking, or set up your own. The code speaks.

$ python league.py
What you code

Three layers, from slow to fast

Your team decides at three levels. The key idea: the AI (if you use it) sets the plan at a slow pace, and a fast, deterministic layer runs it every moment. That way a model never has to decide 20 times per second. Customize only the layer you care about; reuse the rest.

10

Coach

Reads the score and the clock and sets the mentality: attack, balance or defend. Decides rarely, but sets the tone. CoachBrain.decide(ctx)

paceslow
6

Tactics

Positions the team on the pitch with four knobs: line height, width, pressing and flank. This is almost always where the match is won or lost. TeamStrategy.plan(ctx)

pacemedium
9

Player

Decides every moment: move, pass, shoot, sprint. Fast and reactive, one per player. PlayerBrain.decide(view)

everytick

Want the detail of what each layer receives and returns? It's in the Participant guide.

Tactics, no math

Your team, in four knobs

You don't compute positions by hand. You pick four values and the engine turns them into where each player stands. You can fix them or make them change with the match (a reactive tactic).

line_height · 0.0 → 1.0

Line height

How high up your team plays. Low = a safe, dropped-back block; high = you press up top but leave space behind.

width · 0.0 → 1.0

Width

How open the team is. Compact plugs the center; open works the flanks and stretches the opponent.

pressing · 0.0 → 1.0

Pressing

How hard you go for the ball. Careful: right now heavy pressing tires you out and doesn't always win it back (read the “meta” below).

focus · left / center / right

Attacking flank

Which side you funnel play through. Center by default; shift it to a flank to attack there or to find your striker's run.

Real code

Your first tactic, in six lines

A fixed tactic is a dictionary of knobs. A reactive one is a function that recomputes them by reading the match. Both are short.

mi_tactica.py
# 1) FIXED tactic: a constant style
from aicup import TacticalStrategy

mi_estilo = TacticalStrategy("Mi estilo", {
    "line_height": 0.35,   # dropped back, safe
    "width":       0.45,   # compact through the center
    "pressing":    0.30,   # I hold off, I don't dive in
})

# 2) REACTIVE tactic: changes with the match
from aicup.tactics import progress, possession

def mandos(ctx):
    defendiendo = possession(ctx) == "theirs" or progress(ctx) < 0.45
    if defendiendo:
        return {"line_height": 0.30, "pressing": 0.35}   # I drop back
    return {"line_height": 0.74, "pressing": 0.50}       # on the steal, I break forward

mi_contra = TacticalStrategy("Mi contraataque", mandos)

Any knob you leave out uses its default value. The full gallery (tiki-taka, catenaccio, gegenpressing…) and how to write the player and the coach are in the tactics docs.

Recipes to win

What really makes the difference

Tips that come from playing hundreds of matches. No magic: just the habits that separate a team that competes from one that just makes up the numbers.

Measure, don't guess

A single match lies: luck counts. Use sparring with many seeds and decide by win-rate, not by gut feel.

Exploit the meta

Right now a compact, dropped-back block outperforms high pressing. Start solid at the back and build from there.

Manage stamina

Sprinting and hard shots tire you out. Save sprints for the final stretch and press the opponent who's already spent.

Use the team plan

In your player, read view.plan: it tells you where to position and whose turn it is to go for the ball. Don't improvise on your own.

Shoot to the corners

Shooting down the middle hands the ball to the keeper. Aim for the posts and adjust the power: it's not all max force.

Level up in order

First the tactics (knobs), then the player (passes, shots, marking) and finally the coach (when to take risks).

Common mistakes

And how to avoid them

Almost everyone trips up here at the start. Seeing them coming saves you half a dozen silly losses.

Full pressing all the time

You expect to win the ball back and only wear yourself out. Fix: lower the pressing and press in bursts, not all the time.

Wandering keeper

A GK far from goal is goals gifted away. Fix: keep him close; see how the sample player handles it.

Line too high with no cover

You push everyone up and get caught in behind. Fix: push midfielders and forwards higher than the defense, or drop the line.

Overfitting to one opponent

You beat one and lose to everyone else. Fix: test against several opponents and several seeds before calling anything good.

Shooting at max power

Always full force = you run out of stamina and shoot worse late on. Fix: ration your kick_power.

Code that crashes

The engine protects you, but a player that errors out stands still and you lose ticks. Fix: test locally and check the viewer.

The engine's “meta”

Discovering what wins is part of the game

An honest detail about today's engine: compact, defensive tactics perform better than high pressing. The reason is that, for now, pressing doesn't effectively “win” the ball —possession is sticky and taking it away means closing down with a big margin—. That's why catenaccio-style approaches tend to do very well and gegenpressing struggles.

The sample tactics are starting points, not optimal solutions. The engine will evolve (the roadmap includes pressing eventually winning the ball), so the meta will change too. Finding the combination that wins right now is your competitive edge.

Before you compete

Is your team ready?

Run through this quick checklist. If you tick everything, you can upload it and take on the rest.

  • Plays without failing: it lasts a whole match with no exceptions and no players standing still.
  • Beats the template: it takes matches off the benchmark opponent across several seeds.
  • Has a clear idea: you know why it positions the way it does.
  • Uses stamina wisely: it doesn't arrive spent at the end or waste sprints.
  • Shoots with judgment: it aims for the corners and rations the power.
  • Measured with data: you've run it through sparring, not just a single match.
Now it's your turn

Now you know how.
Let the code decide.

Create your account and compete online in minutes, or clone it and work locally. In basic mode it works with no API and no setup.