Skip to main content

Utility

Scores candidates by considerations and picks the best or a weighted-random one. Use it inside a state to choose what to act on; use transitions to choose what to do.

local chaseConsiderations = {
	{ Input = function(agent, root) return (root.Position - agent:GetPosition()).Magnitude end,
	  Max = 60, Invert = true, Curve = VluxyAI.Utility.Curves.Quadratic },
	{ Input = function(agent, root) return if agent.Blackboard.SeenTarget == root then 1 else 0 end },
}

local root = VluxyAI.Utility.Best(agent, agent.Blackboard.NearbyTargets, chaseConsiderations)

Properties​

Curves​

Utility.Curves: {
Linear: Curve,
Quadratic: Curve,
SquareRoot: Curve,
Power: (exponent: number) → Curve,
Logistic: (
steepness: number?,
midpoint: number?
) → Curve,
Threshold: (at: number) → Curve
}

Response curves for Types.Consideration. Each maps [0, 1] to [0, 1].

  • Linear: x.
  • Quadratic: x^2. Rewards the top end.
  • SquareRoot: sqrt(x). Rewards the bottom end.
  • Power(exponent): x^exponent.
  • Logistic(steepness?, midpoint?): an S curve, steepness default 10, midpoint default 0.5.
  • Threshold(at): 0 below at, 1 at and above. A hard veto.

Functions​

Score​

Utility.Score(
agent: Agent,
candidate: T,
considerations: {Consideration<T>}
) → number--

In [0, 1].

Scores one candidate: the product of its considerations. A consideration whose Input returns something that is not a number scores 0, which vetoes the candidate.

Errors

TypeDescription
stringA consideration is malformed.

ScoreAll​

Utility.ScoreAll(
agent: Agent,
candidates: {T},
considerations: {Consideration<T>}
) → {Scored<T>}--

Sorted best first. Stable for ties.

Scores every candidate. Candidates that score 0 are kept, so a debug view can show why nothing was chosen.

Best​

Utility.Best(
agent: Agent,
candidates: {T},
considerations: {Consideration<T>}
) → (
T?,--

The best candidate, or nil when there are none or every one scored 0.

number--

Its score.

)

Picks the highest scoring candidate. Earlier candidates win ties, so a stable input order gives a stable choice.

Weighted​

Utility.Weighted(
agent: Agent,
candidates: {T},
considerations: {Consideration<T>},
random: Random?--

Seed one for a reproducible pick. Default a shared Random.

) → (
T?,--

A candidate chosen with probability proportional to its score, or nil when every one scored 0.

number--

Its score.

)

Picks a weighted-random candidate. Use it when the best choice every time reads as robotic; a candidate that scores twice as much is picked twice as often.

Show raw api
{
    "functions": [
        {
            "name": "Score",
            "desc": "Scores one candidate: the product of its considerations. A consideration whose `Input` returns\nsomething that is not a number scores `0`, which vetoes the candidate.",
            "params": [
                {
                    "name": "agent",
                    "desc": "",
                    "lua_type": "Agent"
                },
                {
                    "name": "candidate",
                    "desc": "",
                    "lua_type": "T"
                },
                {
                    "name": "considerations",
                    "desc": "",
                    "lua_type": "{ Consideration<T> }"
                }
            ],
            "returns": [
                {
                    "desc": "In `[0, 1]`.",
                    "lua_type": "number"
                }
            ],
            "function_type": "static",
            "errors": [
                {
                    "lua_type": "string",
                    "desc": "A consideration is malformed."
                }
            ],
            "source": {
                "line": 154,
                "path": "lib/Brain/Utility.luau"
            }
        },
        {
            "name": "ScoreAll",
            "desc": "Scores every candidate. Candidates that score `0` are kept, so a debug view can show why\nnothing was chosen.",
            "params": [
                {
                    "name": "agent",
                    "desc": "",
                    "lua_type": "Agent"
                },
                {
                    "name": "candidates",
                    "desc": "",
                    "lua_type": "{ T }"
                },
                {
                    "name": "considerations",
                    "desc": "",
                    "lua_type": "{ Consideration<T> }"
                }
            ],
            "returns": [
                {
                    "desc": "Sorted best first. Stable for ties.",
                    "lua_type": "{ Scored<T> }"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 178,
                "path": "lib/Brain/Utility.luau"
            }
        },
        {
            "name": "Best",
            "desc": "Picks the highest scoring candidate. Earlier candidates win ties, so a stable input order gives\na stable choice.",
            "params": [
                {
                    "name": "agent",
                    "desc": "",
                    "lua_type": "Agent"
                },
                {
                    "name": "candidates",
                    "desc": "",
                    "lua_type": "{ T }"
                },
                {
                    "name": "considerations",
                    "desc": "",
                    "lua_type": "{ Consideration<T> }"
                }
            ],
            "returns": [
                {
                    "desc": "The best candidate, or `nil` when there are none or every one scored `0`.",
                    "lua_type": "T?"
                },
                {
                    "desc": "Its score.",
                    "lua_type": "number"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 218,
                "path": "lib/Brain/Utility.luau"
            }
        },
        {
            "name": "Weighted",
            "desc": "Picks a weighted-random candidate. Use it when the best choice every time reads as robotic;\na candidate that scores twice as much is picked twice as often.",
            "params": [
                {
                    "name": "agent",
                    "desc": "",
                    "lua_type": "Agent"
                },
                {
                    "name": "candidates",
                    "desc": "",
                    "lua_type": "{ T }"
                },
                {
                    "name": "considerations",
                    "desc": "",
                    "lua_type": "{ Consideration<T> }"
                },
                {
                    "name": "random",
                    "desc": "Seed one for a reproducible pick. Default a shared `Random`.",
                    "lua_type": "Random?"
                }
            ],
            "returns": [
                {
                    "desc": "A candidate chosen with probability proportional to its score, or `nil` when every one scored `0`.",
                    "lua_type": "T?"
                },
                {
                    "desc": "Its score.",
                    "lua_type": "number"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 245,
                "path": "lib/Brain/Utility.luau"
            }
        }
    ],
    "properties": [
        {
            "name": "Curves",
            "desc": "Response curves for [Types.Consideration]. Each maps `[0, 1]` to `[0, 1]`.\n\n- `Linear`: `x`.\n- `Quadratic`: `x^2`. Rewards the top end.\n- `SquareRoot`: `sqrt(x)`. Rewards the bottom end.\n- `Power(exponent)`: `x^exponent`.\n- `Logistic(steepness?, midpoint?)`: an S curve, steepness default 10, midpoint default 0.5.\n- `Threshold(at)`: `0` below `at`, `1` at and above. A hard veto.",
            "lua_type": "{ Linear: Curve, Quadratic: Curve, SquareRoot: Curve, Power: (exponent: number) -> Curve, Logistic: (steepness: number?, midpoint: number?) -> Curve, Threshold: (at: number) -> Curve }",
            "source": {
                "line": 51,
                "path": "lib/Brain/Utility.luau"
            }
        }
    ],
    "types": [],
    "name": "Utility",
    "desc": "Scores candidates by considerations and picks the best or a weighted-random one. Use it inside\na state to choose what to act on; use transitions to choose what to do.\n\n```lua\nlocal chaseConsiderations = {\n\t{ Input = function(agent, root) return (root.Position - agent:GetPosition()).Magnitude end,\n\t  Max = 60, Invert = true, Curve = VluxyAI.Utility.Curves.Quadratic },\n\t{ Input = function(agent, root) return if agent.Blackboard.SeenTarget == root then 1 else 0 end },\n}\n\nlocal root = VluxyAI.Utility.Best(agent, agent.Blackboard.NearbyTargets, chaseConsiderations)\n```",
    "source": {
        "line": 36,
        "path": "lib/Brain/Utility.luau"
    }
}