feat: add capabilities

This commit is contained in:
Morten Olsen
2023-09-26 09:08:08 +02:00
parent a81afc9221
commit c00b073d37
43 changed files with 3284 additions and 305 deletions

View File

@@ -1,4 +1,4 @@
> bob-the-algorithm@ build /Users/alice/work/private/bob/packages/algorithm
> @bob-the-algorithm/core@0.1.8 build /home/alice/Git/bob/packages/algorithm
> tsc --build configs/tsconfig.libs.json

View File

@@ -21,6 +21,10 @@ type RunOptions<TPlugins extends Plugins> = {
heuristic?: (result: any) => boolean;
};
type PlanableWithPlugins<TPlugins extends Plugins> = Planable<
PluginAttributes<TPlugins>
>;
class Bob<TPlugins extends Plugins> {
#options: CalulationOptions<TPlugins>;
#id: number = 0;
@@ -99,5 +103,5 @@ class Bob<TPlugins extends Plugins> {
};
}
export type { CalulationOptions, CalulationResult };
export type { CalulationOptions, CalulationResult, PlanableWithPlugins };
export { Bob };

View File

@@ -70,7 +70,7 @@ const expandNode = async <
node.time + node.duration,
planable.start?.min || 0,
);
return {
const nextNode = {
...node,
type: 'planable',
exploreId: 0,
@@ -83,6 +83,14 @@ const expandNode = async <
completed: remaining.length === 0,
parent: node.id,
};
return Object.values(plugins).reduce(
// TODO: remove any
(acc, plugin) =>
(plugin.mutateNode
? plugin.mutateNode(acc as any, planable)
: acc) as any,
nextNode,
) as any;
});
return [...planableNodes, ...metaNodes.flat()];

View File

@@ -1,5 +1,8 @@
export type { GraphNode } from './types/node';
export type { Planable } from './types/planable';
export { expandNode } from './algorithm/expand-node';
export { Bob, type CalulationResult } from './algorithm/calulation';
export {
Bob,
type CalulationResult,
type PlanableWithPlugins,
} from './algorithm/calulation';
export { plugins } from './plugins/index';

View File

@@ -0,0 +1,57 @@
import { Type } from '@sinclair/typebox';
import { createPlugin } from './create';
const capabilities = () =>
createPlugin(
Type.Object({
capabilities: Type.Optional(
Type.Object({
provides: Type.Optional(Type.Array(Type.String())),
consumes: Type.Optional(Type.Array(Type.String())),
requires: Type.Optional(Type.Array(Type.String())),
perhibits: Type.Optional(Type.Array(Type.String())),
}),
),
}),
Type.Object({
capabilities: Type.Array(Type.String()),
}),
{
isPlanable: (node, planable) => {
const { requires = [], perhibits = [] } =
planable.attributes?.capabilities || {};
const capabilities = node.context.capabilities;
if (requires.length === 0 && perhibits.length === 0) {
return true;
}
const satisfiesRequire = requires.every((c) =>
capabilities.includes(c),
);
const satisfiesPerhibit = !perhibits.some((c) =>
capabilities.includes(c),
);
return satisfiesRequire && satisfiesPerhibit;
},
mutateNode: (node, planable) => {
const { provides = [], consumes = [] } =
planable.attributes?.capabilities || {};
const capabilities = node.context.capabilities || [];
const newCapabilities = [
...capabilities.filter((c) => !consumes.includes(c)),
...provides,
];
return {
...node,
context: {
...node.context,
capabilities: newCapabilities,
},
};
},
},
);
export { capabilities };

View File

@@ -1,8 +1,10 @@
import { Plugin } from '../types/plugin';
import { transport } from './transport';
import { capabilities } from './capabilities';
const plugins = {
transport,
capabilities,
} satisfies Record<string, (...args: any[]) => Plugin>;
export { plugins };

View File

@@ -47,7 +47,7 @@ const transport = ({ getTravelTime }: TransportOptions) =>
planable: undefined,
location,
exploreId: 0,
score: node.score - 10,
score: node.score - 5,
time: node.time + node.duration,
duration: travelTime,
parent: node.id,

View File

@@ -12,6 +12,10 @@ type Plugin<TAttributes = any, TContext = any> = {
node: GraphNode<TAttributes, TContext>,
planable: Planable<TAttributes>,
) => boolean;
mutateNode?: (
node: GraphNode<TAttributes, TContext>,
planable: Planable<TAttributes>,
) => GraphNode<TAttributes, TContext>;
};
type Plugins = Record<string, Plugin>;