diff --git a/src/index.html b/src/index.html
index 1b8c633..e56f684 100644
--- a/src/index.html
+++ b/src/index.html
@@ -18,6 +18,10 @@
+
+
+
+
diff --git a/src/modules/configuration.js b/src/modules/configuration.js
index 406dc4d..2163e2f 100644
--- a/src/modules/configuration.js
+++ b/src/modules/configuration.js
@@ -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)
diff --git a/src/modules/knowledge.js b/src/modules/knowledge.js
new file mode 100644
index 0000000..6123506
--- /dev/null
+++ b/src/modules/knowledge.js
@@ -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
+`)
diff --git a/src/modules/shop.js b/src/modules/shop.js
index a761e5d..8b6fa9a 100644
--- a/src/modules/shop.js
+++ b/src/modules/shop.js
@@ -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, '', '']
- )
+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)
diff --git a/src/modules/utilities.js b/src/modules/utilities.js
index 2203003..d3fa400 100644
--- a/src/modules/utilities.js
+++ b/src/modules/utilities.js
@@ -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
}