From 2a9b3a32b50195c239fd0f34ea811e51b0c784ab Mon Sep 17 00:00:00 2001 From: waramsey Date: Wed, 10 Mar 2021 19:00:26 -0700 Subject: [PATCH] Genetic Algorithm Node Compatibility Update --- src/flatGenerator.js | 3 +- src/geneticAlgorithm.js | 101 +++++++---------------------------- src/innerCircleLayout.js | 9 ++-- src/spacesSharedFunctions.js | 26 ++++----- src/wallGenerator.js | 5 +- 5 files changed, 43 insertions(+), 101 deletions(-) diff --git a/src/flatGenerator.js b/src/flatGenerator.js index 2170bb2..816e16d 100644 --- a/src/flatGenerator.js +++ b/src/flatGenerator.js @@ -48,7 +48,8 @@ s off f ${1 + vOffset}/${1 + vOffset}/${1 + vOffset} ${2 + vOffset}/${2 + vOffset}/${1 + vOffset} ${3 + vOffset}/${3 + vOffset}/${1 + vOffset} ${4 + vOffset}/${4 + vOffset}/${1 + vOffset} \n`; - fs.appendFileSync(`${baseName}.obj`, obj); + fs.appendFileSync(`${baseName}/objs/layout.obj`, obj); + fs.appendFileSync(`${baseName}/objs/layout.js`, obj); //Second generate the mtl file diff --git a/src/geneticAlgorithm.js b/src/geneticAlgorithm.js index 65c4e89..32c9a46 100644 --- a/src/geneticAlgorithm.js +++ b/src/geneticAlgorithm.js @@ -1,7 +1,8 @@ import { innerCircleLayout } from "./innerCircleLayout.js"; import fs from 'fs'; import fse from 'fs-extra'; -import boot from "../../examples/src/index.js" +// import startup from "../../node/index.js" +import child_process from "child_process" const searchSpace = [ @@ -31,8 +32,8 @@ for (let i = 2; i <= iterations; i++) { function genAlgLoop(population, iteration) { - generateBuildings(population); - return removeLeastFit(evalFitness(population), population, iteration); + let fitness = generateBuildings(population); + return removeLeastFit(evalFitness(population, fitness), population, iteration); } function initPopulation() { @@ -66,9 +67,10 @@ function repopulate(population) { function generateBuildings(population) { let count = 1; + let fitness = []; population.forEach(vector => { innerCircleLayout( - "../runs/ga/thisGeneration/a" + count, + "../../node/node_modules/@crowdedjs/assets/", vector[0] * (searchSpace[0].max - searchSpace[0].min) + searchSpace[0].min, vector[1] * (searchSpace[1].max - searchSpace[1].min) + searchSpace[1].min, vector[2] * (searchSpace[2].max - searchSpace[2].min) + searchSpace[2].min, @@ -76,8 +78,14 @@ function generateBuildings(population) { vector[4] * (searchSpace[4].max - searchSpace[4].min) + searchSpace[4].min, vector[5] * (searchSpace[5].max - searchSpace[5].min) + searchSpace[5].min ); + console.log("Beginning Layout #" + count) + let result = parseInt(child_process.execSync("node ../../node/index.js").toString()); + console.log(" > " + result) + + fitness.push(result) count++; }); + return fitness; } function randomVector() { @@ -117,101 +125,30 @@ function removeLeastFit(fitnessVals, population, iteration, numToKeep = 5) { if (i < numToKeep) newPopulation.push(population[fitnessVals[i][1]]) } - fs.copyFileSync("../runs/ga/thisGeneration/a" + (fitnessVals[0][1] + 1) + ".obj", "../runs/ga/best/bestGen" + iteration + ".obj") + // fs.copyFileSync("../runs/ga/thisGeneration/a" + (fitnessVals[0][1] + 1) + ".obj", "../runs/ga/best/bestGen" + iteration + ".obj") return newPopulation; } -function evalFitness(population) { - //IN DEVELOPMENT. IDEAS: - //we could measure the distance between important points - //That would be keeping in mind that the most crucial, lifesaving travel distances should be weighted - //More commonly traveled distances should also be weighted - //hall width needs to be evaluated. This would be more accurate to do in our simulation, but it would take SO long. - //Probably what we need is a heuristic. - //we could get a room count. We need to make sure that the algorithm doesn't favor tiny ERs. - //we could use the average distance from the center..? - - - //REALLY BASIC HEURISTIC - let bestHeuristics = [0,0,0] - let roomHeuristics = [] - let hallHeuristics = [] - let doorHeuristics = [] - // let bestResult = 0; - // let runtimeResults = [] +function evalFitness(population, fitness) { + let bestResult = Infinity; + let runtimeResults = fitness; for (let i = 0; i < population.length; i++) { - roomHeuristics.push(roomHeuristic("../runs/ga/thisGeneration/a" + (i+1) + "Labels.json")); - hallHeuristics.push(hallHeuristic(population, i)); - doorHeuristics.push(doorHeuristic(population, i)); - // runtimeResults.push(runSimTest(i)) - - if (roomHeuristics[i] > bestHeuristics[0]) - bestHeuristics[0] = roomHeuristics[i]; - if (hallHeuristics[i] > bestHeuristics[1]) - bestHeuristics[1] = hallHeuristics[i]; - if (doorHeuristics[i] > bestHeuristics[2]) - bestHeuristics[2] = doorHeuristics[i]; - // if (runtimeResults[i] > bestResult) - // bestResult = runtimeResults[i]; + if (runtimeResults[i] < bestResult) + bestResult = runtimeResults[i]; }; let fitnessVals = []; for (let i = 0; i < population.length; i++) { fitnessVals.push([ - ( - roomHeuristics[i] + - hallHeuristics[i] + - doorHeuristics[i] - ) / ( - bestHeuristics[0] + - bestHeuristics[1] + - bestHeuristics[2] - ), i + bestResult / runtimeResults[i], i ]) } return fitnessVals; } -function roomHeuristic(filePath) { - //The size of the json file should be proportional to the number of rooms. - const stats = fs.statSync(filePath) - return stats.size; -} - -function hallHeuristic(population, vectorNum) { - let hallValue = population[vectorNum][0] * (searchSpace[0].max - searchSpace[0].min) + searchSpace[0].min; - let hallCutoff = 6; - return hallValue < hallCutoff ? population[vectorNum][0] : hallCutoff / hallValue; -} - -function doorHeuristic(population, vectorNum) { - let doorValue = population[vectorNum][1] * (searchSpace[1].max - searchSpace[1].min) + searchSpace[1].min; - let doorCutoff = 4; - return doorValue < doorCutoff ? population[vectorNum][1] : doorCutoff / doorValue; -} - -// function runSimTest(vectorNum) { -// let params = {}; - -// let assetBase = "../runs/ga/thisGeneration/a" + (vectorNum+1); - -// params.objPath = assetBase + ".obj"; -// params.arrivalPath = "../runs/ga/arrival.json"; //TODO -// params.locationsPath = assetBase + "Labels.json"; -// params.secondsOfSimulation = 300; -// params.millisecondsBetweenFrames = 40; -// params = urlParser(window, params, assetBase); - -// return boot(params); -// } - -function evacHeuristic(params) { - //TODO: time how long it takes for all people to evacuate -} - function printStats(vector) { let toPrint = ""; for (let i = 0; i < searchSpace.length; i++) { diff --git a/src/innerCircleLayout.js b/src/innerCircleLayout.js index 705cf9d..1d88d94 100644 --- a/src/innerCircleLayout.js +++ b/src/innerCircleLayout.js @@ -6,7 +6,8 @@ import flatGenerator from "./flatGenerator.js" export function innerCircleLayout(filePath = "test", hallWidth = 4, doorSize = 3, w = 100, l = 100, midRatio = 1/3, maxRoomSize = 15) { - fs.writeFileSync(filePath + `.obj`, "\n"); + fs.writeFileSync(filePath + `objs/layout.obj`, "\n"); + fs.writeFileSync(filePath + `objs/layout.js`, "export default\n`"); // fs.writeFileSync(filePath + `.obj`, "mtllib room.mtl\n"); // fs.writeFileSync(filePath + `.mtl`, "\n"); @@ -86,6 +87,8 @@ export function innerCircleLayout(filePath = "test", hallWidth = 4, doorSize = 3 //Adding in the exit as the first "room" of filledSpace filledSpace.push({TL:{x:(spaceToFill.BR.x+spaceToFill.TL.x) / 2 - 15,y:spaceToFill.BR.y},BR:{x:(spaceToFill.BR.x+spaceToFill.TL.x) / 2 + 15,y:spaceToFill.BR.y - 30},isRoom:false,name:"Exit"}) - generateLabels(filledSpace, filePath, "room"); - arrivalOnePerRoom(filledSpace, filePath, "room") + generateLabels(filledSpace, filePath + "locations/", "room"); + arrivalOnePerRoom(filledSpace, filePath + "arrivals/", "room"); + + fs.appendFileSync(filePath + `objs/layout.js`, "`"); } diff --git a/src/spacesSharedFunctions.js b/src/spacesSharedFunctions.js index ce94f1c..7e98d8d 100644 --- a/src/spacesSharedFunctions.js +++ b/src/spacesSharedFunctions.js @@ -350,13 +350,13 @@ function deepCloneSpace(target, source) { */ export function generateLabels(filledSpace, filePath, labelBase = "room") { let nameCount = 1; - fs.writeFileSync(filePath + "Labels.json", "[\n"); + fs.writeFileSync(filePath + "locations.js", "export default [\n"); filledSpace.forEach(space => { let name; if (space.name !== undefined) { name = space.name; } else { - name = labelBase + " " + (nameCount + 1); + name = labelBase + " " + nameCount; } let annotationName = name; let position = {x:0,y:0,z:0}; @@ -364,13 +364,13 @@ export function generateLabels(filledSpace, filePath, labelBase = "room") { position.y = 0; position.z = (space.TL.y + space.BR.y) / 2; if (filledSpace.length == nameCount) { - fs.appendFileSync(filePath + "Labels.json", `\t{\n\t\t"name": "${name}",\n\t\t"annotationName": "${annotationName}",\n\t\t"position": {\n\t\t\t"x": ${position.x},\n\t\t\t"y": ${position.y},\n\t\t\t"z": ${position.z}\n\t\t}\n\t}\n`) + fs.appendFileSync(filePath + "locations.js", `\t{\n\t\t"name": "${name}",\n\t\t"annotationName": "${annotationName}",\n\t\t"position": {\n\t\t\t"x": ${position.x},\n\t\t\t"y": ${position.y},\n\t\t\t"z": ${position.z}\n\t\t}\n\t}\n`) } else { - fs.appendFileSync(filePath + "Labels.json", `\t{\n\t\t"name": "${name}",\n\t\t"annotationName": "${annotationName}",\n\t\t"position": {\n\t\t\t"x": ${position.x},\n\t\t\t"y": ${position.y},\n\t\t\t"z": ${position.z}\n\t\t}\n\t},\n`) + fs.appendFileSync(filePath + "locations.js", `\t{\n\t\t"name": "${name}",\n\t\t"annotationName": "${annotationName}",\n\t\t"position": {\n\t\t\t"x": ${position.x},\n\t\t\t"y": ${position.y},\n\t\t\t"z": ${position.z}\n\t\t}\n\t},\n`) } nameCount++; }); - fs.appendFileSync(filePath + "Labels.json", "]"); + fs.appendFileSync(filePath + "locations.js", "]"); } /** @@ -379,21 +379,21 @@ export function generateLabels(filledSpace, filePath, labelBase = "room") { * @param {String} filePath The base path to the files we write to */ export function arrivalOnePerRoom(filledSpace, filePath, labelBase = "room") { - fs.writeFileSync(filePath + "Arrivals.json", "[\n"); - for (let i = 0; i < filledSpace.length; i++) { + fs.writeFileSync(filePath + "arrivals.js", "export default [\n"); + for (let i = 1; i < filledSpace.length; i++) { let name = "EscapePerson"; let type = name; - let arrivalLocation = labelBase + " " + (i + 1); + let arrivalLocation = labelBase + " " + i; let arrivalTick = 10; - let id = i; + let id = i - 1; - if ((i+1) < filledSpace.length) { - fs.appendFileSync(filePath + "Arrivals.json", `\t{\n\t\t"name": "${name}",\n\t\t"type": "${type}",\n\t\t"arrivalLocation": "${arrivalLocation}",\n\t\t"arrivalTick": "${arrivalTick}",\n\t\t"id": "${id}"\n\t},\n`) + if (i < filledSpace.length) { + fs.appendFileSync(filePath + "arrivals.js", `\t{\n\t\t"name": "${name}",\n\t\t"type": "${type}",\n\t\t"arrivalLocation": "${arrivalLocation}",\n\t\t"arrivalTick": ${arrivalTick},\n\t\t"id": ${id}\n\t},\n`) } else { - fs.appendFileSync(filePath + "Arrivals.json", `\t{\n\t\t"name": "${name}",\n\t\t"type": "${type}",\n\t\t"arrivalLocation": "${arrivalLocation}",\n\t\t"arrivalTick": "${arrivalTick}",\n\t\t"id": "${id}"\n\t}\n`) + fs.appendFileSync(filePath + "arrivals.js", `\t{\n\t\t"name": "${name}",\n\t\t"type": "${type}",\n\t\t"arrivalLocation": "${arrivalLocation}",\n\t\t"arrivalTick": ${arrivalTick},\n\t\t"id": ${id}\n\t}\n`) } } - fs.appendFileSync(filePath + "Arrivals.json", "]"); + fs.appendFileSync(filePath + "arrivals.js", "]"); } /** diff --git a/src/wallGenerator.js b/src/wallGenerator.js index 28fd084..cd58bd1 100644 --- a/src/wallGenerator.js +++ b/src/wallGenerator.js @@ -36,7 +36,7 @@ function wallGenerator(width, length, height, baseName, textureOptions, wOffset //First generate the wavefront obj file let obj = ` - o object${vOffset} +o object${vOffset} v ${halfWidth + wOffset} ${halfHeight + hOffset} ${halfLength + lOffset} v ${halfWidth + wOffset} ${halfHeight + hOffset} ${-halfLength + lOffset} v ${halfWidth + wOffset} ${-halfHeight + hOffset} ${halfLength + lOffset} @@ -64,7 +64,8 @@ f ${1 + vOffset}/${1 + vOffset}/${1 + vOffset} ${3 + vOffset}/${3 + vOffset}/${1 f ${4 + vOffset}/${4 + vOffset}/${1 + vOffset} ${2 + vOffset}/${2 + vOffset}/${1 + vOffset} ${6 + vOffset}/${6 + vOffset}/${1 + vOffset} ${8 + vOffset}/${8 + vOffset}/${1 + vOffset} \n`; - fs.appendFileSync(`${baseName}.obj`, obj); + fs.appendFileSync(`${baseName}/objs/layout.obj`, obj); + fs.appendFileSync(`${baseName}/objs/layout.js`, obj); //Second generate the mtl file