Merge branch 'main' of https://git.wmi.amu.edu.pl/s452639/psi
6
cozrobic.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
> tablica na ilość produktów
|
||||||
|
> znalezienie fontu z ikonami
|
||||||
|
> funkcja do wypełniania tej tablicy (usunąć losowanie wartości z drawProducts() )
|
||||||
|
> funckja do odbierania ilości produktów od robota
|
||||||
|
> funkcja do usuwania losowej ilości produktów
|
||||||
|
> funkcja do zamieniania miejscami produktów na półkach (5% szansy)
|
@ -9,3 +9,4 @@ const UnitsCount = ((ColumnsOfGroupsCount * RowsOfGroupsCount) * UnitsInGroupCou
|
|||||||
const AgentMoveSpeed = 60 /* 1 - slowest, 89 - fastest */
|
const AgentMoveSpeed = 60 /* 1 - slowest, 89 - fastest */
|
||||||
const AgentRotationSpeed = 60 /* 1 - slowest, 89 - fastest */
|
const AgentRotationSpeed = 60 /* 1 - slowest, 89 - fastest */
|
||||||
const AgentWaitTime = 500 /* in miliseconds */
|
const AgentWaitTime = 500 /* in miliseconds */
|
||||||
|
const AgentStartPosition = { x: 6, y: 0 }
|
||||||
|
BIN
src/cyfry/1.png
Normal file
After Width: | Height: | Size: 246 B |
BIN
src/cyfry/2.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
src/cyfry/3.png
Normal file
After Width: | Height: | Size: 577 B |
BIN
src/cyfry/4.png
Normal file
After Width: | Height: | Size: 455 B |
BIN
src/cyfry/5.png
Normal file
After Width: | Height: | Size: 367 B |
BIN
src/cyfry/6.png
Normal file
After Width: | Height: | Size: 346 B |
BIN
src/cyfry/7.png
Normal file
After Width: | Height: | Size: 337 B |
BIN
src/cyfry/8.png
Normal file
After Width: | Height: | Size: 619 B |
BIN
src/cyfry/9.png
Normal file
After Width: | Height: | Size: 541 B |
@ -17,6 +17,7 @@
|
|||||||
<!-- logic -->
|
<!-- logic -->
|
||||||
<script src="configuration.js"></script>
|
<script src="configuration.js"></script>
|
||||||
<script src="utilities.js"></script>
|
<script src="utilities.js"></script>
|
||||||
|
<script src="logic/heap.js"></script>
|
||||||
<script src="logic/product.js"></script>
|
<script src="logic/product.js"></script>
|
||||||
<script src="logic/knowledge.js"></script>
|
<script src="logic/knowledge.js"></script>
|
||||||
<script src="logic/time.js"></script>
|
<script src="logic/time.js"></script>
|
||||||
@ -26,6 +27,7 @@
|
|||||||
|
|
||||||
<script src="view/floor.js"></script>
|
<script src="view/floor.js"></script>
|
||||||
<script src="view/grid.js"></script>
|
<script src="view/grid.js"></script>
|
||||||
|
<script src="view/ordersView.js"></script>
|
||||||
<script src="logic/pathfinding.js"></script>
|
<script src="logic/pathfinding.js"></script>
|
||||||
<script src="view/timeController.js"></script>
|
<script src="view/timeController.js"></script>
|
||||||
<script src="view/agentController.js"></script>
|
<script src="view/agentController.js"></script>
|
||||||
@ -49,7 +51,9 @@
|
|||||||
<main>
|
<main>
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="header-line"></div>
|
<div class="header-line">
|
||||||
|
<button onClick="OrdersView.instance.openWindow()">Make order</button>
|
||||||
|
</div>
|
||||||
<img src="img/logo.png" alt="logo">
|
<img src="img/logo.png" alt="logo">
|
||||||
<div class="header-line">
|
<div class="header-line">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@ -301,5 +305,24 @@
|
|||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<div class="orders-window">
|
||||||
|
<div class="close" onClick="OrdersView.instance.closeWindow()"></div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="line">
|
||||||
|
<div class="canvases"></div>
|
||||||
|
<div class="incrementals">
|
||||||
|
<div class="add" onClick="OrdersView.instance.addCanvas()">+</div>
|
||||||
|
<div class="substract" onClick="OrdersView.instance.removeCanvas()">-</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="line gaps">
|
||||||
|
<div class="response">
|
||||||
|
<!-- PYTHON RESPONSE HERE -->
|
||||||
|
</div>
|
||||||
|
<button class="clear" onClick="OrdersView.instance.clear()">CLEAR</button>
|
||||||
|
<button class="order" onClick="OrdersView.instance.order()">ORDER</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -8,16 +8,21 @@ class Agent extends AgentController {
|
|||||||
Agent.instance = this;
|
Agent.instance = this;
|
||||||
|
|
||||||
const cycle = async () => {
|
const cycle = async () => {
|
||||||
const jobRequest = Products.instance.getJobRequest();
|
try {
|
||||||
if (jobRequest) {
|
const jobRequest = Products.instance.getJobRequest();
|
||||||
await this.takeFromStore(jobRequest.product, jobRequest.amount);
|
if (jobRequest) {
|
||||||
await this.deliver(jobRequest.x, jobRequest.y);
|
await this.takeFromStore(jobRequest.product, jobRequest.amount);
|
||||||
} else {
|
await this.deliver(jobRequest.x, jobRequest.y);
|
||||||
await waitFor(1000);
|
} else {
|
||||||
}
|
await waitFor(1000);
|
||||||
|
}
|
||||||
|
|
||||||
await waitFor(this.waitTime);
|
await waitFor(this.waitTime);
|
||||||
cycle();
|
|
||||||
|
cycle();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(() => cycle(), 2000);
|
setTimeout(() => cycle(), 2000);
|
||||||
@ -38,12 +43,16 @@ class Agent extends AgentController {
|
|||||||
* @param {number} y Współrzędna y
|
* @param {number} y Współrzędna y
|
||||||
*/
|
*/
|
||||||
async deliver(x, y) {
|
async deliver(x, y) {
|
||||||
await this.moveTo(x, y);
|
try {
|
||||||
await waitFor(this.waitTime);
|
await this.moveTo(x, y);
|
||||||
Products.instance.exchange(x, y, this.ownedProduct, 50);
|
await this.waitFor(this.waitTime);
|
||||||
|
Products.instance.exchange(x, y, this.ownedProduct, 50);
|
||||||
|
|
||||||
this.ownedProductAmount = 0;
|
this.ownedProductAmount = 0;
|
||||||
this.ownedProduct = null;
|
this.ownedProduct = null;
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,9 +60,34 @@ class Agent extends AgentController {
|
|||||||
* @param {*} product
|
* @param {*} product
|
||||||
*/
|
*/
|
||||||
async takeFromStore(product, amount) {
|
async takeFromStore(product, amount) {
|
||||||
await this.moveTo(9, 8);
|
try {
|
||||||
await waitFor(this.waitTime);
|
await this.moveTo(8, 8);
|
||||||
this.ownedProductAmount = amount;
|
await this.waitFor(this.waitTime);
|
||||||
this.ownedProduct = product;
|
this.ownedProductAmount = amount;
|
||||||
|
this.ownedProduct = product;
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deliverToOrders() {
|
||||||
|
try {
|
||||||
|
await this.moveTo(x, y);
|
||||||
|
await this.waitFor(this.waitTime);
|
||||||
|
|
||||||
|
this.ownedProductAmount = 0;
|
||||||
|
this.ownedProduct = null;
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel all agent actions, teleport to start position
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
this.cancelAllActions();
|
||||||
|
|
||||||
|
this.position = AgentStartPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
869
src/logic/heap.js
Normal file
@ -0,0 +1,869 @@
|
|||||||
|
/**
|
||||||
|
* Heap
|
||||||
|
* @type {Class}
|
||||||
|
*/
|
||||||
|
var Heap = /** @class */ (function () {
|
||||||
|
/**
|
||||||
|
* Heap instance constructor.
|
||||||
|
* @param {Function} compare Optional comparison function, defaults to Heap.minComparator<number>
|
||||||
|
*/
|
||||||
|
function Heap(compare) {
|
||||||
|
var _this = this;
|
||||||
|
if (compare === void 0) { compare = Heap.minComparator; }
|
||||||
|
this.compare = compare;
|
||||||
|
this.heapArray = [];
|
||||||
|
this._limit = 0;
|
||||||
|
/**
|
||||||
|
* Alias of add
|
||||||
|
*/
|
||||||
|
this.offer = this.add;
|
||||||
|
/**
|
||||||
|
* Alias of peek
|
||||||
|
*/
|
||||||
|
this.element = this.peek;
|
||||||
|
/**
|
||||||
|
* Alias of pop
|
||||||
|
*/
|
||||||
|
this.poll = this.pop;
|
||||||
|
/**
|
||||||
|
* Returns the inverse to the comparison function.
|
||||||
|
* @return {Function}
|
||||||
|
*/
|
||||||
|
this._invertedCompare = function (a, b) {
|
||||||
|
return -1 * _this.compare(a, b);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Static methods
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Gets children indices for given index.
|
||||||
|
* @param {Number} idx Parent index
|
||||||
|
* @return {Array(Number)} Array of children indices
|
||||||
|
*/
|
||||||
|
Heap.getChildrenIndexOf = function (idx) {
|
||||||
|
return [idx * 2 + 1, idx * 2 + 2];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Gets parent index for given index.
|
||||||
|
* @param {Number} idx Children index
|
||||||
|
* @return {Number | undefined} Parent index, -1 if idx is 0
|
||||||
|
*/
|
||||||
|
Heap.getParentIndexOf = function (idx) {
|
||||||
|
if (idx <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
var whichChildren = idx % 2 ? 1 : 2;
|
||||||
|
return Math.floor((idx - whichChildren) / 2);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Gets sibling index for given index.
|
||||||
|
* @param {Number} idx Children index
|
||||||
|
* @return {Number | undefined} Sibling index, -1 if idx is 0
|
||||||
|
*/
|
||||||
|
Heap.getSiblingIndexOf = function (idx) {
|
||||||
|
if (idx <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
var whichChildren = idx % 2 ? 1 : -1;
|
||||||
|
return idx + whichChildren;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Min heap comparison function, default.
|
||||||
|
* @param {any} a First element
|
||||||
|
* @param {any} b Second element
|
||||||
|
* @return {Number} 0 if they're equal, positive if `a` goes up, negative if `b` goes up
|
||||||
|
*/
|
||||||
|
Heap.minComparator = function (a, b) {
|
||||||
|
if (a > b) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (a < b) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Max heap comparison function.
|
||||||
|
* @param {any} a First element
|
||||||
|
* @param {any} b Second element
|
||||||
|
* @return {Number} 0 if they're equal, positive if `a` goes up, negative if `b` goes up
|
||||||
|
*/
|
||||||
|
Heap.maxComparator = function (a, b) {
|
||||||
|
if (b > a) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (b < a) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Min number heap comparison function, default.
|
||||||
|
* @param {Number} a First element
|
||||||
|
* @param {Number} b Second element
|
||||||
|
* @return {Number} 0 if they're equal, positive if `a` goes up, negative if `b` goes up
|
||||||
|
*/
|
||||||
|
Heap.minComparatorNumber = function (a, b) {
|
||||||
|
return a - b;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Max number heap comparison function.
|
||||||
|
* @param {Number} a First element
|
||||||
|
* @param {Number} b Second element
|
||||||
|
* @return {Number} 0 if they're equal, positive if `a` goes up, negative if `b` goes up
|
||||||
|
*/
|
||||||
|
Heap.maxComparatorNumber = function (a, b) {
|
||||||
|
return b - a;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Default equality function.
|
||||||
|
* @param {any} a First element
|
||||||
|
* @param {any} b Second element
|
||||||
|
* @return {Boolean} True if equal, false otherwise
|
||||||
|
*/
|
||||||
|
Heap.defaultIsEqual = function (a, b) {
|
||||||
|
return a === b;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Prints a heap.
|
||||||
|
* @param {Heap} heap Heap to be printed
|
||||||
|
* @returns {String}
|
||||||
|
*/
|
||||||
|
Heap.print = function (heap) {
|
||||||
|
function deep(i) {
|
||||||
|
var pi = Heap.getParentIndexOf(i);
|
||||||
|
return Math.floor(Math.log2(pi + 1));
|
||||||
|
}
|
||||||
|
function repeat(str, times) {
|
||||||
|
var out = '';
|
||||||
|
for (; times > 0; --times) {
|
||||||
|
out += str;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
var node = 0;
|
||||||
|
var lines = [];
|
||||||
|
var maxLines = deep(heap.length - 1) + 2;
|
||||||
|
var maxLength = 0;
|
||||||
|
while (node < heap.length) {
|
||||||
|
var i = deep(node) + 1;
|
||||||
|
if (node === 0) {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
// Text representation
|
||||||
|
var nodeText = String(heap.get(node));
|
||||||
|
if (nodeText.length > maxLength) {
|
||||||
|
maxLength = nodeText.length;
|
||||||
|
}
|
||||||
|
// Add to line
|
||||||
|
lines[i] = lines[i] || [];
|
||||||
|
lines[i].push(nodeText);
|
||||||
|
node += 1;
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
.map(function (line, i) {
|
||||||
|
var times = Math.pow(2, maxLines - i) - 1;
|
||||||
|
return (repeat(' ', Math.floor(times / 2) * maxLength) +
|
||||||
|
line
|
||||||
|
.map(function (el) {
|
||||||
|
// centered
|
||||||
|
var half = (maxLength - el.length) / 2;
|
||||||
|
return repeat(' ', Math.ceil(half)) + el + repeat(' ', Math.floor(half));
|
||||||
|
})
|
||||||
|
.join(repeat(' ', times * maxLength)));
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
Python style
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Converts an array into an array-heap, in place
|
||||||
|
* @param {Array} arr Array to be modified
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
* @return {Heap} For convenience, it returns a Heap instance
|
||||||
|
*/
|
||||||
|
Heap.heapify = function (arr, compare) {
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = arr;
|
||||||
|
heap.init();
|
||||||
|
return heap;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Extract the peek of an array-heap
|
||||||
|
* @param {Array} heapArr Array to be modified, should be a heap
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
* @return {any} Returns the extracted peek
|
||||||
|
*/
|
||||||
|
Heap.heappop = function (heapArr, compare) {
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = heapArr;
|
||||||
|
return heap.pop();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Pushes a item into an array-heap
|
||||||
|
* @param {Array} heapArr Array to be modified, should be a heap
|
||||||
|
* @param {any} item Item to push
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
*/
|
||||||
|
Heap.heappush = function (heapArr, item, compare) {
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = heapArr;
|
||||||
|
heap.push(item);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Push followed by pop, faster
|
||||||
|
* @param {Array} heapArr Array to be modified, should be a heap
|
||||||
|
* @param {any} item Item to push
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
* @return {any} Returns the extracted peek
|
||||||
|
*/
|
||||||
|
Heap.heappushpop = function (heapArr, item, compare) {
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = heapArr;
|
||||||
|
return heap.pushpop(item);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Replace peek with item
|
||||||
|
* @param {Array} heapArr Array to be modified, should be a heap
|
||||||
|
* @param {any} item Item as replacement
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
* @return {any} Returns the extracted peek
|
||||||
|
*/
|
||||||
|
Heap.heapreplace = function (heapArr, item, compare) {
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = heapArr;
|
||||||
|
return heap.replace(item);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the `n` most valuable elements of a heap-like Array
|
||||||
|
* @param {Array} heapArr Array, should be an array-heap
|
||||||
|
* @param {number} n Max number of elements
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
* @return {any} Elements
|
||||||
|
*/
|
||||||
|
Heap.heaptop = function (heapArr, n, compare) {
|
||||||
|
if (n === void 0) { n = 1; }
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = heapArr;
|
||||||
|
return heap.top(n);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the `n` least valuable elements of a heap-like Array
|
||||||
|
* @param {Array} heapArr Array, should be an array-heap
|
||||||
|
* @param {number} n Max number of elements
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
* @return {any} Elements
|
||||||
|
*/
|
||||||
|
Heap.heapbottom = function (heapArr, n, compare) {
|
||||||
|
if (n === void 0) { n = 1; }
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = heapArr;
|
||||||
|
return heap.bottom(n);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the `n` most valuable elements of an iterable
|
||||||
|
* @param {number} n Max number of elements
|
||||||
|
* @param {Iterable} Iterable Iterable list of elements
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
* @return {any} Elements
|
||||||
|
*/
|
||||||
|
Heap.nlargest = function (n, iterable, compare) {
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = __spreadArrays(iterable);
|
||||||
|
heap.init();
|
||||||
|
return heap.top(n);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the `n` least valuable elements of an iterable
|
||||||
|
* @param {number} n Max number of elements
|
||||||
|
* @param {Iterable} Iterable Iterable list of elements
|
||||||
|
* @param {Function} compare Optional compare function
|
||||||
|
* @return {any} Elements
|
||||||
|
*/
|
||||||
|
Heap.nsmallest = function (n, iterable, compare) {
|
||||||
|
var heap = new Heap(compare);
|
||||||
|
heap.heapArray = __spreadArrays(iterable);
|
||||||
|
heap.init();
|
||||||
|
return heap.bottom(n);
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
Instance methods
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Adds an element to the heap. Aliases: `offer`.
|
||||||
|
* Same as: push(element)
|
||||||
|
* @param {any} element Element to be added
|
||||||
|
* @return {Boolean} true
|
||||||
|
*/
|
||||||
|
Heap.prototype.add = function (element) {
|
||||||
|
this._sortNodeUp(this.heapArray.push(element) - 1);
|
||||||
|
this._applyLimit();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Adds an array of elements to the heap.
|
||||||
|
* Similar as: push(element, element, ...).
|
||||||
|
* @param {Array} elements Elements to be added
|
||||||
|
* @return {Boolean} true
|
||||||
|
*/
|
||||||
|
Heap.prototype.addAll = function (elements) {
|
||||||
|
var _a;
|
||||||
|
var i = this.length;
|
||||||
|
(_a = this.heapArray).push.apply(_a, elements);
|
||||||
|
for (var l = this.length; i < l; ++i) {
|
||||||
|
this._sortNodeUp(i);
|
||||||
|
}
|
||||||
|
this._applyLimit();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the bottom (lowest value) N elements of the heap.
|
||||||
|
*
|
||||||
|
* @param {Number} n Number of elements.
|
||||||
|
* @return {Array} Array of length <= N.
|
||||||
|
*/
|
||||||
|
Heap.prototype.bottom = function (n) {
|
||||||
|
if (n === void 0) { n = 1; }
|
||||||
|
if (this.heapArray.length === 0 || n <= 0) {
|
||||||
|
// Nothing to do
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
else if (this.heapArray.length === 1) {
|
||||||
|
// Just the peek
|
||||||
|
return [this.heapArray[0]];
|
||||||
|
}
|
||||||
|
else if (n >= this.heapArray.length) {
|
||||||
|
// The whole heap
|
||||||
|
return __spreadArrays(this.heapArray);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Some elements
|
||||||
|
var result = this._bottomN_push(~~n);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Check if the heap is sorted, useful for testing purposes.
|
||||||
|
* @return {Undefined | Element} Returns an element if something wrong is found, otherwise it's undefined
|
||||||
|
*/
|
||||||
|
Heap.prototype.check = function () {
|
||||||
|
var _this = this;
|
||||||
|
return this.heapArray.find(function (el, j) { return !!_this.getChildrenOf(j).find(function (ch) { return _this.compare(el, ch) > 0; }); });
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Remove all of the elements from this heap.
|
||||||
|
*/
|
||||||
|
Heap.prototype.clear = function () {
|
||||||
|
this.heapArray = [];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Clone this heap
|
||||||
|
* @return {Heap}
|
||||||
|
*/
|
||||||
|
Heap.prototype.clone = function () {
|
||||||
|
var cloned = new Heap(this.comparator());
|
||||||
|
cloned.heapArray = this.toArray();
|
||||||
|
cloned._limit = this._limit;
|
||||||
|
return cloned;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Returns the comparison function.
|
||||||
|
* @return {Function}
|
||||||
|
*/
|
||||||
|
Heap.prototype.comparator = function () {
|
||||||
|
return this.compare;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Returns true if this queue contains the specified element.
|
||||||
|
* @param {any} o Element to be found
|
||||||
|
* @param {Function} fn Optional comparison function, receives (element, needle)
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
Heap.prototype.contains = function (o, fn) {
|
||||||
|
if (fn === void 0) { fn = Heap.defaultIsEqual; }
|
||||||
|
return this.heapArray.findIndex(function (el) { return fn(el, o); }) >= 0;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Initialise a heap, sorting nodes
|
||||||
|
* @param {Array} array Optional initial state array
|
||||||
|
*/
|
||||||
|
Heap.prototype.init = function (array) {
|
||||||
|
if (array) {
|
||||||
|
this.heapArray = __spreadArrays(array);
|
||||||
|
}
|
||||||
|
for (var i = Math.floor(this.heapArray.length); i >= 0; --i) {
|
||||||
|
this._sortNodeDown(i);
|
||||||
|
}
|
||||||
|
this._applyLimit();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Test if the heap has no elements.
|
||||||
|
* @return {Boolean} True if no elements on the heap
|
||||||
|
*/
|
||||||
|
Heap.prototype.isEmpty = function () {
|
||||||
|
return this.length === 0;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Get the leafs of the tree (no children nodes)
|
||||||
|
*/
|
||||||
|
Heap.prototype.leafs = function () {
|
||||||
|
if (this.heapArray.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
var pi = Heap.getParentIndexOf(this.heapArray.length - 1);
|
||||||
|
return this.heapArray.slice(pi + 1);
|
||||||
|
};
|
||||||
|
Object.defineProperty(Heap.prototype, "length", {
|
||||||
|
/**
|
||||||
|
* Length of the heap.
|
||||||
|
* @return {Number}
|
||||||
|
*/
|
||||||
|
get: function () {
|
||||||
|
return this.heapArray.length;
|
||||||
|
},
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
Object.defineProperty(Heap.prototype, "limit", {
|
||||||
|
/**
|
||||||
|
* Get length limit of the heap.
|
||||||
|
* @return {Number}
|
||||||
|
*/
|
||||||
|
get: function () {
|
||||||
|
return this._limit;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Set length limit of the heap.
|
||||||
|
* @return {Number}
|
||||||
|
*/
|
||||||
|
set: function (_l) {
|
||||||
|
this._limit = ~~_l;
|
||||||
|
this._applyLimit();
|
||||||
|
},
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Top node. Aliases: `element`.
|
||||||
|
* Same as: `top(1)[0]`
|
||||||
|
* @return {any} Top node
|
||||||
|
*/
|
||||||
|
Heap.prototype.peek = function () {
|
||||||
|
return this.heapArray[0];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Extract the top node (root). Aliases: `poll`.
|
||||||
|
* @return {any} Extracted top node, undefined if empty
|
||||||
|
*/
|
||||||
|
Heap.prototype.pop = function () {
|
||||||
|
var last = this.heapArray.pop();
|
||||||
|
if (this.length > 0 && last !== undefined) {
|
||||||
|
return this.replace(last);
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Pushes element(s) to the heap.
|
||||||
|
* @param {...any} elements Elements to insert
|
||||||
|
* @return {Boolean} True if elements are present
|
||||||
|
*/
|
||||||
|
Heap.prototype.push = function () {
|
||||||
|
var elements = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
elements[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
if (elements.length < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (elements.length === 1) {
|
||||||
|
return this.add(elements[0]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return this.addAll(elements);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Same as push & pop in sequence, but faster
|
||||||
|
* @param {any} element Element to insert
|
||||||
|
* @return {any} Extracted top node
|
||||||
|
*/
|
||||||
|
Heap.prototype.pushpop = function (element) {
|
||||||
|
var _a;
|
||||||
|
if (this.compare(this.heapArray[0], element) < 0) {
|
||||||
|
_a = [this.heapArray[0], element], element = _a[0], this.heapArray[0] = _a[1];
|
||||||
|
this._sortNodeDown(0);
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Remove an element from the heap.
|
||||||
|
* @param {any} o Element to be found
|
||||||
|
* @param {Function} fn Optional function to compare
|
||||||
|
* @return {Boolean} True if the heap was modified
|
||||||
|
*/
|
||||||
|
Heap.prototype.remove = function (o, fn) {
|
||||||
|
if (fn === void 0) { fn = Heap.defaultIsEqual; }
|
||||||
|
if (this.length > 0) {
|
||||||
|
if (o === undefined) {
|
||||||
|
this.pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var idx = this.heapArray.findIndex(function (el) { return fn(el, o); });
|
||||||
|
if (idx >= 0) {
|
||||||
|
if (idx === 0) {
|
||||||
|
this.pop();
|
||||||
|
}
|
||||||
|
else if (idx === this.length - 1) {
|
||||||
|
this.heapArray.pop();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.heapArray.splice(idx, 1, this.heapArray.pop());
|
||||||
|
this._sortNodeUp(idx);
|
||||||
|
this._sortNodeDown(idx);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Pop the current peek value, and add the new item.
|
||||||
|
* @param {any} element Element to replace peek
|
||||||
|
* @return {any} Old peek
|
||||||
|
*/
|
||||||
|
Heap.prototype.replace = function (element) {
|
||||||
|
var peek = this.heapArray[0];
|
||||||
|
this.heapArray[0] = element;
|
||||||
|
this._sortNodeDown(0);
|
||||||
|
return peek;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Size of the heap
|
||||||
|
* @return {Number}
|
||||||
|
*/
|
||||||
|
Heap.prototype.size = function () {
|
||||||
|
return this.length;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the top (highest value) N elements of the heap.
|
||||||
|
*
|
||||||
|
* @param {Number} n Number of elements.
|
||||||
|
* @return {Array} Array of length <= N.
|
||||||
|
*/
|
||||||
|
Heap.prototype.top = function (n) {
|
||||||
|
if (n === void 0) { n = 1; }
|
||||||
|
if (this.heapArray.length === 0 || n <= 0) {
|
||||||
|
// Nothing to do
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
else if (this.heapArray.length === 1 || n === 1) {
|
||||||
|
// Just the peek
|
||||||
|
return [this.heapArray[0]];
|
||||||
|
}
|
||||||
|
else if (n >= this.heapArray.length) {
|
||||||
|
// The whole peek
|
||||||
|
return __spreadArrays(this.heapArray);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Some elements
|
||||||
|
var result = this._topN_push(~~n);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Clone the heap's internal array
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
Heap.prototype.toArray = function () {
|
||||||
|
return __spreadArrays(this.heapArray);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* String output, call to Array.prototype.toString()
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
Heap.prototype.toString = function () {
|
||||||
|
return this.heapArray.toString();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Get the element at the given index.
|
||||||
|
* @param {Number} i Index to get
|
||||||
|
* @return {any} Element at that index
|
||||||
|
*/
|
||||||
|
Heap.prototype.get = function (i) {
|
||||||
|
return this.heapArray[i];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Get the elements of these node's children
|
||||||
|
* @param {Number} idx Node index
|
||||||
|
* @return {Array(any)} Children elements
|
||||||
|
*/
|
||||||
|
Heap.prototype.getChildrenOf = function (idx) {
|
||||||
|
var _this = this;
|
||||||
|
return Heap.getChildrenIndexOf(idx)
|
||||||
|
.map(function (i) { return _this.heapArray[i]; })
|
||||||
|
.filter(function (e) { return e !== undefined; });
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Get the element of this node's parent
|
||||||
|
* @param {Number} idx Node index
|
||||||
|
* @return {any} Parent element
|
||||||
|
*/
|
||||||
|
Heap.prototype.getParentOf = function (idx) {
|
||||||
|
var pi = Heap.getParentIndexOf(idx);
|
||||||
|
return this.heapArray[pi];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Iterator interface
|
||||||
|
*/
|
||||||
|
Heap.prototype[Symbol.iterator] = function () {
|
||||||
|
return __generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0:
|
||||||
|
if (!this.length) return [3 /*break*/, 2];
|
||||||
|
return [4 /*yield*/, this.pop()];
|
||||||
|
case 1:
|
||||||
|
_a.sent();
|
||||||
|
return [3 /*break*/, 0];
|
||||||
|
case 2: return [2 /*return*/];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Returns an iterator. To comply with Java interface.
|
||||||
|
*/
|
||||||
|
Heap.prototype.iterator = function () {
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Limit heap size if needed
|
||||||
|
*/
|
||||||
|
Heap.prototype._applyLimit = function () {
|
||||||
|
if (this._limit && this._limit < this.heapArray.length) {
|
||||||
|
var rm = this.heapArray.length - this._limit;
|
||||||
|
// It's much faster than splice
|
||||||
|
while (rm) {
|
||||||
|
this.heapArray.pop();
|
||||||
|
--rm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the bottom (lowest value) N elements of the heap, without corner cases, unsorted
|
||||||
|
*
|
||||||
|
* @param {Number} n Number of elements.
|
||||||
|
* @return {Array} Array of length <= N.
|
||||||
|
*/
|
||||||
|
Heap.prototype._bottomN_push = function (n) {
|
||||||
|
// Use an inverted heap
|
||||||
|
var bottomHeap = new Heap(this.compare);
|
||||||
|
bottomHeap.limit = n;
|
||||||
|
bottomHeap.heapArray = this.heapArray.slice(-n);
|
||||||
|
bottomHeap.init();
|
||||||
|
var startAt = this.heapArray.length - 1 - n;
|
||||||
|
var parentStartAt = Heap.getParentIndexOf(startAt);
|
||||||
|
var indices = [];
|
||||||
|
for (var i = startAt; i > parentStartAt; --i) {
|
||||||
|
indices.push(i);
|
||||||
|
}
|
||||||
|
var arr = this.heapArray;
|
||||||
|
while (indices.length) {
|
||||||
|
var i = indices.shift();
|
||||||
|
if (this.compare(arr[i], bottomHeap.peek()) > 0) {
|
||||||
|
bottomHeap.replace(arr[i]);
|
||||||
|
if (i % 2) {
|
||||||
|
indices.push(Heap.getParentIndexOf(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bottomHeap.toArray();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Move a node to a new index, switching places
|
||||||
|
* @param {Number} j First node index
|
||||||
|
* @param {Number} k Another node index
|
||||||
|
*/
|
||||||
|
Heap.prototype._moveNode = function (j, k) {
|
||||||
|
var _a;
|
||||||
|
_a = [this.heapArray[k], this.heapArray[j]], this.heapArray[j] = _a[0], this.heapArray[k] = _a[1];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Move a node down the tree (to the leaves) to find a place where the heap is sorted.
|
||||||
|
* @param {Number} i Index of the node
|
||||||
|
*/
|
||||||
|
Heap.prototype._sortNodeDown = function (i) {
|
||||||
|
var _this = this;
|
||||||
|
var moveIt = i < this.heapArray.length - 1;
|
||||||
|
var self = this.heapArray[i];
|
||||||
|
var getPotentialParent = function (best, j) {
|
||||||
|
if (_this.heapArray.length > j && _this.compare(_this.heapArray[j], _this.heapArray[best]) < 0) {
|
||||||
|
best = j;
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
};
|
||||||
|
while (moveIt) {
|
||||||
|
var childrenIdx = Heap.getChildrenIndexOf(i);
|
||||||
|
var bestChildIndex = childrenIdx.reduce(getPotentialParent, childrenIdx[0]);
|
||||||
|
var bestChild = this.heapArray[bestChildIndex];
|
||||||
|
if (typeof bestChild !== 'undefined' && this.compare(self, bestChild) > 0) {
|
||||||
|
this._moveNode(i, bestChildIndex);
|
||||||
|
i = bestChildIndex;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
moveIt = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Move a node up the tree (to the root) to find a place where the heap is sorted.
|
||||||
|
* @param {Number} i Index of the node
|
||||||
|
*/
|
||||||
|
Heap.prototype._sortNodeUp = function (i) {
|
||||||
|
var moveIt = i > 0;
|
||||||
|
while (moveIt) {
|
||||||
|
var pi = Heap.getParentIndexOf(i);
|
||||||
|
if (pi >= 0 && this.compare(this.heapArray[pi], this.heapArray[i]) > 0) {
|
||||||
|
this._moveNode(i, pi);
|
||||||
|
i = pi;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
moveIt = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the top (highest value) N elements of the heap, without corner cases, unsorted
|
||||||
|
* Implementation: push.
|
||||||
|
*
|
||||||
|
* @param {Number} n Number of elements.
|
||||||
|
* @return {Array} Array of length <= N.
|
||||||
|
*/
|
||||||
|
Heap.prototype._topN_push = function (n) {
|
||||||
|
// Use an inverted heap
|
||||||
|
var topHeap = new Heap(this._invertedCompare);
|
||||||
|
topHeap.limit = n;
|
||||||
|
var indices = [0];
|
||||||
|
var arr = this.heapArray;
|
||||||
|
while (indices.length) {
|
||||||
|
var i = indices.shift();
|
||||||
|
if (i < arr.length) {
|
||||||
|
if (topHeap.length < n) {
|
||||||
|
topHeap.push(arr[i]);
|
||||||
|
indices.push.apply(indices, Heap.getChildrenIndexOf(i));
|
||||||
|
}
|
||||||
|
else if (this.compare(arr[i], topHeap.peek()) < 0) {
|
||||||
|
topHeap.replace(arr[i]);
|
||||||
|
indices.push.apply(indices, Heap.getChildrenIndexOf(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return topHeap.toArray();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the top (highest value) N elements of the heap, without corner cases, unsorted
|
||||||
|
* Implementation: init + push.
|
||||||
|
*
|
||||||
|
* @param {Number} n Number of elements.
|
||||||
|
* @return {Array} Array of length <= N.
|
||||||
|
*/
|
||||||
|
Heap.prototype._topN_fill = function (n) {
|
||||||
|
// Use an inverted heap
|
||||||
|
var heapArray = this.heapArray;
|
||||||
|
var topHeap = new Heap(this._invertedCompare);
|
||||||
|
topHeap.limit = n;
|
||||||
|
topHeap.heapArray = heapArray.slice(0, n);
|
||||||
|
topHeap.init();
|
||||||
|
var branch = Heap.getParentIndexOf(n - 1) + 1;
|
||||||
|
var indices = [];
|
||||||
|
for (var i = branch; i < n; ++i) {
|
||||||
|
indices.push.apply(indices, Heap.getChildrenIndexOf(i).filter(function (l) { return l < heapArray.length; }));
|
||||||
|
}
|
||||||
|
if ((n - 1) % 2) {
|
||||||
|
indices.push(n);
|
||||||
|
}
|
||||||
|
while (indices.length) {
|
||||||
|
var i = indices.shift();
|
||||||
|
if (i < heapArray.length) {
|
||||||
|
if (this.compare(heapArray[i], topHeap.peek()) < 0) {
|
||||||
|
topHeap.replace(heapArray[i]);
|
||||||
|
indices.push.apply(indices, Heap.getChildrenIndexOf(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return topHeap.toArray();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the top (highest value) N elements of the heap, without corner cases, unsorted
|
||||||
|
* Implementation: heap.
|
||||||
|
*
|
||||||
|
* @param {Number} n Number of elements.
|
||||||
|
* @return {Array} Array of length <= N.
|
||||||
|
*/
|
||||||
|
Heap.prototype._topN_heap = function (n) {
|
||||||
|
var topHeap = this.clone();
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < n; ++i) {
|
||||||
|
result.push(topHeap.pop());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return index of the top element
|
||||||
|
* @param list
|
||||||
|
*/
|
||||||
|
Heap.prototype._topIdxOf = function (list) {
|
||||||
|
if (!list.length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
var idx = 0;
|
||||||
|
var top = list[idx];
|
||||||
|
for (var i = 1; i < list.length; ++i) {
|
||||||
|
var comp = this.compare(list[i], top);
|
||||||
|
if (comp < 0) {
|
||||||
|
idx = i;
|
||||||
|
top = list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Return the top element
|
||||||
|
* @param list
|
||||||
|
*/
|
||||||
|
Heap.prototype._topOf = function () {
|
||||||
|
var list = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
list[_i] = arguments[_i];
|
||||||
|
}
|
||||||
|
var heap = new Heap(this.compare);
|
||||||
|
heap.init(list);
|
||||||
|
return heap.peek();
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Swap identical elements compared by comparator function
|
||||||
|
*/
|
||||||
|
Heap.prototype.swap = function(el, cmp) {
|
||||||
|
if (!cmp) {
|
||||||
|
cmp = Heap.defaultIsEqual;
|
||||||
|
}
|
||||||
|
this.remove(el, cmp);
|
||||||
|
this.push(el);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Find element in heap
|
||||||
|
*/
|
||||||
|
Heap.prototype.getElement = function(o, cmp) {
|
||||||
|
if (!cmp) {
|
||||||
|
cmp = Heap.defaultIsEqual;
|
||||||
|
}
|
||||||
|
return this.heapArray.find(function (el) { return cmp(el, o); });
|
||||||
|
};
|
||||||
|
return Heap;
|
||||||
|
}());
|
@ -10,13 +10,16 @@
|
|||||||
|
|
||||||
const PATHFINDING_ACTION = Enum('ROTATE', 'MOVE')
|
const PATHFINDING_ACTION = Enum('ROTATE', 'MOVE')
|
||||||
|
|
||||||
|
|
||||||
class Pathfinding {
|
class Pathfinding {
|
||||||
static search(state, expectedState) {
|
static search(state, expectedState) {
|
||||||
return Pathfinding.graphSearch({ state }, { state: expectedState })
|
return Pathfinding.graphSearch({ state }, { state: expectedState })
|
||||||
}
|
}
|
||||||
|
|
||||||
static graphSearch(node, expectedNode, fringe = [], explored = []) {
|
static priorityComparator(a, b) {
|
||||||
|
return a.totalCost - b.totalCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
static graphSearch(node, expectedNode, fringe = new Heap(Pathfinding.priorityComparator), explored = []) {
|
||||||
fringe.push(node);
|
fringe.push(node);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
@ -24,44 +27,47 @@ class Pathfinding {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const elem = fringe.shift();
|
const elem = fringe.pop();
|
||||||
|
|
||||||
if (Pathfinding.reached(elem.state, expectedNode.state)) {
|
if (Pathfinding.isEqual(elem.state, expectedNode.state)) {
|
||||||
return Pathfinding.buildPath(node, elem);
|
return Pathfinding.buildPath(node, elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
explored.push(elem);
|
explored.push(elem);
|
||||||
|
|
||||||
for (const successor of this.successor(elem)) {
|
for (const successor of this.successor(elem)) {
|
||||||
if (!Pathfinding.isNodeInArr(successor, explored) && !Pathfinding.isNodeInArr(successor, fringe)) {
|
const isExplored = Pathfinding.isNodeInArr(successor, explored);
|
||||||
Pathfinding.insertWithPriority(successor, fringe);
|
const elementFromFringe = fringe.getElement(successor, Pathfinding.isNodesEqual);
|
||||||
} else if (Pathfinding.isNodeInArr(successor, fringe)) {
|
const isInFringe = !(elementFromFringe === undefined);
|
||||||
const index = Pathfinding.findIndexOf(successor, fringe);
|
|
||||||
if (successor.totalCost < fringe[index].totalCost) {
|
if (!isExplored && !isInFringe) {
|
||||||
fringe.splice(index, 1, successor);
|
fringe.push(successor);
|
||||||
}
|
} else if (isInFringe && elementFromFringe.totalCost > successor.totalCost) {
|
||||||
|
fringe.swap(successor, Pathfinding.isNodesEqual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debugger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static isNodeInArr(node, arr) {
|
static isNodeInArr(node, arr) {
|
||||||
return !arr.every(n => !Pathfinding.reached(n.state, node.state))
|
return !arr.every(n => !Pathfinding.isEqual(n.state, node.state))
|
||||||
}
|
}
|
||||||
|
|
||||||
static findIndexOf(node, arr) {
|
// static findIndexOf(node, arr) {
|
||||||
return arr.findIndex(n => Pathfinding.reached(n.state, node.state));
|
// return arr.findIndex(n => Pathfinding.isEqual(n.state, node.state));
|
||||||
}
|
// }
|
||||||
|
|
||||||
static insertWithPriority(node, arr) {
|
// static insertWithPriority(node, arr) {
|
||||||
for (const [i, n] of arr.entries()) {
|
// for (const [i, n] of arr.entries()) {
|
||||||
if (node.totalCost < n.totalCost) {
|
// if (node.totalCost < n.totalCost) {
|
||||||
arr.splice(i, 0, node);
|
// arr.splice(i, 0, node);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
arr.push(node);
|
// arr.push(node);
|
||||||
}
|
// }
|
||||||
|
|
||||||
static successor(node) {
|
static successor(node) {
|
||||||
const list = [];
|
const list = [];
|
||||||
@ -105,7 +111,7 @@ class Pathfinding {
|
|||||||
const result = [];
|
const result = [];
|
||||||
let currentElement = expectedNode;
|
let currentElement = expectedNode;
|
||||||
|
|
||||||
while(!Pathfinding.reached(currentElement.state, node.state)) {
|
while(!Pathfinding.isEqual(currentElement.state, node.state)) {
|
||||||
result.unshift(currentElement);
|
result.unshift(currentElement);
|
||||||
currentElement = currentElement.parent;
|
currentElement = currentElement.parent;
|
||||||
}
|
}
|
||||||
@ -113,12 +119,16 @@ class Pathfinding {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getManhattanDistance(node, expectedNode) {
|
// static getManhattanDistance(node, expectedNode) {
|
||||||
return Math.abs(node.state.position.x - expectedNode.state.position.x) + Math.abs(node.state.position.y - expectedNode.state.position.y);
|
// return Math.abs(node.state.position.x - expectedNode.state.position.x) + Math.abs(node.state.position.y - expectedNode.state.position.y);
|
||||||
|
// }
|
||||||
|
|
||||||
|
static isEqual(state, expectedState) {
|
||||||
|
return state.rotation == expectedState.rotation && state.position.x == expectedState.position.x && state.position.y == expectedState.position.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
static reached(state, expectedState) {
|
static isNodesEqual(node, expectedNode) {
|
||||||
return state.rotation == expectedState.rotation && state.position.x == expectedState.position.x && state.position.y == expectedState.position.y;
|
return Pathfinding.isEqual(node.state, expectedNode.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getVectorFromRotation(rotation) {
|
static getVectorFromRotation(rotation) {
|
||||||
|
@ -23,4 +23,134 @@ class Product {
|
|||||||
equals(other) {
|
equals(other) {
|
||||||
return this.name === other.name;
|
return this.name === other.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get REGISTRY() {
|
||||||
|
// in alphabetical order
|
||||||
|
//baby, camp, cat, car, cleaning, cloathes, cocktail, dog, electronic, glas, haunting
|
||||||
|
//kitchen, moving, newborn, swimming, winter, toilet, religion, party
|
||||||
|
//40
|
||||||
|
return {
|
||||||
|
empty: new Product('', ''),
|
||||||
|
airFrashener: new Product('airFrashener', 'fa-wind'),
|
||||||
|
apple: new Product('apple', 'fa-apple-alt'),
|
||||||
|
babyAccessories: new Product('babyAccessories','fa-baby-carriage'),
|
||||||
|
bacon: new Product('bacon', 'fa-bacon'),
|
||||||
|
bandAid: new Product('bandAid', 'fa-band-aid'),
|
||||||
|
basketballBall: new Product('basketballBall', 'fa-basketball-ball'),
|
||||||
|
beer: new Product('beer','fa-beer'),
|
||||||
|
bell: new Product('bell','fa-bell'),
|
||||||
|
bicycle: new Product('bicycle','fa-bicycle'),
|
||||||
|
bone: new Product('bone', 'fa-bone'),
|
||||||
|
book: new Product('book', 'fa-book'),
|
||||||
|
bread: new Product('bread', 'fa-bread-slice'),
|
||||||
|
cake: new Product('cake', 'fa-birthday-cake'),
|
||||||
|
calculator: new Product('calculator', 'fa-calculator'),
|
||||||
|
calendar: new Product('calendar', 'fa-calendar'),
|
||||||
|
camera: new Product('camera','fa-camera'),
|
||||||
|
campAccessories: new Product('campAccessories','fa-campground'),
|
||||||
|
candyCane: new Product('candyCane', 'fa-candy-cane'),
|
||||||
|
carrot: new Product('carrot', 'fa-carrot'),
|
||||||
|
catAccessories: new Product('catAccessories','fa-cat'),
|
||||||
|
carAccessories: new Product('carAccessories','fa-car'),
|
||||||
|
cigarettes: new Product('cigarettes', 'fa-smoking'),
|
||||||
|
chair: new Product('chair', 'fa-chair'),
|
||||||
|
charger: new Product('charger', 'fa-battery-half'),
|
||||||
|
cheese: new Product('cheese', 'fa-cheese'),
|
||||||
|
chess: new Product('chess', 'fa-chess'),
|
||||||
|
cleaningSupplies: new Product('cleaningSupplies', 'fa-broom'),
|
||||||
|
cloathesAccessories: new Product('cloathesAccessories','fa-glasses'),
|
||||||
|
cocktailSupplies: new Product('cocktailSupplies','fa-cocktail'),
|
||||||
|
coffee: new Product('cofee','fa-coffee'),
|
||||||
|
contactLenses: new Product('contactLenses', 'fa-eye'),
|
||||||
|
cookie: new Product('cookie','fa-cookie'),
|
||||||
|
couch: new Product('couch', 'fa-couch'),
|
||||||
|
coughSyrop: new Product('coughSyrop', 'fa-lungs'),
|
||||||
|
cookie: new Product('cookie', 'fa-cookie'),
|
||||||
|
dictionary: new Product('dictionary', 'fa-language'),
|
||||||
|
dogAccessories: new Product('dogAccessories','fa-dog'),
|
||||||
|
drinks: new Product('drinks', 'fa-glass-whiskey'),
|
||||||
|
drone: new Product('drone','fa-plane'),
|
||||||
|
drum: new Product('drum', 'fa-drum'),
|
||||||
|
envelope: new Product('envelope', 'fa-envelope'),
|
||||||
|
egg: new Product('egg','fa-egg'),
|
||||||
|
electronicAccessories: new Product('electronicAccessories','fa-bolt'),
|
||||||
|
eraser: new Product('eraser','fa-eraser'),
|
||||||
|
extinguisher: new Product('extinguisher','fa-fire'),
|
||||||
|
firstAid: new Product('firstAid','fa-first-aid'),
|
||||||
|
fish: new Product('fish','fa-fish'),
|
||||||
|
gamepad: new Product('gamepad', 'fa-gamepad'),
|
||||||
|
giftWrapping: new Product('giftWrapping', 'fa-gift'),
|
||||||
|
glassAccessories: new Product('glassAccessories','fa-wine-glass'),
|
||||||
|
gps: new Product('gps','fa-street-view'),
|
||||||
|
guitar: new Product('guitar','fa-guitar'),
|
||||||
|
hamburger: new Product('hamburger', 'fa-hamburger'),
|
||||||
|
hammer: new Product('hammer', 'fa-hammer'),
|
||||||
|
halloweenAccessories: new Product('halloweenAccessories', 'fa-ghost'),
|
||||||
|
hauntingAccessories: new Product('hauntingAccessories','fa-binoculars'),
|
||||||
|
headphones: new Product('headphones','fa-headphones'),
|
||||||
|
highlighter: new Product('highlighter','fa-highlighter'),
|
||||||
|
homeSecurity: new Product('homeSecurity','fa-key'),
|
||||||
|
hotdog: new Product('hotdog','fa-hotdog'),
|
||||||
|
icecream: new Product('icecream','fa-ice-cream'),
|
||||||
|
insecticide: new Product('insecticide','fa-spider'),
|
||||||
|
jewelry: new Product('jewelry','fa-gem'),
|
||||||
|
keyboard: new Product('keyboard', 'fa-keyboard'),
|
||||||
|
kitchenSupplies: new Product('kitchenSupplies', 'fa-blender'),
|
||||||
|
laptop: new Product('laptop', 'fa-laptop'),
|
||||||
|
lemon: new Product('lemon','fa-lemon'),
|
||||||
|
lightbulb: new Product('lightbulb', 'fa-lightbulb'),
|
||||||
|
microphone: new Product('microphone', 'fa-microphone'),
|
||||||
|
mask: new Product('mask', 'fa-head-side-mask'),
|
||||||
|
monitor: new Product('monitor', 'fa-desktop'),
|
||||||
|
movingAccessories: new Product('movingAccessories','fa-boxes'),
|
||||||
|
newbornAccessorries: new Product('newbornAccessorries','fa-baby-carriage'),
|
||||||
|
newspaper: new Product('newspaper','fa-newspaper'),
|
||||||
|
paintBrush: new Product('paintBrush','fa-paint-brush'),
|
||||||
|
paintRoller: new Product('paintRoller', 'fa-paint-roller'),
|
||||||
|
paper: new Product('paper','fa-paperclip'),
|
||||||
|
partyAccessories: new Product('partyAccessories','fa-glass-cheers'),
|
||||||
|
pen: new Product('pen','fa-pen'),
|
||||||
|
pepper: new Product('pepper','fa-pepper-hot'),
|
||||||
|
personalSafetyAccessories: new Product('personalSafetyAccessories','fa-fingerprint'),
|
||||||
|
piggyBank: new Product('piggyBank', 'fa-piggy-bank'),
|
||||||
|
pills: new Product('pills','fa-pills'),
|
||||||
|
pizza: new Product('pizza','fa-pizza-slice'),
|
||||||
|
plants: new Product('plants','fa-seedling'),
|
||||||
|
printer: new Product('printer','fa-print'),
|
||||||
|
puzzle: new Product('puzzle', 'fa-puzzle-piece'),
|
||||||
|
religionAccessories: new Product('religionAccessories','fa-pray'),
|
||||||
|
ruler: new Product('ruler', 'fa-ruler'),
|
||||||
|
runningAccessories: new Product('runningAccessories','fa-running'),
|
||||||
|
sanitizer: new Product('sanitizer', 'fa-spray-can'),
|
||||||
|
scissors: new Product('scissors', 'fa-cut'),
|
||||||
|
seeds: new Product('seeds', 'fa-seedling'),
|
||||||
|
skatingAccessories: new Product('skatingAccessories','fa-skating'),
|
||||||
|
skiingAccessories: new Product('skiingAccessories','fa-skiing'),
|
||||||
|
soap: new Product('soap','fa-pump-soap'),
|
||||||
|
spaAccessories: new Product('spaAccessories','fa-spa'),
|
||||||
|
sportCloathes: new Product('sportCloathes','fa-futbol'),
|
||||||
|
stamp: new Product('stamp', 'fa-stamp'),
|
||||||
|
suitcase: new Product('suitcase', 'fa-suitcase-rolling'),
|
||||||
|
summerHoliday: new Product('summerHoliday','fa-umbrella-beach'),
|
||||||
|
sunscreen: new Product('sunscreen','fa-sun'),
|
||||||
|
swimmingAccessories: new Product('swimmingAccessories','fa-swimmer'),
|
||||||
|
thermometer: new Product('thermometer', 'fa-thermometer'),
|
||||||
|
toiletSupplies: new Product('toiletSupplies','fa-toilet-paper'),
|
||||||
|
tools: new Product('tools','fa-wrench'),
|
||||||
|
toothpaste: new Product('toothpaste', 'fa-tooth'),
|
||||||
|
toys: new Product('toys','fa-horse'),
|
||||||
|
trashBin: new Product('trashBin', 'fa-trash'),
|
||||||
|
tv: new Product('tv', 'fa-tv'),
|
||||||
|
umbrella: new Product('umbrella', 'fa-umbrella'),
|
||||||
|
vinyl: new Product('vinyl', 'fa-record-vinyl'),
|
||||||
|
volleyballBall: new Product('volleyballBall', 'fa-volleyball-ball'),
|
||||||
|
wine: new Product('wine','fa-wine-bottle'),
|
||||||
|
winterCloathes: new Product('winterCloathes','fa-mitten'),
|
||||||
|
winterHoliday: new Product('winterHoliday','fa-tree')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static RANDOM_FROM_REGISTRY() {
|
||||||
|
return Product.REGISTRY[Object.keys(Product.REGISTRY).filter(p => p !== 'empty')[Math.floor(Math.random() * (Object.keys(Product.REGISTRY).length - 1))]];
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
const SHELF_TYPE = Object.freeze({
|
const SHELF_TYPE = Object.freeze({
|
||||||
FRIDGE_SHELF: 'FRIDGE_SHELF',
|
FRIDGE_SHELF: 'lodowka',
|
||||||
LARGE_SHELF: 'LARGE_SHELF',
|
LARGE_SHELF: 'gabarytowa',
|
||||||
BASKET_SHELF: 'BASKET_SHELF',
|
BASKET_SHELF: 'kosze',
|
||||||
DISCOUNT_SHELF: 'DISCOUNT_SHELF',
|
DISCOUNT_SHELF: 'przecena',
|
||||||
STANDARD_SHELF: 'STANDARD_SHELF',
|
STANDARD_SHELF: 'standardowa',
|
||||||
FREESTANDING_SHELF: 'FREESTANDING_SHELF',
|
FREESTANDING_SHELF: 'wolnostojaca',
|
||||||
});
|
});
|
||||||
|
|
||||||
class Shelf {
|
class Shelf {
|
||||||
|
@ -60,11 +60,13 @@ class Time {
|
|||||||
async addDays(days) {
|
async addDays(days) {
|
||||||
await Products.instance.next(days);
|
await Products.instance.next(days);
|
||||||
Products.instance.update();
|
Products.instance.update();
|
||||||
const ul = document.querySelector('ul#history');
|
|
||||||
this.setDay(this.day += Number(days));
|
this.setDay(this.day += Number(days));
|
||||||
|
const ul = document.querySelector('ul#history');
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
li.innerHTML = `${this.day}: ${nice(Products.instance.max_similarity)}`;
|
li.innerHTML = `${this.day}: ${nice(Products.instance.max_similarity)}`;
|
||||||
ul.appendChild(li);
|
ul.appendChild(li);
|
||||||
|
|
||||||
|
Agent.instance.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -12,7 +12,8 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
const timeController = new TimeController();
|
const timeController = new TimeController();
|
||||||
const floor = new Floor(floorCanvas);
|
const floor = new Floor(floorCanvas);
|
||||||
const grid = new Grid(gridCanvas);
|
const grid = new Grid(gridCanvas);
|
||||||
const agent = new Agent(agentCanvas);
|
new Agent(agentCanvas);
|
||||||
|
new OrdersView();
|
||||||
|
|
||||||
await Knowledge.load()
|
await Knowledge.load()
|
||||||
const products = new Products(productsCanvas);
|
const products = new Products(productsCanvas);
|
||||||
|
140
src/neural_network.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
|
||||||
|
from emnist import list_datasets
|
||||||
|
from emnist import extract_test_samples
|
||||||
|
from emnist import extract_training_samples
|
||||||
|
import numpy as np
|
||||||
|
import torch
|
||||||
|
from torch import nn
|
||||||
|
from torch import optim
|
||||||
|
import scipy.special
|
||||||
|
from matplotlib.pyplot import imshow
|
||||||
|
import glob
|
||||||
|
import imageio
|
||||||
|
|
||||||
|
dig_train_images, dig_train_labels = extract_training_samples('digits')
|
||||||
|
dig_test_images, dig_test_labels = extract_test_samples('digits')
|
||||||
|
let_train_images, let_train_labels = extract_training_samples('letters')
|
||||||
|
let_test_images, let_test_labels = extract_test_samples('letters')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#print(dig_train_images[0])
|
||||||
|
dig_train_images = dig_train_images.reshape(len(dig_train_images),28*28)
|
||||||
|
d_train = dig_train_images[:1000]
|
||||||
|
d_labels = dig_train_labels[:1000]
|
||||||
|
|
||||||
|
dig_test_images = dig_test_images.reshape(len(dig_test_images),28*28)
|
||||||
|
d_test = dig_test_images[:600]
|
||||||
|
d_labelstest = dig_test_labels[:600]
|
||||||
|
|
||||||
|
print(d_test.shape)
|
||||||
|
print(d_labelstest)
|
||||||
|
#print(dig_train_images[0])
|
||||||
|
#print(dig_train_images.shape)
|
||||||
|
|
||||||
|
|
||||||
|
class NeuralNetwork:
|
||||||
|
def __init__(self, inputNodes, hiddenNodes, outputNodes, learningGrade, fileWeight, fileHidden):
|
||||||
|
self.inodes = inputNodes
|
||||||
|
self.hnodes = hiddenNodes
|
||||||
|
self.onodes = outputNodes
|
||||||
|
|
||||||
|
"""te pierwsze dwa użyj przy nauce, potem zostaw cały czas te 2"""
|
||||||
|
#self.weights = (np.random.rand(self.hnodes, self.inodes) - 0.5)
|
||||||
|
#self.hidden = (np.random.rand(self.onodes, self.hnodes) - 0.5)
|
||||||
|
self.weights = np.load(fileWeight)
|
||||||
|
self.hidden = np.load(fileHidden)
|
||||||
|
|
||||||
|
#print( 'Matrix1 \n', self.weights)
|
||||||
|
#print( 'Matrix2 \n', self.hidden)
|
||||||
|
|
||||||
|
self.lr = learningGrade
|
||||||
|
|
||||||
|
self.activationFunction = lambda x: scipy.special.expit(x)
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def train(self, inputsList, targetsList):
|
||||||
|
|
||||||
|
inputs = np.array(inputsList,ndmin=2).T
|
||||||
|
targets = np.array(targetsList,ndmin=2).T
|
||||||
|
|
||||||
|
#forward pass
|
||||||
|
hiddenInputs = np.dot(self.weights, inputs) + 2
|
||||||
|
hiddenOutputs = self.activationFunction(hiddenInputs)
|
||||||
|
|
||||||
|
finalInputs = np.dot(self.hidden, hiddenOutputs) + 1
|
||||||
|
finalOutputs = self.activationFunction(finalInputs)
|
||||||
|
|
||||||
|
outputErrors = targets - finalOutputs
|
||||||
|
#print(outputErrors.shape)
|
||||||
|
x =self.weights.T
|
||||||
|
#print(x.shape)
|
||||||
|
hiddenErrors = np.dot(self.hidden.T, outputErrors)
|
||||||
|
|
||||||
|
#print('OutputErrors', outputErrors.shape)
|
||||||
|
#print('finalOutputs',finalOutputs.shape)
|
||||||
|
#print(x.shape)
|
||||||
|
self.hidden += self.lr * np.dot((outputErrors * finalOutputs * (1.0 - finalOutputs)) , np.transpose(hiddenOutputs))
|
||||||
|
self.weights += self.lr * np.dot((hiddenErrors * hiddenOutputs * (1.0 - hiddenOutputs)) , np.transpose(inputs))
|
||||||
|
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def saveTraining(self, fileWeight, fileHidden):
|
||||||
|
np.save(fileWeight, self.weights)
|
||||||
|
np.save(fileHidden, self.hidden)
|
||||||
|
|
||||||
|
def query(self, inputsList):
|
||||||
|
|
||||||
|
inputs = np.array(inputsList, ndmin=2).T
|
||||||
|
|
||||||
|
|
||||||
|
hiddenInputs = np.dot(self.weights, inputs)
|
||||||
|
hiddenOutputs = self.activationFunction(hiddenInputs)
|
||||||
|
|
||||||
|
finalInputs = np.dot(self.hidden, hiddenOutputs)
|
||||||
|
finalOutputs = self.activationFunction(finalInputs)
|
||||||
|
|
||||||
|
return finalOutputs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
""" dodaj tablicę literek"""
|
||||||
|
#n = NeuralNetwork(inputNodes=3, hiddenNodes=5, outputNodes=2, learningGrade=0.2)
|
||||||
|
digitNetwork = NeuralNetwork(inputNodes=784, hiddenNodes=200, outputNodes=10, learningGrade=0.1, fileWeight="Dweights.npy", fileHidden="Dhidden.npy")
|
||||||
|
|
||||||
|
def trainNetwork(n, fWeight, fHidden, trainingSamples):
|
||||||
|
epochs = 10
|
||||||
|
outputNodes = 10
|
||||||
|
for e in range(epochs):
|
||||||
|
m=0
|
||||||
|
print('Epoch', e+1)
|
||||||
|
|
||||||
|
for record in trainingSamples:
|
||||||
|
inputs = (np.asfarray(record[0:])/255 * 0.99) + 0.01
|
||||||
|
#print(inputs.shape)
|
||||||
|
|
||||||
|
targets = np.zeros(outputNodes) + 0.01
|
||||||
|
targets[d_labels[m]] = 0.99
|
||||||
|
#print(targets)
|
||||||
|
n.train(inputs,targets)
|
||||||
|
|
||||||
|
m+=1
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
n.saveTraining(fileWeight=fWeight, fileHidden=fHidden)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##################################### ODPALANIE TRAINING
|
||||||
|
#trainNetwork(digitNetwork, "Dweights.npy", "Dhidden.npy", d_train)
|
||||||
|
|
||||||
|
#record = d_test[0]
|
||||||
|
#print('Label', d_labelstest[0])
|
||||||
|
#inputs = np.asfarray(record[0:])/ 255 * 0.99 + 0.01
|
||||||
|
#print(n.query(inputs))
|
||||||
|
|
||||||
|
|
||||||
|
#testing
|
108
src/styles.css
@ -28,6 +28,7 @@ main {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ######################################## */
|
/* ######################################## */
|
||||||
@ -48,6 +49,10 @@ main {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-line:first-of-type {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
.header-line fieldset {
|
.header-line fieldset {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
@ -84,6 +89,21 @@ main {
|
|||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: transparent;
|
||||||
|
color: #3498db;
|
||||||
|
border: 1px solid #3498db;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #0A0A0A;
|
||||||
|
}
|
||||||
|
|
||||||
.logs-label {
|
.logs-label {
|
||||||
margin: 0 20px 30px 10px;
|
margin: 0 20px 30px 10px;
|
||||||
}
|
}
|
||||||
@ -169,3 +189,91 @@ main {
|
|||||||
#products i {
|
#products i {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ######################################## */
|
||||||
|
/* # Orders window styling # */
|
||||||
|
/* ######################################## */
|
||||||
|
|
||||||
|
.orders-window {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
content: "\2716";
|
||||||
|
font-size: 30px;
|
||||||
|
color: white;
|
||||||
|
line-height: 100px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orders-window canvas {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border: 1px solid black;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line.gaps > *:not(:first-child) {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line .incrementals div {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line .incrementals {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.incrementals div {
|
||||||
|
border: 1px solid #3498db;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.incrementals div:hover {
|
||||||
|
border: 1px solid #217bb8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.response {
|
||||||
|
width: 100%;
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #3498db;
|
||||||
|
background-color: black;
|
||||||
|
}
|
@ -1,11 +1,13 @@
|
|||||||
class AgentController {
|
class AgentController {
|
||||||
constructor(canvas) {
|
constructor(canvas) {
|
||||||
// Inicjalizacja
|
// Inicjalizacja
|
||||||
|
this.canvas = canvas;
|
||||||
this.ctx = canvas.getContext('2d');
|
this.ctx = canvas.getContext('2d');
|
||||||
this.setCanvasSize(canvas);
|
this.setCanvasSize(canvas);
|
||||||
|
|
||||||
this.ownedProduct = null;
|
this.ownedProduct = null;
|
||||||
this.ownedProductAmount = 0;
|
this.ownedProductAmount = 0;
|
||||||
|
this.isDestroyed = false;
|
||||||
|
|
||||||
// Akcje
|
// Akcje
|
||||||
this.actions = {
|
this.actions = {
|
||||||
@ -16,7 +18,7 @@ class AgentController {
|
|||||||
this.currentAction = this.actions.STATIONARY;
|
this.currentAction = this.actions.STATIONARY;
|
||||||
|
|
||||||
// Pozycja i rotacja
|
// Pozycja i rotacja
|
||||||
this.position = { x: 6, y: 0 };
|
this.position = AgentStartPosition;
|
||||||
this.rotation = { z: 0 };
|
this.rotation = { z: 0 };
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
@ -59,10 +61,18 @@ class AgentController {
|
|||||||
|
|
||||||
if (nearestPoint) {
|
if (nearestPoint) {
|
||||||
if (nearestPoint.action == PATHFINDING_ACTION.MOVE) {
|
if (nearestPoint.action == PATHFINDING_ACTION.MOVE) {
|
||||||
await this.moveInLine(nearestPoint.state.position, nearestPoint.actionCost);
|
try {
|
||||||
|
await this.moveInLine(nearestPoint.state.position, nearestPoint.actionCost);
|
||||||
|
} catch (e) {
|
||||||
|
return reject();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (nearestPoint.action == PATHFINDING_ACTION.ROTATE) {
|
if (nearestPoint.action == PATHFINDING_ACTION.ROTATE) {
|
||||||
await this.rotate({ z: nearestPoint.state.rotation }, nearestPoint.actionCost);
|
try {
|
||||||
|
await this.rotate({ z: nearestPoint.state.rotation }, nearestPoint.actionCost);
|
||||||
|
} catch (e) {
|
||||||
|
return reject();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nearestPoint = this.currentPath[++this.currentPathIndex];
|
nearestPoint = this.currentPath[++this.currentPathIndex];
|
||||||
@ -95,6 +105,9 @@ class AgentController {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const cycle = () => {
|
const cycle = () => {
|
||||||
|
if (this.currentAction == this.actions.STATIONARY) return resolve();
|
||||||
|
if (this.isDestroyed) return reject();
|
||||||
|
|
||||||
let { speed } = this;
|
let { speed } = this;
|
||||||
speed *= (actionCost - 1) * 4 + 1;
|
speed *= (actionCost - 1) * 4 + 1;
|
||||||
|
|
||||||
@ -125,6 +138,11 @@ class AgentController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async waitFor() {
|
||||||
|
await waitFor(this.waitTime);
|
||||||
|
if (this.isDestroyed) throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {{ x: number, y: number }} position
|
* @param {{ x: number, y: number }} position
|
||||||
@ -174,6 +192,8 @@ class AgentController {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
const cycle = () => {
|
const cycle = () => {
|
||||||
|
if (this.isDestroyed) return reject();
|
||||||
|
|
||||||
this.currentAction = this.actions.IN_ROTATION;
|
this.currentAction = this.actions.IN_ROTATION;
|
||||||
|
|
||||||
const oldZRotation = this.rotation.z;
|
const oldZRotation = this.rotation.z;
|
||||||
@ -261,13 +281,17 @@ class AgentController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
findPathTo(dx, dy, sx, sy) {
|
findPathTo(dx, dy, sx, sy) {
|
||||||
if (Grid.instance.getGrid()[dx][dy] == GRID_FIELD_TYPE.SHELF || Grid.instance.getGrid()[dx][dy] == GRID_FIELD_TYPE.STORAGE) {
|
const position = { x: sx, y: sy };
|
||||||
|
const rotation = this.rotation.z;
|
||||||
|
|
||||||
|
if (Grid.instance.getGrid()[dx][dy] == GRID_FIELD_TYPE.SHELF ||
|
||||||
|
Grid.instance.getGrid()[dx][dy] == GRID_FIELD_TYPE.STORAGE) {
|
||||||
if (Grid.instance.getGrid()[dx][dy - 1] == GRID_FIELD_TYPE.PATH) {
|
if (Grid.instance.getGrid()[dx][dy - 1] == GRID_FIELD_TYPE.PATH) {
|
||||||
return Pathfinding.search({ position: { x: sx, y: sy }, rotation: this.rotation.z }, { position: { x: dx, y: dy - 1 }, rotation: 180 });
|
return Pathfinding.search({ position, rotation }, { position: { x: dx, y: dy - 1 }, rotation: 180 });
|
||||||
}
|
}
|
||||||
return Pathfinding.search({ position: { x: sx, y: sy }, rotation: this.rotation.z }, { position: { x: dx, y: dy + 1 }, rotation: 0 });
|
return Pathfinding.search({ position, rotation }, { position: { x: dx, y: dy + 1 }, rotation: 0 });
|
||||||
}
|
}
|
||||||
return Pathfinding.search({ position: { x: sx, y: sy }, rotation: this.rotation.z }, { position: { x: dx, y: dy }, rotation: this.rotation.z });
|
return Pathfinding.search({ position, rotation }, { position: { x: dx, y: dy }, rotation });
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCanvas() {
|
clearCanvas() {
|
||||||
@ -290,4 +314,14 @@ class AgentController {
|
|||||||
this.ctx.closePath();
|
this.ctx.closePath();
|
||||||
this.ctx.stroke();
|
this.ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.isDestroyed = true;
|
||||||
|
this.update = () => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelAllActions() {
|
||||||
|
Agent.instance.destroy();
|
||||||
|
Agent.instance = new Agent(this.canvas);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,7 +1,8 @@
|
|||||||
const GRID_FIELD_TYPE = Object.freeze({
|
const GRID_FIELD_TYPE = Object.freeze({
|
||||||
PATH: 'PATH',
|
PATH: 'PATH',
|
||||||
SHELF: 'SHELF',
|
SHELF: 'SHELF',
|
||||||
STORAGE: 'STORAGE'
|
STORAGE: 'STORAGE',
|
||||||
|
ORDERS: 'ORDERS'
|
||||||
});
|
});
|
||||||
|
|
||||||
class Grid {
|
class Grid {
|
||||||
@ -22,6 +23,7 @@ class Grid {
|
|||||||
this.drawCostMap();
|
this.drawCostMap();
|
||||||
this.drawShelfs();
|
this.drawShelfs();
|
||||||
this.drawStorages();
|
this.drawStorages();
|
||||||
|
this.drawOrders();
|
||||||
|
|
||||||
Grid.instance = this;
|
Grid.instance = this;
|
||||||
}
|
}
|
||||||
@ -52,7 +54,7 @@ class Grid {
|
|||||||
[...fact(1), GRID_FIELD_TYPE.PATH, ...fact(2), GRID_FIELD_TYPE.PATH, ...fact(2), GRID_FIELD_TYPE.PATH]
|
[...fact(1), GRID_FIELD_TYPE.PATH, ...fact(2), GRID_FIELD_TYPE.PATH, ...fact(2), GRID_FIELD_TYPE.PATH]
|
||||||
);
|
);
|
||||||
|
|
||||||
const lastLine = [...fact(6), GRID_FIELD_TYPE.PATH, ...fact(6, GRID_FIELD_TYPE.STORAGE), GRID_FIELD_TYPE.PATH, ...fact(6)];
|
const lastLine = [...fact(6), GRID_FIELD_TYPE.PATH, ...fact(3, GRID_FIELD_TYPE.STORAGE), ...fact(3, GRID_FIELD_TYPE.ORDERS), GRID_FIELD_TYPE.PATH, ...fact(6)];
|
||||||
for (let i = 0; i < 20; i++) {
|
for (let i = 0; i < 20; i++) {
|
||||||
this.grid[i] = [...this.grid[i], lastLine[i]];
|
this.grid[i] = [...this.grid[i], lastLine[i]];
|
||||||
}
|
}
|
||||||
@ -128,6 +130,35 @@ class Grid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawOrders () {
|
||||||
|
let isFirstOfType = true;
|
||||||
|
let isLastOfType = false;
|
||||||
|
|
||||||
|
let firstX;
|
||||||
|
for (let [x, line] of this.grid.entries()) {
|
||||||
|
for (let [y, type] of line.entries()) {
|
||||||
|
if (type === GRID_FIELD_TYPE.ORDERS) {
|
||||||
|
if (this.grid[x + 1] && this.grid[x + 1][y] !== GRID_FIELD_TYPE.ORDERS) {
|
||||||
|
isLastOfType = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFirstOfType) {
|
||||||
|
isFirstOfType = false;
|
||||||
|
firstX = x;
|
||||||
|
this.orders(x * 100, y * 100, 100, 100, true, false, true, true);
|
||||||
|
} else if (isLastOfType) {
|
||||||
|
isLastOfType = false;
|
||||||
|
isFirstOfType = true;
|
||||||
|
this.orders(x * 100, y * 100, 100, 100, true, true, true, false);
|
||||||
|
this.ordersLabel(firstX * 100, y * 100, (x - firstX + 1) * 100, 100);
|
||||||
|
} else {
|
||||||
|
this.orders(x * 100, y * 100, 100, 100, true, false, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
storeLabel(x, y, w, h) {
|
storeLabel(x, y, w, h) {
|
||||||
let fontSize = 40;
|
let fontSize = 40;
|
||||||
this.ctx.font = `${fontSize}px Montserrat`;
|
this.ctx.font = `${fontSize}px Montserrat`;
|
||||||
@ -136,21 +167,46 @@ class Grid {
|
|||||||
this.ctx.fillText("STORE", x + (w/2), y + (h/2) + 15);
|
this.ctx.fillText("STORE", x + (w/2), y + (h/2) + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ordersLabel(x, y, w, h) {
|
||||||
|
let fontSize = 40;
|
||||||
|
this.ctx.font = `${fontSize}px Montserrat`;
|
||||||
|
this.ctx.textAlign = "center";
|
||||||
|
this.ctx.fillStyle = '#3498db';
|
||||||
|
this.ctx.fillText("ORDERS", x + (w/2), y + (h/2) + 15);
|
||||||
|
}
|
||||||
|
|
||||||
shelf (shelf, x, y, w, h) {
|
shelf (shelf, x, y, w, h) {
|
||||||
this.ctx.strokeStyle = '#ffffff';
|
this.ctx.strokeStyle = '#ffffff';
|
||||||
this.ctx.lineWidth = 5;
|
this.ctx.lineWidth = 5;
|
||||||
this.ctx.strokeRect(x, y, w, h);
|
this.ctx.strokeRect(x, y, w, h);
|
||||||
this.drawFixIfOnEdge(x, y, w, h);
|
this.drawFixIfOnEdge(x, y, w, h);
|
||||||
|
|
||||||
var img = new Image();
|
const descriptors = Object.getOwnPropertyDescriptors(SHELF_TYPE);
|
||||||
img.src = `img/shelves/${shelf.type}.svg`;
|
let imageSource = null;
|
||||||
img.onload = () => {
|
for (const key of Object.keys(descriptors)) {
|
||||||
this.ctx.drawImage(img, x, y, w, h);
|
if (descriptors[key].value === shelf.type) {
|
||||||
|
imageSource = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (imageSource && shelf.type !== SHELF_TYPE.STANDARD_SHELF) {
|
||||||
|
var img = new Image();
|
||||||
|
img.src = `img/shelves/${imageSource}.svg`;
|
||||||
|
img.onload = () => {
|
||||||
|
this.ctx.drawImage(img, x, y, w, h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storage (x, y, w, h, hasTop, hasRight, hasBottom, hasLeft) {
|
storage (x, y, w, h, hasTop, hasRight, hasBottom, hasLeft) {
|
||||||
this.ctx.strokeStyle = '#ffff00';
|
this.connectedSquare (x, y, w, h, hasTop, hasRight, hasBottom, hasLeft, '#ffff00');
|
||||||
|
}
|
||||||
|
|
||||||
|
orders (x, y, w, h, hasTop, hasRight, hasBottom, hasLeft) {
|
||||||
|
this.connectedSquare (x, y, w, h, hasTop, hasRight, hasBottom, hasLeft, '#3498db');
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedSquare (x, y, w, h, hasTop, hasRight, hasBottom, hasLeft, color) {
|
||||||
|
this.ctx.strokeStyle = color;
|
||||||
this.ctx.lineWidth = 5;
|
this.ctx.lineWidth = 5;
|
||||||
if (hasTop) {
|
if (hasTop) {
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
|
101
src/view/ordersView.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
class OrdersView {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
OrdersView.instance = this;
|
||||||
|
|
||||||
|
this.addMultipleCanvases(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
order() {
|
||||||
|
const formData = new FormData();
|
||||||
|
Promise.all(
|
||||||
|
[...document.querySelectorAll('.orders-window .canvases canvas')].map((canv, index) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
canv.toBlob(blob => {
|
||||||
|
formData.append(`file-${index}`, blob,`file-${index}.png`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
).then(async () => {
|
||||||
|
const response = await fetch('/api/neural', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
//const json = await response.json();
|
||||||
|
console.log(await response.text());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
[...document.querySelectorAll('.orders-window .canvases canvas')].forEach(canv => {
|
||||||
|
canv.getContext('2d').clearRect(0, 0, 100, 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openWindow() {
|
||||||
|
document.querySelector('.orders-window').style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
closeWindow() {
|
||||||
|
document.querySelector('.orders-window').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
addMultipleCanvases(amount) {
|
||||||
|
for (let i = 0; i < amount; i++) {
|
||||||
|
this.addCanvas();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addCanvas() {
|
||||||
|
const canv = document.createElement('canvas');
|
||||||
|
this.initializeDrawingOnCanvas(canv);
|
||||||
|
document.querySelector('.orders-window .canvases').append(canv);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCanvas() {
|
||||||
|
const c = document.querySelector('.orders-window .canvases');
|
||||||
|
c.removeChild(c.lastChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeDrawingOnCanvas(canvas) {
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
let coord = { x: 0, y: 0 };
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", start);
|
||||||
|
document.addEventListener("mouseup", stop);
|
||||||
|
window.addEventListener("resize", resize);
|
||||||
|
|
||||||
|
resize();
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
ctx.canvas.width = 100;
|
||||||
|
ctx.canvas.height = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reposition(event) {
|
||||||
|
coord.x = event.clientX - canvas.offsetLeft;
|
||||||
|
coord.y = event.clientY - canvas.offsetTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
function start(event) {
|
||||||
|
document.addEventListener("mousemove", draw);
|
||||||
|
reposition(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stop() {
|
||||||
|
document.removeEventListener("mousemove", draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw(event) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.lineWidth = 5;
|
||||||
|
ctx.lineCap = "round";
|
||||||
|
ctx.strokeStyle = "#000000";
|
||||||
|
ctx.moveTo(coord.x, coord.y);
|
||||||
|
reposition(event);
|
||||||
|
ctx.lineTo(coord.x, coord.y);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|