Skip to content

Commit

Permalink
feat(util): add and test entity containment helpers (fixes #53)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssube committed May 23, 2021
1 parent e64e561 commit 7932e27
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 6 deletions.
74 changes: 74 additions & 0 deletions src/util/state/index.ts
@@ -1,7 +1,9 @@
import { doesExist } from '@apextoaster/js-utils';

import { WorldEntity, WorldEntityType } from '../../model/entity';
import { Actor } from '../../model/entity/Actor';
import { Entity } from '../../model/entity/Base';
import { Room } from '../../model/entity/Room';
import { Metadata } from '../../model/meta/Metadata';
import { State } from '../../model/State';
import { DEFAULT_MATCHERS } from '../entity';
Expand Down Expand Up @@ -61,3 +63,75 @@ export function searchState(state: Immutable<State>, search: Partial<SearchParam

return results;
}

/**
* Find the room that contains a particular entity.
*
* @todo stop searching each room once it has been added
*/
export function findRoom(state: State, search: Partial<SearchParams>, matchers = DEFAULT_MATCHERS): Array<Room> {
const results = new Set<Room>();

for (const room of state.rooms) {
if (doesExist(search.room) && matchers.metadata(room, search.room) === false) {
continue;
}

for (const actor of room.actors) {
if (doesExist(search.actor) && matchers.metadata(actor, search.actor) === false) {
continue;
}

if (matchers.entity(actor, search, matchers)) {
results.add(room);
}
}

for (const item of room.items) {
if (matchers.entity(item, search, matchers)) {
results.add(room);
}
}
}

return Array.from(results);
}

/**
* Find the room or actor that contains a particular item.
*
* @todo stop searching each room once it has been added
*/
export function findContainer(state: State, search: Partial<SearchParams>, matchers = DEFAULT_MATCHERS): Array<Actor | Room> {
const results = new Set<Actor | Room>();

for (const room of state.rooms) {
if (doesExist(search.room) && matchers.metadata(room, search.room) === false) {
continue;
}

for (const actor of room.actors) {
if (doesExist(search.actor) && matchers.metadata(actor, search.actor) === false) {
continue;
}

if (matchers.entity(actor, search, matchers)) {
results.add(room);
}

for (const item of actor.items) {
if (matchers.entity(item, search, matchers)) {
results.add(actor);
}
}
}

for (const item of room.items) {
if (matchers.entity(item, search, matchers)) {
results.add(room);
}
}
}

return Array.from(results);
}
7 changes: 3 additions & 4 deletions test/util/TestConfig.ts
Expand Up @@ -13,9 +13,8 @@ describe('config utils', () => {
expect(data.logger.name).to.equal('textual-engine');
});

// TODO: the js-yaml error escape the assertion and causes this test to fail, not sure why
it('should throw when loading data files', async () => {
return expect(loadConfig('data/base.yml')).to.eventually.be.rejectedWith(ConfigError);
});
it('should throw when loading data files', async () =>
expect(loadConfig('data/base.yml')).to.eventually.be.rejectedWith(ConfigError)
);
});

4 changes: 2 additions & 2 deletions test/util/TestDebug.ts
Expand Up @@ -31,7 +31,7 @@ describe('state debug utils', () => {
},
};

const lines = await debugState(state);
const lines = debugState(state);
expect(lines).to.include('state: ');

for (const room of state.rooms) {
Expand Down Expand Up @@ -66,7 +66,7 @@ describe('state debug utils', () => {
},
};

const lines = await graphState(state);
const lines = graphState(state);
expect(lines).to.include('strict digraph {');

for (const room of state.rooms) {
Expand Down
188 changes: 188 additions & 0 deletions test/util/state/TestSearch.ts
@@ -0,0 +1,188 @@
import { expect } from 'chai';
import { ActorType, ACTOR_TYPE } from '../../../src/model/entity/Actor';

import { ITEM_TYPE } from '../../../src/model/entity/Item';
import { ROOM_TYPE } from '../../../src/model/entity/Room';
import { State } from '../../../src/model/State';
import { findContainer, findRoom, searchState } from '../../../src/util/state';

const TEST_STATE: State = {
focus: {
actor: '',
room: '',
},
meta: {
desc: '',
id: '',
name: '',
template: '',
},
rooms: [{
actors: [{
actorType: ActorType.DEFAULT,
items: [{
meta: {
desc: 'bon',
id: 'bon',
name: 'bon',
template: 'bon',
},
slots: new Map(),
stats: new Map(),
type: ITEM_TYPE,
verbs: new Map(),
}],
meta: {
desc: 'bun',
id: 'bun',
name: 'bun',
template: 'bun',
},
skills: new Map(),
slots: new Map(),
stats: new Map(),
type: ACTOR_TYPE,
}],
items: [],
meta: {
desc: 'foo',
id: 'foo',
name: 'foo',
template: 'foo',
},
portals: [],
slots: new Map(),
type: ROOM_TYPE,
verbs: new Map(),
}, {
actors: [],
items: [{
meta: {
desc: 'bin',
id: 'bin',
name: 'bin',
template: 'bin',
},
slots: new Map(),
stats: new Map(),
type: ITEM_TYPE,
verbs: new Map(),
}],
meta: {
desc: 'bar',
id: 'bar',
name: 'bar',
template: 'bar',
},
portals: [],
slots: new Map(),
type: ROOM_TYPE,
verbs: new Map(),
}],
start: {
actor: '',
room: '',
},
step: {
time: 0,
turn: 0,
},
world: {
depth: 0,
seed: '',
},
};

describe('state search utils', () => {
describe('search state helper', () => {
it('should return matching entities', async () => {
const results = searchState(TEST_STATE, {
meta: {
id: 'bar',
},
type: ROOM_TYPE,
});

expect(results).to.deep.equal([
TEST_STATE.rooms[1],
]);
});

it('should skip the contents of rooms that do not match the room filter', async () => {
const results = searchState(TEST_STATE, {
meta: {
id: 'bin',
},
room: {
id: 'foo',
},
type: ROOM_TYPE,
});

expect(results).to.deep.equal([]);
});

xit('should skip the inventory of actors that do not match the actor filter');
});

describe('find room helper', () => {
it('should return the room containing an actor', async () => {
const results = findRoom(TEST_STATE, {
meta: {
id: 'bun',
},
});
expect(results).to.deep.equal([
TEST_STATE.rooms[0],
]);
});

it('should return the room containing an item', async () => {
const results = findRoom(TEST_STATE, {
meta: {
id: 'bin',
},
});
expect(results).to.deep.equal([
TEST_STATE.rooms[1],
]);
});
});

describe('find container helper', () => {
it('should return the actor containing an item', async () => {
const results = findContainer(TEST_STATE, {
meta: {
id: 'bon',
},
});
expect(results).to.deep.equal([
TEST_STATE.rooms[0].actors[0],
]);
});

it('should return the room containing an actor', async () => {
const results = findContainer(TEST_STATE, {
meta: {
id: 'bun',
},
});
expect(results).to.deep.equal([
TEST_STATE.rooms[0],
]);
});

it('should return the room containing an item', async () => {
const results = findContainer(TEST_STATE, {
meta: {
id: 'bin',
},
});
expect(results).to.deep.equal([
TEST_STATE.rooms[1],
]);
});
});
});


0 comments on commit 7932e27

Please sign in to comment.