diff --git a/demo/dist/metacar.min.js b/demo/dist/metacar.min.js index e9742e5..8513460 100644 --- a/demo/dist/metacar.min.js +++ b/demo/dist/metacar.min.js @@ -131,7 +131,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Car\", function() { return Car; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\nvar Global_carId = 0;\nvar Car = (function () {\n function Car(level, info, textures, options) {\n if (options === void 0) { options = {}; }\n var _this = this;\n this.level = level;\n options.image = options.image || _global__WEBPACK_IMPORTED_MODULE_0__[\"CAR_IMG\"].DEFAULT;\n options.lidar = options.lidar || false;\n options.lidarInfo = options.lidarInfo || { pts: 5, width: 4, height: 5, pos: 0 };\n this.core = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Sprite\"](textures[options.image]);\n this.info = info;\n this.core.scale.x = 0.8;\n this.core.scale.y = 0.8;\n this.core.anchor.x = 0.5;\n this.core.anchor.y = 0.5;\n this.core.road = undefined;\n this.core.carId = Global_carId;\n Global_carId += 1;\n this.core.agent = false;\n this.core.obstacle = true;\n this.core.mapId = _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].CAR;\n if (options.lidar) {\n this.createLidar(options.lidarInfo);\n this.core.lidar = this.lidar;\n }\n if (options.motionEngine) {\n this.motion = options.motionEngine;\n this.motion.setUp(this.core, this.lidar);\n this.core.rotationStep = 0.5;\n }\n else {\n this.core.rotationStep = 0.5;\n }\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n this.core.x = (this.info.mx) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.y = (this.info.my) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.checkAndsetNewRoad = function (road) { return _this.checkAndsetNewRoad(road); };\n var road = this.level.getRoad(this.core.my, this.core.mx);\n this.core.line = 0;\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n }\n Car.prototype.checkAndsetNewRoad = function (n_road) {\n var current_road = this.core.road;\n if (!n_road) {\n n_road = this.level.getRoad(this.core.my, this.core.mx);\n ;\n }\n if (n_road != current_road) {\n if (current_road) {\n current_road.cars.splice(current_road.cars.indexOf(this.core.carId), 1);\n }\n this.core.road = n_road;\n this.core.haveTurned = false;\n this.turnedRandom = undefined;\n if (n_road)\n n_road.cars.push(this.core.carId);\n }\n };\n Car.prototype.reset = function () {\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n var road = this.level.getRoad(this.core.my, this.core.mx);\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n };\n Car.prototype.getState = function () {\n return this.motion.state.map(function (arr) { return arr.slice(); });\n };\n Car.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n if (action == null) {\n var _a = this.motion.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n }\n else {\n var _b = this.motion.actionStep(delta, action), agent_col = _b.agent_col, on_road = _b.on_road;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n Car.prototype.createLidar = function (lidarOptions) {\n this.lidar = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Container\"]();\n var area = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n area.pt = false;\n area.alpha = 0.5;\n area.beginFill(0x515151);\n area.drawRect(0, 0, this.core.width * lidarOptions.width, this.core.height * lidarOptions.height);\n area.endFill();\n var x_step = area.width / lidarOptions.pts;\n var y_step = area.height / lidarOptions.pts;\n for (var xs = lidarOptions.pts - 1; xs >= 0; xs--) {\n for (var ys = 0; ys < lidarOptions.pts; ys++) {\n var x = (x_step / 4) + xs * x_step;\n var y = (y_step / 4) + ys * y_step;\n var pt = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n pt.pt = true;\n pt.beginFill(0xffffff);\n pt.drawRect(x, y, 5, 5);\n pt.endFill();\n this.lidar.addChild(pt);\n }\n }\n this.lidar.pts = lidarOptions.pts;\n this.lidar.addChild(area);\n this.lidar.x = this.core.x;\n this.lidar.y = this.core.y;\n this.lidar.pivot.y = this.lidar.height / 2;\n this.lidar.pivot.x = this.core.width / 2 - (lidarOptions.pos * this.core.width);\n this.lidar.rotation = this.core.rotation;\n };\n return Car;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/car.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Car\", function() { return Car; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\nvar Global_carId = 0;\nvar Car = (function () {\n function Car(level, info, textures, options) {\n if (options === void 0) { options = {}; }\n var _this = this;\n this.level = level;\n options.image = options.image || _global__WEBPACK_IMPORTED_MODULE_0__[\"CAR_IMG\"].DEFAULT;\n options.lidar = options.lidar || false;\n options.lidarInfo = options.lidarInfo || { pts: 5, width: 4, height: 5, pos: 0 };\n this.core = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Sprite\"](textures[options.image]);\n this.info = info;\n this.core.scale.x = 0.8;\n this.core.scale.y = 0.8;\n this.core.anchor.x = 0.5;\n this.core.anchor.y = 0.5;\n this.core.road = undefined;\n this.core.carId = Global_carId;\n Global_carId += 1;\n this.core.agent = false;\n this.core.obstacle = true;\n this.core.mapId = _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].CAR;\n if (options.lidar) {\n this.createLidar(options.lidarInfo);\n this.core.lidar = this.lidar;\n }\n if (options.motionEngine) {\n this.motion = options.motionEngine;\n this.motion.setUp(this.core, this.lidar);\n this.core.rotationStep = 0.5;\n }\n else {\n this.core.rotationStep = 0.5;\n }\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n this.core.x = (this.info.mx) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.y = (this.info.my) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.checkAndsetNewRoad = function (road) { return _this.checkAndsetNewRoad(road); };\n var road = this.level.getRoad(this.core.my, this.core.mx);\n this.core.line = 0;\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n }\n Car.prototype.checkAndsetNewRoad = function (n_road) {\n var current_road = this.core.road;\n if (!n_road) {\n n_road = this.level.getRoad(this.core.my, this.core.mx);\n ;\n }\n if (n_road != current_road) {\n if (current_road) {\n current_road.cars.splice(current_road.cars.indexOf(this.core.carId), 1);\n }\n this.core.road = n_road;\n this.core.haveTurned = false;\n this.turnedRandom = undefined;\n if (n_road)\n n_road.cars.push(this.core.carId);\n }\n };\n Car.prototype.reset = function () {\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n var road = this.level.getRoad(this.core.my, this.core.mx);\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n };\n Car.prototype.getState = function (linear) {\n if (linear === void 0) { linear = false; }\n if (!linear)\n return this.motion.state.map(function (arr) { return arr.slice(); });\n else {\n var state_1 = [];\n this.motion.state.map(function (row) { state_1 = state_1.concat(row); });\n return state_1;\n }\n };\n Car.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n if (action == null) {\n var _a = this.motion.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n }\n else {\n var _b = this.motion.actionStep(delta, action), agent_col = _b.agent_col, on_road = _b.on_road;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n Car.prototype.createLidar = function (lidarOptions) {\n this.lidar = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Container\"]();\n var area = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n area.pt = false;\n area.alpha = 0.5;\n area.beginFill(0x515151);\n area.drawRect(0, 0, this.core.width * lidarOptions.width, this.core.height * lidarOptions.height);\n area.endFill();\n var x_step = area.width / lidarOptions.pts;\n var y_step = area.height / lidarOptions.pts;\n for (var xs = lidarOptions.pts - 1; xs >= 0; xs--) {\n for (var ys = 0; ys < lidarOptions.pts; ys++) {\n var x = (x_step / 4) + xs * x_step;\n var y = (y_step / 4) + ys * y_step;\n var pt = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n pt.pt = true;\n pt.beginFill(0xffffff);\n pt.drawRect(x, y, 5, 5);\n pt.endFill();\n this.lidar.addChild(pt);\n }\n }\n this.lidar.pts = lidarOptions.pts;\n this.lidar.addChild(area);\n this.lidar.x = this.core.x;\n this.lidar.y = this.core.y;\n this.lidar.pivot.y = this.lidar.height / 2;\n this.lidar.pivot.x = this.core.width / 2 - (lidarOptions.pos * this.core.width);\n this.lidar.rotation = this.core.rotation;\n };\n return Car;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/car.ts?"); /***/ }), @@ -239,7 +239,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaCar\", function() { return MetaCar; });\n/* harmony import */ var _level__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./level */ \"./src/level.ts\");\n/* harmony import */ var _ui_event__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ui_event */ \"./src/ui_event.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n\n\n\nvar MetaCar = (function () {\n function MetaCar(canvasId, levelToLoad) {\n this.eventList = [\"train\", \"play\", \"stop\", \"reset_env\", \"reset_agent\", \"load\"];\n if (!canvasId || this.levelToLoad) {\n console.error(\"You must specify the canvasId and the levelToLoad\");\n }\n this.canvasId = canvasId;\n this.levelToLoad = levelToLoad;\n }\n MetaCar.prototype._setEvents = function () {\n var _this = this;\n this.event = new _ui_event__WEBPACK_IMPORTED_MODULE_1__[\"UIEvent\"](this.level, this.canvasId);\n this.eventCallback = [\n function (fc) { return _this.event.onTrain(fc); },\n function (fc) { return _this.event.onPlay(fc); },\n function (fc) { return _this.event.onStop(fc); },\n function (fc) { return _this.event.onResetEnv(fc); },\n function (fc) { return _this.event.onResetAgent(fc); },\n function (fc, opt) { return _this.event.onLoad(fc, opt); }\n ];\n };\n MetaCar.prototype.load = function (level, agent) {\n var _this = this;\n return new Promise(function (resolve, reject) {\n console.log(typeof _this.levelToLoad, _this.levelToLoad);\n if (typeof _this.levelToLoad == \"string\") {\n _utils__WEBPACK_IMPORTED_MODULE_2__[\"loadCustomURL\"](_this.levelToLoad, function (content) {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](content, _this.canvasId);\n _this._setEvents();\n _this.level.load(function (delta) { return _this.loop(delta); });\n resolve();\n });\n }\n else {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](_this.levelToLoad, _this.canvasId);\n _this._setEvents();\n _this.level.load(function (delta) { return _this.loop(delta); });\n resolve();\n }\n });\n };\n MetaCar.prototype.addEvent = function (eventName, fc, options) {\n var index = this.eventList.indexOf(eventName);\n if (index == -1) {\n this.event.onCustomEvent(eventName, fc);\n return;\n }\n var event = this.eventList[index];\n if (event != \"load\") {\n this.eventCallback[index](fc);\n }\n else {\n this.eventCallback[index](fc, options);\n }\n };\n MetaCar.prototype.render = function (val) {\n this.level.render(val);\n };\n MetaCar.prototype.save = function (content, file_name) {\n _utils__WEBPACK_IMPORTED_MODULE_2__[\"saveAs\"](content, file_name);\n };\n MetaCar.prototype.actionSpace = function () {\n return this.level.agent.motion.actionSpace();\n };\n MetaCar.prototype.getState = function () {\n return this.level.agent.getState();\n };\n MetaCar.prototype.step = function (action) {\n return this.level.step(1, action);\n };\n MetaCar.prototype.reset = function () {\n this.level.reset();\n };\n MetaCar.prototype.randomRoadPosition = function () {\n var roads = this.level.getRoads();\n var keys = Object.keys(roads);\n keys.sort(function () { return Math.random() - 0.5; });\n for (var k in keys) {\n var road = roads[keys[k]];\n if (road.cars.length == 0) {\n road.setCarPosition(this.level.agent.core);\n break;\n }\n }\n };\n MetaCar.prototype.loop = function (delta) {\n if (this.event.isPlaying()) {\n this.event.playCallback();\n }\n else {\n this.level.step(delta);\n }\n };\n return MetaCar;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/metacar.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaCar\", function() { return MetaCar; });\n/* harmony import */ var _level__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./level */ \"./src/level.ts\");\n/* harmony import */ var _ui_event__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ui_event */ \"./src/ui_event.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n\n\n\nvar MetaCar = (function () {\n function MetaCar(canvasId, levelToLoad) {\n this.eventList = [\"train\", \"play\", \"stop\", \"reset_env\", \"load\"];\n if (!canvasId || !levelToLoad) {\n console.error(\"You must specify the canvasId and the levelToLoad\");\n }\n this.canvasId = canvasId;\n this.levelToLoad = levelToLoad;\n }\n MetaCar.prototype.load = function () {\n var _this = this;\n return new Promise(function (resolve, reject) {\n console.log(typeof _this.levelToLoad, _this.levelToLoad);\n if (typeof _this.levelToLoad == \"string\") {\n _utils__WEBPACK_IMPORTED_MODULE_2__[\"loadCustomURL\"](_this.levelToLoad, function (content) {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](content, _this.canvasId);\n _this._setEvents();\n _this.level.load(function (delta) { return _this._loop(delta); });\n resolve();\n });\n }\n else {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](_this.levelToLoad, _this.canvasId);\n _this._setEvents();\n _this.level.load(function (delta) { return _this._loop(delta); });\n resolve();\n }\n });\n };\n MetaCar.prototype.addEvent = function (eventName, fc, options) {\n var index = this.eventList.indexOf(eventName);\n if (index == -1) {\n this.event.onCustomEvent(eventName, fc);\n return;\n }\n var event = this.eventList[index];\n if (event != \"load\") {\n this.eventCallback[index](fc);\n }\n else {\n this.eventCallback[index](fc, options);\n }\n };\n MetaCar.prototype.render = function (val) {\n this.level.render(val);\n };\n MetaCar.prototype.save = function (content, file_name) {\n _utils__WEBPACK_IMPORTED_MODULE_2__[\"saveAs\"](content, file_name);\n };\n MetaCar.prototype.actionSpace = function () {\n return this.level.agent.motion.actionSpace();\n };\n MetaCar.prototype.getState = function (linear) {\n if (linear === void 0) { linear = false; }\n return this.level.agent.getState(linear);\n };\n MetaCar.prototype.step = function (action) {\n return this.level.step(1, action);\n };\n MetaCar.prototype.reset = function () {\n this.level.reset();\n };\n MetaCar.prototype.randomRoadPosition = function () {\n var roads = this.level.getRoads();\n var keys = Object.keys(roads);\n keys.sort(function () { return Math.random() - 0.5; });\n for (var k in keys) {\n var road = roads[keys[k]];\n if (road.cars.length == 0) {\n road.setCarPosition(this.level.agent.core);\n break;\n }\n }\n };\n MetaCar.prototype._loop = function (delta) {\n if (this.event.isPlaying()) {\n this.event.playCallback();\n }\n else {\n this.level.step(delta);\n }\n };\n MetaCar.prototype._setEvents = function () {\n var _this = this;\n this.event = new _ui_event__WEBPACK_IMPORTED_MODULE_1__[\"UIEvent\"](this.level, this.canvasId);\n this.eventCallback = [\n function (fc) { return _this.event.onTrain(fc); },\n function (fc) { return _this.event.onPlay(fc); },\n function (fc) { return _this.event.onStop(fc); },\n function (fc) { return _this.event.onResetEnv(fc); },\n function (fc, opt) { return _this.event.onLoad(fc, opt); }\n ];\n };\n return MetaCar;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/metacar.ts?"); /***/ }), @@ -275,7 +275,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UIEvent\", function() { return UIEvent; });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\n\nvar UIEvent = (function () {\n function UIEvent(level, canvasId) {\n this.selectedItems = false;\n this.level = level;\n this.canvasId = canvasId;\n var canvas = document.getElementById(canvasId);\n var buttons = document.createElement('div');\n buttons.classList.add(\"metacar_buttons_container\");\n buttons.id = \"metacar_\" + canvasId + \"_buttons_container\";\n canvas.parentNode.insertBefore(buttons, canvas.nextSibling);\n this.buttonsContainer = buttons;\n }\n UIEvent.prototype.isPlaying = function () {\n return this.playing;\n };\n UIEvent.prototype.getEditorSize = function () {\n return { width: this.editorWidth, height: this.editorHeight };\n };\n UIEvent.prototype._createButton = function (parent, name) {\n var button = document.createElement('button');\n button.classList.add(\"metacar_button_train\");\n button.id = \"metacar_\" + this.canvasId + \"_button_\" + name;\n name = name.replace(/_/g, \" \");\n button.innerHTML = name.charAt(0).toUpperCase() + name.slice(1);\n ;\n parent.appendChild(button);\n return button;\n };\n UIEvent.prototype.onTrain = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"train\");\n button.addEventListener(\"click\", function () {\n _this.level.render(false);\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onPlay = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"play\");\n button.addEventListener(\"click\", function () {\n if (fc) {\n _this.playing = true;\n _this.playCallback = fc;\n }\n });\n };\n UIEvent.prototype.onStop = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"stop\");\n button.addEventListener(\"click\", function () {\n _this.playing = false;\n _this.playCallback = undefined;\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onResetEnv = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"reset_env\");\n button.addEventListener(\"click\", function () {\n _this.level.reset();\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onResetAgent = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"reset_agent\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onCustomEvent = function (name, fc) {\n var button = this._createButton(this.buttonsContainer, name);\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onSaveEditor = function (fc, options) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"save\");\n button.addEventListener(\"click\", function () {\n var size = _this.getEditorSize();\n var content = _this.level.exportMap(size.width, size.height, options.name, options.download);\n if (fc)\n fc(content);\n });\n };\n UIEvent.prototype.onLoad = function (fc, options) {\n if (options === void 0) { options = Object(); }\n options.local = options.local || false;\n var button = this._createButton(this.buttonsContainer, \"load_trained_agent\");\n var input_file = document.createElement('input');\n input_file.type = \"file\";\n input_file.accept = \"*/*\";\n input_file.style.display = \"none\";\n input_file.classList.add(\"metacar_button_input_file\");\n input_file.id = \"metacar_\" + this.canvasId + \"_button_input_file\";\n this.buttonsContainer.appendChild(input_file);\n input_file.addEventListener(\"change\", function (dump) {\n _utils__WEBPACK_IMPORTED_MODULE_0__[\"readDump\"](dump, function (content) {\n if (fc)\n fc(content);\n });\n });\n button.addEventListener(\"click\", function () {\n if (options.local) {\n input_file.click();\n }\n else {\n if (fc)\n fc();\n }\n });\n };\n UIEvent.prototype._createRangeBar = function (name) {\n var inputProgress = document.createElement('input');\n inputProgress.type = \"range\";\n inputProgress.min = \"5\";\n inputProgress.max = \"15\";\n inputProgress.value = \"5\";\n inputProgress.classList.add(\"metacar_\" + name + \"_input\");\n inputProgress.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_input\";\n return inputProgress;\n };\n UIEvent.prototype._createSpan = function (name, text) {\n var span = document.createElement('span');\n span.classList.add(\"metacar_\" + name + \"_span\");\n span.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_span\";\n span.innerHTML = text;\n return span;\n };\n UIEvent.prototype._createImage = function (name, src) {\n var img = document.createElement('img');\n img.classList.add(\"metacar_img\");\n img.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_img\";\n img.src = src;\n return img;\n };\n UIEvent.prototype._listenRangeChanges = function (widthInput, heightInput) {\n var _this = this;\n widthInput.onchange = function () {\n var width = parseInt((widthInput).value);\n var height = parseInt((heightInput).value);\n _this.level.resize(width, height);\n _this.editorWidth = width;\n _this.editorHeight = height;\n };\n heightInput.onchange = function () {\n var width = parseInt((widthInput).value);\n var height = parseInt((heightInput).value);\n _this.level.resize(width, height);\n _this.editorWidth = width;\n _this.editorHeight = height;\n };\n };\n UIEvent.prototype._listenCanvasEditor = function () {\n var _this = this;\n document.getElementById(this.canvasId).addEventListener('contextmenu', function (event) { return event.preventDefault(); });\n document.getElementById(this.canvasId).addEventListener(\"click\", function () {\n var selectedItem = _this.level.getSelectedItems();\n if (selectedItem) {\n _this.level.setCurrentItem();\n }\n });\n };\n UIEvent.prototype._listenEditorImgs = function () {\n var classname = document.getElementsByClassName(\"metacar_img\");\n var that = this;\n for (var i = 0; i < classname.length; i++) {\n classname[i].addEventListener('click', function () {\n that.level.selectedItem({\n image: this.getAttribute('data-img'),\n type: this.getAttribute('data-type'),\n data: this.getAttribute(\"data-data\")\n });\n }, false);\n }\n };\n UIEvent.prototype.createEditorElementsEvents = function () {\n var widthText = this._createSpan(\"width\", \"Width\");\n var widthProgress = this._createRangeBar(\"width\");\n var heightText = this._createSpan(\"height\", \"Height\");\n var heightProgress = this._createRangeBar(\"height\");\n this.buttonsContainer.appendChild(widthText);\n this.buttonsContainer.appendChild(widthProgress);\n this.buttonsContainer.appendChild(heightText);\n this.buttonsContainer.appendChild(heightProgress);\n this._listenRangeChanges(widthProgress, heightProgress);\n this._listenCanvasEditor();\n var map = this.level.getMap();\n var width = map[0].length;\n var height = map.length;\n widthProgress.value = width.toString();\n heightProgress.value = height.toString();\n this.editorWidth = width;\n this.editorHeight = height;\n var agentImg = this._createImage(\"car_agent\", _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + \"car_agent.png\");\n agentImg.dataset.type = \"agent\";\n agentImg.dataset.img = \"car_agent.png\";\n this.buttonsContainer.appendChild(agentImg);\n var carImg = this._createImage(\"car_agent\", _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + \"car.png\");\n carImg.dataset.type = \"car\";\n carImg.dataset.img = \"car.png\";\n this.buttonsContainer.appendChild(carImg);\n var roads = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][\"ROADS\"];\n for (var arrow in roads) {\n var nImg = this._createImage(roads[arrow].image.replace(\".png\", \"\"), _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + roads[arrow].image);\n nImg.dataset.type = \"road\";\n nImg.dataset.img = roads[arrow].image;\n nImg.dataset.data = arrow;\n this.buttonsContainer.appendChild(nImg);\n }\n for (var key in _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"]) {\n if (key != \"ROADS\") {\n var nImg = this._createImage(key, _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image);\n nImg.dataset.img = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image;\n nImg.dataset.data = key;\n nImg.dataset.type = \"asset\";\n this.buttonsContainer.appendChild(nImg);\n }\n }\n this._listenEditorImgs();\n };\n return UIEvent;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/ui_event.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UIEvent\", function() { return UIEvent; });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\n\nvar UIEvent = (function () {\n function UIEvent(level, canvasId) {\n this.selectedItems = false;\n this.level = level;\n this.canvasId = canvasId;\n var canvas = document.getElementById(canvasId);\n var buttons = document.createElement('div');\n buttons.classList.add(\"metacar_buttons_container\");\n buttons.id = \"metacar_\" + canvasId + \"_buttons_container\";\n canvas.parentNode.insertBefore(buttons, canvas.nextSibling);\n this.buttonsContainer = buttons;\n }\n UIEvent.prototype.isPlaying = function () {\n return this.playing;\n };\n UIEvent.prototype.getEditorSize = function () {\n return { width: this.editorWidth, height: this.editorHeight };\n };\n UIEvent.prototype._createButton = function (parent, name) {\n var button = document.createElement('button');\n button.classList.add(\"metacar_button_train\");\n button.id = \"metacar_\" + this.canvasId + \"_button_\" + name;\n name = name.replace(/_/g, \" \");\n button.innerHTML = name.charAt(0).toUpperCase() + name.slice(1);\n ;\n parent.appendChild(button);\n return button;\n };\n UIEvent.prototype.onTrain = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"train\");\n button.addEventListener(\"click\", function () {\n _this.level.render(false);\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onPlay = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"play\");\n button.addEventListener(\"click\", function () {\n if (fc) {\n _this.playing = true;\n _this.playCallback = fc;\n }\n });\n };\n UIEvent.prototype.onStop = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"stop\");\n button.addEventListener(\"click\", function () {\n _this.playing = false;\n _this.playCallback = undefined;\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onResetEnv = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"reset_env\");\n button.addEventListener(\"click\", function () {\n _this.level.reset();\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onCustomEvent = function (name, fc) {\n var button = this._createButton(this.buttonsContainer, name);\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onSaveEditor = function (fc, options) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"save\");\n button.addEventListener(\"click\", function () {\n var size = _this.getEditorSize();\n var content = _this.level.exportMap(size.width, size.height, options.name, options.download);\n if (fc)\n fc(content);\n });\n };\n UIEvent.prototype.onLoad = function (fc, options) {\n if (options === void 0) { options = Object(); }\n options.local = options.local || false;\n var button = this._createButton(this.buttonsContainer, \"load_trained_agent\");\n var input_file = document.createElement('input');\n input_file.type = \"file\";\n input_file.accept = \"*/*\";\n input_file.style.display = \"none\";\n input_file.classList.add(\"metacar_button_input_file\");\n input_file.id = \"metacar_\" + this.canvasId + \"_button_input_file\";\n this.buttonsContainer.appendChild(input_file);\n input_file.addEventListener(\"change\", function (dump) {\n _utils__WEBPACK_IMPORTED_MODULE_0__[\"readDump\"](dump, function (content) {\n if (fc)\n fc(content);\n });\n });\n button.addEventListener(\"click\", function () {\n if (options.local) {\n input_file.click();\n }\n else {\n if (fc)\n fc();\n }\n });\n };\n UIEvent.prototype._createRangeBar = function (name) {\n var inputProgress = document.createElement('input');\n inputProgress.type = \"range\";\n inputProgress.min = \"5\";\n inputProgress.max = \"15\";\n inputProgress.value = \"5\";\n inputProgress.classList.add(\"metacar_\" + name + \"_input\");\n inputProgress.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_input\";\n return inputProgress;\n };\n UIEvent.prototype._createSpan = function (name, text) {\n var span = document.createElement('span');\n span.classList.add(\"metacar_\" + name + \"_span\");\n span.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_span\";\n span.innerHTML = text;\n return span;\n };\n UIEvent.prototype._createImage = function (name, src) {\n var img = document.createElement('img');\n img.classList.add(\"metacar_img\");\n img.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_img\";\n img.src = src;\n return img;\n };\n UIEvent.prototype._listenRangeChanges = function (widthInput, heightInput) {\n var _this = this;\n widthInput.onchange = function () {\n var width = parseInt((widthInput).value);\n var height = parseInt((heightInput).value);\n _this.level.resize(width, height);\n _this.editorWidth = width;\n _this.editorHeight = height;\n };\n heightInput.onchange = function () {\n var width = parseInt((widthInput).value);\n var height = parseInt((heightInput).value);\n _this.level.resize(width, height);\n _this.editorWidth = width;\n _this.editorHeight = height;\n };\n };\n UIEvent.prototype._listenCanvasEditor = function () {\n var _this = this;\n document.getElementById(this.canvasId).addEventListener('contextmenu', function (event) { return event.preventDefault(); });\n document.getElementById(this.canvasId).addEventListener(\"click\", function () {\n var selectedItem = _this.level.getSelectedItems();\n if (selectedItem) {\n _this.level.setCurrentItem();\n }\n });\n };\n UIEvent.prototype._listenEditorImgs = function () {\n var classname = document.getElementsByClassName(\"metacar_img\");\n var that = this;\n for (var i = 0; i < classname.length; i++) {\n classname[i].addEventListener('click', function () {\n that.level.selectedItem({\n image: this.getAttribute('data-img'),\n type: this.getAttribute('data-type'),\n data: this.getAttribute(\"data-data\")\n });\n }, false);\n }\n };\n UIEvent.prototype.createEditorElementsEvents = function () {\n var widthText = this._createSpan(\"width\", \"Width\");\n var widthProgress = this._createRangeBar(\"width\");\n var heightText = this._createSpan(\"height\", \"Height\");\n var heightProgress = this._createRangeBar(\"height\");\n this.buttonsContainer.appendChild(widthText);\n this.buttonsContainer.appendChild(widthProgress);\n this.buttonsContainer.appendChild(heightText);\n this.buttonsContainer.appendChild(heightProgress);\n this._listenRangeChanges(widthProgress, heightProgress);\n this._listenCanvasEditor();\n var map = this.level.getMap();\n var width = map[0].length;\n var height = map.length;\n widthProgress.value = width.toString();\n heightProgress.value = height.toString();\n this.editorWidth = width;\n this.editorHeight = height;\n var agentImg = this._createImage(\"car_agent\", _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + \"car_agent.png\");\n agentImg.dataset.type = \"agent\";\n agentImg.dataset.img = \"car_agent.png\";\n this.buttonsContainer.appendChild(agentImg);\n var carImg = this._createImage(\"car_agent\", _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + \"car.png\");\n carImg.dataset.type = \"car\";\n carImg.dataset.img = \"car.png\";\n this.buttonsContainer.appendChild(carImg);\n var roads = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][\"ROADS\"];\n for (var arrow in roads) {\n var nImg = this._createImage(roads[arrow].image.replace(\".png\", \"\"), _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + roads[arrow].image);\n nImg.dataset.type = \"road\";\n nImg.dataset.img = roads[arrow].image;\n nImg.dataset.data = arrow;\n this.buttonsContainer.appendChild(nImg);\n }\n for (var key in _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"]) {\n if (key != \"ROADS\") {\n var nImg = this._createImage(key, _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image);\n nImg.dataset.img = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image;\n nImg.dataset.data = key;\n nImg.dataset.type = \"asset\";\n this.buttonsContainer.appendChild(nImg);\n }\n }\n this._listenEditorImgs();\n };\n return UIEvent;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/ui_event.ts?"); /***/ }), diff --git a/demo/webapp/public/js/level1.js b/demo/webapp/public/js/level1.js index b0ac3db..8901978 100644 --- a/demo/webapp/public/js/level1.js +++ b/demo/webapp/public/js/level1.js @@ -6,7 +6,6 @@ var env = new metacar.env("canvas", levelUrl); // Create the Policy agent var agent = new PolicyAgent(env); - env.load().then(() => { // The level is loaded. Add listernes env.addEvent("train", () => agent.train()); diff --git a/demo/webapp/public/js/policy_agent.js b/demo/webapp/public/js/policy_agent.js index 6489aef..924c457 100644 --- a/demo/webapp/public/js/policy_agent.js +++ b/demo/webapp/public/js/policy_agent.js @@ -22,7 +22,7 @@ class PolicyAgent { Build the Value function @weights (Object) Weights for the layer */ - const LEARNING_RATE = 0.01; + const LEARNING_RATE = 0.05; const value_optimizer = tf.train.adam(LEARNING_RATE); /* ----------------------- @@ -59,7 +59,7 @@ class PolicyAgent { Build the policy network @weights (Object) Weights for the layer */ - const LEARNING_RATE = 0.01; + const LEARNING_RATE = 0.05; this.policy_optimizer = tf.train.adam(LEARNING_RATE); /* ----------------------- @@ -123,17 +123,21 @@ class PolicyAgent { trainPolicy(states, actions, advantages, batch_size, mini_batch_size){ /* Train the policy model - @states (Js array) - @actions (Js array) - @advantages (Js array) + @states Tensor2D + @actions Tensor2D + @advantages Tensor2D @batch_size (Integer) Size of the batch size @mini_batch_size (Integer) Size of each mini batch size */ - for (var b = 0; b < batch_size; b+=mini_batch_size) { + const size = states.shape[0]; - const tf_states = tf.tensor3d(states.slice(b, b+mini_batch_size)).reshape([-1, this.ttLidarPts]); - const tf_actions = tf.tensor1d(actions.slice(b, b+mini_batch_size), "int32"); - const tf_advantages = tf.tensor1d(advantages.slice(b, b+mini_batch_size)); + for (var b = 0; b < batch_size; b+=mini_batch_size) { + + let to = (b + mini_batch_size < size) ? mini_batch_size : (size - b); + + const tf_states = states.slice(b, to); + const tf_actions = actions.slice(b, to); + const tf_advantages = advantages.slice(b, to); this.policy_optimizer.minimize(() => { let softmaxs = this.policyPredict(tf_states); @@ -152,7 +156,7 @@ class PolicyAgent { // Maximum number of step per episode this.nb_step = 800; this.mini_batch_size = 200; - this.episodeNb = 250; + this.episodeNb = 100; } save(env){ @@ -211,28 +215,32 @@ class PolicyAgent { let reward = 0; const rewards = []; const states = []; + const stateValues = []; const actions = []; console.log("---"); console.time("Exploring"); for (var step = 0; step < this.nb_step; step++) { // Get the current state - const array_st = this.env.getState(); + const array_st = this.env.getState(true); // Convert the state into a tensor - const st = tf.tensor(array_st, [this.lidarPts, this.lidarPts]).reshape([1, this.ttLidarPts]); + //const st = tf.tensor(array_st, [this.lidarPts, this.lidarPts]).reshape([1, this.ttLidarPts]); + const st = tf.tensor2d([array_st]); // Predict the policy - const softmax = this.policyPredict(st); + const softmax = this.policyModel.predict(st); + // Predict the value + const value = this.valueModel.predict(st); // Get the action. Pseudo Random choice. We prefer action with // Higher probability const action = randomChoice(softmax.buffer().values); // Create the next batch rewards.push(reward); states.push(array_st); + stateValues.push(value); actions.push(action); // Stop the episode if the car go out of the road or crash an // other car if (reward == -10){ - console.log("Early stop Episode"); softmax.dispose(); st.dispose(); break; @@ -258,24 +266,28 @@ class PolicyAgent { G = rewards[t] + (this.gamma*G); returns.push(G); // Predict the value function for this state - const st = tf.tensor2d(states[t], [this.lidarPts, this.lidarPts]).reshape([1, this.ttLidarPts]); - const Vs = this.valueModel.predict(st); + const V = stateValues[t]; // Advantage - advantages.push(G - Vs.buffer().values[0]); - st.dispose(); - Vs.dispose(); + advantages.push(G - V.buffer().values[0]); + V.dispose(); } returns = returns.reverse(); advantages = advantages.reverse(); // Train the value model - const tf_batch_states = tf.tensor3d(states).reshape([batch_size, this.ttLidarPts]); + const tf_batch_states = tf.tensor2d(states); const tf_value_target = tf.tensor1d(returns); + const tf_actions = tf.tensor1d(actions, "int32"); + const tf_advantages = tf.tensor1d(advantages); await this.trainValueFc(tf_batch_states, tf_value_target, mini_batch_size); + // Train the policy model + this.trainPolicy(tf_batch_states, tf_actions, tf_advantages, batch_size, mini_batch_size); + tf_batch_states.dispose(); tf_value_target.dispose(); - // Train the policy model - this.trainPolicy(states, actions, advantages, batch_size, mini_batch_size); + tf_actions.dispose(); + tf_advantages.dispose(); + // Set the agent on a new free road this.env.randomRoadPosition(); //env.reset(); diff --git a/demo/webapp/public/models/policy-model-policy-agent.json b/demo/webapp/public/models/policy-model-policy-agent.json deleted file mode 100644 index 5f2819f..0000000 --- a/demo/webapp/public/models/policy-model-policy-agent.json +++ /dev/null @@ -1 +0,0 @@ -{"modelTopology":{"class_name":"Model","config":{"name":"model1","layers":[{"name":"input1","class_name":"InputLayer","config":{"batch_input_shape":[null,25],"dtype":"float32","sparse":false,"name":"input1"},"inbound_nodes":[]},{"name":"dense_Dense3","class_name":"Dense","config":{"units":9,"activation":"tanh","use_bias":true,"kernel_initializer":{"class_name":"RandomNormal","config":{"mean":0,"stddev":0.05,"seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense3","trainable":true,"batch_input_shape":[null,25],"dtype":"float32"},"inbound_nodes":[[["input1",0,0,{}]]]},{"name":"dense_Dense4","class_name":"Dense","config":{"units":3,"activation":"softmax","use_bias":true,"kernel_initializer":{"class_name":"RandomNormal","config":{"mean":0,"stddev":0.05,"seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense4","trainable":true,"batch_input_shape":[null,9],"dtype":"float32"},"inbound_nodes":[[["dense_Dense3",0,0,{}]]]}],"input_layers":[["input1",0,0]],"output_layers":[["dense_Dense4",0,0]]},"keras_version":"tfjs-layers 0.6.6","backend":"tensor_flow.js"},"weightsManifest":[{"paths":["./policy-model-policy-agent.weights.bin"],"weights":[{"name":"dense_Dense3/kernel","shape":[25,9],"dtype":"float32"},{"name":"dense_Dense3/bias","shape":[9],"dtype":"float32"},{"name":"dense_Dense4/kernel","shape":[9,3],"dtype":"float32"},{"name":"dense_Dense4/bias","shape":[3],"dtype":"float32"}]}]} \ No newline at end of file diff --git a/demo/webapp/public/models/policy/policy-model-policy-agent.weights.bin b/demo/webapp/public/models/policy/policy-model-policy-agent.weights.bin deleted file mode 100644 index 757ab32..0000000 Binary files a/demo/webapp/public/models/policy/policy-model-policy-agent.weights.bin and /dev/null differ diff --git a/demo/webapp/public/models/policy/value-model-policy-agent.weights.bin b/demo/webapp/public/models/policy/value-model-policy-agent.weights.bin index cf13e0b..4fb897e 100644 Binary files a/demo/webapp/public/models/policy/value-model-policy-agent.weights.bin and b/demo/webapp/public/models/policy/value-model-policy-agent.weights.bin differ diff --git a/demo/webapp/public/models/value-model-policy-agent.json b/demo/webapp/public/models/value-model-policy-agent.json deleted file mode 100644 index 4f8b75a..0000000 --- a/demo/webapp/public/models/value-model-policy-agent.json +++ /dev/null @@ -1 +0,0 @@ -{"modelTopology":{"class_name":"Sequential","config":[{"class_name":"Dense","config":{"units":9,"activation":"tanh","use_bias":true,"kernel_initializer":{"class_name":"RandomNormal","config":{"mean":0,"stddev":0.05,"seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense1","trainable":true,"batch_input_shape":[null,25],"dtype":"float32"}},{"class_name":"Dense","config":{"units":1,"activation":"linear","use_bias":true,"kernel_initializer":{"class_name":"RandomNormal","config":{"mean":0,"stddev":0.05,"seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense2","trainable":true,"batch_input_shape":[null,9],"dtype":"float32"}}],"keras_version":"tfjs-layers 0.6.6","backend":"tensor_flow.js"},"weightsManifest":[{"paths":["./value-model-policy-agent.weights.bin"],"weights":[{"name":"dense_Dense1/kernel","shape":[25,9],"dtype":"float32"},{"name":"dense_Dense1/bias","shape":[9],"dtype":"float32"},{"name":"dense_Dense2/kernel","shape":[9,1],"dtype":"float32"},{"name":"dense_Dense2/bias","shape":[1],"dtype":"float32"}]}]} \ No newline at end of file diff --git a/demo/webapp/public/models/value-model-policy-agent.weights.bin b/demo/webapp/public/models/value-model-policy-agent.weights.bin deleted file mode 100644 index 4fb897e..0000000 Binary files a/demo/webapp/public/models/value-model-policy-agent.weights.bin and /dev/null differ diff --git a/dist/metacar.min.js b/dist/metacar.min.js index e9742e5..8513460 100644 --- a/dist/metacar.min.js +++ b/dist/metacar.min.js @@ -131,7 +131,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Car\", function() { return Car; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\nvar Global_carId = 0;\nvar Car = (function () {\n function Car(level, info, textures, options) {\n if (options === void 0) { options = {}; }\n var _this = this;\n this.level = level;\n options.image = options.image || _global__WEBPACK_IMPORTED_MODULE_0__[\"CAR_IMG\"].DEFAULT;\n options.lidar = options.lidar || false;\n options.lidarInfo = options.lidarInfo || { pts: 5, width: 4, height: 5, pos: 0 };\n this.core = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Sprite\"](textures[options.image]);\n this.info = info;\n this.core.scale.x = 0.8;\n this.core.scale.y = 0.8;\n this.core.anchor.x = 0.5;\n this.core.anchor.y = 0.5;\n this.core.road = undefined;\n this.core.carId = Global_carId;\n Global_carId += 1;\n this.core.agent = false;\n this.core.obstacle = true;\n this.core.mapId = _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].CAR;\n if (options.lidar) {\n this.createLidar(options.lidarInfo);\n this.core.lidar = this.lidar;\n }\n if (options.motionEngine) {\n this.motion = options.motionEngine;\n this.motion.setUp(this.core, this.lidar);\n this.core.rotationStep = 0.5;\n }\n else {\n this.core.rotationStep = 0.5;\n }\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n this.core.x = (this.info.mx) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.y = (this.info.my) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.checkAndsetNewRoad = function (road) { return _this.checkAndsetNewRoad(road); };\n var road = this.level.getRoad(this.core.my, this.core.mx);\n this.core.line = 0;\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n }\n Car.prototype.checkAndsetNewRoad = function (n_road) {\n var current_road = this.core.road;\n if (!n_road) {\n n_road = this.level.getRoad(this.core.my, this.core.mx);\n ;\n }\n if (n_road != current_road) {\n if (current_road) {\n current_road.cars.splice(current_road.cars.indexOf(this.core.carId), 1);\n }\n this.core.road = n_road;\n this.core.haveTurned = false;\n this.turnedRandom = undefined;\n if (n_road)\n n_road.cars.push(this.core.carId);\n }\n };\n Car.prototype.reset = function () {\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n var road = this.level.getRoad(this.core.my, this.core.mx);\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n };\n Car.prototype.getState = function () {\n return this.motion.state.map(function (arr) { return arr.slice(); });\n };\n Car.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n if (action == null) {\n var _a = this.motion.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n }\n else {\n var _b = this.motion.actionStep(delta, action), agent_col = _b.agent_col, on_road = _b.on_road;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n Car.prototype.createLidar = function (lidarOptions) {\n this.lidar = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Container\"]();\n var area = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n area.pt = false;\n area.alpha = 0.5;\n area.beginFill(0x515151);\n area.drawRect(0, 0, this.core.width * lidarOptions.width, this.core.height * lidarOptions.height);\n area.endFill();\n var x_step = area.width / lidarOptions.pts;\n var y_step = area.height / lidarOptions.pts;\n for (var xs = lidarOptions.pts - 1; xs >= 0; xs--) {\n for (var ys = 0; ys < lidarOptions.pts; ys++) {\n var x = (x_step / 4) + xs * x_step;\n var y = (y_step / 4) + ys * y_step;\n var pt = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n pt.pt = true;\n pt.beginFill(0xffffff);\n pt.drawRect(x, y, 5, 5);\n pt.endFill();\n this.lidar.addChild(pt);\n }\n }\n this.lidar.pts = lidarOptions.pts;\n this.lidar.addChild(area);\n this.lidar.x = this.core.x;\n this.lidar.y = this.core.y;\n this.lidar.pivot.y = this.lidar.height / 2;\n this.lidar.pivot.x = this.core.width / 2 - (lidarOptions.pos * this.core.width);\n this.lidar.rotation = this.core.rotation;\n };\n return Car;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/car.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Car\", function() { return Car; });\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\nvar Global_carId = 0;\nvar Car = (function () {\n function Car(level, info, textures, options) {\n if (options === void 0) { options = {}; }\n var _this = this;\n this.level = level;\n options.image = options.image || _global__WEBPACK_IMPORTED_MODULE_0__[\"CAR_IMG\"].DEFAULT;\n options.lidar = options.lidar || false;\n options.lidarInfo = options.lidarInfo || { pts: 5, width: 4, height: 5, pos: 0 };\n this.core = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Sprite\"](textures[options.image]);\n this.info = info;\n this.core.scale.x = 0.8;\n this.core.scale.y = 0.8;\n this.core.anchor.x = 0.5;\n this.core.anchor.y = 0.5;\n this.core.road = undefined;\n this.core.carId = Global_carId;\n Global_carId += 1;\n this.core.agent = false;\n this.core.obstacle = true;\n this.core.mapId = _global__WEBPACK_IMPORTED_MODULE_0__[\"MAP\"].CAR;\n if (options.lidar) {\n this.createLidar(options.lidarInfo);\n this.core.lidar = this.lidar;\n }\n if (options.motionEngine) {\n this.motion = options.motionEngine;\n this.motion.setUp(this.core, this.lidar);\n this.core.rotationStep = 0.5;\n }\n else {\n this.core.rotationStep = 0.5;\n }\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n this.core.x = (this.info.mx) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.y = (this.info.my) * _global__WEBPACK_IMPORTED_MODULE_0__[\"ROADSIZE\"];\n this.core.checkAndsetNewRoad = function (road) { return _this.checkAndsetNewRoad(road); };\n var road = this.level.getRoad(this.core.my, this.core.mx);\n this.core.line = 0;\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n }\n Car.prototype.checkAndsetNewRoad = function (n_road) {\n var current_road = this.core.road;\n if (!n_road) {\n n_road = this.level.getRoad(this.core.my, this.core.mx);\n ;\n }\n if (n_road != current_road) {\n if (current_road) {\n current_road.cars.splice(current_road.cars.indexOf(this.core.carId), 1);\n }\n this.core.road = n_road;\n this.core.haveTurned = false;\n this.turnedRandom = undefined;\n if (n_road)\n n_road.cars.push(this.core.carId);\n }\n };\n Car.prototype.reset = function () {\n this.core.mx = this.info.mx;\n this.core.my = this.info.my;\n var road = this.level.getRoad(this.core.my, this.core.mx);\n if (road) {\n road.setCarPosition(this.core, this.info.line);\n }\n };\n Car.prototype.getState = function (linear) {\n if (linear === void 0) { linear = false; }\n if (!linear)\n return this.motion.state.map(function (arr) { return arr.slice(); });\n else {\n var state_1 = [];\n this.motion.state.map(function (row) { state_1 = state_1.concat(row); });\n return state_1;\n }\n };\n Car.prototype.step = function (delta, action) {\n if (action === void 0) { action = null; }\n if (action == null) {\n var _a = this.motion.step(delta), agent_col = _a.agent_col, on_road = _a.on_road;\n }\n else {\n var _b = this.motion.actionStep(delta, action), agent_col = _b.agent_col, on_road = _b.on_road;\n }\n return { agent_col: agent_col, on_road: on_road };\n };\n Car.prototype.createLidar = function (lidarOptions) {\n this.lidar = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Container\"]();\n var area = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n area.pt = false;\n area.alpha = 0.5;\n area.beginFill(0x515151);\n area.drawRect(0, 0, this.core.width * lidarOptions.width, this.core.height * lidarOptions.height);\n area.endFill();\n var x_step = area.width / lidarOptions.pts;\n var y_step = area.height / lidarOptions.pts;\n for (var xs = lidarOptions.pts - 1; xs >= 0; xs--) {\n for (var ys = 0; ys < lidarOptions.pts; ys++) {\n var x = (x_step / 4) + xs * x_step;\n var y = (y_step / 4) + ys * y_step;\n var pt = new _global__WEBPACK_IMPORTED_MODULE_0__[\"Graphics\"]();\n pt.pt = true;\n pt.beginFill(0xffffff);\n pt.drawRect(x, y, 5, 5);\n pt.endFill();\n this.lidar.addChild(pt);\n }\n }\n this.lidar.pts = lidarOptions.pts;\n this.lidar.addChild(area);\n this.lidar.x = this.core.x;\n this.lidar.y = this.core.y;\n this.lidar.pivot.y = this.lidar.height / 2;\n this.lidar.pivot.x = this.core.width / 2 - (lidarOptions.pos * this.core.width);\n this.lidar.rotation = this.core.rotation;\n };\n return Car;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/car.ts?"); /***/ }), @@ -239,7 +239,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaCar\", function() { return MetaCar; });\n/* harmony import */ var _level__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./level */ \"./src/level.ts\");\n/* harmony import */ var _ui_event__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ui_event */ \"./src/ui_event.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n\n\n\nvar MetaCar = (function () {\n function MetaCar(canvasId, levelToLoad) {\n this.eventList = [\"train\", \"play\", \"stop\", \"reset_env\", \"reset_agent\", \"load\"];\n if (!canvasId || this.levelToLoad) {\n console.error(\"You must specify the canvasId and the levelToLoad\");\n }\n this.canvasId = canvasId;\n this.levelToLoad = levelToLoad;\n }\n MetaCar.prototype._setEvents = function () {\n var _this = this;\n this.event = new _ui_event__WEBPACK_IMPORTED_MODULE_1__[\"UIEvent\"](this.level, this.canvasId);\n this.eventCallback = [\n function (fc) { return _this.event.onTrain(fc); },\n function (fc) { return _this.event.onPlay(fc); },\n function (fc) { return _this.event.onStop(fc); },\n function (fc) { return _this.event.onResetEnv(fc); },\n function (fc) { return _this.event.onResetAgent(fc); },\n function (fc, opt) { return _this.event.onLoad(fc, opt); }\n ];\n };\n MetaCar.prototype.load = function (level, agent) {\n var _this = this;\n return new Promise(function (resolve, reject) {\n console.log(typeof _this.levelToLoad, _this.levelToLoad);\n if (typeof _this.levelToLoad == \"string\") {\n _utils__WEBPACK_IMPORTED_MODULE_2__[\"loadCustomURL\"](_this.levelToLoad, function (content) {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](content, _this.canvasId);\n _this._setEvents();\n _this.level.load(function (delta) { return _this.loop(delta); });\n resolve();\n });\n }\n else {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](_this.levelToLoad, _this.canvasId);\n _this._setEvents();\n _this.level.load(function (delta) { return _this.loop(delta); });\n resolve();\n }\n });\n };\n MetaCar.prototype.addEvent = function (eventName, fc, options) {\n var index = this.eventList.indexOf(eventName);\n if (index == -1) {\n this.event.onCustomEvent(eventName, fc);\n return;\n }\n var event = this.eventList[index];\n if (event != \"load\") {\n this.eventCallback[index](fc);\n }\n else {\n this.eventCallback[index](fc, options);\n }\n };\n MetaCar.prototype.render = function (val) {\n this.level.render(val);\n };\n MetaCar.prototype.save = function (content, file_name) {\n _utils__WEBPACK_IMPORTED_MODULE_2__[\"saveAs\"](content, file_name);\n };\n MetaCar.prototype.actionSpace = function () {\n return this.level.agent.motion.actionSpace();\n };\n MetaCar.prototype.getState = function () {\n return this.level.agent.getState();\n };\n MetaCar.prototype.step = function (action) {\n return this.level.step(1, action);\n };\n MetaCar.prototype.reset = function () {\n this.level.reset();\n };\n MetaCar.prototype.randomRoadPosition = function () {\n var roads = this.level.getRoads();\n var keys = Object.keys(roads);\n keys.sort(function () { return Math.random() - 0.5; });\n for (var k in keys) {\n var road = roads[keys[k]];\n if (road.cars.length == 0) {\n road.setCarPosition(this.level.agent.core);\n break;\n }\n }\n };\n MetaCar.prototype.loop = function (delta) {\n if (this.event.isPlaying()) {\n this.event.playCallback();\n }\n else {\n this.level.step(delta);\n }\n };\n return MetaCar;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/metacar.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"MetaCar\", function() { return MetaCar; });\n/* harmony import */ var _level__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./level */ \"./src/level.ts\");\n/* harmony import */ var _ui_event__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ui_event */ \"./src/ui_event.ts\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n\n\n\nvar MetaCar = (function () {\n function MetaCar(canvasId, levelToLoad) {\n this.eventList = [\"train\", \"play\", \"stop\", \"reset_env\", \"load\"];\n if (!canvasId || !levelToLoad) {\n console.error(\"You must specify the canvasId and the levelToLoad\");\n }\n this.canvasId = canvasId;\n this.levelToLoad = levelToLoad;\n }\n MetaCar.prototype.load = function () {\n var _this = this;\n return new Promise(function (resolve, reject) {\n console.log(typeof _this.levelToLoad, _this.levelToLoad);\n if (typeof _this.levelToLoad == \"string\") {\n _utils__WEBPACK_IMPORTED_MODULE_2__[\"loadCustomURL\"](_this.levelToLoad, function (content) {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](content, _this.canvasId);\n _this._setEvents();\n _this.level.load(function (delta) { return _this._loop(delta); });\n resolve();\n });\n }\n else {\n _this.level = new _level__WEBPACK_IMPORTED_MODULE_0__[\"Level\"](_this.levelToLoad, _this.canvasId);\n _this._setEvents();\n _this.level.load(function (delta) { return _this._loop(delta); });\n resolve();\n }\n });\n };\n MetaCar.prototype.addEvent = function (eventName, fc, options) {\n var index = this.eventList.indexOf(eventName);\n if (index == -1) {\n this.event.onCustomEvent(eventName, fc);\n return;\n }\n var event = this.eventList[index];\n if (event != \"load\") {\n this.eventCallback[index](fc);\n }\n else {\n this.eventCallback[index](fc, options);\n }\n };\n MetaCar.prototype.render = function (val) {\n this.level.render(val);\n };\n MetaCar.prototype.save = function (content, file_name) {\n _utils__WEBPACK_IMPORTED_MODULE_2__[\"saveAs\"](content, file_name);\n };\n MetaCar.prototype.actionSpace = function () {\n return this.level.agent.motion.actionSpace();\n };\n MetaCar.prototype.getState = function (linear) {\n if (linear === void 0) { linear = false; }\n return this.level.agent.getState(linear);\n };\n MetaCar.prototype.step = function (action) {\n return this.level.step(1, action);\n };\n MetaCar.prototype.reset = function () {\n this.level.reset();\n };\n MetaCar.prototype.randomRoadPosition = function () {\n var roads = this.level.getRoads();\n var keys = Object.keys(roads);\n keys.sort(function () { return Math.random() - 0.5; });\n for (var k in keys) {\n var road = roads[keys[k]];\n if (road.cars.length == 0) {\n road.setCarPosition(this.level.agent.core);\n break;\n }\n }\n };\n MetaCar.prototype._loop = function (delta) {\n if (this.event.isPlaying()) {\n this.event.playCallback();\n }\n else {\n this.level.step(delta);\n }\n };\n MetaCar.prototype._setEvents = function () {\n var _this = this;\n this.event = new _ui_event__WEBPACK_IMPORTED_MODULE_1__[\"UIEvent\"](this.level, this.canvasId);\n this.eventCallback = [\n function (fc) { return _this.event.onTrain(fc); },\n function (fc) { return _this.event.onPlay(fc); },\n function (fc) { return _this.event.onStop(fc); },\n function (fc) { return _this.event.onResetEnv(fc); },\n function (fc, opt) { return _this.event.onLoad(fc, opt); }\n ];\n };\n return MetaCar;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/metacar.ts?"); /***/ }), @@ -275,7 +275,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UIEvent\", function() { return UIEvent; });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\n\nvar UIEvent = (function () {\n function UIEvent(level, canvasId) {\n this.selectedItems = false;\n this.level = level;\n this.canvasId = canvasId;\n var canvas = document.getElementById(canvasId);\n var buttons = document.createElement('div');\n buttons.classList.add(\"metacar_buttons_container\");\n buttons.id = \"metacar_\" + canvasId + \"_buttons_container\";\n canvas.parentNode.insertBefore(buttons, canvas.nextSibling);\n this.buttonsContainer = buttons;\n }\n UIEvent.prototype.isPlaying = function () {\n return this.playing;\n };\n UIEvent.prototype.getEditorSize = function () {\n return { width: this.editorWidth, height: this.editorHeight };\n };\n UIEvent.prototype._createButton = function (parent, name) {\n var button = document.createElement('button');\n button.classList.add(\"metacar_button_train\");\n button.id = \"metacar_\" + this.canvasId + \"_button_\" + name;\n name = name.replace(/_/g, \" \");\n button.innerHTML = name.charAt(0).toUpperCase() + name.slice(1);\n ;\n parent.appendChild(button);\n return button;\n };\n UIEvent.prototype.onTrain = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"train\");\n button.addEventListener(\"click\", function () {\n _this.level.render(false);\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onPlay = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"play\");\n button.addEventListener(\"click\", function () {\n if (fc) {\n _this.playing = true;\n _this.playCallback = fc;\n }\n });\n };\n UIEvent.prototype.onStop = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"stop\");\n button.addEventListener(\"click\", function () {\n _this.playing = false;\n _this.playCallback = undefined;\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onResetEnv = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"reset_env\");\n button.addEventListener(\"click\", function () {\n _this.level.reset();\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onResetAgent = function (fc) {\n var button = this._createButton(this.buttonsContainer, \"reset_agent\");\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onCustomEvent = function (name, fc) {\n var button = this._createButton(this.buttonsContainer, name);\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onSaveEditor = function (fc, options) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"save\");\n button.addEventListener(\"click\", function () {\n var size = _this.getEditorSize();\n var content = _this.level.exportMap(size.width, size.height, options.name, options.download);\n if (fc)\n fc(content);\n });\n };\n UIEvent.prototype.onLoad = function (fc, options) {\n if (options === void 0) { options = Object(); }\n options.local = options.local || false;\n var button = this._createButton(this.buttonsContainer, \"load_trained_agent\");\n var input_file = document.createElement('input');\n input_file.type = \"file\";\n input_file.accept = \"*/*\";\n input_file.style.display = \"none\";\n input_file.classList.add(\"metacar_button_input_file\");\n input_file.id = \"metacar_\" + this.canvasId + \"_button_input_file\";\n this.buttonsContainer.appendChild(input_file);\n input_file.addEventListener(\"change\", function (dump) {\n _utils__WEBPACK_IMPORTED_MODULE_0__[\"readDump\"](dump, function (content) {\n if (fc)\n fc(content);\n });\n });\n button.addEventListener(\"click\", function () {\n if (options.local) {\n input_file.click();\n }\n else {\n if (fc)\n fc();\n }\n });\n };\n UIEvent.prototype._createRangeBar = function (name) {\n var inputProgress = document.createElement('input');\n inputProgress.type = \"range\";\n inputProgress.min = \"5\";\n inputProgress.max = \"15\";\n inputProgress.value = \"5\";\n inputProgress.classList.add(\"metacar_\" + name + \"_input\");\n inputProgress.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_input\";\n return inputProgress;\n };\n UIEvent.prototype._createSpan = function (name, text) {\n var span = document.createElement('span');\n span.classList.add(\"metacar_\" + name + \"_span\");\n span.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_span\";\n span.innerHTML = text;\n return span;\n };\n UIEvent.prototype._createImage = function (name, src) {\n var img = document.createElement('img');\n img.classList.add(\"metacar_img\");\n img.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_img\";\n img.src = src;\n return img;\n };\n UIEvent.prototype._listenRangeChanges = function (widthInput, heightInput) {\n var _this = this;\n widthInput.onchange = function () {\n var width = parseInt((widthInput).value);\n var height = parseInt((heightInput).value);\n _this.level.resize(width, height);\n _this.editorWidth = width;\n _this.editorHeight = height;\n };\n heightInput.onchange = function () {\n var width = parseInt((widthInput).value);\n var height = parseInt((heightInput).value);\n _this.level.resize(width, height);\n _this.editorWidth = width;\n _this.editorHeight = height;\n };\n };\n UIEvent.prototype._listenCanvasEditor = function () {\n var _this = this;\n document.getElementById(this.canvasId).addEventListener('contextmenu', function (event) { return event.preventDefault(); });\n document.getElementById(this.canvasId).addEventListener(\"click\", function () {\n var selectedItem = _this.level.getSelectedItems();\n if (selectedItem) {\n _this.level.setCurrentItem();\n }\n });\n };\n UIEvent.prototype._listenEditorImgs = function () {\n var classname = document.getElementsByClassName(\"metacar_img\");\n var that = this;\n for (var i = 0; i < classname.length; i++) {\n classname[i].addEventListener('click', function () {\n that.level.selectedItem({\n image: this.getAttribute('data-img'),\n type: this.getAttribute('data-type'),\n data: this.getAttribute(\"data-data\")\n });\n }, false);\n }\n };\n UIEvent.prototype.createEditorElementsEvents = function () {\n var widthText = this._createSpan(\"width\", \"Width\");\n var widthProgress = this._createRangeBar(\"width\");\n var heightText = this._createSpan(\"height\", \"Height\");\n var heightProgress = this._createRangeBar(\"height\");\n this.buttonsContainer.appendChild(widthText);\n this.buttonsContainer.appendChild(widthProgress);\n this.buttonsContainer.appendChild(heightText);\n this.buttonsContainer.appendChild(heightProgress);\n this._listenRangeChanges(widthProgress, heightProgress);\n this._listenCanvasEditor();\n var map = this.level.getMap();\n var width = map[0].length;\n var height = map.length;\n widthProgress.value = width.toString();\n heightProgress.value = height.toString();\n this.editorWidth = width;\n this.editorHeight = height;\n var agentImg = this._createImage(\"car_agent\", _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + \"car_agent.png\");\n agentImg.dataset.type = \"agent\";\n agentImg.dataset.img = \"car_agent.png\";\n this.buttonsContainer.appendChild(agentImg);\n var carImg = this._createImage(\"car_agent\", _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + \"car.png\");\n carImg.dataset.type = \"car\";\n carImg.dataset.img = \"car.png\";\n this.buttonsContainer.appendChild(carImg);\n var roads = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][\"ROADS\"];\n for (var arrow in roads) {\n var nImg = this._createImage(roads[arrow].image.replace(\".png\", \"\"), _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + roads[arrow].image);\n nImg.dataset.type = \"road\";\n nImg.dataset.img = roads[arrow].image;\n nImg.dataset.data = arrow;\n this.buttonsContainer.appendChild(nImg);\n }\n for (var key in _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"]) {\n if (key != \"ROADS\") {\n var nImg = this._createImage(key, _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image);\n nImg.dataset.img = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image;\n nImg.dataset.data = key;\n nImg.dataset.type = \"asset\";\n this.buttonsContainer.appendChild(nImg);\n }\n }\n this._listenEditorImgs();\n };\n return UIEvent;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/ui_event.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UIEvent\", function() { return UIEvent; });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ \"./src/utils.ts\");\n/* harmony import */ var _global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./global */ \"./src/global.ts\");\n\n\nvar UIEvent = (function () {\n function UIEvent(level, canvasId) {\n this.selectedItems = false;\n this.level = level;\n this.canvasId = canvasId;\n var canvas = document.getElementById(canvasId);\n var buttons = document.createElement('div');\n buttons.classList.add(\"metacar_buttons_container\");\n buttons.id = \"metacar_\" + canvasId + \"_buttons_container\";\n canvas.parentNode.insertBefore(buttons, canvas.nextSibling);\n this.buttonsContainer = buttons;\n }\n UIEvent.prototype.isPlaying = function () {\n return this.playing;\n };\n UIEvent.prototype.getEditorSize = function () {\n return { width: this.editorWidth, height: this.editorHeight };\n };\n UIEvent.prototype._createButton = function (parent, name) {\n var button = document.createElement('button');\n button.classList.add(\"metacar_button_train\");\n button.id = \"metacar_\" + this.canvasId + \"_button_\" + name;\n name = name.replace(/_/g, \" \");\n button.innerHTML = name.charAt(0).toUpperCase() + name.slice(1);\n ;\n parent.appendChild(button);\n return button;\n };\n UIEvent.prototype.onTrain = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"train\");\n button.addEventListener(\"click\", function () {\n _this.level.render(false);\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onPlay = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"play\");\n button.addEventListener(\"click\", function () {\n if (fc) {\n _this.playing = true;\n _this.playCallback = fc;\n }\n });\n };\n UIEvent.prototype.onStop = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"stop\");\n button.addEventListener(\"click\", function () {\n _this.playing = false;\n _this.playCallback = undefined;\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onResetEnv = function (fc) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"reset_env\");\n button.addEventListener(\"click\", function () {\n _this.level.reset();\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onCustomEvent = function (name, fc) {\n var button = this._createButton(this.buttonsContainer, name);\n button.addEventListener(\"click\", function () {\n if (fc)\n fc();\n });\n };\n UIEvent.prototype.onSaveEditor = function (fc, options) {\n var _this = this;\n var button = this._createButton(this.buttonsContainer, \"save\");\n button.addEventListener(\"click\", function () {\n var size = _this.getEditorSize();\n var content = _this.level.exportMap(size.width, size.height, options.name, options.download);\n if (fc)\n fc(content);\n });\n };\n UIEvent.prototype.onLoad = function (fc, options) {\n if (options === void 0) { options = Object(); }\n options.local = options.local || false;\n var button = this._createButton(this.buttonsContainer, \"load_trained_agent\");\n var input_file = document.createElement('input');\n input_file.type = \"file\";\n input_file.accept = \"*/*\";\n input_file.style.display = \"none\";\n input_file.classList.add(\"metacar_button_input_file\");\n input_file.id = \"metacar_\" + this.canvasId + \"_button_input_file\";\n this.buttonsContainer.appendChild(input_file);\n input_file.addEventListener(\"change\", function (dump) {\n _utils__WEBPACK_IMPORTED_MODULE_0__[\"readDump\"](dump, function (content) {\n if (fc)\n fc(content);\n });\n });\n button.addEventListener(\"click\", function () {\n if (options.local) {\n input_file.click();\n }\n else {\n if (fc)\n fc();\n }\n });\n };\n UIEvent.prototype._createRangeBar = function (name) {\n var inputProgress = document.createElement('input');\n inputProgress.type = \"range\";\n inputProgress.min = \"5\";\n inputProgress.max = \"15\";\n inputProgress.value = \"5\";\n inputProgress.classList.add(\"metacar_\" + name + \"_input\");\n inputProgress.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_input\";\n return inputProgress;\n };\n UIEvent.prototype._createSpan = function (name, text) {\n var span = document.createElement('span');\n span.classList.add(\"metacar_\" + name + \"_span\");\n span.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_span\";\n span.innerHTML = text;\n return span;\n };\n UIEvent.prototype._createImage = function (name, src) {\n var img = document.createElement('img');\n img.classList.add(\"metacar_img\");\n img.id = \"metacar_\" + this.canvasId + \"_\" + name + \"_img\";\n img.src = src;\n return img;\n };\n UIEvent.prototype._listenRangeChanges = function (widthInput, heightInput) {\n var _this = this;\n widthInput.onchange = function () {\n var width = parseInt((widthInput).value);\n var height = parseInt((heightInput).value);\n _this.level.resize(width, height);\n _this.editorWidth = width;\n _this.editorHeight = height;\n };\n heightInput.onchange = function () {\n var width = parseInt((widthInput).value);\n var height = parseInt((heightInput).value);\n _this.level.resize(width, height);\n _this.editorWidth = width;\n _this.editorHeight = height;\n };\n };\n UIEvent.prototype._listenCanvasEditor = function () {\n var _this = this;\n document.getElementById(this.canvasId).addEventListener('contextmenu', function (event) { return event.preventDefault(); });\n document.getElementById(this.canvasId).addEventListener(\"click\", function () {\n var selectedItem = _this.level.getSelectedItems();\n if (selectedItem) {\n _this.level.setCurrentItem();\n }\n });\n };\n UIEvent.prototype._listenEditorImgs = function () {\n var classname = document.getElementsByClassName(\"metacar_img\");\n var that = this;\n for (var i = 0; i < classname.length; i++) {\n classname[i].addEventListener('click', function () {\n that.level.selectedItem({\n image: this.getAttribute('data-img'),\n type: this.getAttribute('data-type'),\n data: this.getAttribute(\"data-data\")\n });\n }, false);\n }\n };\n UIEvent.prototype.createEditorElementsEvents = function () {\n var widthText = this._createSpan(\"width\", \"Width\");\n var widthProgress = this._createRangeBar(\"width\");\n var heightText = this._createSpan(\"height\", \"Height\");\n var heightProgress = this._createRangeBar(\"height\");\n this.buttonsContainer.appendChild(widthText);\n this.buttonsContainer.appendChild(widthProgress);\n this.buttonsContainer.appendChild(heightText);\n this.buttonsContainer.appendChild(heightProgress);\n this._listenRangeChanges(widthProgress, heightProgress);\n this._listenCanvasEditor();\n var map = this.level.getMap();\n var width = map[0].length;\n var height = map.length;\n widthProgress.value = width.toString();\n heightProgress.value = height.toString();\n this.editorWidth = width;\n this.editorHeight = height;\n var agentImg = this._createImage(\"car_agent\", _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + \"car_agent.png\");\n agentImg.dataset.type = \"agent\";\n agentImg.dataset.img = \"car_agent.png\";\n this.buttonsContainer.appendChild(agentImg);\n var carImg = this._createImage(\"car_agent\", _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + \"car.png\");\n carImg.dataset.type = \"car\";\n carImg.dataset.img = \"car.png\";\n this.buttonsContainer.appendChild(carImg);\n var roads = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][\"ROADS\"];\n for (var arrow in roads) {\n var nImg = this._createImage(roads[arrow].image.replace(\".png\", \"\"), _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + roads[arrow].image);\n nImg.dataset.type = \"road\";\n nImg.dataset.img = roads[arrow].image;\n nImg.dataset.data = arrow;\n this.buttonsContainer.appendChild(nImg);\n }\n for (var key in _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"]) {\n if (key != \"ROADS\") {\n var nImg = this._createImage(key, _global__WEBPACK_IMPORTED_MODULE_1__[\"IMAGE_FOLDER\"] + _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image);\n nImg.dataset.img = _global__WEBPACK_IMPORTED_MODULE_1__[\"ASSETS\"][key].image;\n nImg.dataset.data = key;\n nImg.dataset.type = \"asset\";\n this.buttonsContainer.appendChild(nImg);\n }\n }\n this._listenEditorImgs();\n };\n return UIEvent;\n}());\n\n\n\n//# sourceURL=webpack://metacar/./src/ui_event.ts?"); /***/ }), diff --git a/src/car.ts b/src/car.ts index 73c5a07..236c303 100644 --- a/src/car.ts +++ b/src/car.ts @@ -11,6 +11,7 @@ import { CAR_IMG, Sprite, MAP, ROADSIZE, Container, Graphics } from "./global"; import { RoadSprite } from "./asset_manager"; +import { stat } from "fs"; var Global_carId = 0; @@ -174,16 +175,22 @@ export class Car { } } - getState(): number[][]{ + getState(linear:boolean = false): number[][]|number[]{ /* Get the current state of the car The state is the current value of each point of the lidar. */ - return this.motion.state.map(function(arr: any) { return arr.slice(); }); + if (!linear) + return this.motion.state.map(function(arr: any) { return arr.slice(); }); + else{ + let state: number[] = []; + this.motion.state.map((row: number[]) => { state = state.concat(row);}); + return state; + } } - step(delta: number, action:number=null){ + step(delta: number, action:number|number[]=null){ /* Take one step into the environement @delta (Float) time since the last update diff --git a/src/level.ts b/src/level.ts index 105e339..06c798b 100644 --- a/src/level.ts +++ b/src/level.ts @@ -75,7 +75,7 @@ export class Level extends World { return reward; } - step(delta: number, action:number=null){ + step(delta: number, action:number|number[]=null){ /* Process one step into the environement @delta (Float) time since the last update diff --git a/src/metacar.ts b/src/metacar.ts index 1b36cba..41753f4 100644 --- a/src/metacar.ts +++ b/src/metacar.ts @@ -7,6 +7,10 @@ import {actionSpaceDescription} from "./motion_engine"; import {UIEvent} from "./ui_event"; import * as U from "./utils"; +/** + * @local Chooce whether to load a file from the computer. + * A popup is open if True. + */ export interface eventLoadOptions { local: boolean; } @@ -17,44 +21,28 @@ export class MetaCar { private level: Level; private canvasId: string; private levelToLoad: string|Object; - private eventList: string[] = ["train", "play", "stop", "reset_env", "reset_agent", "load"] + private eventList: string[] = ["train", "play", "stop", "reset_env", "load"] private eventCallback: any[]; private event: UIEvent; + /** + * Class used to create a new environement. + * @canvasId: HTML canvas ID + * @levelToLoad: URL of the level or directly the level's object. + * URL format: embedded://... or http(s)://... + */ constructor(canvasId: string, levelToLoad: string|Object) { - /** - * @canvasId: HTML canvas ID to used - * @level: URL or Local storage URL. - * localstorage://level-name - * embedded:// - * http(s):// - */ - if (!canvasId || this.levelToLoad){ + if (!canvasId || !levelToLoad){ console.error("You must specify the canvasId and the levelToLoad"); } this.canvasId = canvasId; this.levelToLoad = levelToLoad; } - private _setEvents(){ - // SetEvents callback - this.event = new UIEvent(this.level, this.canvasId); - this.eventCallback = [ - (fc: any) => this.event.onTrain(fc), - (fc: any) => this.event.onPlay(fc), - (fc:any) => this.event.onStop(fc), - (fc: any) => this.event.onResetEnv(fc), - (fc: any) => this.event.onResetAgent(fc), - (fc: any, opt: eventLoadOptions) => this.event.onLoad(fc, opt) - ]; - } - - load(level: string, agent: any): Promise{ - /* - Load the environement - @level (String) Name of the json level to load - @agent (Agent class) - */ + /* + Load the environement with the parameters passed in the constructor. + */ + public load(): Promise{ return new Promise((resolve, reject) => { console.log(typeof this.levelToLoad, this.levelToLoad); @@ -62,56 +50,34 @@ export class MetaCar { U.loadCustomURL(this.levelToLoad, (content: LevelInfo) => { this.level = new Level(content, this.canvasId); this._setEvents(); - this.level.load((delta: number) => this.loop(delta)); + this.level.load((delta: number) => this._loop(delta)); resolve(); }); } else{ this.level = new Level(this.levelToLoad, this.canvasId); this._setEvents(); - this.level.load((delta: number) => this.loop(delta)); + this.level.load((delta: number) => this._loop(delta)); resolve(); } }); - - /* - - this.agent = agent; - this.level = new Level(level, "canvas"); - this.level.load((delta: number) => this.loop(delta)); - - document.getElementById("train").addEventListener("click", () => { - this.level.app.ticker.stop(); // .add(delta => this.loop(delta)); - this.agent.train(this); - }); - document.getElementById("stop").addEventListener("click", () => { - this.isPlaying = false; - this.level.render(); - this.agent.stop(); - }); - document.getElementById("reset").addEventListener("click", () => { - this.level.reset(); - }); - document.getElementById("play").addEventListener("click", () => { - this.isPlaying = true - }); - document.getElementById("saveAgent").addEventListener("click", () => { - this.agent.save(this); - }); - document.getElementById("dumpFile").addEventListener("change", (e) => { - //readDump(e, (content) => this.agent.restore(this, content)); - }); - */ } /** - * This method is used to add button under the canvas. When a + * This method is used to add a button under the canvas. When a * click is detected on the window, the associated @fc is called. * Some events are recognized by the environement, others can be custom. + * The following are recognized: + * - train: The render is stopped before to called @fc. You must called render(true) once your training is done. + * - play: Your function (@fc) will be called at each frame update. + * - stop: The last function passed to the play event will not be called anymore. Then @fc is called. + * - reset_env: Reset the environement. Then, @fc is called. + * - load: Load: @fc is called. You can set @options to {local:true} to load the content of a file from your computer. + * If @options is set, a content variable will be passed to the @fc function (the content of the selected file). * @eventName Name of the event to listen. * @fc Function to call each time this event is raised. */ - addEvent(eventName: string, fc: any, options?: eventLoadOptions):void { + public addEvent(eventName: string, fc: any, options?: eventLoadOptions):void { const index = this.eventList.indexOf(eventName); if (index == -1){ this.event.onCustomEvent(eventName, fc); @@ -126,14 +92,20 @@ export class MetaCar { } } - render(val: boolean){ - /* - Choose whether to render the environement. - */ + /** + * Choose whether to render the environement. + * @val: True or False. + */ + public render(val: boolean){ this.level.render(val); } - save(content: any, file_name: string){ + /** + * Usefull method to save/download a string as file. + * @content The content of the file + * @file_name The name of the file + */ + public save(content: string, file_name: string){ /* Save the agent */ @@ -142,35 +114,44 @@ export class MetaCar { /** * Get the action space of the environement + * @return The Description of the action space. */ - actionSpace(): actionSpaceDescription{ + public actionSpace(): actionSpaceDescription{ return this.level.agent.motion.actionSpace(); } /** * Return the current state of the environement. * The size of the state depends of the size of the Lidar. + * @return The state as a 2D Array or 1D Array (linear:true) */ - getState(): number[][]{ - return this.level.agent.getState(); + public getState(linear:boolean = false): number[][]|number[]{ + return this.level.agent.getState(linear); } - step(action: number){ - /* - Step into the environement - @action (Integer) - */ + /** + Step into the environement + @action Action to process to step + @return Reward value + */ + public step(action: number|number[]): number{ return this.level.step(1, action); } - reset(){ + /** + * Reset the environement + */ + public reset(): void{ /* Reset the agent position */ this.level.reset(); } - randomRoadPosition(){ + /** + * Set the agent on a new random road on the map. + */ + randomRoadPosition(): void{ /* This position */ @@ -186,7 +167,10 @@ export class MetaCar { } } - loop(delta: number){ + /** + * @delta Time since the last update + */ + private _loop(delta: number): void{ if (this.event.isPlaying()){ this.event.playCallback(); } @@ -195,4 +179,20 @@ export class MetaCar { } } + /** + * Create the UIEvent instance and set the events + * callbacks relative to the UI. + */ + private _setEvents(): void{ + // SetEvents callback + this.event = new UIEvent(this.level, this.canvasId); + this.eventCallback = [ + (fc: any) => this.event.onTrain(fc), + (fc: any) => this.event.onPlay(fc), + (fc:any) => this.event.onStop(fc), + (fc: any) => this.event.onResetEnv(fc), + (fc: any, opt: eventLoadOptions) => this.event.onLoad(fc, opt) + ]; + } + } diff --git a/src/ui_event.ts b/src/ui_event.ts index e5bc918..596eda7 100644 --- a/src/ui_event.ts +++ b/src/ui_event.ts @@ -97,14 +97,6 @@ export class UIEvent { if (fc) fc(); }); } - - public onResetAgent(fc: any){ - // Create the button - const button = this._createButton(this.buttonsContainer, "reset_agent"); - button.addEventListener("click", () => { - if (fc) fc(); - }); - } public onCustomEvent(name: string, fc: any){ // Create the button