utilitai
Version:
Utility AI library built with TypeScript
95 lines (80 loc) • 2.74 kB
text/typescript
import type { AppraisalFunction, CurveFunction, Appraisal, Action, ScoringFunction, Consideration, Reasoner, Context } from "../types";
/**
* This was a PoC for utility theory as a factory function and contains some of the early ideas. It will eventually be removed.
*/
enum ActionName {
Idle,
Attack,
Flee
}
// Helper functions
export const createAppraisal = (
fn: AppraisalFunction,
computeCurve?: CurveFunction,
): Appraisal => ({
evaluate: fn,
computeCurve: computeCurve || quadraticCurve,
});
export const createConsideration = (
action: Action,
appraisals: Appraisal[],
scoringMethod: ScoringFunction,
bonusFactor?: number,
weight?: number,
parameters?: Record<string, any>,
): Consideration => ({
action,
appraisals,
scoringMethod,
bonusFactor: bonusFactor || 1,
weight: weight || 1,
parameters,
});
export const createReasoner = (baseConsiderations: Consideration[]): Reasoner => {
return {
considerations: baseConsiderations,
evaluate: (context: Context, dynamicConsiderations: Consideration[] = []) => {
let bestScore = -Infinity;
let bestAction: Action | null = null;
for (const consideration of [
...baseConsiderations,
...dynamicConsiderations
]) {
if (consideration.weight <= 0) continue;
const scores = [] as number[];
for (const appraisal of consideration.appraisals) {
const score = appraisal.evaluate({
...context,
...consideration.parameters
});
if (score === 0) continue;
scores.push(score);
}
const score = consideration.scoringMethod(scores) * consideration.weight;
if (score > bestScore) {
bestScore = score;
bestAction = consideration.action;
}
}
return bestAction || { name: ActionName.Idle };
},
}
};
/*
const ScoreAllConsiderations = (considerations: Consideration[], context: Context) => {
let cutoff = 0;
for (const consideration of considerations) {
const bonus = consideration.bonusFactor;
if (bonus < cutoff) continue;
}
}
*/
// Example scoring methods
export const averageScoring: ScoringFunction = (scores) =>
scores.reduce((sum, score) => sum + score, 0) / scores.length;
export const multiplicativeScoring: ScoringFunction = (scores) =>
scores.reduce((product, score) => product * score, 1);
// Example curve functions
export const linearCurve: CurveFunction = (score) => score;
export const quadraticCurve: CurveFunction = (score) => score * score;
export const inverseQuadraticCurve: CurveFunction = (score) => 1 - score * score;