diff --git a/README.md b/README.md index f503364..562b233 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The `BehaviourTree` constructor can take an options object as an argument, the p | Option |Type | Description | | :--------------------|:- |:- | | getDeltaTime |() => number| A function returning a delta time in seconds that is used to calculate the elapsed duration of any `wait` nodes. If this function is not defined then `Date().getTime()` is used instead by default. | -| random |() => number| A function returning a floating-point number between 0 (inclusive) and 1 (exclusive). If defined, this function is used to source a pseudo-random number to use in operations such as the selection of active children for any `lotto` nodes and the selection of durations for `wait` nodes when minimum and maximum durations are defined. If not defined then `Math.random` will be used instead by default. This function can be useful in seeding all random numbers used in the running of a tree instance to make any behaviour completely deterministic. | +| random |() => number| A function returning a floating-point number between 0 (inclusive) and 1 (exclusive). If defined, this function is used to source a pseudo-random number to use in operations such as the selection of active children for any `lotto` nodes as well as the selection of durations for `wait` nodes, iterations for `repeat` nodes and attempts for `retry` nodes when minimum and maximum bounds are defined. If not defined then `Math.random` will be used instead by default. This function can be useful in seeding all random numbers used in the running of a tree instance to make any behaviour completely deterministic. | # Nodes @@ -666,6 +666,7 @@ A practical look at behaviour trees and a good example of modelling behaviour fo ## Version History | Version | Notes | | -------------- |:----------------------------------------------------------------------------------------| +| 3.2.0 | The 'random' function option is used for iteration and attempt selection for `repeat` and `retry` nodes respectively when minimum and maximum bounds are defined | | 3.1.0 | Added 'random' function option to allow users to provide psuedo-random numbers for use in operations such as `lotto` node child selection and wait node duration selection when a minimum and maximum duration are defined. Wait nodes will now remain in the running state indefinitely until they are aborted if no duration is defined for them | | 3.0.0 | Converted to Typescript | | 2.3.0 | Added Global Functions and Subtrees | diff --git a/dist/RootAstNodesBuilder.d.ts b/dist/RootAstNodesBuilder.d.ts index d6973c6..23c835b 100644 --- a/dist/RootAstNodesBuilder.d.ts +++ b/dist/RootAstNodesBuilder.d.ts @@ -66,10 +66,17 @@ export type RootAstNode = DecoratorAstNode & { type: "root"; name: null | string; }; -export type IterableAstNode = DecoratorAstNode & { - type: "repeat" | "retry"; - iterations: null | number; - maximumIterations: null | number; +export type RepeatAstNode = DecoratorAstNode & { + type: "repeat"; + iterations: number | null; + iterationsMin: number | null; + iterationsMax: number | null; +}; +export type RetryAstNode = DecoratorAstNode & { + type: "retry"; + attempts: number | null; + attemptsMin: number | null; + attemptsMax: number | null; }; export type ActionAstNode = LeafAstNode & { type: "action"; @@ -87,7 +94,7 @@ export type WaitAstNode = LeafAstNode & { durationMin: number | null; durationMax: number | null; }; -export type AnyAstNode = BranchAstNode | CompositeAstNode | LottoAstNode | DecoratorAstNode | RootAstNode | IterableAstNode | LeafAstNode | ActionAstNode | ConditionAstNode | WaitAstNode; +export type AnyAstNode = BranchAstNode | CompositeAstNode | LottoAstNode | DecoratorAstNode | RootAstNode | RepeatAstNode | RetryAstNode | LeafAstNode | ActionAstNode | ConditionAstNode | WaitAstNode; /** * Create an array of root AST nodes based on the given definition. * @param definition The definition to parse the AST nodes from. diff --git a/dist/bundle.js b/dist/bundle.js index 9ee6013..82f3ec6 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -582,17 +582,19 @@ var mistreevous = (() => { // src/nodes/decorator/Repeat.ts var Repeat = class extends Decorator { - constructor(attributes, iterations, maximumIterations, child) { + constructor(attributes, iterations, iterationsMin, iterationsMax, child) { super("repeat", attributes, child); this.iterations = iterations; - this.maximumIterations = maximumIterations; + this.iterationsMin = iterationsMin; + this.iterationsMax = iterationsMax; } targetIterationCount = null; currentIterationCount = 0; onUpdate(agent, options) { if (this.is("mistreevous.ready" /* READY */)) { this.child.reset(); - this.setTargetIterationCount(); + this.currentIterationCount = 0; + this.setTargetIterationCount(options); } if (this.canIterate()) { this.setState("mistreevous.running" /* RUNNING */); @@ -612,9 +614,12 @@ var mistreevous = (() => { } getName = () => { if (this.iterations !== null) { - return `REPEAT ${this.maximumIterations ? this.iterations + "x-" + this.maximumIterations + "x" : this.iterations + "x"}`; + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; } - return "REPEAT"; }; reset = () => { this.setState("mistreevous.ready" /* READY */); @@ -627,9 +632,14 @@ var mistreevous = (() => { } return true; }; - setTargetIterationCount = () => { - if (typeof this.iterations === "number") { - this.targetIterationCount = typeof this.maximumIterations === "number" ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations) : this.iterations; + setTargetIterationCount = (options) => { + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); } else { this.targetIterationCount = null; } @@ -638,19 +648,21 @@ var mistreevous = (() => { // src/nodes/decorator/Retry.ts var Retry = class extends Decorator { - constructor(attributes, iterations, maximumIterations, child) { + constructor(attributes, attempts, attemptsMin, attemptsMax, child) { super("retry", attributes, child); - this.iterations = iterations; - this.maximumIterations = maximumIterations; + this.attempts = attempts; + this.attemptsMin = attemptsMin; + this.attemptsMax = attemptsMax; } - targetIterationCount = null; - currentIterationCount = 0; + targetAttemptCount = null; + currentAttemptCount = 0; onUpdate(agent, options) { if (this.is("mistreevous.ready" /* READY */)) { this.child.reset(); - this.setTargetIterationCount(); + this.currentAttemptCount = 0; + this.setTargetAttemptCount(options); } - if (this.canIterate()) { + if (this.canAttempt()) { this.setState("mistreevous.running" /* RUNNING */); if (this.child.getState() === "mistreevous.failed" /* FAILED */) { this.child.reset(); @@ -660,34 +672,42 @@ var mistreevous = (() => { this.setState("mistreevous.succeeded" /* SUCCEEDED */); return; } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.currentIterationCount += 1; + this.currentAttemptCount += 1; } } else { this.setState("mistreevous.failed" /* FAILED */); } } getName = () => { - if (this.iterations !== null) { - return `RETRY ${this.maximumIterations ? this.iterations + "x-" + this.maximumIterations + "x" : this.iterations + "x"}`; + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; } - return "RETRY"; }; reset = () => { this.setState("mistreevous.ready" /* READY */); - this.currentIterationCount = 0; + this.currentAttemptCount = 0; this.child.reset(); }; - canIterate = () => { - if (this.targetIterationCount !== null) { - return this.currentIterationCount < this.targetIterationCount; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + return this.currentAttemptCount < this.targetAttemptCount; } return true; }; - setTargetIterationCount = () => { - if (typeof this.iterations === "number") { - this.targetIterationCount = typeof this.maximumIterations === "number" ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations) : this.iterations; + setTargetAttemptCount = (options) => { + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); } else { - this.targetIterationCount = null; + this.targetAttemptCount = null; } }; }; @@ -1161,31 +1181,37 @@ var mistreevous = (() => { type: "repeat", attributes: [], iterations: null, - maximumIterations: null, + iterationsMin: null, + iterationsMax: null, children: [], validate() { if (this.children.length !== 1) { throw new Error("a repeat node must have a single child"); } - if (this.iterations !== null && this.iterations < 0) { - throw new Error("a repeat node must have a positive number of iterations if defined"); - } - if (this.maximumIterations !== null) { - if (this.maximumIterations < 0) { - throw new Error("a repeat node must have a positive maximum iterations count if defined"); + if (this.iterations !== null) { + if (this.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + if (this.iterationsMin < 0 || this.iterationsMax < 0) { + throw new Error( + "a repeat node must have a positive minimum and maximum iteration count if defined" + ); } - if (this.iterations > this.maximumIterations) { + if (this.iterationsMin > this.iterationsMax) { throw new Error( - "a repeat node must not have an iteration count that exceeds the maximum iteration count" + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" ); } + } else { } }, createNodeInstance(namedRootNodeProvider, visitedBranches) { return new Repeat( this.attributes, this.iterations, - this.maximumIterations, + this.iterationsMin, + this.iterationsMax, this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) ); } @@ -1193,32 +1219,36 @@ var mistreevous = (() => { RETRY: () => ({ type: "retry", attributes: [], - iterations: null, - maximumIterations: null, + attempts: null, + attemptsMin: null, + attemptsMax: null, children: [], validate() { if (this.children.length !== 1) { throw new Error("a retry node must have a single child"); } - if (this.iterations !== null && this.iterations < 0) { - throw new Error("a retry node must have a positive number of iterations if defined"); - } - if (this.maximumIterations !== null) { - if (this.maximumIterations < 0) { - throw new Error("a retry node must have a positive maximum iterations count if defined"); + if (this.attempts !== null) { + if (this.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); + } + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + if (this.attemptsMin < 0 || this.attemptsMax < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); } - if (this.iterations > this.maximumIterations) { + if (this.attemptsMin > this.attemptsMax) { throw new Error( - "a retry node must not have an iteration count that exceeds the maximum iteration count" + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" ); } + } else { } }, createNodeInstance(namedRootNodeProvider, visitedBranches) { return new Retry( this.attributes, - this.iterations, - this.maximumIterations, + this.attempts, + this.attemptsMin, + this.attemptsMax, this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) ); } @@ -1475,17 +1505,17 @@ var mistreevous = (() => { const node = ASTNodeFactories.REPEAT(); currentScope.push(node); if (tokens[0] === "[") { - const iterationArguments = getArguments( + const nodeArguments = getArguments( tokens, placeholders, (arg) => arg.type === "number" && !!arg.isInteger, "repeat node iteration counts must be integer values" ).map((argument) => argument.value); - if (iterationArguments.length === 1) { - node.iterations = iterationArguments[0]; - } else if (iterationArguments.length === 2) { - node.iterations = iterationArguments[0]; - node.maximumIterations = iterationArguments[1]; + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.iterationsMin = nodeArguments[0]; + node.iterationsMax = nodeArguments[1]; } else { throw new Error("invalid number of repeat node iteration count arguments defined"); } @@ -1499,19 +1529,19 @@ var mistreevous = (() => { const node = ASTNodeFactories.RETRY(); currentScope.push(node); if (tokens[0] === "[") { - const iterationArguments = getArguments( + const nodeArguments = getArguments( tokens, placeholders, (arg) => arg.type === "number" && !!arg.isInteger, - "retry node iteration counts must be integer values" + "retry node attempt counts must be integer values" ).map((argument) => argument.value); - if (iterationArguments.length === 1) { - node.iterations = iterationArguments[0]; - } else if (iterationArguments.length === 2) { - node.iterations = iterationArguments[0]; - node.maximumIterations = iterationArguments[1]; + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.attemptsMin = nodeArguments[0]; + node.attemptsMax = nodeArguments[1]; } else { - throw new Error("invalid number of retry node iteration count arguments defined"); + throw new Error("invalid number of retry node attempt count arguments defined"); } } node.attributes = getAttributes(tokens, placeholders); @@ -1545,7 +1575,7 @@ var mistreevous = (() => { break; } default: { - throw new Error("unexpected token: " + token); + throw new Error(`unexpected token '${token}'`); } } } @@ -1591,7 +1621,7 @@ var mistreevous = (() => { var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); if (!tokenMatchesExpectation) { const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); - throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); } } return popped; @@ -1793,8 +1823,7 @@ var mistreevous = (() => { BehaviourTree.applyLeafNodeGuardPaths(rootNode); return rootNode; } catch (exception) { - throw new Error(`error parsing tree: ${exception.message} -${exception.stack}`); + throw new Error(`error parsing tree: ${exception.message}`); } } static applyLeafNodeGuardPaths(rootNode) { diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 788cf5e..60beb25 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration count node arguments ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * Carries out a node update that traverses the tree from the root node outwards to any child nodes, skipping those that are already in a resolved state of SUCCEEDED or FAILED.\n * After being updated, leaf nodes will have a state of SUCCEEDED, FAILED or RUNNING. Leaf nodes that are left in the RUNNING state as part of a tree step will be revisited each\n * subsequent step until they move into a resolved state of either SUCCEEDED or FAILED, after which execution will move through the tree to the next node with a state of READY.\n *\n * Calling this method when the tree is already in a resolved state of SUCCEEDED or FAILED will cause it to be reset before tree traversal begins.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * Carries out a node update that traverses the tree from the root node outwards to any child nodes, skipping those that are already in a resolved state of SUCCEEDED or FAILED.\n * After being updated, leaf nodes will have a state of SUCCEEDED, FAILED or RUNNING. Leaf nodes that are left in the RUNNING state as part of a tree step will be revisited each\n * subsequent step until they move into a resolved state of either SUCCEEDED or FAILED, after which execution will move through the tree to the next node with a state of READY.\n *\n * Calling this method when the tree is already in a resolved state of SUCCEEDED or FAILED will cause it to be reset before tree traversal begins.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index c2c0040..5915643 100644 --- a/dist/index.js +++ b/dist/index.js @@ -582,17 +582,19 @@ var Root = class extends Decorator { // src/nodes/decorator/Repeat.ts var Repeat = class extends Decorator { - constructor(attributes, iterations, maximumIterations, child) { + constructor(attributes, iterations, iterationsMin, iterationsMax, child) { super("repeat", attributes, child); this.iterations = iterations; - this.maximumIterations = maximumIterations; + this.iterationsMin = iterationsMin; + this.iterationsMax = iterationsMax; } targetIterationCount = null; currentIterationCount = 0; onUpdate(agent, options) { if (this.is("mistreevous.ready" /* READY */)) { this.child.reset(); - this.setTargetIterationCount(); + this.currentIterationCount = 0; + this.setTargetIterationCount(options); } if (this.canIterate()) { this.setState("mistreevous.running" /* RUNNING */); @@ -612,9 +614,12 @@ var Repeat = class extends Decorator { } getName = () => { if (this.iterations !== null) { - return `REPEAT ${this.maximumIterations ? this.iterations + "x-" + this.maximumIterations + "x" : this.iterations + "x"}`; + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; } - return "REPEAT"; }; reset = () => { this.setState("mistreevous.ready" /* READY */); @@ -627,9 +632,14 @@ var Repeat = class extends Decorator { } return true; }; - setTargetIterationCount = () => { - if (typeof this.iterations === "number") { - this.targetIterationCount = typeof this.maximumIterations === "number" ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations) : this.iterations; + setTargetIterationCount = (options) => { + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); } else { this.targetIterationCount = null; } @@ -638,19 +648,21 @@ var Repeat = class extends Decorator { // src/nodes/decorator/Retry.ts var Retry = class extends Decorator { - constructor(attributes, iterations, maximumIterations, child) { + constructor(attributes, attempts, attemptsMin, attemptsMax, child) { super("retry", attributes, child); - this.iterations = iterations; - this.maximumIterations = maximumIterations; + this.attempts = attempts; + this.attemptsMin = attemptsMin; + this.attemptsMax = attemptsMax; } - targetIterationCount = null; - currentIterationCount = 0; + targetAttemptCount = null; + currentAttemptCount = 0; onUpdate(agent, options) { if (this.is("mistreevous.ready" /* READY */)) { this.child.reset(); - this.setTargetIterationCount(); + this.currentAttemptCount = 0; + this.setTargetAttemptCount(options); } - if (this.canIterate()) { + if (this.canAttempt()) { this.setState("mistreevous.running" /* RUNNING */); if (this.child.getState() === "mistreevous.failed" /* FAILED */) { this.child.reset(); @@ -660,34 +672,42 @@ var Retry = class extends Decorator { this.setState("mistreevous.succeeded" /* SUCCEEDED */); return; } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.currentIterationCount += 1; + this.currentAttemptCount += 1; } } else { this.setState("mistreevous.failed" /* FAILED */); } } getName = () => { - if (this.iterations !== null) { - return `RETRY ${this.maximumIterations ? this.iterations + "x-" + this.maximumIterations + "x" : this.iterations + "x"}`; + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; } - return "RETRY"; }; reset = () => { this.setState("mistreevous.ready" /* READY */); - this.currentIterationCount = 0; + this.currentAttemptCount = 0; this.child.reset(); }; - canIterate = () => { - if (this.targetIterationCount !== null) { - return this.currentIterationCount < this.targetIterationCount; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + return this.currentAttemptCount < this.targetAttemptCount; } return true; }; - setTargetIterationCount = () => { - if (typeof this.iterations === "number") { - this.targetIterationCount = typeof this.maximumIterations === "number" ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations) : this.iterations; + setTargetAttemptCount = (options) => { + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); } else { - this.targetIterationCount = null; + this.targetAttemptCount = null; } }; }; @@ -1161,31 +1181,37 @@ var ASTNodeFactories = { type: "repeat", attributes: [], iterations: null, - maximumIterations: null, + iterationsMin: null, + iterationsMax: null, children: [], validate() { if (this.children.length !== 1) { throw new Error("a repeat node must have a single child"); } - if (this.iterations !== null && this.iterations < 0) { - throw new Error("a repeat node must have a positive number of iterations if defined"); - } - if (this.maximumIterations !== null) { - if (this.maximumIterations < 0) { - throw new Error("a repeat node must have a positive maximum iterations count if defined"); + if (this.iterations !== null) { + if (this.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + if (this.iterationsMin < 0 || this.iterationsMax < 0) { + throw new Error( + "a repeat node must have a positive minimum and maximum iteration count if defined" + ); } - if (this.iterations > this.maximumIterations) { + if (this.iterationsMin > this.iterationsMax) { throw new Error( - "a repeat node must not have an iteration count that exceeds the maximum iteration count" + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" ); } + } else { } }, createNodeInstance(namedRootNodeProvider, visitedBranches) { return new Repeat( this.attributes, this.iterations, - this.maximumIterations, + this.iterationsMin, + this.iterationsMax, this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) ); } @@ -1193,32 +1219,36 @@ var ASTNodeFactories = { RETRY: () => ({ type: "retry", attributes: [], - iterations: null, - maximumIterations: null, + attempts: null, + attemptsMin: null, + attemptsMax: null, children: [], validate() { if (this.children.length !== 1) { throw new Error("a retry node must have a single child"); } - if (this.iterations !== null && this.iterations < 0) { - throw new Error("a retry node must have a positive number of iterations if defined"); - } - if (this.maximumIterations !== null) { - if (this.maximumIterations < 0) { - throw new Error("a retry node must have a positive maximum iterations count if defined"); + if (this.attempts !== null) { + if (this.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); + } + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + if (this.attemptsMin < 0 || this.attemptsMax < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); } - if (this.iterations > this.maximumIterations) { + if (this.attemptsMin > this.attemptsMax) { throw new Error( - "a retry node must not have an iteration count that exceeds the maximum iteration count" + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" ); } + } else { } }, createNodeInstance(namedRootNodeProvider, visitedBranches) { return new Retry( this.attributes, - this.iterations, - this.maximumIterations, + this.attempts, + this.attemptsMin, + this.attemptsMax, this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) ); } @@ -1475,17 +1505,17 @@ function buildRootASTNodes(definition) { const node = ASTNodeFactories.REPEAT(); currentScope.push(node); if (tokens[0] === "[") { - const iterationArguments = getArguments( + const nodeArguments = getArguments( tokens, placeholders, (arg) => arg.type === "number" && !!arg.isInteger, "repeat node iteration counts must be integer values" ).map((argument) => argument.value); - if (iterationArguments.length === 1) { - node.iterations = iterationArguments[0]; - } else if (iterationArguments.length === 2) { - node.iterations = iterationArguments[0]; - node.maximumIterations = iterationArguments[1]; + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.iterationsMin = nodeArguments[0]; + node.iterationsMax = nodeArguments[1]; } else { throw new Error("invalid number of repeat node iteration count arguments defined"); } @@ -1499,19 +1529,19 @@ function buildRootASTNodes(definition) { const node = ASTNodeFactories.RETRY(); currentScope.push(node); if (tokens[0] === "[") { - const iterationArguments = getArguments( + const nodeArguments = getArguments( tokens, placeholders, (arg) => arg.type === "number" && !!arg.isInteger, - "retry node iteration counts must be integer values" + "retry node attempt counts must be integer values" ).map((argument) => argument.value); - if (iterationArguments.length === 1) { - node.iterations = iterationArguments[0]; - } else if (iterationArguments.length === 2) { - node.iterations = iterationArguments[0]; - node.maximumIterations = iterationArguments[1]; + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.attemptsMin = nodeArguments[0]; + node.attemptsMax = nodeArguments[1]; } else { - throw new Error("invalid number of retry node iteration count arguments defined"); + throw new Error("invalid number of retry node attempt count arguments defined"); } } node.attributes = getAttributes(tokens, placeholders); @@ -1545,7 +1575,7 @@ function buildRootASTNodes(definition) { break; } default: { - throw new Error("unexpected token: " + token); + throw new Error(`unexpected token '${token}'`); } } } @@ -1591,7 +1621,7 @@ function popAndCheck(tokens, expected) { var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); if (!tokenMatchesExpectation) { const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); - throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); } } return popped; @@ -1793,8 +1823,7 @@ var BehaviourTree = class { BehaviourTree.applyLeafNodeGuardPaths(rootNode); return rootNode; } catch (exception) { - throw new Error(`error parsing tree: ${exception.message} -${exception.stack}`); + throw new Error(`error parsing tree: ${exception.message}`); } } static applyLeafNodeGuardPaths(rootNode) { diff --git a/dist/index.js.map b/dist/index.js.map index bde8841..32e48d6 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration count node arguments ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * Carries out a node update that traverses the tree from the root node outwards to any child nodes, skipping those that are already in a resolved state of SUCCEEDED or FAILED.\n * After being updated, leaf nodes will have a state of SUCCEEDED, FAILED or RUNNING. Leaf nodes that are left in the RUNNING state as part of a tree step will be revisited each\n * subsequent step until they move into a resolved state of either SUCCEEDED or FAILED, after which execution will move through the tree to the next node with a state of READY.\n *\n * Calling this method when the tree is already in a resolved state of SUCCEEDED or FAILED will cause it to be reset before tree traversal begins.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * Carries out a node update that traverses the tree from the root node outwards to any child nodes, skipping those that are already in a resolved state of SUCCEEDED or FAILED.\n * After being updated, leaf nodes will have a state of SUCCEEDED, FAILED or RUNNING. Leaf nodes that are left in the RUNNING state as part of a tree step will be revisited each\n * subsequent step until they move into a resolved state of either SUCCEEDED or FAILED, after which execution will move through the tree to the next node with a state of READY.\n *\n * Calling this method when the tree is already in a resolved state of SUCCEEDED or FAILED will cause it to be reset before tree traversal begins.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/nodes/decorator/Repeat.d.ts b/dist/nodes/decorator/Repeat.d.ts index 1a1de42..8a99d2d 100644 --- a/dist/nodes/decorator/Repeat.d.ts +++ b/dist/nodes/decorator/Repeat.d.ts @@ -13,14 +13,16 @@ import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; */ export default class Repeat extends Decorator { private iterations; - private maximumIterations; + private iterationsMin; + private iterationsMax; /** * @param attributes The node attributes. - * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined. - * @param maximumIterations The maximum number of iterations to repeat the child node. + * @param iterations The number of iterations to repeat the child node. + * @param iterationsMin The minimum possible number of iterations to repeat the child node. + * @param iterationsMax The maximum possible number of iterations to repeat the child node. * @param child The child node. */ - constructor(attributes: Attribute[], iterations: number | null, maximumIterations: number | null, child: Node); + constructor(attributes: Attribute[], iterations: number | null, iterationsMin: number | null, iterationsMax: number | null, child: Node); /** * The number of target iterations to make. */ @@ -50,6 +52,7 @@ export default class Repeat extends Decorator { private canIterate; /** * Sets the target iteration count. + * @param options The behaviour tree options object. */ private setTargetIterationCount; } diff --git a/dist/nodes/decorator/Retry.d.ts b/dist/nodes/decorator/Retry.d.ts index 08d4b0e..fd4745a 100644 --- a/dist/nodes/decorator/Retry.d.ts +++ b/dist/nodes/decorator/Retry.d.ts @@ -12,23 +12,25 @@ import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state. */ export default class Retry extends Decorator { - private iterations; - private maximumIterations; + private attempts; + private attemptsMin; + private attemptsMax; /** * @param attributes The node attributes. - * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined. - * @param maximumIterations The maximum number of iterations to repeat the child node. + * @param attempts The number of attempts to retry the child node. + * @param attemptsMin The minimum possible number of attempts to retry the child node. + * @param attemptsMax The maximum possible number of attempts to retry the child node. * @param child The child node. */ - constructor(attributes: Attribute[], iterations: number | null, maximumIterations: number | null, child: Node); + constructor(attributes: Attribute[], attempts: number | null, attemptsMin: number | null, attemptsMax: number | null, child: Node); /** - * The number of target iterations to make. + * The number of target attempts to make. */ - private targetIterationCount; + private targetAttemptCount; /** - * The current iteration count. + * The current attempt count. */ - private currentIterationCount; + private currentAttemptCount; /** * Called when the node is being updated. * @param agent The agent. @@ -44,12 +46,13 @@ export default class Retry extends Decorator { */ reset: () => void; /** - * Gets whether an iteration can be made. - * @returns Whether an iteration can be made. + * Gets whether an attempt can be made. + * @returns Whether an attempt can be made. */ - canIterate: () => boolean; + canAttempt: () => boolean; /** - * Sets the target iteration count. + * Sets the target attempt count. + * @param options The behaviour tree options object. */ - setTargetIterationCount: () => void; + setTargetAttemptCount: (options: BehaviourTreeOptions) => void; } diff --git a/dist/nodes/leaf/Wait.d.ts b/dist/nodes/leaf/Wait.d.ts index 78f16a0..43d08f0 100644 --- a/dist/nodes/leaf/Wait.d.ts +++ b/dist/nodes/leaf/Wait.d.ts @@ -12,7 +12,7 @@ export default class Wait extends Leaf { private durationMax; /** * @param attributes The node attributes. - * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined. + * @param duration The duration that this node will wait to succeed in milliseconds. * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed. * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed. */ diff --git a/package-lock.json b/package-lock.json index 094aa76..819d4b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "mistreevous", - "version": "3.1.0", + "version": "3.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -708,7 +708,7 @@ }, "expect": { "version": "25.5.0", - "resolved": false, + "resolved": "", "integrity": "sha512-w7KAXo0+6qqZZhovCaBVPSIqQp7/UTcx4M9uKt2m6pd2VB1voyC8JizLRqeEqud3AAVP02g+hbErDu5gu64tlA==", "dev": true, "requires": { @@ -1687,7 +1687,7 @@ }, "prettier": { "version": "2.7.1", - "resolved": false, + "resolved": "", "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true }, @@ -1821,7 +1821,7 @@ }, "should": { "version": "1.3.0", - "resolved": false, + "resolved": "", "integrity": "sha1-ILcaCbXtFhRrkDAivTBu8zLv6HM=", "dev": true }, diff --git a/package.json b/package.json index fd5b813..edf7641 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mistreevous", - "version": "3.1.0", + "version": "3.2.0", "description": "A tool to build behaviour trees in JavaScript", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -43,7 +43,7 @@ "machine", "state" ], - "author": "nikolas howard smells bad", + "author": "nikolas howard", "license": "MIT", "bugs": { "url": "https://github.com/nikkorn/mistreevous/issues" diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index cda86d7..7903613 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -227,7 +227,7 @@ export class BehaviourTree { return rootNode; } catch (exception) { // There was an issue in trying to parse and build the tree definition. - throw new Error(`error parsing tree: ${(exception as Error).message}\n${(exception as Error).stack}`); + throw new Error(`error parsing tree: ${(exception as Error).message}`); } } diff --git a/src/RootAstNodesBuilder.ts b/src/RootAstNodesBuilder.ts index bafd329..24e74dc 100644 --- a/src/RootAstNodesBuilder.ts +++ b/src/RootAstNodesBuilder.ts @@ -111,10 +111,18 @@ export type RootAstNode = DecoratorAstNode & { name: null | string; }; -export type IterableAstNode = DecoratorAstNode & { - type: "repeat" | "retry"; - iterations: null | number; - maximumIterations: null | number; +export type RepeatAstNode = DecoratorAstNode & { + type: "repeat"; + iterations: number | null; + iterationsMin: number | null; + iterationsMax: number | null; +}; + +export type RetryAstNode = DecoratorAstNode & { + type: "retry"; + attempts: number | null; + attemptsMin: number | null; + attemptsMax: number | null; }; export type ActionAstNode = LeafAstNode & { @@ -142,7 +150,8 @@ export type AnyAstNode = | LottoAstNode | DecoratorAstNode | RootAstNode - | IterableAstNode + | RepeatAstNode + | RetryAstNode | LeafAstNode | ActionAstNode | ConditionAstNode @@ -268,11 +277,12 @@ const ASTNodeFactories = { ); } }), - REPEAT: (): IterableAstNode => ({ + REPEAT: (): RepeatAstNode => ({ type: "repeat", attributes: [], iterations: null, - maximumIterations: null, + iterationsMin: null, + iterationsMax: null, children: [], validate() { // A repeat node must have a single node. @@ -280,40 +290,45 @@ const ASTNodeFactories = { throw new Error("a repeat node must have a single child"); } - // A repeat node must have a positive number of iterations if defined. - if (this.iterations !== null && this.iterations! < 0) { - throw new Error("a repeat node must have a positive number of iterations if defined"); - } - - // There is validation to carry out if a longest duration was defined. - if (this.maximumIterations !== null) { - // A repeat node must have a positive maximum iterations count if defined. - if (this.maximumIterations! < 0) { - throw new Error("a repeat node must have a positive maximum iterations count if defined"); + if (this.iterations !== null) { + // A repeat node must have a positive number of iterations if defined. + if (this.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + // A repeat node must have a positive min and max iteration count if they are defined. + if (this.iterationsMin < 0 || this.iterationsMax < 0) { + throw new Error( + "a repeat node must have a positive minimum and maximum iteration count if defined" + ); } - // A repeat node must not have an iteration count that exceeds the maximum iteration count. - if (this.iterations! > this.maximumIterations!) { + // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count. + if (this.iterationsMin > this.iterationsMax) { throw new Error( - "a repeat node must not have an iteration count that exceeds the maximum iteration count" + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" ); } + } else { + // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely. } }, createNodeInstance(namedRootNodeProvider, visitedBranches) { return new Repeat( this.attributes, - this.iterations!, - this.maximumIterations!, + this.iterations, + this.iterationsMin, + this.iterationsMax, this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) ); } }), - RETRY: (): IterableAstNode => ({ + RETRY: (): RetryAstNode => ({ type: "retry", attributes: [], - iterations: null, - maximumIterations: null, + attempts: null, + attemptsMin: null, + attemptsMax: null, children: [], validate() { // A retry node must have a single node. @@ -321,31 +336,33 @@ const ASTNodeFactories = { throw new Error("a retry node must have a single child"); } - // A retry node must have a positive number of iterations if defined. - if (this.iterations !== null && this.iterations! < 0) { - throw new Error("a retry node must have a positive number of iterations if defined"); - } - - // There is validation to carry out if a longest duration was defined. - if (this.maximumIterations !== null) { - // A retry node must have a positive maximum iterations count if defined. - if (this.maximumIterations! < 0) { - throw new Error("a retry node must have a positive maximum iterations count if defined"); + if (this.attempts !== null) { + // A retry node must have a positive number of attempts if defined. + if (this.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); + } + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + // A retry node must have a positive min and max attempts count if they are defined. + if (this.attemptsMin < 0 || this.attemptsMax < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); } - // A retry node must not have an iteration count that exceeds the maximum iteration count. - if (this.iterations! > this.maximumIterations!) { + // A retry node must not have a minimum attempt count that exceeds the maximum attempt count. + if (this.attemptsMin > this.attemptsMax) { throw new Error( - "a retry node must not have an iteration count that exceeds the maximum iteration count" + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" ); } + } else { + // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely. } }, createNodeInstance(namedRootNodeProvider, visitedBranches) { return new Retry( this.attributes, - this.iterations!, - this.maximumIterations!, + this.attempts, + this.attemptsMin, + this.attemptsMax, this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) ); } @@ -766,10 +783,13 @@ export default function buildRootASTNodes(definition: string): RootAstNode[] { // Push the REPEAT node into the current scope. currentScope.push(node); - // Check for iteration count node arguments ([]) + // The arguments of a repeat node are optional. We may have: + // - No node arguments, in which case the repeat note will iterate indefinitely. + // - One node argument which will be the explicit number of iterations to make. + // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked. if (tokens[0] === "[") { // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait. - const iterationArguments = getArguments( + const nodeArguments = getArguments( tokens, placeholders, (arg) => arg.type === "number" && !!arg.isInteger, @@ -777,13 +797,13 @@ export default function buildRootASTNodes(definition: string): RootAstNode[] { ).map((argument) => argument.value); // We should have got one or two iteration counts. - if (iterationArguments.length === 1) { + if (nodeArguments.length === 1) { // A static iteration count was defined. - node.iterations = iterationArguments[0] as number; - } else if (iterationArguments.length === 2) { + node.iterations = nodeArguments[0] as number; + } else if (nodeArguments.length === 2) { // A minimum and maximum iteration count was defined. - node.iterations = iterationArguments[0] as number; - node.maximumIterations = iterationArguments[1] as number; + node.iterationsMin = nodeArguments[0] as number; + node.iterationsMax = nodeArguments[1] as number; } else { // An incorrect number of iteration counts was defined. throw new Error("invalid number of repeat node iteration count arguments defined"); @@ -807,27 +827,30 @@ export default function buildRootASTNodes(definition: string): RootAstNode[] { // Push the RETRY node into the current scope. currentScope.push(node); - // Check for iteration counts ([]) + // The arguments of a retry node are optional. We may have: + // - No node arguments, in which case the retry note will attempt indefinitely. + // - One node argument which will be the explicit number of attempts to make. + // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked. if (tokens[0] === "[") { - // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait. - const iterationArguments = getArguments( + // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait. + const nodeArguments = getArguments( tokens, placeholders, (arg) => arg.type === "number" && !!arg.isInteger, - "retry node iteration counts must be integer values" + "retry node attempt counts must be integer values" ).map((argument) => argument.value); - // We should have got one or two iteration counts. - if (iterationArguments.length === 1) { - // A static iteration count was defined. - node.iterations = iterationArguments[0] as number; - } else if (iterationArguments.length === 2) { - // A minimum and maximum iteration count was defined. - node.iterations = iterationArguments[0] as number; - node.maximumIterations = iterationArguments[1] as number; + // We should have got one or two attempt counts. + if (nodeArguments.length === 1) { + // A static attempt count was defined. + node.attempts = nodeArguments[0] as number; + } else if (nodeArguments.length === 2) { + // A minimum and maximum attempt count was defined. + node.attemptsMin = nodeArguments[0] as number; + node.attemptsMax = nodeArguments[1] as number; } else { - // An incorrect number of iteration counts was defined. - throw new Error("invalid number of retry node iteration count arguments defined"); + // An incorrect number of attempt counts was defined. + throw new Error("invalid number of retry node attempt count arguments defined"); } } @@ -890,7 +913,7 @@ export default function buildRootASTNodes(definition: string): RootAstNode[] { } default: { - throw new Error("unexpected token: " + token); + throw new Error(`unexpected token '${token}'`); } } } @@ -972,7 +995,8 @@ function popAndCheck(tokens: string[], expected: string | string[]) { .concat(expected) .map((item) => "'" + item + "'") .join(" or "); - throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + + throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); } } diff --git a/src/nodes/decorator/Repeat.ts b/src/nodes/decorator/Repeat.ts index eca08d4..ba35ad9 100644 --- a/src/nodes/decorator/Repeat.ts +++ b/src/nodes/decorator/Repeat.ts @@ -16,14 +16,16 @@ import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; export default class Repeat extends Decorator { /** * @param attributes The node attributes. - * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined. - * @param maximumIterations The maximum number of iterations to repeat the child node. + * @param iterations The number of iterations to repeat the child node. + * @param iterationsMin The minimum possible number of iterations to repeat the child node. + * @param iterationsMax The maximum possible number of iterations to repeat the child node. * @param child The child node. */ constructor( attributes: Attribute[], private iterations: number | null, - private maximumIterations: number | null, + private iterationsMin: number | null, + private iterationsMax: number | null, child: Node ) { super("repeat", attributes, child); @@ -50,8 +52,11 @@ export default class Repeat extends Decorator { // Reset the child node. this.child.reset(); + // Reset the current iteration count. + this.currentIterationCount = 0; + // Set the target iteration count. - this.setTargetIterationCount(); + this.setTargetIterationCount(options); } // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state. @@ -91,13 +96,12 @@ export default class Repeat extends Decorator { */ getName = () => { if (this.iterations !== null) { - return `REPEAT ${ - this.maximumIterations ? this.iterations + "x-" + this.maximumIterations + "x" : this.iterations + "x" - }`; + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; } - - // Return the default repeat node name. - return "REPEAT"; }; /** @@ -130,15 +134,21 @@ export default class Repeat extends Decorator { /** * Sets the target iteration count. + * @param options The behaviour tree options object. */ - private setTargetIterationCount = () => { - // Are we dealing with a finite number of iterations? - if (typeof this.iterations === "number") { - // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations. - this.targetIterationCount = - typeof this.maximumIterations === "number" - ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations) - : this.iterations; + private setTargetIterationCount = (options: BehaviourTreeOptions) => { + // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count. + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + // We will be picking a random iteration count between a min and max iteration count, if the optional 'random' + // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random. + const random = typeof options.random === "function" ? options.random : Math.random; + + // Pick a random iteration count between a min and max iteration count. + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); } else { this.targetIterationCount = null; } diff --git a/src/nodes/decorator/Retry.ts b/src/nodes/decorator/Retry.ts index 52f73da..2f68a39 100644 --- a/src/nodes/decorator/Retry.ts +++ b/src/nodes/decorator/Retry.ts @@ -16,28 +16,30 @@ import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; export default class Retry extends Decorator { /** * @param attributes The node attributes. - * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined. - * @param maximumIterations The maximum number of iterations to repeat the child node. + * @param attempts The number of attempts to retry the child node. + * @param attemptsMin The minimum possible number of attempts to retry the child node. + * @param attemptsMax The maximum possible number of attempts to retry the child node. * @param child The child node. */ constructor( attributes: Attribute[], - private iterations: number | null, - private maximumIterations: number | null, + private attempts: number | null, + private attemptsMin: number | null, + private attemptsMax: number | null, child: Node ) { super("retry", attributes, child); } /** - * The number of target iterations to make. + * The number of target attempts to make. */ - private targetIterationCount: number | null = null; + private targetAttemptCount: number | null = null; /** - * The current iteration count. + * The current attempt count. */ - private currentIterationCount: number = 0; + private currentAttemptCount: number = 0; /** * Called when the node is being updated. @@ -45,22 +47,25 @@ export default class Retry extends Decorator { * @param options The behaviour tree options object. */ protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void { - // If this node is in the READY state then we need to reset the child and the target iteration count. + // If this node is in the READY state then we need to reset the child and the target attempt count. if (this.is(State.READY)) { // Reset the child node. this.child.reset(); - // Set the target iteration count. - this.setTargetIterationCount(); + // Reset the current attempt count. + this.currentAttemptCount = 0; + + // Set the target attempt count. + this.setTargetAttemptCount(options); } - // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state. - // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded. - if (this.canIterate()) { - // This node is in the running state and can do its initial iteration. + // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state. + // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded. + if (this.canAttempt()) { + // This node is in the running state and can do its initial attempt. this.setState(State.RUNNING); - // We may have already completed an iteration, meaning that the child node will be in the FAILED state. + // We may have already completed an attempt, meaning that the child node will be in the FAILED state. // If this is the case then we will have to reset the child node now. if (this.child.getState() === State.FAILED) { this.child.reset(); @@ -70,15 +75,15 @@ export default class Retry extends Decorator { this.child.update(agent, options); // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded. - // If it has moved into the FAILED state then we have completed the current iteration. + // If it has moved into the FAILED state then we have completed the current attempt. if (this.child.getState() === State.SUCCEEDED) { // The child has succeeded, meaning that this node has succeeded. this.setState(State.SUCCEEDED); return; } else if (this.child.getState() === State.FAILED) { - // We have completed an iteration. - this.currentIterationCount += 1; + // We have completed an attempt. + this.currentAttemptCount += 1; } } else { // This node is in the 'FAILED' state as we cannot iterate any more. @@ -90,14 +95,13 @@ export default class Retry extends Decorator { * Gets the name of the node. */ getName = () => { - if (this.iterations !== null) { - return `RETRY ${ - this.maximumIterations ? this.iterations + "x-" + this.maximumIterations + "x" : this.iterations + "x" - }`; + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; } - - // Return the default retry node name. - return "RETRY"; }; /** @@ -107,40 +111,46 @@ export default class Retry extends Decorator { // Reset the state of this node. this.setState(State.READY); - // Reset the current iteration count. - this.currentIterationCount = 0; + // Reset the current attempt count. + this.currentAttemptCount = 0; // Reset the child node. this.child.reset(); }; /** - * Gets whether an iteration can be made. - * @returns Whether an iteration can be made. + * Gets whether an attempt can be made. + * @returns Whether an attempt can be made. */ - canIterate = () => { - if (this.targetIterationCount !== null) { - // We can iterate as long as we have not reached our target iteration count. - return this.currentIterationCount < this.targetIterationCount; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + // We can attempt as long as we have not reached our target attempt count. + return this.currentAttemptCount < this.targetAttemptCount; } - // If neither an iteration count or a condition function were defined then we can iterate indefinitely. + // If neither an attempt count or a condition function were defined then we can attempt indefinitely. return true; }; /** - * Sets the target iteration count. + * Sets the target attempt count. + * @param options The behaviour tree options object. */ - setTargetIterationCount = () => { - // Are we dealing with a finite number of iterations? - if (typeof this.iterations === "number") { - // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations. - this.targetIterationCount = - typeof this.maximumIterations === "number" - ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations) - : this.iterations; + setTargetAttemptCount = (options: BehaviourTreeOptions) => { + // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count. + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + // We will be picking a random attempt count between a min and max attempt count, if the optional 'random' + // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random. + const random = typeof options.random === "function" ? options.random : Math.random; + + // Pick a random attempt count between a min and max attempt count. + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); } else { - this.targetIterationCount = null; + this.targetAttemptCount = null; } }; } diff --git a/src/nodes/leaf/Wait.ts b/src/nodes/leaf/Wait.ts index 854682a..9b1af40 100644 --- a/src/nodes/leaf/Wait.ts +++ b/src/nodes/leaf/Wait.ts @@ -11,7 +11,7 @@ import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; export default class Wait extends Leaf { /** * @param attributes The node attributes. - * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined. + * @param duration The duration that this node will wait to succeed in milliseconds. * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed. * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed. */ @@ -61,7 +61,7 @@ export default class Wait extends Leaf { // function option is defined then we will be using that, otherwise we will fall back to using Math.random. const random = typeof options.random === "function" ? options.random : Math.random; - // Pick a random duration a min and max duration. + // Pick a random duration between a min and max duration. this.totalDuration = Math.floor( random() * (this.durationMax - this.durationMin + 1) + this.durationMin ); diff --git a/test/behaviourTree.test.js b/test/behaviourTree.test.js index 6416553..cd35a6e 100644 --- a/test/behaviourTree.test.js +++ b/test/behaviourTree.test.js @@ -29,7 +29,7 @@ describe("A BehaviourTree instance", () => { assert.throws( () => new mistreevous.BehaviourTree("invalid-token { }", {}), Error, - "error parsing tree: unexpected token: invalid-token" + "error parsing tree: unexpected token 'invalid-token'" ); }); diff --git a/test/nodes/decorator/repeat.test.js b/test/nodes/decorator/repeat.test.js index cd17f22..a61cd8f 100644 --- a/test/nodes/decorator/repeat.test.js +++ b/test/nodes/decorator/repeat.test.js @@ -1,5 +1,6 @@ const mistreevous = require("../../../dist/index"); const chai = require("chai"); +const sinon = require("sinon"); var assert = chai.assert; @@ -19,12 +20,22 @@ describe("A Repeat node", () => { }); describe("when updated as part of a tree step", () => { + var sandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + sandbox.replace(globalThis.Math, "random", () => 0.5); + }); + + afterEach(() => sandbox.restore()); + it("will move to the FAILED state if the child node moves to the FAILED state", () => { const definition = "root { repeat { condition [someCondition] } }"; const agent = { someCondition: () => false }; const tree = new mistreevous.BehaviourTree(definition, agent); let node = findNode(tree, "repeat", "REPEAT"); + assert.exists(node); assert.strictEqual(node.state, mistreevous.State.READY); tree.step(); @@ -39,6 +50,7 @@ describe("A Repeat node", () => { const tree = new mistreevous.BehaviourTree(definition, agent); let node = findNode(tree, "repeat", "REPEAT"); + assert.exists(node); assert.strictEqual(node.state, mistreevous.State.READY); tree.step(); @@ -47,12 +59,13 @@ describe("A Repeat node", () => { assert.strictEqual(node.state, mistreevous.State.RUNNING); }); - it("and a maximum iteration node argument is defined will attempt to re-run the child node until the maximum iteration is reached", () => { + it("and an iteration count node argument is defined will attempt to re-run the child node until the iteration count is reached", () => { const definition = "root { repeat [3] { condition [someCondition] } }"; const agent = { someCondition: () => true }; const tree = new mistreevous.BehaviourTree(definition, agent); let node = findNode(tree, "repeat", "REPEAT 3x"); + assert.exists(node); assert.strictEqual(node.state, mistreevous.State.READY); tree.step(); @@ -75,5 +88,79 @@ describe("A Repeat node", () => { node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); }); + + describe("and minumum and maximum iteration count node arguments are defined", () => { + it("and if the 'random' behaviour tree option is not defined will pick an iteration count from between the minimum and maximum bounds using Math.random", () => { + // We have spied on Math.random to always return 0.5 for the sake of this test, so our iteration count should always be 4. + const definition = "root { repeat [2, 6] { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.exists(node); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + }); + + it("and if the 'random' behaviour tree option is defined will use it to pick an iteration count from between the minimum and maximum bounds", () => { + const definition = "root { repeat [2, 10] { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on the iteration count picked. + // A value of 0.2 should always result in an iteration count of 3. + random: () => 0.2 + }; + const tree = new mistreevous.BehaviourTree(definition, agent, options); + + let node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.exists(node); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + }); + }); }); }); diff --git a/test/nodes/decorator/retry.test.js b/test/nodes/decorator/retry.test.js index 2b6e3ca..5076c76 100644 --- a/test/nodes/decorator/retry.test.js +++ b/test/nodes/decorator/retry.test.js @@ -1,5 +1,6 @@ const mistreevous = require("../../../dist/index"); const chai = require("chai"); +const sinon = require("sinon"); var assert = chai.assert; @@ -19,12 +20,22 @@ describe("A Retry node", () => { }); describe("when updated as part of a tree step", () => { + var sandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + sandbox.replace(globalThis.Math, "random", () => 0.5); + }); + + afterEach(() => sandbox.restore()); + it("will move to the SUCCEEDED state if the child node moves to the SUCCEEDED state", () => { const definition = "root { retry { condition [someCondition] } }"; const agent = { someCondition: () => true }; const tree = new mistreevous.BehaviourTree(definition, agent); let node = findNode(tree, "retry", "RETRY"); + assert.exists(node); assert.strictEqual(node.state, mistreevous.State.READY); tree.step(); @@ -39,6 +50,7 @@ describe("A Retry node", () => { const tree = new mistreevous.BehaviourTree(definition, agent); let node = findNode(tree, "retry", "RETRY"); + assert.exists(node); assert.strictEqual(node.state, mistreevous.State.READY); tree.step(); @@ -47,12 +59,13 @@ describe("A Retry node", () => { assert.strictEqual(node.state, mistreevous.State.RUNNING); }); - it("and a maximum attempt node argument is defined will attempt to re-run the child node until the maximum attempt is reached", () => { + it("and an attempt count node argument is defined will attempt to re-run the child node until the attempt count is reached", () => { const definition = "root { retry [3] { condition [someCondition] } }"; const agent = { someCondition: () => false }; const tree = new mistreevous.BehaviourTree(definition, agent); let node = findNode(tree, "retry", "RETRY 3x"); + assert.exists(node); assert.strictEqual(node.state, mistreevous.State.READY); tree.step(); @@ -75,5 +88,79 @@ describe("A Retry node", () => { node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, mistreevous.State.FAILED); }); + + describe("and minumum and maximum attempt count node arguments are defined", () => { + it("and if the 'random' behaviour tree option is not defined will pick an attempt count from between the minimum and maximum bounds using Math.random", () => { + // We have spied on Math.random to always return 0.5 for the sake of this test, so our attempt count should always be 4. + const definition = "root { retry [2, 6] { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.exists(node); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, mistreevous.State.FAILED); + }); + + it("and if the 'random' behaviour tree option is defined will use it to pick an attempt count from between the minimum and maximum bounds", () => { + const definition = "root { retry [2, 10] { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on the attempt count picked. + // A value of 0.2 should always result in an attempt count of 3. + random: () => 0.2 + }; + const tree = new mistreevous.BehaviourTree(definition, agent, options); + + let node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.exists(node); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, mistreevous.State.FAILED); + }); + }); }); });