agents-flow
Version:
Framework for multi-agent interactive fiction videogame.
1 lines • 89.1 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/input.ts","../node_modules/role-methods/dist/index.mjs","../src/phrase.ts","../src/interfaces.ts","../src/roles.ts","../src/step.ts","../src/agent.ts","../src/location.ts","../src/interaction.ts","../src/ongoing.ts","../src/historic.ts","../src/scenario.ts"],"sourcesContent":["export class Input{\r\n private _choiceIndex: number;\r\n\r\n constructor(choiceIndex: number){\r\n this._choiceIndex = choiceIndex;\r\n }\r\n\r\n get choiceIndex(){\r\n return this._choiceIndex;\r\n }\r\n\r\n get isVoid(): boolean{\r\n return this._choiceIndex < 0;\r\n }\r\n\r\n static void(): Input{\r\n return new Input(-1);\r\n }\r\n}","var n,r=100,t=0;function o(n){var r=n+1;return Math.floor(Math.random()*r)}function u(n){return 1===n.length?n[0]:n[o(n.length-1)]}function e(){var r=o(100),t=n.None;return r<=10&&(t=n.Low),r>=90&&(t=n.High),t}function i(n,r){var t=o(n)-o(r);return t<0&&(t=0),t}function f(n,r){return 0!=n&&(0==r||o(n+r)<n)}function c(){return f(50,50)}function a(n){return f(n,100-n)}!function(n){n[n.Low=-1]=\"Low\",n[n.None=0]=\"None\",n[n.High=1]=\"High\"}(n||(n={}));export{n as Critic,r as Max,t as Min,f as against,a as check,c as coin,e as critic,i as hit,o as random,u as randomFromList};\n//# sourceMappingURL=index.mjs.map\n","import { Effect, EffectDirection, Situation, apply } from \"npc-emotional\";\r\nimport { Sentence } from \"first-order-logic\";\r\nimport { Roles } from \"./roles\";\r\nimport { Crowd } from \"./agent\";\r\nimport { randomFromList } from \"role-methods\";\r\nimport { Happiness } from \"npc-mind\";\r\nimport { Relation } from \"npc-relations\";\r\n\r\nexport class PhraseResult{\r\n private _content: string;\r\n private _effect: Effect;\r\n private _sentence: Sentence;\r\n\r\n constructor(content: string, effect: Effect, sentence: Sentence = null){\r\n if(content == null || content.trim() === \"\")\r\n throw new Error(\"Content cannot be empty.\");\r\n\r\n if(effect == null)\r\n throw new Error(\"Effect cannot be null.\");\r\n \r\n this._content = content;\r\n this._effect = effect;\r\n this._sentence = sentence;\r\n }\r\n\r\n get content(){\r\n return this._content;\r\n }\r\n\r\n get effect(){\r\n return this._effect;\r\n }\r\n\r\n get sentence(){\r\n return this._sentence;\r\n }\r\n\r\n get hasSentence(): boolean{\r\n return this._sentence !== null;\r\n }\r\n}\r\n\r\nexport type TextFunc = (roles: Roles) => string;\r\nexport type EffectFunc = (roles: Roles) => Effect;\r\nexport type SentenceFunc = (roles: Roles) => Sentence;\r\n\r\nexport class Alternative{\r\n private _text: TextFunc;\r\n private _effect: EffectFunc;\r\n private _sentence: SentenceFunc;\r\n\r\n constructor(text: TextFunc, effect: EffectFunc = null, sentence: SentenceFunc = null){\r\n if(text == null)\r\n throw new Error(\"Text function cannot be null.\");\r\n \r\n this._text = text;\r\n this._effect = (effect == null) ? (roles: Roles) => Effect.null() : effect;\r\n this._sentence = sentence;\r\n }\r\n\r\n get text(): TextFunc{\r\n return this._text;\r\n }\r\n\r\n get effect(): EffectFunc{\r\n return this._effect;\r\n }\r\n\r\n get sentence(): SentenceFunc{\r\n return this._sentence;\r\n }\r\n}\r\n\r\nconst PhraseSplitter: string = \":\";\r\n\r\nexport class Phrase{\r\n private _alternatives: Alternative[];\r\n private _performerRole: string;\r\n private _targetRole: string;\r\n private _isIntimate: boolean;\r\n\r\n constructor(performerRole: string, targetRole: string = null){\r\n if(performerRole == null || performerRole.trim() === \"\")\r\n throw new Error(\"Performer role cannot be null.\");\r\n \r\n if(targetRole != null && targetRole.trim() === \"\")\r\n throw new Error(\"If defining target role, it can't be empty.\");\r\n \r\n this._performerRole = performerRole;\r\n this._targetRole = targetRole;\r\n this._isIntimate = false;\r\n\r\n this._alternatives = [];\r\n }\r\n\r\n get performerRole(){\r\n return this._performerRole;\r\n }\r\n\r\n get targetRole(){\r\n return this._targetRole;\r\n }\r\n\r\n get isIntimate(){\r\n return this._isIntimate;\r\n }\r\n\r\n get isMultialternative(): boolean{\r\n return this._alternatives.length > 1;\r\n }\r\n\r\n allAlternatives(roles: Roles): string[]{\r\n return this._alternatives.map(a => a.text(roles));\r\n }\r\n\r\n withAlternative(alternative: TextFunc, effect: EffectFunc = null, sentence: SentenceFunc = null): Phrase{\r\n if(alternative == null)\r\n throw new Error(\"Alternative cannnot be null\");\r\n \r\n this._alternatives.push(new Alternative(alternative, effect, sentence));\r\n \r\n return this;\r\n }\r\n\r\n intimate(): void{\r\n this._isIntimate = true;\r\n }\r\n\r\n action(roles: Roles, crowd: Crowd, alternativeIndex: number = -1): PhraseResult{\r\n let alternative = this.chooseAlternative(roles, crowd, alternativeIndex);\r\n let textAlternative = alternative.text(roles);\r\n\r\n if(textAlternative.includes(PhraseSplitter)){\r\n let parts = textAlternative.split(PhraseSplitter);\r\n return new PhraseResult(\r\n roles.get(Phrase.uncorcheted(parts[0])).say(roles.assignRoles(parts[1])),\r\n alternative.effect(roles),\r\n alternative.sentence == null ? null : alternative.sentence(roles)\r\n );\r\n }\r\n\r\n return new PhraseResult(\r\n roles.assignRoles(textAlternative),\r\n alternative.effect(roles),\r\n alternative.sentence == null ? null : alternative.sentence(roles)\r\n );\r\n }\r\n\r\n private chooseAlternative(roles: Roles, crowd: Crowd, alternativeIndex: number): Alternative{\r\n if(this._alternatives.length === 1) return this._alternatives[0];\r\n if(alternativeIndex >= 0) return this._alternatives[alternativeIndex];\r\n\r\n if(this.performerHasMeaningfulDesires(roles, crowd))\r\n return this.calculateAlternativeBasedOnDesires(roles, crowd);\r\n \r\n return this.calculateAlternativeBasedOnEmotions(roles);\r\n }\r\n\r\n private performerHasMeaningfulDesires(roles: Roles, crowd: Crowd): boolean{\r\n let desires = roles.get(this._performerRole).Desires;\r\n return desires.any && desires.anyInvolved(crowd.all);\r\n }\r\n\r\n private calculateAlternativeBasedOnDesires(roles: Roles, crowd: Crowd): Alternative{\r\n const MinHeuristicValue: number = -1000000;\r\n\r\n let performer = roles.get(this._performerRole);\r\n\r\n let selectedAlternative = this._alternatives[0];\r\n let highestPunctuation: number = MinHeuristicValue;\r\n for (let alternative of this._alternatives)\r\n {\r\n let punctuation: number = MinHeuristicValue;\r\n let effect = alternative.effect(roles);\r\n if(effect.direction === EffectDirection.Neutral)\r\n {\r\n punctuation = performer.Desires.heuristicTotal(crowd);\r\n }\r\n else\r\n {\r\n var alternativeStatus = crowd.copy();\r\n\r\n var situation = new Situation(\r\n alternativeStatus.get(performer.Name),\r\n alternativeStatus.get(roles.get(effect.target).Name),\r\n this._isIntimate\r\n ? effect.isThirdPerson\r\n ? [ alternativeStatus.get(roles.get(this._targetRole).Name) ]\r\n : []\r\n : alternativeStatus.all\r\n .filter(x =>\r\n x.Name !== roles.get(effect.target).Name\r\n && x.Name !== performer.Name)\r\n );\r\n\r\n apply(effect, situation, this._isIntimate);\r\n\r\n punctuation = performer.Desires.heuristicTotal(alternativeStatus);\r\n }\r\n\r\n if(punctuation > highestPunctuation)\r\n {\r\n selectedAlternative = alternative;\r\n highestPunctuation = punctuation;\r\n }\r\n }\r\n\r\n return selectedAlternative;\r\n }\r\n\r\n private calculateAlternativeBasedOnEmotions(roles: Roles): Alternative{\r\n var direction = this._targetRole == null\r\n ? this.calculateEffectDirection(roles.get(this._performerRole).Happiness)\r\n : this.calculateEffectDirectionWithRelation(\r\n roles.get(this._performerRole).Relations.get(roles.get(this._targetRole).Name),\r\n roles.get(this._performerRole).Happiness);\r\n\r\n var directedAlternatives = this._alternatives\r\n .filter(a => a.effect(roles).direction === direction);\r\n\r\n if (directedAlternatives.length === 0)\r\n directedAlternatives = this._alternatives;\r\n\r\n return randomFromList(directedAlternatives);\r\n }\r\n\r\n private calculateEffectDirection(happiness: Happiness): EffectDirection{\r\n return happiness.isHappy\r\n ? EffectDirection.Positive\r\n : happiness.isUnhappy\r\n ? EffectDirection.Negative\r\n : EffectDirection.Neutral;\r\n }\r\n \r\n private calculateEffectDirectionWithRelation(relation: Relation, happiness: Happiness): EffectDirection{\r\n if (relation.isPonderatedGood && happiness.isHappy) return EffectDirection.Positive;\r\n else if (relation.isPonderatedBad && happiness.isUnhappy) return EffectDirection.Negative;\r\n else if (relation.isPonderatedNeutral && happiness.isNeutral) return EffectDirection.Neutral;\r\n else if (relation.isPonderatedNeutral && happiness.isHappy) return EffectDirection.Positive;\r\n else if (relation.isPonderatedNeutral && happiness.isUnhappy) return EffectDirection.Negative;\r\n else if (relation.isPonderatedGood && happiness.isNeutral) return EffectDirection.Positive;\r\n else if (relation.isPonderatedBad && happiness.isNeutral) return EffectDirection.Negative;\r\n else if (relation.isPonderatedGood && happiness.isUnhappy) return EffectDirection.Neutral;\r\n else if (relation.isPonderatedBad && happiness.isHappy) return EffectDirection.Neutral;\r\n else throw new Error(\"Not existing option.\");\r\n }\r\n\r\n private static uncorcheted(input: string): string{\r\n return input.replace(\"[\", \"\").replace(\"]\", \"\");\r\n }\r\n}","import { Roles, RolesDescriptor } from \"./roles\";\r\nimport { Phrase } from \"./phrase\";\r\nimport { TruthTable, Sentence } from \"first-order-logic\";\r\nimport { MapStructure } from \"./location\";\r\nimport { Agent } from \".\";\r\n\r\nexport interface IDeliverer{\r\n isFinished: boolean;\r\n deliver(roles: Roles): Phrase;\r\n}\r\n\r\nexport type Preconditions = (table: TruthTable, roles: Roles, map: MapStructure) => boolean;\r\nexport type Postconditions = (table: TruthTable, roles: Roles, map: MapStructure) => TruthTable;\r\n\r\nexport interface IInteraction{\r\n name: string;\r\n description: string;\r\n preconditions: Preconditions;\r\n postconditions: Postconditions;\r\n isIntimate: boolean;\r\n deliverer: IDeliverer;\r\n rolesDescriptor: RolesDescriptor;\r\n timing: Timing;\r\n\r\n intimate():IInteraction;\r\n getPermutations(main: Agent, other: Agent[]): Roles[];\r\n equals(interaction: IInteraction): boolean;\r\n globallyEquals(interaction: IInteraction): boolean;\r\n}\r\n\r\nexport enum Timing{\r\n Single,\r\n GlobalSingle,\r\n Repeteable\r\n}","import { Agent } from \"./agent\";\r\n\r\nexport class RolesDescriptor{\r\n private _main: string;\r\n private _secondarys: Set<string>;\r\n\r\n constructor(main: string, secondarys: string[] = []){\r\n if(main == null || main.trim() === \"\")\r\n throw new Error(\"Main cannot be null.\");\r\n \r\n if(secondarys == null)\r\n throw new Error(\"Secondarys cannot be null.\");\r\n \r\n this._main = main;\r\n this._secondarys = new Set(secondarys);\r\n }\r\n\r\n get main(){\r\n return this._main;\r\n }\r\n\r\n get secondarys(): string[]{\r\n return Array.from(this._secondarys.values());\r\n }\r\n\r\n get all(): string[]{\r\n return [this._main, ...this.secondarys];\r\n }\r\n}\r\n\r\nexport class Roles{\r\n private _roles: Map<string, Agent>;\r\n\r\n constructor(){\r\n this._roles = new Map<string, Agent>();\r\n }\r\n\r\n get roleNames(): string[]{\r\n return Array.from(this._roles.keys());\r\n }\r\n\r\n get agents(): Agent[]{\r\n return Array.from(this._roles.values());\r\n }\r\n\r\n match(role: string, agent: Agent): Roles{\r\n this.validateRole(role);\r\n this.validateAgent(agent);\r\n \r\n this._roles.set(role, agent);\r\n\r\n return this;\r\n }\r\n\r\n get(role: string): Agent{\r\n this.validateRole(role);\r\n\r\n if(!this._roles.has(role))\r\n throw new Error(\"Specified role doesn't exist\");\r\n \r\n return this._roles.get(role);\r\n }\r\n\r\n has(role: string): boolean{\r\n this.validateRole(role);\r\n\r\n return this._roles.has(role);\r\n }\r\n\r\n matched(agent: Agent): boolean{\r\n this.validateAgent(agent);\r\n\r\n return this.agents.some(a => a.Name === agent.Name);\r\n }\r\n\r\n assignRoles(input: string): string{\r\n let assignedResult: string = input;\r\n\r\n for(let roleName of this._roles.keys()){\r\n assignedResult = assignedResult.replace(`[${roleName}]`, this._roles.get(roleName).Name);\r\n }\r\n\r\n return assignedResult;\r\n }\r\n\r\n equals(other: Roles): boolean{\r\n if(other == null) return false;\r\n\r\n if(this._roles.size !== other._roles.size) return false;\r\n \r\n for(let roleName of this._roles.keys()){\r\n if(!other._roles.has(roleName)) return false;\r\n if(this._roles.get(roleName).Name !== other._roles.get(roleName).Name) return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n toString(): string{\r\n return this.roleNames.map(r => `${this._roles.get(r).Name} as ${r}`).join(\",\");\r\n }\r\n\r\n private validateRole(role: string): void{\r\n if(role == null || role.trim() === \"\")\r\n throw new Error(\"Role cannot be empty.\");\r\n }\r\n\r\n private validateAgent(agent: Agent): void{\r\n if(agent == null)\r\n throw new Error(\"Agent cannot be null.\");\r\n }\r\n}","import { Reactions } from \"npc-emotional\";\r\n\r\nexport class Step{\r\n private _content: string[];\r\n private _ender: boolean;\r\n private _choices: Choices;\r\n private _reactions: Reactions;\r\n\r\n private constructor(){\r\n this._content = [];\r\n this._choices = null;\r\n this._reactions = null;\r\n }\r\n\r\n get content(): string[]{\r\n return this._content;\r\n }\r\n\r\n get isEnder(): boolean{\r\n return this._ender;\r\n }\r\n\r\n get hasChoices(): boolean{\r\n return this._choices !== null;\r\n }\r\n\r\n get choices(): Choices{\r\n return this._choices;\r\n }\r\n\r\n get reactions(): Reactions{\r\n return this._reactions;\r\n }\r\n\r\n get hasReactions(): boolean{\r\n return this._reactions != null;\r\n }\r\n\r\n append(text: string): Step{\r\n if(text != null && text.trim() !== \"\"){\r\n this._content.push(text);\r\n }\r\n \r\n return this;\r\n }\r\n\r\n static fromContent(content: string, isEnder: boolean = false): Step{\r\n if(content == null || content.trim() === \"\")\r\n throw new Error(\"Content cannot be empty.\");\r\n \r\n let step = new Step();\r\n step._content = [ content ];\r\n step._ender = isEnder;\r\n step._choices = null;\r\n\r\n return step;\r\n }\r\n\r\n static fromChoices(choices: string[], isEnder: boolean = false): Step{\r\n if(choices == null || choices.length === 0)\r\n throw new Error(\"Choices cannot be empty.\");\r\n \r\n let step = new Step();\r\n step._ender = isEnder;\r\n step._choices = new Choices(choices); \r\n\r\n return step;\r\n }\r\n\r\n static fromReactions(reactions: Reactions, isEnder: boolean = false): Step{\r\n if(reactions == null)\r\n throw new Error(\"Reactions cannot be null.\");\r\n \r\n let step = new Step();\r\n step._ender = isEnder;\r\n step._reactions = reactions;\r\n\r\n return step;\r\n }\r\n}\r\n\r\nexport class Choices{\r\n private _items: string[];\r\n\r\n constructor(items: string[]){\r\n if(items == null || items.length === 0)\r\n throw new Error(\"Items cannot be empty.\");\r\n \r\n this._items = items;\r\n }\r\n\r\n get count(): number{\r\n return this._items.length;\r\n }\r\n\r\n get items(){\r\n return this._items;\r\n }\r\n\r\n isValidItem(index: number): boolean{\r\n return index >= 0 && index < this._items.length;\r\n }\r\n}","import { Aspect, Likes } from \"npc-aspect\";\r\nimport { RelationSet } from \"npc-relations\";\r\nimport { Individual, LogicAgent, TruthTable, Sentence } from \"first-order-logic\";\r\nimport { IEmotional } from \"npc-emotional\";\r\nimport { Happiness, Personality } from \"npc-mind\";\r\nimport { randomFromList } from \"role-methods\";\r\n\r\nexport type PassTurn = (turn: number, agent: Agent) => string;\r\n\r\nexport class Agent implements IEmotional{\r\n private _name: string;\r\n private _aspect: Aspect;\r\n private _likes: Likes;\r\n private _relations: RelationSet;\r\n private _happiness: Happiness;\r\n private _personality: Personality;\r\n private _isHuman: boolean;\r\n private _characteristics: Characteristics;\r\n private _desires: Desires;\r\n private _onTurnPassed: PassTurn;\r\n private _logic: LogicAgent;\r\n private _isActive: boolean;\r\n\r\n constructor(\r\n name: string,\r\n aspect: Aspect,\r\n relations: RelationSet,\r\n happiness: Happiness,\r\n personality: Personality,\r\n likes: Likes,\r\n characteristics: string[],\r\n human: boolean,\r\n onTurnPassed: PassTurn = null\r\n ){\r\n if(name == null || name.trim() === \"\")\r\n throw new Error(\"Name cannot be empty.\");\r\n \r\n if(aspect == null)\r\n throw new Error(\"Aspect cannot be null.\");\r\n \r\n if(relations == null)\r\n throw new Error(\"Relations cannot be null.\");\r\n \r\n if(happiness == null)\r\n throw new Error(\"Happiness cannot be null.\");\r\n \r\n if(personality == null)\r\n throw new Error(\"Personality cannot be null.\");\r\n \r\n if(likes == null)\r\n throw new Error(\"Likes cannot be null.\");\r\n \r\n if(characteristics == null)\r\n throw new Error(\"Characteristics cannot be null.\");\r\n \r\n this._name = name;\r\n this._aspect = aspect;\r\n this._relations = relations;\r\n this._happiness = happiness;\r\n this._personality = personality;\r\n this._likes = likes;\r\n this._characteristics = new Characteristics(name, characteristics);\r\n this._desires = new Desires();\r\n this._isHuman = human;\r\n this._isActive = true;\r\n this._onTurnPassed = onTurnPassed == null \r\n ? (turn: number, agent: Agent) => \"\" \r\n : onTurnPassed;\r\n this._logic = new LogicAgent();\r\n this._logic.population.add(this.Individual);\r\n }\r\n\r\n get Name(){\r\n return this._name;\r\n }\r\n\r\n get Aspect(){\r\n return this._aspect;\r\n }\r\n\r\n get Likes(){\r\n return this._likes;\r\n }\r\n\r\n get Relations(){\r\n return this._relations;\r\n }\r\n\r\n get Happiness(){\r\n return this._happiness;\r\n }\r\n\r\n get Personality(){\r\n return this._personality;\r\n }\r\n\r\n get IsHuman(){\r\n return this._isHuman;\r\n }\r\n\r\n get Characteristics(){\r\n return this._characteristics;\r\n }\r\n\r\n get Desires(){\r\n return this._desires;\r\n }\r\n\r\n get IsActive(){\r\n return this._isActive;\r\n }\r\n\r\n get OnTurnPassed(){\r\n return this._onTurnPassed;\r\n }\r\n\r\n get Individual(): Individual{\r\n return new Individual(this.Name.replace(\" \", \"\"));\r\n }\r\n\r\n get logic(){\r\n return this._logic;\r\n }\r\n\r\n say(content: string){\r\n if(content == null)\r\n throw new Error(\"Content cannot be null.\");\r\n \r\n return `${this.Name}: - ${content}`;\r\n }\r\n\r\n activate(): void{\r\n this._isActive = true;\r\n }\r\n\r\n deactivate(): void{\r\n this._isActive = false;\r\n }\r\n\r\n humanize(): void{\r\n this._isHuman = true;\r\n }\r\n\r\n dehumanize(): void{\r\n this._isHuman = false;\r\n }\r\n\r\n copy(): Agent{\r\n return new Agent(\r\n this._name,\r\n this._aspect.copy(),\r\n this._relations.copy(),\r\n this._happiness.copy(),\r\n this._personality.copy(),\r\n this._likes.copy(),\r\n this._characteristics.table.elements.map(sentence => sentence.function.name),\r\n this._isHuman\r\n );\r\n }\r\n\r\n passTurn(turn: number): string{\r\n return this._onTurnPassed(turn, this);\r\n }\r\n}\r\n\r\nexport class Crowd{\r\n private _crowd: Map<string, Agent>;\r\n\r\n constructor(agents: Agent[]){\r\n if(agents == null)\r\n throw new Error(\"Agents cannot be null.\");\r\n \r\n this._crowd = new Map<string, Agent>();\r\n for(let agent of agents){\r\n this._crowd.set(agent.Name, agent);\r\n }\r\n }\r\n\r\n get all(): Agent[]{\r\n return Array.from(this._crowd.values());\r\n }\r\n\r\n get(name: string): Agent{\r\n return this._crowd.get(name);\r\n }\r\n\r\n copy(): Crowd{\r\n return new Crowd(this.all.map(agent => agent.copy()));\r\n }\r\n}\r\n\r\nexport type Heuristic = (crowd: Crowd) => number;\r\n\r\nexport class Desire{\r\n private _involved: Set<string>;\r\n private _heuristic: Heuristic;\r\n\r\n constructor(heuristic: Heuristic, involved: string[]){\r\n if(heuristic == null)\r\n throw new Error(\"Heuristic cannot be null.\");\r\n \r\n if(involved == null)\r\n throw new Error(\"Involved agents cannot be null.\");\r\n \r\n this._heuristic = heuristic;\r\n this._involved = new Set<string>(involved);\r\n }\r\n\r\n get heuristic(){\r\n return this._heuristic;\r\n }\r\n\r\n anyInvolved(agents: Agent[]){\r\n return agents.some(agent => this._involved.has(agent.Name));\r\n }\r\n}\r\n\r\nexport class Desires{\r\n private _desires: Desire[];\r\n\r\n constructor(){\r\n this._desires = [];\r\n }\r\n\r\n get any(): boolean{\r\n return this._desires.length > 0;\r\n }\r\n\r\n append(desire: Desire): Desires{\r\n if(desire != null)\r\n this._desires.push(desire);\r\n \r\n return this;\r\n }\r\n\r\n clear(): void{\r\n this._desires = [];\r\n }\r\n\r\n anyInvolved(agents: Agent[]): boolean{\r\n return this._desires.some(desire => desire.anyInvolved(agents));\r\n }\r\n\r\n heuristicTotal(crowd: Crowd){\r\n return this._desires.reduce((accumulated, desire) => accumulated + desire.heuristic(crowd), 0);\r\n }\r\n}\r\n\r\nexport class Agents{\r\n private _agents: Agent[];\r\n private _availableAgents: Agent[];\r\n\r\n constructor(agents: Agent[]){\r\n if(agents == null)\r\n throw new Error(\"Agents cannot be null.\");\r\n \r\n this._agents = agents;\r\n this._availableAgents = [];\r\n }\r\n\r\n get all(): Agent[]{\r\n return this._agents;\r\n }\r\n\r\n get count(): number{\r\n return this._agents.length;\r\n }\r\n\r\n allExcept(agent: Agent): Agent[]{\r\n return this._agents.filter(a => a.Name !== agent.Name);\r\n }\r\n\r\n popRandomAgent(): Agent{\r\n if(this._availableAgents.length === 0)\r\n this._availableAgents = [...this._agents];\r\n \r\n let ponderatedAgents: Agent[] = [];\r\n for(let agent of this._availableAgents){\r\n for(let i = 0; i < agent.Personality.introvertyExtroverty; i++){\r\n ponderatedAgents.push(agent);\r\n }\r\n }\r\n\r\n let selectedAgent = randomFromList(ponderatedAgents);\r\n this._availableAgents = this._availableAgents.filter(a => a.Name !== selectedAgent.Name);\r\n return selectedAgent;\r\n }\r\n}\r\n\r\nexport class Characteristics{\r\n private _name: string;\r\n private _table: TruthTable;\r\n\r\n constructor(name: string, characteristics: string[] = []){\r\n if(name == null || name.trim() === \"\")\r\n throw new Error(\"Name cannot be empty.\");\r\n \r\n this._name = name;\r\n\r\n this._table = new TruthTable();\r\n for(let characteristic of characteristics){\r\n if(name != null && name.trim() !== \"\"){\r\n this._table.add(Sentence.build(characteristic, this._name));\r\n }\r\n }\r\n }\r\n\r\n get table(){\r\n return this._table;\r\n }\r\n\r\n is(characteristic: string){\r\n if(characteristic == null || characteristic.trim() === \"\")\r\n throw new Error(\"Characteristic cannot be empty.\");\r\n \r\n return this._table.exists(Sentence.build(characteristic, this._name));\r\n }\r\n}","import { Agent } from \"./agent\";\r\n\r\nexport class Location{\r\n private _name: string;\r\n private _connections: Map<string, Location>;\r\n private _agents: Map<string, Agent>;\r\n\r\n constructor(name){\r\n if(name == null || name.trim() === \"\")\r\n throw new Error(\"Location cannot be null.\");\r\n \r\n this._name = name;\r\n this._connections = new Map<string, Location>();\r\n this._agents = new Map<string, Agent>();\r\n }\r\n\r\n get name(){\r\n return this._name;\r\n }\r\n\r\n get connections(): Location[]{\r\n return Array.from(this._connections.values());\r\n }\r\n\r\n get agents(): Agent[]{\r\n return Array.from(this._agents.values());\r\n }\r\n\r\n append(agents: Agent[]): void{\r\n if(agents == null) return;\r\n\r\n for(let agent of agents){\r\n this._agents.set(agent.Name, agent);\r\n }\r\n }\r\n\r\n remove(agent: Agent): void{\r\n if(agent == null) return;\r\n\r\n this._agents.delete(agent.Name);\r\n }\r\n\r\n has(agent: Agent): boolean{\r\n if(agent == null) return false;\r\n\r\n return this._agents.has(agent.Name);\r\n }\r\n\r\n connectWith(location: Location): void{\r\n if(location == null) return;\r\n\r\n this._connections.set(location.name, location);\r\n }\r\n\r\n isConnected(location: Location): boolean{\r\n if(location == null) return false;\r\n\r\n return this._connections.has(location.name);\r\n }\r\n\r\n static join(first: Location, second: Location): void{\r\n first.connectWith(second);\r\n second.connectWith(first);\r\n }\r\n}\r\n\r\nexport class MapStructure{\r\n private _locations: Map<string, Location>;\r\n private _ubications: Map<string, string>;\r\n\r\n constructor(locations: Location[]){\r\n if(locations == null)\r\n throw new Error(\"Locations cannot be null.\");\r\n \r\n this._locations = new Map<string, Location>();\r\n this._ubications = new Map<string, string>();\r\n\r\n for(let location of locations){\r\n this._locations.set(location.name, location);\r\n }\r\n }\r\n\r\n getLocation(location: string): Location{\r\n if(location == null || location.trim() === \"\" || !this._locations.has(location)) return null;\r\n\r\n return this._locations.get(location);\r\n }\r\n\r\n getUbication(agent: Agent): Location{\r\n if(agent == null || !this._ubications.has(agent.Name)) return null;\r\n\r\n return this._locations.get(this._ubications.get(agent.Name));\r\n }\r\n\r\n move(agent: Agent, destination: Location): boolean{\r\n if(agent == null || destination == null || !this._locations.has(destination.name))\r\n return false;\r\n \r\n if(!this._ubications.has(agent.Name)){\r\n this._ubications.set(agent.Name, destination.name);\r\n destination.append([ agent ]);\r\n return true;\r\n }\r\n\r\n let actualLocation = this.getUbication(agent);\r\n if(!actualLocation.has(agent))\r\n return false;\r\n \r\n if(!actualLocation.isConnected(destination))\r\n return false;\r\n \r\n this._ubications.set(agent.Name, destination.name);\r\n actualLocation.remove(agent);\r\n destination.append([ agent ]);\r\n return true;\r\n }\r\n\r\n areInTheSameLocation(first: Agent, second: Agent): boolean{\r\n if(first == null || second == null || !this._ubications.has(first.Name) || !this._ubications.has(second.Name))\r\n return false;\r\n \r\n return this._ubications.get(first.Name) === this._ubications.get(second.Name);\r\n }\r\n}","import { IDeliverer, IInteraction, Postconditions, Preconditions, Timing } from \"./interfaces\";\r\nimport { Phrase } from \"./phrase\";\r\nimport { Roles, RolesDescriptor } from \"./roles\";\r\nimport { Queue } from \"data-structs-n-algos\";\r\nimport { Agent } from \"./agent\";\r\nimport { TruthTable } from \"first-order-logic\";\r\n\r\nexport class Deliverer implements IDeliverer{\r\n private _phrases: Queue<Phrase>;\r\n\r\n constructor(phrases: Phrase[]){\r\n if(phrases == null)\r\n throw new Error(\"Phrases cannot be null.\");\r\n \r\n this._phrases = new Queue<Phrase>(phrases);\r\n }\r\n\r\n get isFinished(): boolean{\r\n return this._phrases.isEmpty();\r\n }\r\n\r\n deliver(roles: Roles): Phrase {\r\n if(!this.isFinished)\r\n return this._phrases.dequeue();\r\n\r\n throw new Error(\"No phrases to deliver.\");\r\n }\r\n}\r\n\r\nexport abstract class BaseInteraction implements IInteraction{\r\n private _name: string;\r\n private _description: string;\r\n private _preconditions: Preconditions;\r\n private _postconditions: Postconditions;\r\n private _timing: Timing;\r\n\r\n protected _isIntimate: boolean;\r\n\r\n constructor(\r\n name: string, \r\n description: string, \r\n timing: Timing,\r\n preconditions: Preconditions,\r\n postconditions: Postconditions){\r\n\r\n if(name == null || name.trim() === \"\")\r\n throw new Error(\"Name cannot be empty.\");\r\n \r\n if(description == null || description.trim() === \"\")\r\n throw new Error(\"Description cannot be empty.\");\r\n \r\n if(preconditions == null)\r\n throw new Error(\"Preconditions cannot be null.\");\r\n \r\n if(postconditions == null)\r\n throw new Error(\"Postconditions cannot be null.\");\r\n\r\n this._name = name;\r\n this._description = description;\r\n this._timing = timing;\r\n this._preconditions = preconditions;\r\n this._postconditions = postconditions;\r\n this._isIntimate = false;\r\n }\r\n\r\n get name(){\r\n return this._name;\r\n }\r\n\r\n get description(){\r\n return this._description;\r\n }\r\n\r\n get preconditions(){\r\n return this._preconditions;\r\n }\r\n\r\n get postconditions(){\r\n return this._postconditions;\r\n }\r\n\r\n get isIntimate(){\r\n return this._isIntimate;\r\n }\r\n\r\n get timing(){\r\n return this._timing;\r\n }\r\n\r\n abstract get deliverer(): IDeliverer;\r\n abstract get rolesDescriptor(): RolesDescriptor;\r\n\r\n abstract intimate(): IInteraction;\r\n\r\n equals(interaction: IInteraction): boolean {\r\n if(interaction == null) return false;\r\n\r\n return this._name === interaction.name;\r\n }\r\n\r\n globallyEquals(interaction: IInteraction): boolean {\r\n if(interaction == null) return false;\r\n\r\n return this._name === interaction.name;\r\n }\r\n\r\n getPermutations(main: Agent, other: Agent[]): Roles[] {\r\n let result: Roles[] = [];\r\n let descriptor = this.rolesDescriptor;\r\n\r\n if (other.length < descriptor.secondarys.length) return result;\r\n\r\n let agentCombinations = this.calculateAgentCombinations(other, descriptor.secondarys.length);\r\n\r\n for (let combination of agentCombinations)\r\n {\r\n if (combination.length === 0)\r\n {\r\n result.push(new Roles().match(descriptor.main, main));\r\n continue;\r\n }\r\n\r\n for (let agent of combination)\r\n {\r\n var roles = new Roles().match(descriptor.main, main);\r\n\r\n roles.match(descriptor.secondarys[0], agent);\r\n var remainingSecondarys = descriptor.secondarys.filter(x => !roles.has(x));\r\n var remainingAgents = combination.filter(x => !roles.matched(x));\r\n\r\n this.fillRemainingPermutations(roles, remainingSecondarys, remainingAgents);\r\n\r\n result.push(roles);\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private calculateAgentCombinations(agents: Agent[], size: number): Agent[][]{\r\n let oneElemSequences = agents.map(a => [ a ]);\r\n\r\n let result: Agent[][] = [];\r\n result.push([]);\r\n\r\n for (let oneElemSequence of oneElemSequences)\r\n {\r\n let length: number = result.length;\r\n\r\n for (let i = 0; i < length; i++)\r\n {\r\n if (result[i].length >= size)\r\n continue;\r\n\r\n result.push(result[i].concat(oneElemSequence));\r\n }\r\n }\r\n\r\n return result.filter(x => x.length === size);\r\n }\r\n\r\n private fillRemainingPermutations(roles: Roles, secondarys: string[], agents: Agent[]): void{\r\n if (secondarys.length === 0) return;\r\n\r\n for (let agent of agents)\r\n {\r\n roles.match(secondarys[0], agent);\r\n var remainingSecondarys = secondarys.filter(x => !roles.has(x));\r\n var remainingAgents = agents.filter(x => !roles.matched(x));\r\n\r\n this.fillRemainingPermutations(roles, remainingSecondarys, remainingAgents);\r\n }\r\n }\r\n}\r\n\r\nexport class Interaction extends BaseInteraction{\r\n private _phrases: Phrase[];\r\n private _rolesDescriptor: RolesDescriptor;\r\n\r\n constructor(\r\n name: string, \r\n description: string, \r\n rolesDescriptor: RolesDescriptor,\r\n phrases: Phrase[],\r\n timing: Timing = Timing.Single,\r\n preconditions: Preconditions = (table, roles, map) => true,\r\n postconditions: Postconditions = (roles, map) => TruthTable.empty){\r\n \r\n super(name, description, timing, preconditions, postconditions);\r\n\r\n if(rolesDescriptor == null)\r\n throw new Error(\"Roles descriptor cannot be null.\");\r\n \r\n if(phrases == null || phrases.length === 0)\r\n throw new Error(\"Interaction must have almost one phrase.\");\r\n \r\n this._rolesDescriptor = rolesDescriptor;\r\n this._phrases = phrases;\r\n }\r\n\r\n get deliverer(): IDeliverer {\r\n return new Deliverer(this._phrases);\r\n }\r\n\r\n get rolesDescriptor(): RolesDescriptor {\r\n return this._rolesDescriptor;\r\n }\r\n\r\n intimate(): IInteraction {\r\n this._isIntimate = true;\r\n\r\n for(let phrase of this._phrases){\r\n phrase.intimate();\r\n }\r\n\r\n return this;\r\n }\r\n}","import { Effect, EffectDirection, EffectReaction, Reactions, Situation, apply } from \"npc-emotional\";\r\nimport { Phrase } from \"./phrase\";\r\nimport { IDeliverer, IInteraction } from \"./interfaces\";\r\nimport { TruthTable } from \"first-order-logic\";\r\nimport { Roles } from \"./roles\";\r\nimport { MapStructure, Location } from \"./location\";\r\nimport { Step } from \"./step\";\r\nimport { Input } from \"./input\";\r\nimport { Crowd } from \"./agent\";\r\n\r\nexport class OnGoingInteraction{\r\n private _deliverer: IDeliverer;\r\n private _effect: Effect;\r\n private _performerRole:string;\r\n private _targetRole:string;\r\n private _actualPhrase: Phrase;\r\n private _onGoingPostconditions: TruthTable;\r\n\r\n private _roles: Roles;\r\n private _map: MapStructure;\r\n private _table: TruthTable;\r\n private _interaction: IInteraction;\r\n\r\n constructor(interaction: IInteraction, roles: Roles, map: MapStructure, table: TruthTable){\r\n if(interaction == null)\r\n throw new Error(\"Interaction cannot be null.\");\r\n \r\n if(roles == null)\r\n throw new Error(\"Roles cannot be null.\");\r\n \r\n if(map == null)\r\n throw new Error(\"Map cannot be null.\");\r\n \r\n if(table == null)\r\n throw new Error(\"Postconditions table cannot be null.\");\r\n\r\n this._interaction = interaction;\r\n this._roles = roles;\r\n this._map = map;\r\n this._table = table;\r\n\r\n this._effect = Effect.null();\r\n this._performerRole = null;\r\n this._targetRole = null;\r\n this._onGoingPostconditions = new TruthTable();\r\n }\r\n\r\n get interaction(){\r\n return this._interaction;\r\n }\r\n\r\n get roles(){\r\n return this._roles;\r\n }\r\n\r\n get map(){\r\n return this._map;\r\n }\r\n\r\n get isInteractionEnded(): boolean{\r\n return this._deliverer.isFinished && this._effect.isNull;\r\n }\r\n\r\n get location(): Location{\r\n return this._map.getUbication(this._roles.get(this._interaction.rolesDescriptor.main));\r\n }\r\n\r\n get postconditions(): TruthTable\r\n {\r\n this._onGoingPostconditions.join(this._interaction.postconditions(this._table, this._roles, this._map));\r\n return this._onGoingPostconditions;\r\n }\r\n\r\n performStep(input: Input): Step{\r\n this.initializeDeliverer();\r\n \r\n if (!this._effect.isNull)\r\n return this.calculateAgentsReactions();\r\n\r\n if (input.isVoid)\r\n {\r\n this._actualPhrase = this._deliverer.deliver(this._roles);\r\n this.forcePhraseRelations(this._actualPhrase.performerRole, this._actualPhrase.targetRole);\r\n\r\n if (this._roles.get(this._actualPhrase.performerRole).IsHuman && this._actualPhrase.isMultialternative)\r\n return Step.fromChoices(this._actualPhrase\r\n .allAlternatives(this._roles)\r\n .map(alternative => this._roles.assignRoles(alternative)));\r\n else\r\n return this.executePhraseAction(input);\r\n }\r\n else\r\n return this.executePhraseAction(input);\r\n }\r\n\r\n private initializeDeliverer(): void\r\n {\r\n if (this._deliverer == null)\r\n this._deliverer = this._interaction.deliverer;\r\n }\r\n\r\n private forcePhraseRelations(performerRole: string, targetRole: string): void\r\n {\r\n if (targetRole != null && targetRole.trim() !== \"\")\r\n {\r\n this._roles.get(performerRole).Relations.get(this._roles.get(targetRole).Name);\r\n this._roles.get(targetRole).Relations.get(this._roles.get(performerRole).Name);\r\n }\r\n }\r\n\r\n private executePhraseAction(input: Input): Step{\r\n let result = this._actualPhrase.action(\r\n this._roles, \r\n new Crowd(this.location.agents), \r\n input.choiceIndex);\r\n\r\n this._effect = result.effect;\r\n this._performerRole = this._actualPhrase.performerRole;\r\n this._targetRole = this._actualPhrase.targetRole;\r\n\r\n if (result.hasSentence && !this._onGoingPostconditions.exists(result.sentence))\r\n this._onGoingPostconditions.add(result.sentence);\r\n\r\n return Step.fromContent(result.content, this.isInteractionEnded);\r\n }\r\n\r\n private calculateAgentsReactions(): Step{\r\n let reactions = new Reactions();\r\n\r\n if(this._effect.direction != EffectDirection.Neutral)\r\n {\r\n var situation = this._effect.isTargeted\r\n ? new Situation(\r\n this._roles.get(this._performerRole),\r\n this._roles.get(this._effect.target),\r\n this._interaction.isIntimate\r\n ? this._effect.isThirdPerson\r\n ? [ this._roles.get(this._targetRole) ]\r\n : []\r\n : this.location.agents\r\n .filter(x => x.Name !== this._roles.get(this._effect.target).Name \r\n && x.Name !== this._roles.get(this._performerRole).Name))\r\n : new Situation(\r\n this._roles.get(this._performerRole),\r\n null,\r\n this.location.agents\r\n .filter(x => x.Name !== this._roles.get(this._performerRole).Name));\r\n\r\n reactions.append(apply(this._effect, situation, this._interaction.isIntimate));\r\n }\r\n\r\n this._effect = Effect.null();\r\n\r\n return Step.fromReactions(reactions, this.isInteractionEnded);\r\n }\r\n\r\n equals(other: OnGoingInteraction): boolean{\r\n return this._interaction.equals(other.interaction) && this._roles.equals(other.roles);\r\n }\r\n\r\n toString(): string\r\n {\r\n return this._roles.assignRoles(this._interaction.description);\r\n }\r\n}","import { Agent } from \"./agent\";\r\nimport { OnGoingInteraction } from \"./ongoing\";\r\nimport { IInteraction } from \"./interfaces\";\r\n\r\nexport type Historic = {\r\n agent: Agent;\r\n ongoing: OnGoingInteraction;\r\n}\r\n\r\nexport class HistoricInteractions{\r\n private _executions: Historic[];\r\n\r\n constructor(){\r\n this._executions = [];\r\n }\r\n\r\n add(agent: Agent, ongoing: OnGoingInteraction){\r\n if(agent == null)\r\n throw new Error(\"Agent cannot be null.\");\r\n \r\n if(ongoing == null)\r\n throw new Error(\"On going interaction cannot be null.\");\r\n \r\n this._executions.push({\r\n agent,\r\n ongoing\r\n });\r\n }\r\n\r\n hasExecutedInteraction(interaction: IInteraction): boolean{\r\n return this._executions.some(e => e.ongoing.interaction.equals(interaction));\r\n }\r\n\r\n hasExecutedOnGoingInteraction(ongoing: OnGoingInteraction): boolean{\r\n return this._executions.some(e => e.ongoing.equals(ongoing));\r\n }\r\n}","import { modusPonens, TruthTable } from \"first-order-logic\";\r\nimport { OnGoingInteraction } from \"./ongoing\";\r\nimport { IInteraction, Timing } from \"./interfaces\";\r\nimport { Agent , Agents} from \"./agent\";\r\nimport { MapStructure } from \"./location\";\r\nimport { HistoricInteractions } from \"./historic\";\r\nimport { Input } from \"./input\";\r\nimport { Step } from \"./step\";\r\nimport { randomFromList } from \"role-methods\";\r\n\r\ninterface AgentPossibleInteractions{\r\n agent: Agent;\r\n possibleInteractions: OnGoingInteraction[]\r\n}\r\n\r\nexport type ScenarioCondition = (scenario: Scenario) => boolean;\r\n\r\nexport class FinishingConditions{\r\n private _conditions: ScenarioCondition[];\r\n\r\n constructor(){\r\n this._conditions = [];\r\n }\r\n\r\n with(condition: ScenarioCondition): FinishingConditions{\r\n if(condition == null)\r\n throw new Error(\"Condition cannot be null\");\r\n \r\n this._conditions.push(condition);\r\n\r\n return this;\r\n }\r\n\r\n allMet(scenario: Scenario): boolean{\r\n return this._conditions.every(c => c(scenario));\r\n }\r\n}\r\n\r\nexport class World{\r\n private _scenarios: Scenario[];\r\n private _lastScenario: Scenario;\r\n\r\n constructor(){\r\n this._scenarios = [];\r\n this._lastScenario = null;\r\n }\r\n\r\n get currentScenario(): Scenario{\r\n let notFinishedScenarios = this._scenarios.filter(s => !s.isFinished);\r\n\r\n if(notFinishedScenarios.length === 0)\r\n return null;\r\n\r\n if(this._lastScenario === null){\r\n this._lastScenario = notFinishedScenarios[0];\r\n }else{\r\n if(this._lastScenario.name !== notFinishedScenarios[0].name && notFinishedScenarios[0].isInheritor){\r\n notFinishedScenarios[0].postconditions.join(this._lastScenario.postconditions);\r\n }\r\n }\r\n \r\n return notFinishedScenarios[0];\r\n }\r\n\r\n add(scenario: Scenario){\r\n if(scenario == null)\r\n throw new Error(\"Scenario cannot be null.\");\r\n \r\n this._scenarios.push(scenario);\r\n }\r\n}\r\n\r\nexport type ScenarioTurnPassed = (turn: number, scenario: Scenario) => string;\r\nexport const ScenarioEndAllConditionsMet: string = \"0\";\r\nexport const ScenarioEndNoInteractions: string = \"1\";\r\n\r\nexport class Scenario{\r\n private _interactions: IInteraction[];\r\n private _finishingConditions: FinishingConditions;\r\n private _globalPostconditions: TruthTable;\r\n private _onTurnPassed: ScenarioTurnPassed;\r\n\r\n private _currentInteraction: OnGoingInteraction;\r\n private _selectableInteractions: OnGoingInteraction[];\r\n private _interactor: Agent;\r\n\r\n private get thereIsCurrentInteraction(): boolean{\r\n return this._currentInteraction != null;\r\n }\r\n\r\n private _name: string;\r\n private _map: MapStructure;\r\n private _agents: Agents;\r\n private _historic: HistoricInteractions;\r\n private _isFinished: boolean;\r\n private _turn: number;\r\n private _isInheritor: boolean;\r\n\r\n constructor(\r\n name: string,\r\n map: MapStructure,\r\n agents: Agents,\r\n interactions: IInteraction[],\r\n finishingConditions: FinishingConditions,\r\n onTurnPassed: ScenarioTurnPassed = null\r\n ){\r\n if(name == null || name.trim() === \"\")\r\n throw new Error(\"Name cannot be empty.\");\r\n \r\n if(map == null)\r\n throw new Error(\"Map cannot be null.\");\r\n \r\n if(agents == null)\r\n throw new Error(\"Agents cannot be null.\");\r\n \r\n if(interactions == null)\r\n throw new Error(\"Interactions cannot be null.\");\r\n \r\n if(finishingConditions == null)\r\n throw new Error(\"FinishingConditions cannot be null.\");\r\n \r\n this._name = name;\r\n this._map = map;\r\n this._agents = agents;\r\n this._interactions = interactions;\r\n this._finishingConditions = finishingConditions;\r\n this._onTurnPassed = onTurnPassed == null ? (turn: number, scenario: Scenario) => \"\" : onTurnPassed;\r\n\r\n this._isFinished = false;\r\n this._selectableInteractions = [];\r\n this._interactor = null;\r\n this._historic = new HistoricInteractions();\r\n this._globalPostconditions = new TruthTable();\r\n this._turn = 0;\r\n this._isInheritor = false;\r\n }\r\n\r\n get name(){\r\n return this._name;\r\n }\r\n\r\n get map(){\r\n return this._map;\r\n }\r\n\r\n get agents(){\r\n return this._agents;\r\n }\r\n\r\n get interactions(){\r\n return this._interactions;\r\n }\r\n\r\n get historic(){\r\n return this._historic;\r\n }\r\n\r\n get isFinished(){\r\n return this._isFinished;\r\n }\r\n\r\n get turn(){\r\n return this._turn;\r\n }\r\n\r\n get isInheritor(){\r\n return this._isInheritor;\r\n }\r\n\r\n