Late night addition of semantic networks
This commit is contained in:
parent
da5bcc30c7
commit
7c7a055a4a
@ -18,6 +18,10 @@
|
||||
<script src="modules/agentController.js"></script>
|
||||
<script src="modules/agent.js"></script>
|
||||
<script src="modules/products.js"></script>
|
||||
<script src="modules/knowledge.js"></script>
|
||||
<script src="modules/configuration.js"></script>
|
||||
<script src="modules/utilities.js"></script>
|
||||
<script src="modules/shop.js"></script>
|
||||
|
||||
<!-- Main script file -->
|
||||
<script src="main.js"></script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
export const UnitsInGroupCount = 6
|
||||
export const RowsOfGroupsCount = 6
|
||||
export const ColumnsOfGroupsCount = 3
|
||||
export const StorageCenterLocation = { x: 7, y: 8, w: UnitsInGroupCount, h: 1 }
|
||||
const UnitsInGroupCount = 6
|
||||
const RowsOfGroupsCount = 6
|
||||
const ColumnsOfGroupsCount = 3
|
||||
const StorageCenterLocation = { x: 7, y: 8, w: UnitsInGroupCount, h: 1 }
|
||||
|
||||
export const UnitsCount = ((ColumnsOfGroupsCount * RowsOfGroupsCount) * UnitsInGroupCount
|
||||
const UnitsCount = ((ColumnsOfGroupsCount * RowsOfGroupsCount) * UnitsInGroupCount
|
||||
- StorageCenterLocation.w * StorageCenterLocation.h)
|
||||
|
106
src/modules/knowledge.js
Normal file
106
src/modules/knowledge.js
Normal file
@ -0,0 +1,106 @@
|
||||
function flattenToUnique(array, view = x => x) {
|
||||
return array.reduce((set, value) => {
|
||||
const v = view(value)
|
||||
console.log(v)
|
||||
v && v.forEach(cat => set.add(cat))
|
||||
return set
|
||||
}, new Set())
|
||||
}
|
||||
|
||||
class SemanticNetwork {
|
||||
/**
|
||||
* @param {string} definition
|
||||
*/
|
||||
constructor(definition) {
|
||||
/**
|
||||
* @param {string} stmt
|
||||
* @returns {[{ name: string; categories: string[]; locations: string[] }]}
|
||||
*/
|
||||
function parseStatement(stmt) {
|
||||
const [name, ...keywords] = stmt.split(':').map(x => x.trim())
|
||||
const o = { name }
|
||||
for (const keyword of keywords) {
|
||||
const command = keyword[0]
|
||||
const items = keyword.slice(1).split(',').map(x => x.trim()).filter(x => x.length > 0)
|
||||
switch (command) {
|
||||
case 'c': o.categories = items; break
|
||||
case 'p': o.locations = items; break
|
||||
}
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
this.data = definition.split('\n').filter(x => x.trim().length > 0)
|
||||
.map(parseStatement)
|
||||
}
|
||||
|
||||
getAllNames() {
|
||||
return this.data.map(({ name }) => name)
|
||||
}
|
||||
|
||||
getAllCategories() {
|
||||
return flattenToUnique(this.data, ({ categories }) => categories)
|
||||
}
|
||||
|
||||
getAllLocations() {
|
||||
return flattenToUnique(this.data, ({ locations }) => locations)
|
||||
}
|
||||
|
||||
findByName(nameToFind) {
|
||||
return this.data.find(({ name }) => name === nameToFind)
|
||||
}
|
||||
|
||||
findAllByCategory(categoryToFind) {
|
||||
return this.data.filter(({ categories }) => categories.indexOf(categoryToFind) >= 0)
|
||||
}
|
||||
|
||||
findAllByLocation(locationToFind) {
|
||||
return this.data.filter(({ locations }) => locations.indexOf(locationToFind) >= 0)
|
||||
}
|
||||
}
|
||||
|
||||
class AgentSemanticNetwork extends SemanticNetwork {}
|
||||
|
||||
class Arrangement {
|
||||
constructor() {
|
||||
this.products = [...Array(UnitsCount)].map(() => ({
|
||||
product: '',
|
||||
count: 0,
|
||||
icon: ''
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
class Knowledge {
|
||||
static semanticNetwork
|
||||
static agentSemanticNetwork
|
||||
static arrangement
|
||||
|
||||
constructor(definition) {
|
||||
Knowledge.fullSemanticNetwork = new SemanticNetwork(definition)
|
||||
Knowledge.agentSemanticNetwork = new AgentSemanticNetwork(definition)
|
||||
Knowledge.arrangement = new Arrangement()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
keywords:
|
||||
p - powiązane pomieszczenia / miejsca
|
||||
c - category
|
||||
*/
|
||||
new Knowledge(`
|
||||
Piłka :c sport,rozrywka, piłka nożna
|
||||
Kubek klubowy :c sport,rozrywka,piłka nożna :p kuchnia
|
||||
Waga łazienkowa :c zdrowie,agd,elektronika :p łazienka
|
||||
Czajnik elektryczny :c agd,elektronika,zdrowie :p kuchnia
|
||||
Widelec :c agd,jedzenie,zastawa kuchenna :p kuchnia
|
||||
Łyżka :c agd,jedzenie,zastawa kuchenna :p kuchnia
|
||||
Nóż stołowy :c agd,jedzenie,zastawa kuchenna :p kuchnia
|
||||
Nóż kuchenny :c agd,gotowanie,przyrząd kuchenny :p kuchnia
|
||||
Deska do krojenia :cagd,gotowanie,przyrząd kuchenny :p kuchnia
|
||||
Gąbki kuchenne :c agd,gotowanie,sprzątanie :p kuchnia
|
||||
Worki na śmieci :c agd,gotowanie,sprzątanie :p kuchnia
|
||||
Miska :c agd,jedzenie,gotowanie,zastawa kuchenna :p kuchnia
|
||||
Laptop :c elektronika,gaming :p biuro,szkoła
|
||||
Telefon :c elektronika :p biuro,szkoła
|
||||
`)
|
@ -1,22 +1,19 @@
|
||||
import { fromTable } from './utilities'
|
||||
import { RowsOfGroupsCount, StorageCenterLocation, UnitsCount } from './configuration'
|
||||
|
||||
/**
|
||||
* Zwraca koordynaty półek przy danym kafelku ścieżki
|
||||
* @param {number} gridX
|
||||
* @param {number} gridY
|
||||
* @returns {{x:number;y:number}[]} Koordynaty sąsiednich półek do kafelka
|
||||
*/
|
||||
export function nearbyStorageUnitsCoords(gridX, gridY) {
|
||||
function nearbyStorageUnitsCoords(gridX, gridY) {
|
||||
function outsideOfStorageCenter(v) {
|
||||
const { x, y, w, h } = StorageCenterLocation
|
||||
return v.x <= x || v.x >= x + w || v.y <= y || v.y >= y + h
|
||||
}
|
||||
return (gridX % UnitsInGroupCount == 0
|
||||
return (gridX % UnitsInGroupCount == 0
|
||||
? (gridY % 3 == 1
|
||||
? /* skrzyżowanie */ [[-1, -1], [-1, 1], [1, -1], [1,1]]
|
||||
: /* korytarz góra-dół */ [[-1, 0], [1, 0]])
|
||||
: /* korytarz lewo-prawo */ [[0, -1], [0, 1]])
|
||||
? /* skrzyżowanie */[[-1, -1], [-1, 1], [1, -1], [1, 1]]
|
||||
: /* korytarz góra-dół */[[-1, 0], [1, 0]])
|
||||
: /* korytarz lewo-prawo */[[0, -1], [0, 1]])
|
||||
.map(([xoff, yoff]) => ({ x: gridX + xoff, y: yGrid + yoff }))
|
||||
.filter(outsideOfStorageCenter)
|
||||
}
|
||||
@ -27,25 +24,19 @@ export function nearbyStorageUnitsCoords(gridX, gridY) {
|
||||
* @param {number} gridY
|
||||
* @returns {{x:number;y:number}[]} Indeksy sąsiednich półek do kafelka
|
||||
*/
|
||||
export function nearbyStorageUnitsIndexes(gridX, gridY) {
|
||||
function nearbyStorageUnitsIndexes(gridX, gridY) {
|
||||
return nearbyStorageUnitsCoords(gridX, gridY)
|
||||
.map(({ x, y }) => x * UnitsCount + y * UnitsCount * RowsOfGroupsCount)
|
||||
}
|
||||
|
||||
class Shop {
|
||||
constructor() {
|
||||
// pełna lista wszystkich możliwych produktów dostępnych w sklepie,
|
||||
// w formacie [{ name: '', category: '', ... }, { name: '', category: '', ...}, ...]
|
||||
// kolejność przedmiotów jest niezmienna, przez co można przechowywać ich indeksy zamiast referencji
|
||||
this.products = fromTable(
|
||||
['name', 'category', 'intrest', '', 'icon'],
|
||||
/* 0 */ ['Lodówka', 'AGD', 0.4, '', '<path-to-icon>']
|
||||
)
|
||||
function ensureArray(maybeArray) {
|
||||
return Array.isArray(maybeArray) ? maybeArray : []
|
||||
}
|
||||
|
||||
this.productPlacement = [...Array(UnitsCount)].map(_ => ({
|
||||
productId: null,
|
||||
count: 0,
|
||||
}))
|
||||
class Shop {
|
||||
constructor(semanticNetwork) {
|
||||
this.semanticNetwork = semanticNetwork
|
||||
this.products = [...Array(UnitsCount)].map(x => ({ name: '', count: 0 }))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,7 +48,24 @@ class Shop {
|
||||
return nearbyStorageUnitsIndexes(gridX, gridY)
|
||||
.map(i => this.productPlacement[i])
|
||||
}
|
||||
|
||||
productsSimilarityScore(name1, name2) {
|
||||
const [ o1, o2 ] = [name1, name2].map(name => this.semanticNetwork.findByName(name))
|
||||
if (!o1 || !o2)
|
||||
throw new Error("names should be in semantic network!")
|
||||
|
||||
function calcScore(p) {
|
||||
if (!o1[p] || !o2[p])
|
||||
return 0
|
||||
|
||||
const set = new Set([...o1[p], ...o2[p]])
|
||||
const matching = o1[p].reduce((s, v) => s + (o2[p].indexOf(v) >= 0 ? 1 : 0), 0)
|
||||
return matching / [...set].lengthsss
|
||||
}
|
||||
|
||||
const [ l, c ] = [calcScore('locations'), calcScore('categories')]
|
||||
return l <= Number.EPSILON ? c * 0.7 : l * 0.65 + c * 0.35 // TODO: maybe find better formula? needs testing
|
||||
}
|
||||
}
|
||||
|
||||
const shop = new Shop()
|
||||
export default shop
|
||||
const shop = new Shop(semanticNetwork)
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @param {...any[]} rows
|
||||
* @returns
|
||||
*/
|
||||
export function fromTable(header, ...rows) {
|
||||
function fromTable(header, ...rows) {
|
||||
function tupleToRecord(names, array) {
|
||||
return names.reduce((p, v, i) => ({ ...p, [v]: array[i] }), {})
|
||||
}
|
||||
@ -18,6 +18,6 @@ export function fromTable(header, ...rows) {
|
||||
* @param {number} lo Minimum return value
|
||||
* @param {number} hi Maximum return value
|
||||
* */
|
||||
export function clamp(v, lo, hi) {
|
||||
function clamp(v, lo, hi) {
|
||||
return v <= lo ? lo : v >= hi ? hi : v
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user