{"id":208701,"student_id":12205,"content":"var SIZE = 50; // 每個世代的個數\nvar DNA_LENGTH = 30; // DNA 的長度\nvar generation = 0; // 紀錄目前是第幾代\nvar count = 0;\n\n// 初始化第一代車子\nfor (var i = 0; i \u003c SIZE; i++) {\n let car = new Car();\n car.reset(50, 250, 0);\n car.addSensor(45);\n car.addSensor(0);\n car.addSensor(-45);\n car.score = 0;\n car.speed = 0;\n car.gens = randomDNA(DNA_LENGTH);\n car.xx = car.x; //car.xx 前一輪的 x 座標\n car.yy = car.y; //car.yy 前一輪的 y 座標\n \n forever(function(){\n if (car.status != 'running'){\n return;\n }\n var outputs = NN(car.sensorsData.concat(car.speed), car.gens);\n car.turn(outputs[0]*3); // 控制左轉/右轉\n car.speedUp(outputs[1]/10); // 控制加速/減速\n car.score += car.speed;\n\n if (count % 30 === 0) { // 每30 tick 計算一次分數\n var diff = (car.xx - car.x)**2 + (car.yy - car.y)**2;\n if (car.speed == 0) car.status = 'broken';\n car.score += diff;\n car.xx = car.x;\n car.yy = car.y;\n }\n count++;\n });\n}\n\n// 避免緩慢的車子消耗時間,手動進入下一個世代來加速學習\nwhen('keydown', 'space', nextGeneration);\nwhen('keydown', 'enter', function(){\n console.log(cars[0].sensorsData)\n console.log(cars[0].speed)\n});\n\nforever(function(){\n // count++;\n print('generation:' + generation);\n for (var i=0; i\u003ccars.length; i++) {\n if (cars[i].status == 'running'){\n // console.log(\"Running Car Speed:\", cars[i].speed)\n return;\n } \n }\n nextGeneration();\n});\n\nfunction nextGeneration () {\n cars.sort(function (a, b) {\n return b.score - a.score;\n });\n // 取出表現最佳的兩台車基因(參數),產生下一代車子\n var parentA = cars[0].gens;\n var parentB = cars[1].gens;\n \n for (var i=0; i\u003ccars.length; i++) {\n cars[i].gens = crossover(parentA, parentB);\n cars[i].reset(50, 250, 0);\n cars[i].score = 0;\n cars[i].speed = 0;\n }\n \n generation++;\n}\n\nfunction crossover(a, b) {\n var dna = [];\n for (var i = 0; i \u003c DNA_LENGTH; i++) {\n dna[i] = Math.random() \u003e 0.5 ? a[i] : b[i];\n if (Math.random() \u003c 0.1) dna[i] = Math.random() * 2 - 1; // 變異\n }\n return dna;\n}\n\nfunction randomDNA(length) {\n var dna = [];\n for (var i = 0; i \u003c length; i++) dna.push(Math.random() * 2 - 1);\n return dna;\n}\n\nfunction sigmoid(x) {\n return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x));\n}\n\n\n// input*4 hidden*5 output*2\n//weights: 基因\nfunction NN (inputs, weights) {\n // Input Layer -\u003e Hidden Layer\n var A = inputs[0], B = inputs[1], C = inputs[2], D = inputs[3];\n\n a = A * weights[0] + B * weights[1] + C * weights[2] + D * weights[3];\n b = A * weights[4] + B * weights[5] + C * weights[6] + D * weights[7];\n c = A * weights[8] + B * weights[9] + C * weights[10] + D * weights[11];\n d = A * weights[12] + B * weights[13] + C * weights[14] + D * weights[15];\n e = A * weights[16] + B * weights[17] + C * weights[18] + D * weights[19];\n \n a = sigmoid(a); //介於 -1 ~ 1\n b = sigmoid(b); //介於 -1 ~ 1\n c = sigmoid(c); //介於 -1 ~ 1\n d = sigmoid(d); //介於 -1 ~ 1\n e = sigmoid(e); //介於 -1 ~ 1\n \n // Hidden Layer -\u003e Output Layer\n output1 = a * weights[20] + b * weights[21] + c * weights[22] + d * weights[23] + e * weights[24];\n output2 = a * weights[25] + b * weights[26] + c * weights[27] + d * weights[28] + e * weights[29];\n \n output1 = sigmoid(output1); //介於 -1 ~ 1, direction\n output2 = sigmoid(output2); //介於 -1 ~ 1, speed\n \n return [output1, output2];\n}\n","created_at":"2020-12-02T19:36:36.729+08:00","updated_at":"2020-12-02T19:36:36.729+08:00","name":"自動駕駛(賽車版) 副本 副本","language":"javascript","screenshot":{"url":null},"parent_id":204467,"plugin":"function Point (x, y) {\n this.x = x || 0;\n this.y = y || 0;\n}\n\nfunction Line (p1, p2, size, color) {\n\n this.p1 = p1;\n this.p2 = p2;\n this.size = size || 1;\n this.color = color || 'black';\n this.a = 0;\n this.b = 0;\n \n // 使用在繪圖用對應的 forever\n this.instance = createSprite('dot.jpg');\n this.instance.hidden = true;\n \n // y = ax + b\n // a:斜率 b:常數\n this.update = function () {\n // 計算斜率\n this.a = (this.p1.y - this.p2.y) / (this.p1.x - this.p2.x);\n \n // 這招真的很無恥,斜率 1000 畫面上分辨不出是否垂直線\n // 在計算交會點的時候就很方便,不用再判斷是否為垂直線\n if (Math.abs(this.a) \u003e 1000) this.a = 1000;\n \n // 計算常數項\n this.b = this.p1.y - this.p1.x*this.a;\n }\n this.update(); // 初始化更新\n \n \n // 取得兩線斷相交的座標,如果沒有相交就回傳 undefined\n this.touched = function (line) {\n\n if (!this.isCrossWith(line)) return; // undefined\n \n let x = (line.b - this.b)/(this.a - line.a);\n let y = this.a*x + this.b;\n return {x: x, y: y};\n }\n \n // 兩線斷是否相交\n this.isCrossWith = function (line) {\n return line._calc(this.p1.x, this.p1.y) * line._calc(this.p2.x, this.p2.y) \u003c 0 \u0026\u0026\n this._calc(line.p1.x, line.p1.y) * this._calc(line.p2.x, line.p2.y) \u003c 0\n }\n\n this._calc = function (x, y) {\n if (Math.abs(this.a) == Infinity) return x - this.b;\n return this.a*x + this.b - y;\n }\n \n // 渲染線條\n this.render = function () {\n pen.size = this.size;\n pen.color = this.color;\n pen.drawLine(this.p1.x, this.p1.y, this.p2.x, this.p2.y);\n }\n \n // 刪除線條\n this.destroy = this.instance.destroy.bind(this.instance);\n \n var self = this;\n this.instance.forever(function(){\n self.update();\n self.render();\n });\n}\n\n\nvar walls = []; // 存放賽道線條\nvar cars = []; // 存放所有製造出來的車子\n\n\nfunction Car (x, y) {\n \n let width = 17; // 車體中心到四個角的距離\n let sensorLength = 1000; // 感測器的長度距離\n\n let center = createSprite('dot.jpg');\n center.x = x || 320;\n center.y = y || 240;\n center.speed = 1; // 預設車速\n center.status = 'running'; // running, broken\n \n // 車體的四個點\n let p1 = new Point();\n let p2 = new Point();\n let p3 = new Point();\n let p4 = new Point();\n center.corner = [p1, p2, p3, p4];\n \n // 車體邊框\n center.border = [\n new Line(p1, p2, 2),\n new Line(p2, p3, 2),\n new Line(p3, p4, 2),\n new Line(p4, p1, 2),\n ];\n \n // 感測器的線段終點\n center.censorPoints = [];\n // 感測器的線段\n center.sensors = []\n // sensors 角度\n center.offset = [];\n // 感測器讀取的資料\n center.sensorsData = [];\n \n\n center.updateLines = function () {\n for (var i=0; i\u003c4; i++) {\n this.border[i].update();\n }\n for (var i=0; i\u003cthis.offset.length; i++) {\n this.sensors[i].update();\n }\n }\n \n center.update = function () {\n var self = this;\n this.border.forEach((line) =\u003e {\n if (self.status == 'broken') line.color = 'gray';\n else line.color = 'black';\n });\n \n // 更新車體的四個點座標\n var offset = [30, 150, -150, -30];\n for (var i=0; i\u003c4; i++) {\n this.direction += offset[i];\n this.stepForward(width);\n this.corner[i].x = this.x;\n this.corner[i].y = this.y;\n this.stepForward(-width);\n this.direction -= offset[i];\n }\n \n // 更新感測器的線\n var offset = [-45, -22.5, 0, 22.5, 45];\n var offset = [-60, 0, 60];\n for (var i=0; i\u003cthis.offset.length; i++) {\n center.direction += this.offset[i];\n center.stepForward(sensorLength);\n center.censorPoints[i].x = center.x;\n center.censorPoints[i].y = center.y;\n center.stepForward(-sensorLength);\n center.direction -= this.offset[i];\n }\n \n this.updateLines();\n };\n \n center.turn = function (direction) {\n if (isNaN(direction) || this.status == 'broken') return;\n if (direction \u003e this.speed) direction = this.speed;\n if (direction \u003c -this.speed) direction = -this.speed;\n this.direction += direction;\n }\n \n center.speedUp = function (speed) {\n if (isNaN(speed) || this.status == 'broken') return;\n this.speed += speed;\n if (this.speed \u003c 0) this.speed = 0;\n }\n \n center.reset = function (x, y, direction) {\n this.x = x;\n this.y = y;\n this.direction = direction;\n this.update();\n this.status = 'running';\n }\n \n center.addSensor = function (direction) {\n let point = new Point();\n let line = new Line(this, point, 0, '#00000000');\n this.censorPoints.push(point);\n this.sensors.push(line);\n this.offset.push(direction);\n }\n \n forever(function () {\n if (center.status == 'running') {\n center.stepForward(center.speed);\n }\n center.update();\n });\n \n center.update(); // 初始化更新\n \n cars.push(center);\n return center;\n}\n\n\nforever(function(){\n \n // 檢查車子是否碰到賽道邊界,碰到則將車子狀態改成 broken\n cars.forEach(function (car) {\n for (var x=0; x\u003ccar.border.length; x++) {\n for (var y=0; y\u003cwalls.length; y++) {\n if (car.border[x].touched(walls[y])) {\n car.status = 'broken';\n return;\n }\n }\n }\n });\n \n // 更新車子感測器的數值\n cars.forEach(function (car) {\n if (car.status == 'broken') return;\n for (var x=0; x\u003ccar.sensors.length; x++) {\n \n var shortest = Infinity;\n var target = {};\n \n for (var y=0; y\u003cwalls.length; y++) {\n let pos = car.sensors[x].touched(walls[y]);\n if (pos) {\n let length = Math.sqrt((pos.x - car.x)**2 + (pos.y - car.y)**2);\n if (length \u003c shortest) {\n shortest = Math.round(length);\n target = pos;\n }\n }\n }\n \n car.sensorsData[x] = shortest;\n pen.color = '#aaa';\n pen.size = 1;\n pen.drawLine(car.x, car.y, target.x, target.y);\n pen.fillColor = 'red';\n pen.drawCircle(target.x, target.y, 3);\n }\n });\n});\n\n// 初始化賽道牆壁\nfunction initalMaps (map) {\n walls.forEach(function (line) { line.destroy() });\n walls = [];\n map.forEach(function (points) {\n for (var i=1; i\u003cpoints.length; i++) {\n let p1 = new Point(points[i - 1].x, points[i - 1].y);\n let p2 = new Point(points[i].x, points[i].y);\n let l =new Line(p1, p2, 3);\n walls.push(l)\n }\n });\n}\n\nlet maps = [[{\"x\":4,\"y\":92},{\"x\":6,\"y\":67},{\"x\":14,\"y\":46},{\"x\":31,\"y\":28},{\"x\":52,\"y\":14},{\"x\":79,\"y\":9},{\"x\":542,\"y\":8},{\"x\":571,\"y\":11},{\"x\":594,\"y\":21},{\"x\":611,\"y\":38},{\"x\":623,\"y\":63},{\"x\":629,\"y\":90},{\"x\":631,\"y\":394},{\"x\":623,\"y\":419},{\"x\":611,\"y\":438},{\"x\":594,\"y\":454},{\"x\":567,\"y\":464},{\"x\":536,\"y\":467},{\"x\":120,\"y\":469},{\"x\":90,\"y\":467},{\"x\":62,\"y\":461},{\"x\":38,\"y\":446},{\"x\":22,\"y\":427},{\"x\":12,\"y\":399},{\"x\":9,\"y\":364},{\"x\":5,\"y\":93}],[{\"x\":103,\"y\":143},{\"x\":104,\"y\":121},{\"x\":116,\"y\":104},{\"x\":135,\"y\":92},{\"x\":161,\"y\":84},{\"x\":481,\"y\":84},{\"x\":508,\"y\":90},{\"x\":525,\"y\":107},{\"x\":533,\"y\":130},{\"x\":533,\"y\":169},{\"x\":532,\"y\":340},{\"x\":527,\"y\":360},{\"x\":514,\"y\":372},{\"x\":496,\"y\":381},{\"x\":471,\"y\":384},{\"x\":166,\"y\":384},{\"x\":146,\"y\":381},{\"x\":126,\"y\":371},{\"x\":112,\"y\":351},{\"x\":106,\"y\":325},{\"x\":103,\"y\":144}]]\ninitalMaps(maps);\n","description":null,"note":null,"status":"public","like_student_ids":[],"is_featured":false,"views":207,"hashid":"5j3s99zvj","is_content_changed":false,"review_status":"unsubmitted","submitted_at":null,"reviewed_at":null,"advise":null,"is_deleted":false}
[{"id":3637398,"file_name":"dot.jpg","project_id":208701,"asset_id":113889,"created_at":"2020-12-02T19:36:36.736+08:00","updated_at":"2020-12-02T19:36:36.736+08:00"}]
Orange Apple Learning Platform
My Projects
View Project Page
Export
Remix
Import
Delete
Download Android APP (APK)
Screenshot
繁中
简中
English
日本語
1:1:1
1:1
Full Width
Scan the QRCode below with your phone to install
Or you can
download APK
to this computer
Scan the QRCode below with your phone to install
Or you can
download APK
to this computer