chore: pathfinding replacement
This commit is contained in:
parent
37c068e91b
commit
5653fa6b02
@ -20,6 +20,7 @@
|
||||
|
||||
<script src="modules/floor.js"></script>
|
||||
<script src="modules/grid.js"></script>
|
||||
<script src="modules/pathfinding.js"></script>
|
||||
<script src="modules/agentController.js"></script>
|
||||
<script src="modules/agent.js"></script>
|
||||
<script src="modules/products.js"></script>
|
||||
|
@ -8,4 +8,6 @@ window.addEventListener('DOMContentLoaded', () => document.fonts.ready.then(() =
|
||||
const grid = new Grid(gridCanvas);
|
||||
const agent = new Agent(agentCanvas);
|
||||
const products = new Products(productsCanvas);
|
||||
|
||||
window.products = products;
|
||||
}));
|
@ -4,15 +4,22 @@ class Agent extends AgentController {
|
||||
|
||||
const cycle = async () => {
|
||||
|
||||
await this.takeFromStore(Product.RANDOM_FROM_REGISTRY(), Math.floor(Math.random() * 40) + 10);
|
||||
const randomPlace = Grid.instance.randomPlace();
|
||||
await this.deliver(randomPlace.x, randomPlace.y);
|
||||
// await this.takeFromStore(Product.RANDOM_FROM_REGISTRY(), Math.floor(Math.random() * 40) + 10);
|
||||
// const randomPlace = Grid.instance.randomPlace();
|
||||
// await this.deliver(randomPlace.x, randomPlace.y);
|
||||
const jobRequest = window.products.getJobRequest();
|
||||
if (jobRequest) {
|
||||
console.log(jobRequest);
|
||||
const requiredAmount = 50 - jobRequest.amount;
|
||||
await this.takeFromStore(jobRequest.product, requiredAmount);
|
||||
await this.deliver(jobRequest.x, jobRequest.y);
|
||||
}
|
||||
|
||||
await waitFor(2000);
|
||||
cycle();
|
||||
};
|
||||
|
||||
cycle();
|
||||
setTimeout(() => cycle(), 2000);
|
||||
|
||||
}
|
||||
|
||||
@ -32,6 +39,7 @@ class Agent extends AgentController {
|
||||
*/
|
||||
async deliver(x, y) {
|
||||
await this.moveTo(x, y);
|
||||
window.products.exchange(x, y, this.ownedProduct, 50);
|
||||
this.ownedProductAmount = 0;
|
||||
this.ownedProduct = Product.REGISTRY.empty;
|
||||
}
|
||||
@ -41,7 +49,8 @@ class Agent extends AgentController {
|
||||
* @param {*} product
|
||||
*/
|
||||
async takeFromStore(product, amount) {
|
||||
await this.moveTo(6, 8);
|
||||
await this.moveTo(9, 8);
|
||||
await waitFor(1000);
|
||||
this.ownedProductAmount = amount;
|
||||
this.ownedProduct = product;
|
||||
}
|
||||
|
@ -48,10 +48,11 @@ class AgentController {
|
||||
let nearestPoint = this.currentPath[this.currentPathIndex];
|
||||
|
||||
if (nearestPoint) {
|
||||
const requiredRotation = this.findRequiredRotation(nearestPoint);
|
||||
await this.rotate({ z: requiredRotation });
|
||||
if (!nearestPoint.options || !nearestPoint.options.isShelf) {
|
||||
await this.moveInLine(nearestPoint);
|
||||
if (nearestPoint.action == PATHFINDING_ACTION.MOVE) {
|
||||
await this.moveInLine(nearestPoint.state.position);
|
||||
}
|
||||
if (nearestPoint.action == PATHFINDING_ACTION.ROTATE) {
|
||||
await this.rotate({ z: nearestPoint.state.rotation });
|
||||
}
|
||||
|
||||
nearestPoint = this.currentPath[++this.currentPathIndex];
|
||||
@ -134,9 +135,6 @@ class AgentController {
|
||||
*/
|
||||
rotate(rotation) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// console.log(this.rotation); // 270
|
||||
// console.log(rotation); // 0
|
||||
|
||||
if (this.rotation.z == rotation.z) {
|
||||
resolve();
|
||||
}
|
||||
@ -172,7 +170,6 @@ class AgentController {
|
||||
|
||||
moveTo(x, y) {
|
||||
this.currentPath = this.findPathTo(x, y, this.position.x, this.position.y);
|
||||
console.log(this.currentPath);
|
||||
return this.updateAgentPosition();
|
||||
}
|
||||
|
||||
@ -181,8 +178,8 @@ class AgentController {
|
||||
this.ctx.beginPath();
|
||||
this.ctx.strokeWidth = 5;
|
||||
this.ctx.strokeStyle = 'red';
|
||||
this.ctx.moveTo(path[i].x * 100 + 50, path[i].y * 100 + 50);
|
||||
this.ctx.lineTo(path[i + 1].x * 100 + 50, path[i + 1].y * 100 + 50);
|
||||
this.ctx.moveTo(path[i].state.position.x * 100 + 50, path[i].state.position.y * 100 + 50);
|
||||
this.ctx.lineTo(path[i + 1].state.position.x * 100 + 50, path[i + 1].state.position.y * 100 + 50);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
}
|
||||
@ -230,44 +227,13 @@ class AgentController {
|
||||
}
|
||||
|
||||
findPathTo(dx, dy, sx, sy) {
|
||||
const grid = JSON.parse(JSON.stringify(Grid.instance.grid));
|
||||
const queue = [];
|
||||
const lastPoint = [];
|
||||
|
||||
if (grid[dx][dy] === GRID_FIELD_TYPE.SHELF) {
|
||||
if(grid[dx][dy + 1] === GRID_FIELD_TYPE.PATH) {
|
||||
lastPoint.push({ x: dx, y: dy, options: { isShelf: true } });
|
||||
dy++;
|
||||
} else if(grid[dx][dy - 1] === GRID_FIELD_TYPE.PATH) {
|
||||
lastPoint.push({ x: dx, y: dy, options: { isShelf: true } });
|
||||
dy--;
|
||||
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) {
|
||||
return Pathfinding.search({ position: { x: sx, y: sy }, rotation: this.rotation.z }, { 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 });
|
||||
}
|
||||
|
||||
queue.push({ x: sx, y: sy, path: [] });
|
||||
|
||||
while(queue.length) {
|
||||
const { x, y, path } = queue.shift();
|
||||
path.push({ x, y });
|
||||
|
||||
if (x === dx && y === dy) {
|
||||
return [...path, ...lastPoint];
|
||||
}
|
||||
if (grid[x][y - 1] === GRID_FIELD_TYPE.PATH) {
|
||||
queue.push({ x, y: y - 1, path: [...path] });
|
||||
}
|
||||
if (grid[x][y + 1] === GRID_FIELD_TYPE.PATH) {
|
||||
queue.push({ x, y: y + 1, path: [...path] });
|
||||
}
|
||||
if (grid[x - 1] && grid[x - 1][y] === GRID_FIELD_TYPE.PATH) {
|
||||
queue.push({ x: x - 1, y, path: [...path] });
|
||||
}
|
||||
if (grid[x + 1] && grid[x + 1][y] === GRID_FIELD_TYPE.PATH) {
|
||||
queue.push({ x: x + 1, y, path: [...path] });
|
||||
}
|
||||
|
||||
grid[x][y] = -1;
|
||||
}
|
||||
return Pathfinding.search({ position: { x: sx, y: sy }, rotation: this.rotation.z }, { position: { x: dx, y: dy }, rotation: this.rotation.z });
|
||||
}
|
||||
|
||||
clearCanvas() {
|
||||
|
100
src/modules/pathfinding.js
Normal file
100
src/modules/pathfinding.js
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @typedef IPosition
|
||||
* @property {number} x
|
||||
* @property {number} y
|
||||
*
|
||||
* @typedef {Object} IState
|
||||
* @property {number} rotation
|
||||
* @property {IPosition} position
|
||||
*/
|
||||
|
||||
const PATHFINDING_ACTION = {
|
||||
ROTATE: 0,
|
||||
MOVE: 1,
|
||||
}
|
||||
|
||||
|
||||
class Pathfinding {
|
||||
static search(state, expectedState) {
|
||||
return Pathfinding.graphSearch({ state }, { state: expectedState })
|
||||
}
|
||||
|
||||
|
||||
static graphSearch(node, expectedNode, fringe = [], explored = []) {
|
||||
fringe.push(node);
|
||||
|
||||
while(true) {
|
||||
if (fringe.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const elem = fringe.shift();
|
||||
|
||||
if (Pathfinding.reached(elem.state, expectedNode.state)) {
|
||||
return Pathfinding.buildPath(node, elem);
|
||||
}
|
||||
|
||||
explored.push(elem);
|
||||
|
||||
for (const successor of this.successor(elem)) {
|
||||
if (explored.every(n => !Pathfinding.reached(n.state, successor.state))) {
|
||||
fringe.push(successor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static successor(node) {
|
||||
const list = [];
|
||||
const grid = Grid.instance.getGrid();
|
||||
|
||||
list.push({
|
||||
state: { ...node.state, rotation: (node.state.rotation + 270) % 360 },
|
||||
action: PATHFINDING_ACTION.ROTATE,
|
||||
parent: node
|
||||
});
|
||||
list.push({
|
||||
state: { ...node.state, rotation: (node.state.rotation + 90) % 360 },
|
||||
action: PATHFINDING_ACTION.ROTATE,
|
||||
parent: node
|
||||
});
|
||||
|
||||
const direction = Pathfinding.getVectorFromRotation(node.state.rotation);
|
||||
const prediction = { x: node.state.position.x + direction.x, y: node.state.position.y + direction.y }
|
||||
|
||||
if (grid[prediction.x] && grid[prediction.x][prediction.y] == GRID_FIELD_TYPE.PATH) {
|
||||
list.push({
|
||||
state: { ...node.state, position: prediction },
|
||||
action: PATHFINDING_ACTION.MOVE,
|
||||
parent: node
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static buildPath(node, expectedNode) {
|
||||
const result = [];
|
||||
let currentElement = expectedNode;
|
||||
|
||||
while(!Pathfinding.reached(currentElement.state, node.state)) {
|
||||
result.unshift(currentElement);
|
||||
currentElement = currentElement.parent;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static reached(state, expectedState) {
|
||||
return state.rotation == expectedState.rotation && state.position.x == expectedState.position.x && state.position.y == expectedState.position.y;
|
||||
}
|
||||
|
||||
static getVectorFromRotation(rotation) {
|
||||
switch (rotation) {
|
||||
case 0: return { x: 0, y: -1 };
|
||||
case 90: return { x: 1, y: 0 };
|
||||
case 180: return { x: 0, y: 1 };
|
||||
case 270: return { x: -1, y: 0 };
|
||||
}
|
||||
}
|
||||
}
|
@ -130,6 +130,8 @@ class Products {
|
||||
const amount = this.gridProductsAmount[x][y]
|
||||
this.gridProducts[x][y] = incomingProduct
|
||||
this.gridProductsAmount[x][y] = incomingAmount
|
||||
this.clearCanvas();
|
||||
this.drawProducts();
|
||||
return { product, amount }
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user