Forest Logo
search
package_2

luce

By @raiven4ever

Roblox

Mirrored

Luce

Luce is a small, dependency-free Luau implementation of the Weng–Lin Bayesian rating system using the Plackett–Luce model. It supports individual and team ratings, ranked matches, ties, win probabilities, and draw probabilities.

[!WARNING] Luce was made primarily for learning and curiosity. It has not received the testing or real-world validation of an established rating library, so use it at your own risk. For production or otherwise intensive use, consider openskill.lua instead.

Luce may still suit smaller projects that want a focused, inspectable Plackett–Luce implementation with no runtime dependencies.

Installation

Add Luce to your wally.toml:

[dependencies]
Luce = "raiven4ever/luce@1.0.0"

Then install it:

wally install

Ratings

A rating contains an estimated skill (mu), uncertainty (sigma), and an optional Roblox user ID:

export type Rating = {
	mu: number,
	sigma: number,
	userId: number?,
}

The conventional defaults are mu = 25 and sigma = 25 / 3.

local alice = luce.rating()
local bob = luce.rating(30, 6, 123456)

Example

Each inner array represents one team. Lower rank numbers indicate better placements, while equal ranks indicate a tie.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local luce = require(ReplicatedStorage.Packages.Luce)

local teams = {
	{ luce.rating(25, 25 / 3, 123456) },
	{ luce.rating(25, 25 / 3, 654321) },
}

local winProbabilities = luce.winProbabilities(teams)
local drawProbability = luce.drawProbability(teams)

-- Team 1 finished first and team 2 finished second.
local updatedTeams = luce.rate(teams, { 1, 2 })

local updatedWinner = updatedTeams[1][1]
local updatedLoser = updatedTeams[2][1]

API

luce.rating(mu?, sigma?, userId?)

Creates a new rating. Omitted mu and sigma values use the conventional defaults. userId is optional and is preserved when the rating is updated.

luce.rate(teams, ranks)

Updates the ratings after a match and returns a new array of teams in the same order as the input. The input ratings are not mutated.

ranks[i] is the placement of teams[i]: lower numbers are better, and equal numbers represent a tie. A match must contain at least two non-empty teams.

local updatedTeams = luce.rate(teams, { 1, 2, 2 })

Here, the first team won while the second and third teams tied for second.

luce.winProbabilities(teams)

Returns one win probability per team in input order. The returned values sum to one.

local probabilities = luce.winProbabilities(teams)
print(probabilities[1])

luce.drawProbability(teams)

Returns the Plackett–Luce likelihood that all supplied teams tie.

This value is not a third mutually exclusive outcome alongside the values from winProbabilities, so the draw probability and win probabilities are not expected to sum to one.

Model

Luce follows the Plackett–Luce approximation described in A Bayesian Approximation Method for Online Ranking by Ruby C. Weng and Chih-Jen Lin. Version 1.0.0 uses the conventional values beta = 25 / 6 and tau = 25 / 300.

License

Luce is released into the public domain under the Unlicense.

Package Details

Install command (Click to copy)


Version

1.0.0

License

Unlicense

check_circle

Safe for commercial use

infoThe package archive does not include its license text; the license is declared in its manifest metadata.

Automated license review — not legal advice.