The Algorithm Behind
Every Pick.
A 12-team snake draft simulator powered by VOR-based ranking, 9 AI strategy archetypes, a real-time pick engine, and live NFL projections from SportsData.io.
228 Picks. 9 Strategies. 1 Algorithm.
What looks like a game is actually a multi-agent optimization problem — every AI bot runs a different strategy, reacts to positional scarcity, and competes on a shared ranking surface built from projected statistics.
Player Pool Assembled
220+ players loaded with projected stats for 2026 — or live data from SportsData.io if available. Each player gets 5 raw stats mapped by position: pass yards, rush TDs, receptions, etc.
VOR Rankings Computed
Value Over Replacement normalizes fantasy points across positions. A RB scoring 280 pts outranks a QB at 350 pts once scarcity is factored — the drop-off from elite to replacement RBs is far steeper.
9 AI Archetypes Ready
Each bot runs a named strategy (Robust RB, Zero RB, Hero RB, TE Premium, Late QB, Stars & Scrubs, Balanced BPA, Contrarian, Anchor RB) with distinct positional weight multipliers.
Snake Draft Executes
19 rounds, 12 teams, 228 picks. Pick order reverses each round — the snake format. A real-time engine fires picks with a configurable timer, live ticker, and feed showing every selection.
Positional Runs Emerge
When 3+ players at a position are drafted in a short window, the AI urgency multiplier kicks in for remaining players at that spot — simulating the cascading runs seen in real draft rooms.
Draft Grade Calculated
Post-draft analytics rank all 12 teams on starter projected points, total VOR captured, bye week concentration, and bench depth. Grades A+ through D are assigned by rank position.
Try It: Two Ways to Explore
ELI5 explains the draft strategy concept in plain English. Engineer mode runs the full 19-round simulator with live data, real-time pick feed, and post-draft analytics.
Pick Your Draft Strategy
Each archetype bets differently on where value hides. Pick one and see which players your algorithm would target in the first 8 rounds.
2026 Fantasy Draft Room
12-team snake draft simulator with 9 AI archetypes, VOR-based rankings, and real-time analytics.
Your Competition
Six Concepts That Drive Every Pick
From the math behind VOR to the game theory of positional scarcity — understand the engine before you run it.
Four Engineering Decisions That Matter
Why the simulator behaves the way it does — each choice reflects a real fantasy football principle with a measurable effect on draft outcomes.
VOR Over Raw Points
A QB scoring 350 pts and a RB scoring 250 pts aren't comparable. VOR subtracts the replacement-level baseline per position (QB13, RB25, WR25, TE13 in a 12-team league). After VOR adjustment, the RB often ranks higher because the RB1→RB25 drop-off is twice as steep as QB1→QB13. This is why elite RBs routinely go before elite QBs in real drafts.
9 Archetypes, Not One Optimal Bot
Real drafts have diverse strategies. Zero RB exploits waiver-wire RB value; Robust RB locks in scarce positional value early; TE Premium bets on the extreme scarcity cliff at tight end. By modeling 9 real strategies, the simulator creates realistic positional runs, reaches, and value falls that a single-strategy AI would never produce. Draft variance requires behavioral diversity.
±8% Jitter Creates Realistic Variance
Perfect AI play is boring and unrealistic. Real drafters have biases, sleeper picks, and team preferences. The val *= (0.92 + Math.random() * 0.16) jitter causes occasional reaches (3–5 picks early) and steals (player falls unexpectedly), creating the variance that makes each draft unique and strategically meaningful.
SportsData.io Projections with Fallback
On load, the simulator fetches live 2026 season projections and ADP from SportsData.io via two API endpoints (player projections + DST). If the API fails or returns insufficient data (<60 players), it silently falls back to hardcoded 2026 projections — a graceful degradation pattern that keeps the demo functional regardless of external API availability.
Core Algorithms
The Python implementations behind VOR ranking, AI strategy weighting, snake order generation, and post-draft grading.
🧮 VOR Calculation Engine (Python)
# ── Value Over Replacement (VOR) Calculation ──────────────────────
# VOR normalizes fantasy points across positions by subtracting
# the "replacement level" — the best player available on waivers.
def compute_vor(players: list[dict], league_size: int = 12) -> list[dict]:
"""
Compute VOR for each player.
Replacement level = the (N+1)th player at each position,
where N = starting slots × league_size.
"""
# Replacement thresholds: how many starters exist league-wide
# QB1 × 12 = 12 starters → replacement = QB13
# RB1-RB2 × 12 = 24 starters → replacement = RB25
starters_per_team = {"QB": 1, "RB": 2, "WR": 2, "TE": 1, "K": 1, "DST": 1}
replacement_rank = {
pos: (slots * league_size) + 1
for pos, slots in starters_per_team.items()
}
# e.g. {"QB": 13, "RB": 25, "WR": 25, "TE": 13, "K": 13, "DST": 13}
from collections import defaultdict
by_pos = defaultdict(list)
for p in players:
by_pos[p["pos"]].append(p)
for pos in by_pos:
by_pos[pos].sort(key=lambda x: x["projected_pts"], reverse=True)
replacement_pts = {}
for pos, rank in replacement_rank.items():
idx = min(rank - 1, len(by_pos[pos]) - 1)
replacement_pts[pos] = by_pos[pos][idx]["projected_pts"] if idx >= 0 else 0
for p in players:
p["vor"] = round(p["projected_pts"] - replacement_pts[p["pos"]], 1)
players.sort(key=lambda x: x["vor"], reverse=True)
return players
# Example: QB with 350 pts, replacement QB13 = 260 pts → VOR = 90
# RB with 280 pts, replacement RB25 = 120 pts → VOR = 160
# The RB ranks HIGHER despite fewer raw points — scarcity wins.
🤖 AI Draft Strategy Engine (Python)
# ── AI Draft Strategy: Weighted VOR with Archetype Biases ─────────
STRATEGIES = {
"Robust RB": {"QB": 0.50, "RB": 1.55, "WR": 0.85, "TE": 0.60, "K": 0.30, "DST": 0.30},
"Zero RB": {"QB": 0.70, "RB": 0.45, "WR": 1.50, "TE": 1.15, "K": 0.30, "DST": 0.30},
"Hero RB": {"QB": 0.60, "RB": 1.10, "WR": 1.35, "TE": 0.75, "K": 0.30, "DST": 0.30},
"TE Premium": {"QB": 0.65, "RB": 1.00, "WR": 1.00, "TE": 1.70, "K": 0.30, "DST": 0.30},
"Late QB": {"QB": 0.25, "RB": 1.25, "WR": 1.25, "TE": 0.90, "K": 0.30, "DST": 0.30},
"Balanced BPA": {"QB": 1.00, "RB": 1.00, "WR": 1.00, "TE": 1.00, "K": 0.50, "DST": 0.50},
}
def ai_pick(available: list, team_roster: list, strategy: dict) -> dict:
"""Select best player using strategy-weighted VOR."""
weights = strategy
pos_counts = {p["pos"]: pos_counts.get(p["pos"], 0) + 1 for p in team_roster}
pos_needs = {"QB": 3, "RB": 5, "WR": 5, "TE": 2, "K": 2, "DST": 2}
best, best_score = None, float("-inf")
for player in available[:60]: # scan top 60 by VOR
score = player["vor"] * weights.get(player["pos"], 1.0)
# Need bonus: +15% if roster slot open
if pos_counts.get(player["pos"], 0) < pos_needs[player["pos"]]:
score *= 1.15
else:
score *= 0.45 # heavy penalty if position full
# Scarcity check: positional urgency
remaining = sum(1 for p in available[:40] if p["pos"] == player["pos"])
if remaining <= 3:
score *= 1.35
elif remaining <= 6:
score *= 1.12
# Behavioral jitter: ±8% randomization
import random
score *= (0.92 + random.random() * 0.16)
if score > best_score:
best, best_score = player, score
return best
🐍 Snake Draft Order Generator (Python)
# ── Snake Draft Order ────────────────────────────────────────────
# In a snake draft, odd rounds go 1→12, even rounds go 12→1.
# This creates the "snake" pattern that ensures fairness.
def build_draft_queue(num_teams: int = 12, num_rounds: int = 19) -> list[dict]:
"""
Returns a flat list of {round, pick_in_round, team_idx}
in snake order across all rounds.
"""
queue = []
for r in range(num_rounds):
order = list(range(num_teams))
if r % 2 == 1: # even rounds (0-indexed) reverse
order = order[::-1]
for pick_pos, team_idx in enumerate(order):
queue.append({
"round": r,
"pick_in_round": pick_pos,
"team_idx": team_idx,
"overall_pick": r * num_teams + pick_pos + 1,
})
return queue
# Example output (12-team, first 2 rounds):
# Round 1: teams 0,1,2,...,11 (picks 1–12)
# Round 2: teams 11,10,9,...,0 (picks 13–24)
# Team 0 gets picks 1 and 24 (gap = 23)
# Team 11 gets picks 12 and 13 (back-to-back)
📊 Post-Draft Grade Analysis (Python)
# ── Post-Draft Grading Algorithm ──────────────────────────────────
# Grades each team on four dimensions then assigns A+ through D.
def grade_team(roster: list, all_teams: list, league_size: int = 12) -> dict:
by_pos = {}
for p in roster:
by_pos.setdefault(p["pos"], []).append(p)
for pos in by_pos:
by_pos[pos].sort(key=lambda x: x["projected_pts"], reverse=True)
# 1. Starter Projected Points
starter_pts = 0
if by_pos.get("QB"): starter_pts += by_pos["QB"][0]["projected_pts"]
for i in range(min(2, len(by_pos.get("RB", [])))):
starter_pts += by_pos["RB"][i]["projected_pts"]
for i in range(min(2, len(by_pos.get("WR", [])))):
starter_pts += by_pos["WR"][i]["projected_pts"]
if by_pos.get("TE"): starter_pts += by_pos["TE"][0]["projected_pts"]
# FLEX: best remaining RB/WR/TE
flex = sorted(
[p for pos in ["RB","WR","TE"] for p in by_pos.get(pos,[])[2:]],
key=lambda x: x["projected_pts"], reverse=True
)
if flex: starter_pts += flex[0]["projected_pts"]
if by_pos.get("K"): starter_pts += by_pos["K"][0]["projected_pts"]
if by_pos.get("DST"): starter_pts += by_pos["DST"][0]["projected_pts"]
# 2. Bye Week Concentration Penalty
bye_counts = {}
for p in roster:
bye_counts[p["bye"]] = bye_counts.get(p["bye"], 0) + 1
bye_penalty = sum(1 for count in bye_counts.values() if count >= 3)
# 3. Rank among all teams, assign grade
all_starter_pts = sorted(
[compute_starter_pts(t) for t in all_teams], reverse=True
)
rank = all_starter_pts.index(starter_pts) + 1
grade_map = ["A+","A","A","A-","B+","B","B","B-","C+","C","C-","D"]
grade_idx = min(rank - 1 + bye_penalty, len(grade_map) - 1)
return {
"grade": grade_map[grade_idx],
"rank": rank,
"starter_pts": round(starter_pts),
"bye_conflicts": bye_penalty,
"total_vor": round(sum(p["vor"] for p in roster)),
}
🏈 Built for the Portfolio
This demo is part of the 7-Ideations Framework — a portfolio approach that walks from narrative to live demo to classroom to production code. Every pick in the simulator reflects a real algorithmic decision: VOR ranking, strategy-weighted AI, scarcity detection, and post-draft analytics.
The most modern resume for the most modern city on earth.