matchmaker 0.2.0 copy "matchmaker: ^0.2.0" to clipboard
matchmaker: ^0.2.0 copied to clipboard

A pure Dart package for skill rating and matchmaking systems. Matchmaker provides battle-tested rating algorithms for competitive games and multiplayer applications.

Matchmaker #

pub package License: MIT

Skill rating and matchmaking algorithms for competitive games. Currently supports Glicko-2 and Elo.

Supported Rating Systems #

Glicko-2 #

Glicko-2 is an improved version of the classic Elo rating system. While Elo just tracks a single number, Glicko-2 tracks three things:

  • Rating: Your skill level (usually starts at 1500)
  • Rating Deviation (RD): How certain we are about your rating. New players have high RD, which drops as they play more
  • Volatility: How consistent you are. Erratic players have high volatility

Best for: Games with varying player activity, 1v1 competitive games, any scenario where you need to track rating uncertainty.

Elo #

The classic rating system developed by Arpad Elo for chess. Simple and effective - just one number that goes up when you win and down when you lose. Rating differences directly translate to win probabilities using a logistic curve.

  • Clean mathematical foundation (logistic function)
  • No uncertainty tracking - just skill level
  • Easy to understand and explain to players
  • Battle-tested across decades of competitive chess

Best for: Simple 1v1 games, when you want something straightforward, or when rating updates need to be transparent to players.

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  matchmaker: ^0.1.0

Usage #

Glicko-2 #

Quick Start

import 'package:matchmaker/matchmaker.dart';

void main() {
  const glicko = Glicko2();

  // New players start with default ratings
  const ricardo = Glicko2Rating(
    rating: 1500,
    rd: 200,
    volatility: 0.06,
  );

  const lucas = Glicko2Rating(
    rating: 1400,
    rd: 30,
    volatility: 0.06,
  );

  // Ricardo plays against Lucas and wins
  final results = [MatchResult.win(lucas)];

  // Calculate Ricardo's new rating
  final newRating = glicko.calculateNewRating(ricardo, results);

  print('New rating: ${newRating.rating.toStringAsFixed(0)}');
  print('New RD: ${newRating.rd.toStringAsFixed(2)}');
}

Tournament with multiple matches

const glicko = Glicko2();

const ricardo = Glicko2Rating(rating: 1500, rd: 200, volatility: 0.06);
const lucas = Glicko2Rating(rating: 1400, rd: 150, volatility: 0.06);
const rodrigo = Glicko2Rating(rating: 1600, rd: 180, volatility: 0.06);

// Ricardo plays three games
final results = [
  MatchResult.win(lucas),
  MatchResult.loss(rodrigo),
  MatchResult.draw(rodrigo),
];

final newRating = glicko.calculateNewRating(ricardo, results);

Predict match outcomes

const strong = Glicko2Rating(rating: 1800, rd: 50, volatility: 0.06);
const weak = Glicko2Rating(rating: 1200, rd: 200, volatility: 0.06);

final winChance = glicko.predictOutcome(strong, weak);
print('Win probability: ${(winChance * 100).toStringAsFixed(1)}%');

Confidence intervals

const player = Glicko2Rating(rating: 1650, rd: 80, volatility: 0.06);
final interval = player.getConfidenceInterval();

print('95% confident true skill is between '
      '${interval.lower.toStringAsFixed(0)} and '
      '${interval.upper.toStringAsFixed(0)}');

Handle inactive players

When a player doesn't compete, their rating stays the same but uncertainty increases:

var player = const Glicko2Rating(rating: 1600, rd: 50, volatility: 0.06);

// No games this period
player = glicko.calculateNewRating(player, []);

print('Rating: ${player.rating}');   // Still 1600
print('RD: ${player.rd}');           // Increased

Configuration

Customize the Glicko-2 system if you want:

const glicko = Glicko2(
  volatilityConstraint: 0.5,  // How much volatility can change (0.3-1.2)
);

volatilityConstraint: Lower (0.3-0.6) for stable games, higher (0.8-1.2) for unpredictable ones. Default 0.5 works well for most cases.

Rating Periods

Glicko-2 works best when you batch games into rating periods instead of updating after every single game. Think of it like updating ratings once a week instead of after each match.

How many games per period? Aim for 10-15 games per player, minimum 5.

How long should a period be?

  • Active games: 1 day to 1 week
  • Normal activity: 1-2 weeks
  • Slow games: 2 weeks to 1 month

Here's the basic flow:

// Collect all matches during the rating period
final playerMatches = <String, List<MatchResult>>{};

// ... games happen ...

// At the end of the period, update everyone at once
for (final playerId in playerMatches.keys) {
  final currentRating = getCurrentRating(playerId);
  final matches = playerMatches[playerId]!;
  
  final newRating = glicko.calculateNewRating(currentRating, matches);
  saveRating(playerId, newRating);
}

Elo #

Quick Start

import 'package:matchmaker/matchmaker.dart';

void main() {
  const elo = Elo();

  // Players start with a rating (usually 1500)
  const ricardo = EloRating(rating: 1500);
  const lucas = EloRating(rating: 1400);

  // Ricardo beats Lucas
  final results = [MatchResult.win(lucas)];
  final newRating = elo.calculateNewRating(ricardo, results);

  print('Ricardo new rating: ${newRating.rating.toStringAsFixed(0)}');
  // Output: Ricardo new rating: 1521
}

Predict match outcomes

const elo = Elo();
const stronger = EloRating(rating: 1700);
const weaker = EloRating(rating: 1500);

final winChance = elo.predictOutcome(stronger, weaker);
print('Win probability: ${(winChance * 100).toStringAsFixed(1)}%');
// Output: Win probability: 76.0%

Series of games

const elo = Elo();
var player = const EloRating(rating: 1500);
const opponent = EloRating(rating: 1600);

// Player loses, then wins, then draws
player = elo.calculateNewRating(player, [MatchResult.loss(opponent)]);
player = elo.calculateNewRating(player, [MatchResult.win(opponent)]);
player = elo.calculateNewRating(player, [MatchResult.draw(opponent)]);

print('Final rating: ${player.rating.toStringAsFixed(0)}');

Multiple games at once

const elo = Elo();
const player = EloRating(rating: 1500);
const opponent = EloRating(rating: 1600);

// Process multiple games in one batch
final results = [
  MatchResult.win(opponent),
  MatchResult.loss(opponent),
  MatchResult.draw(opponent),
];

final newRating = elo.calculateNewRating(player, results);

Configuration

const elo = Elo(
  kFactor: 16,        // How fast ratings change (10-32)
  defaultRating: 1500, // Starting rating for new players
);

kFactor: Controls how much ratings change per game

  • 32: Fast changes, good for newer players (USCF standard)
  • 24: Medium speed
  • 16: Slower changes, good for established players
  • 10: Very stable, for high-level play (FIDE standard)

Lower K-factors make ratings more stable but slower to adjust. Higher values let ratings adapt quickly but can be more volatile.

License #

MIT

1
likes
160
points
124
downloads

Publisher

unverified uploader

Weekly Downloads

A pure Dart package for skill rating and matchmaking systems. Matchmaker provides battle-tested rating algorithms for competitive games and multiplayer applications.

Repository (GitHub)
View/report issues
Contributing

Topics

#game #rating #matchmaking #glicko #elo

Documentation

API reference

License

MIT (license)

More

Packages that depend on matchmaker