{"id":679296,"student_id":10,"content":"","created_at":"2024-01-15T23:01:53.409+08:00","updated_at":"2024-01-15T23:01:53.409+08:00","name":"L13_自動駕駛 _試玩版 副本","language":"javascript","screenshot":{"url":null},"parent_id":298671,"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 carArray = []; // 存放所有製造出來的車子\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.color = 'black'; // 顏色\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.sensorData = [];\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 = center.color;\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 carArray.push(center);\n return center;\n}\n\n\nforever(function(){\n \n // 檢查車子是否碰到賽道邊界,碰到則將車子狀態改成 broken\n carArray.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 carArray.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.sensorData[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\":7,\"y\":91},{\"x\":10,\"y\":65},{\"x\":24,\"y\":40},{\"x\":45,\"y\":22},{\"x\":70,\"y\":10},{\"x\":93,\"y\":6},{\"x\":532,\"y\":4},{\"x\":563,\"y\":7},{\"x\":593,\"y\":15},{\"x\":614,\"y\":33},{\"x\":628,\"y\":58},{\"x\":632,\"y\":84},{\"x\":632,\"y\":112},{\"x\":629,\"y\":389},{\"x\":626,\"y\":416},{\"x\":613,\"y\":441},{\"x\":594,\"y\":459},{\"x\":563,\"y\":469},{\"x\":523,\"y\":471},{\"x\":432,\"y\":471},{\"x\":327,\"y\":470},{\"x\":308,\"y\":462},{\"x\":293,\"y\":440},{\"x\":292,\"y\":409},{\"x\":292,\"y\":381},{\"x\":369,\"y\":189},{\"x\":369,\"y\":174},{\"x\":360,\"y\":160},{\"x\":324,\"y\":160},{\"x\":284,\"y\":160},{\"x\":248,\"y\":162},{\"x\":238,\"y\":180},{\"x\":234,\"y\":205},{\"x\":235,\"y\":378},{\"x\":235,\"y\":412},{\"x\":229,\"y\":440},{\"x\":204,\"y\":461},{\"x\":164,\"y\":470},{\"x\":121,\"y\":474},{\"x\":76,\"y\":472},{\"x\":45,\"y\":464},{\"x\":26,\"y\":446},{\"x\":12,\"y\":422},{\"x\":7,\"y\":389},{\"x\":8,\"y\":92}],[{\"x\":100,\"y\":106},{\"x\":102,\"y\":89},{\"x\":114,\"y\":82},{\"x\":492,\"y\":81},{\"x\":510,\"y\":86},{\"x\":519,\"y\":100},{\"x\":521,\"y\":367},{\"x\":514,\"y\":382},{\"x\":495,\"y\":388},{\"x\":421,\"y\":388},{\"x\":406,\"y\":374},{\"x\":478,\"y\":188},{\"x\":486,\"y\":163},{\"x\":489,\"y\":136},{\"x\":477,\"y\":112},{\"x\":456,\"y\":97},{\"x\":425,\"y\":90},{\"x\":171,\"y\":91},{\"x\":147,\"y\":98},{\"x\":135,\"y\":118},{\"x\":131,\"y\":141},{\"x\":131,\"y\":362},{\"x\":131,\"y\":379},{\"x\":118,\"y\":390},{\"x\":105,\"y\":379},{\"x\":102,\"y\":361},{\"x\":100,\"y\":105}]]\ninitalMaps(maps);\n\n\nvar DNA_LENGTH = 30; // DNA 的長度\nvar generation = 0; // 紀錄目前是第幾代\nvar cars = []; // 用來存放所有車子角色\n\nfor (var i = 0; i \u003c 20; i += 1) {\n // 創造車子並初始化設定\n var car = new Car();\n car.speed = 3; // 設定車速\n car.reset(50, 250, 0); // 重置位置 xy 座標 50, 250 並將方向朝向上方\n car.addSensor(60);\n car.addSensor(30);\n car.addSensor(0);\n car.addSensor(-30);\n car.addSensor(-60);\n car.gens = randomDNA(24);\n car.score = 0;\n \n cars.push(car);\n}\n\n\n// 避免緩慢的車子消耗時間,手動進入下一個世代來加速學習\nwhen('keydown', 'space', nextGeneration);\nforever(gameloop); //重複不斷執行遊戲迴圈\n\n// 遊戲迴圈\nfunction gameloop () {\n print('generation:' + generation);\n \n drawText(cars[0].score, 10, 30);\n \n var count = 0;\n \n for (var i = 0; i \u003c cars.length; i += 1) {\n var car = cars[i];\n var output = NN(car.sensorData, car.gens);\n car.turn(output * 3);\n car.color = 'black';\n \n if (car.status == 'running') {\n count += 1;\n car.score += 1;\n }\n }\n \n if (count \u003c= 2) {\n nextGeneration();\n }\n \n cars.sort(function (a, b) {\n return b.score - a.score;\n });\n \n cars[0].color = 'red';\n cars[1].color = 'orange';\n \n}\n\nfunction nextGeneration () {\n console.log('產生下一代車子...');\n generation++;\n \n var parentA = cars[0].gens;\n var parentB = cars[1].gens;\n \n for (var i = 0; i \u003c cars.length; i += 1) {\n var car = cars[i];\n car.reset(50, 250, 0); //重置\n car.gens = crossover(parentA, parentB);\n car.score = 0;\n }\n}\n\n// 兩組基因交配產生新的基因\nfunction crossover(a, b) {\n var dna = [];\n for (var i = 0; i \u003c a.length; i += 1) {\n dna.push(Math.random() \u003e 0.5 ? a[i] : b[i]);\n \n if (Math.random() \u003c 0.1) {\n dna[i] = Math.random() * 2 - 1;\n }\n }\n return dna;\n}\n\n// 產生隨機的基因組\nfunction randomDNA(length) {\n var dna = [];\n for (var i = 0; i \u003c length; i += 1) {\n dna.push(Math.random() * 2 - 1);\n }\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 \n var i = inputs;\n var w = weights;\n \n var a = i[0]*w[0] + i[1]*w[1] + i[2]*w[2] + i[3]*w[3] + i[4]*w[4];\n var b = i[0]*w[5] + i[1]*w[6] + i[2]*w[7] + i[3]*w[8] + i[4]*w[9];\n var c = i[0]*w[10] + i[1]*w[11] + i[2]*w[12] + i[3]*w[13] + i[4]*w[14];\n var 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 var e = a*w[20] + b*w[21] + c*w[22] + d*w[23];\n \n return sigmoid(e);\n}\n","description":null,"note":null,"status":"public","like_student_ids":[],"is_featured":false,"views":273,"hashid":"yeysgprrm","is_content_changed":false,"review_status":"unsubmitted","submitted_at":null,"reviewed_at":null,"advise":null,"is_deleted":false}
[{"id":15239650,"file_name":"dot.jpg","project_id":679296,"asset_id":418204,"created_at":"2024-01-15T23:01:53.416+08:00","updated_at":"2024-01-15T23:01:53.416+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