{"id":48761,"student_id":10,"content":"","created_at":"2018-11-16T16:28:10.776+08:00","updated_at":"2019-11-08T16:50:40.579+08:00","name":"自動駕駛 v2","language":"javascript","screenshot":{"url":"/uploads/project/screenshot/48761/fdf5027dfcf8a1d74ae62a222a589d32.jpg"},"parent_id":48758,"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 // 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) === Infinity) 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 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 var self = this;\n 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 = 10; // 車體中心到四個角的距離\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 let a = center.a = new Point();\n let b = center.b = new Point();\n let c = center.c = new Point();\n let d = center.d = new Point();\n let e = center.e = new Point();\n center.censorPoints = [a, b, c, d, e];\n \n // 感測器的線段\n center.sensors = [\n new Line(center, a, 0, '#00000000'),\n new Line(center, b, 0, '#00000000'),\n new Line(center, c, 0, '#00000000'),\n new Line(center, d, 0, '#00000000'),\n new Line(center, e, 0, '#00000000'),\n ]\n \n // 感測器讀取的資料\n center.sensorsData = [0, 0, 0, 0, 0];\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 center.updateLines = function () {\n for (var i=0; i\u003c4; i++) {\n this.border[i].update();\n }\n for (var i=0; i\u003c5; 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 for (var i=0; i\u003c5; i++) {\n center.direction += 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 -= offset[i];\n }\n \n this.updateLines();\n };\n \n center.turn = function (direction) {\n if (this.status == 'broken') return;\n this.direction += direction;\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 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\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 \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// 地圖產生工具\n// https://koding.school/projects/36ys55kv/edit\nvar shapes = [[{\"x\":98,\"y\":10},{\"x\":98,\"y\":10},{\"x\":497,\"y\":10},{\"x\":535,\"y\":10},{\"x\":567,\"y\":22},{\"x\":593,\"y\":42},{\"x\":613,\"y\":68},{\"x\":621,\"y\":94},{\"x\":628,\"y\":126},{\"x\":629,\"y\":173},{\"x\":629,\"y\":249},{\"x\":625,\"y\":266},{\"x\":615,\"y\":278},{\"x\":599,\"y\":285},{\"x\":575,\"y\":293},{\"x\":549,\"y\":301},{\"x\":533,\"y\":318},{\"x\":539,\"y\":333},{\"x\":563,\"y\":343},{\"x\":599,\"y\":356},{\"x\":625,\"y\":379},{\"x\":629,\"y\":402},{\"x\":629,\"y\":438},{\"x\":620,\"y\":455},{\"x\":593,\"y\":472},{\"x\":537,\"y\":474},{\"x\":397,\"y\":474},{\"x\":368,\"y\":465},{\"x\":361,\"y\":452},{\"x\":320,\"y\":375},{\"x\":282,\"y\":290},{\"x\":283,\"y\":269},{\"x\":299,\"y\":251},{\"x\":353,\"y\":206},{\"x\":401,\"y\":166},{\"x\":405,\"y\":154},{\"x\":402,\"y\":140},{\"x\":393,\"y\":127},{\"x\":377,\"y\":124},{\"x\":361,\"y\":125},{\"x\":338,\"y\":126},{\"x\":318,\"y\":140},{\"x\":295,\"y\":159},{\"x\":271,\"y\":181},{\"x\":243,\"y\":207},{\"x\":219,\"y\":229},{\"x\":217,\"y\":244},{\"x\":214,\"y\":266},{\"x\":225,\"y\":286},{\"x\":265,\"y\":369},{\"x\":266,\"y\":386},{\"x\":258,\"y\":410},{\"x\":245,\"y\":429},{\"x\":226,\"y\":449},{\"x\":204,\"y\":466},{\"x\":170,\"y\":474},{\"x\":126,\"y\":474},{\"x\":85,\"y\":474},{\"x\":65,\"y\":459},{\"x\":43,\"y\":430},{\"x\":26,\"y\":394},{\"x\":12,\"y\":355},{\"x\":7,\"y\":323},{\"x\":6,\"y\":271},{\"x\":5,\"y\":218},{\"x\":5,\"y\":182},{\"x\":4,\"y\":122},{\"x\":12,\"y\":88},{\"x\":37,\"y\":58},{\"x\":98,\"y\":10}],\n[{\"x\":119,\"y\":63},{\"x\":119,\"y\":63},{\"x\":487,\"y\":61},{\"x\":521,\"y\":66},{\"x\":539,\"y\":78},{\"x\":552,\"y\":97},{\"x\":559,\"y\":117},{\"x\":566,\"y\":149},{\"x\":567,\"y\":169},{\"x\":569,\"y\":213},{\"x\":565,\"y\":225},{\"x\":551,\"y\":234},{\"x\":527,\"y\":247},{\"x\":498,\"y\":262},{\"x\":480,\"y\":277},{\"x\":474,\"y\":295},{\"x\":473,\"y\":321},{\"x\":479,\"y\":341},{\"x\":498,\"y\":363},{\"x\":516,\"y\":371},{\"x\":543,\"y\":384},{\"x\":562,\"y\":400},{\"x\":566,\"y\":415},{\"x\":560,\"y\":425},{\"x\":539,\"y\":427},{\"x\":420,\"y\":425},{\"x\":410,\"y\":415},{\"x\":376,\"y\":355},{\"x\":347,\"y\":294},{\"x\":361,\"y\":275},{\"x\":409,\"y\":238},{\"x\":469,\"y\":189},{\"x\":475,\"y\":162},{\"x\":474,\"y\":131},{\"x\":464,\"y\":108},{\"x\":442,\"y\":82},{\"x\":406,\"y\":71},{\"x\":368,\"y\":67},{\"x\":324,\"y\":69},{\"x\":285,\"y\":71},{\"x\":272,\"y\":78},{\"x\":240,\"y\":105},{\"x\":213,\"y\":129},{\"x\":185,\"y\":156},{\"x\":161,\"y\":182},{\"x\":143,\"y\":205},{\"x\":137,\"y\":238},{\"x\":137,\"y\":270},{\"x\":154,\"y\":306},{\"x\":194,\"y\":367},{\"x\":196,\"y\":383},{\"x\":183,\"y\":399},{\"x\":165,\"y\":409},{\"x\":128,\"y\":410},{\"x\":106,\"y\":399},{\"x\":99,\"y\":383},{\"x\":86,\"y\":359},{\"x\":78,\"y\":326},{\"x\":78,\"y\":301},{\"x\":78,\"y\":252},{\"x\":78,\"y\":198},{\"x\":78,\"y\":166},{\"x\":81,\"y\":118},{\"x\":93,\"y\":90},{\"x\":106,\"y\":76},{\"x\":119,\"y\":63}]]\n\nshapes.forEach((points) =\u003e {\n for (var i=0; i\u003cpoints.length; i++) {\n points[i] = new Point(points[i].x, points[i].y);\n } \n});\n\nshapes.forEach((points) =\u003e {\n for (var i=1; i\u003cpoints.length; i++) {\n walls.push(new Line(points[i], points[i - 1], 2));\n } \n});\n\n//---------------------------------------------\nvar SIZE = 70; // 每個世代的個數\n\nfor (var i = 0; i \u003c SIZE; i++) {\n let car = new Car();\n car.reset(100, 30, 90);\n car.score = 0;\n car.gens = randomDNA(32);\n car.speed = 5;\n\n forever(function(){\n if (car.status != 'running') return;\n var outputs = NN(car.sensorsData, car.gens);\n car.turn(outputs*30);\n car.score++;\n });\n}\n\nforever(function(){\n for (var i=0; i\u003ccars.length; i++) {\n if (cars[i].status == 'running') return;\n }\n \n cars.sort(function (a, b) {\n return a.score - b.score; \n });\n \n let newGens = [];\n for (let i=0; i\u003cSIZE - 0; i++) {\n let rand1 = Math.floor(Math.sqrt(Math.random() * SIZE*SIZE));\n let rand2 = Math.floor(Math.sqrt(Math.random() * SIZE*SIZE));\n let newDNA = crossover(cars[rand1].gens, cars[rand2].gens);\n newGens.push(newDNA);\n }\n \n for (var i=0; i\u003ccars.length; i++) {\n cars[i].gens = newGens[i];\n cars[i].reset(100, 30, 90)\n cars[i].score = 0;\n }\n});\n\nfunction crossover(a, b) {\n let dna = [];\n for (let i = 0; i \u003c a.length; i++) {\n dna[i] = Math.random() \u003e 0.5 ? a[i] : b[i];\n if (Math.random() \u003c 0.04) dna[i] = Math.random() * 0.2 - 0.1; // mutation\n }\n return dna;\n}\n\nfunction randomDNA(length) {\n let dna = [];\n for (let i = 0; i \u003c length; i++) dna.push(Math.random() * 0.2 - 0.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// input*5 hidden*4 output*1\nfunction NN(inputs, weights) {\n let w = weights;\n let i = inputs;\n let a = i[0]*w[0] + i[1]*w[1] + i[2] *w[2] + i[3]*w[3] + i[4]*w[4];\n let b = i[0]*w[5] + i[1]*w[6] + i[2] *w[7] + i[3]*w[8] + i[4]*w[9];\n let c = i[0]*w[10] + i[1]*w[11] + i[2] *w[12] + i[3]*w[13] + i[4]*w[14];\n let d = i[0]*w[15] + i[1]*w[16] + i[2] *w[17] + i[3]*w[18] + i[4]*w[19];\n\n a = sigmoid(a);\n b = sigmoid(b);\n c = sigmoid(c);\n d = sigmoid(d);\n\n let e = a*w[20] + b*w[21] + c*w[22] +d*w[23];\n return e;\n}\n","description":null,"note":null,"status":"public","like_student_ids":[],"is_featured":false,"views":502,"hashid":"6rpsddkm","is_content_changed":false,"review_status":"unsubmitted","submitted_at":null,"reviewed_at":null,"advise":null,"is_deleted":false}
[{"id":874044,"file_name":"dot.jpg","project_id":48761,"asset_id":96139,"created_at":"2018-11-16T16:28:10.791+08:00","updated_at":"2018-11-16T16:28:10.791+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