# *ㄅㄅㄅㄅㄅ宗のbolg* 海你好!我是陳柏宗 |Bert| DMHS 502A 有事請called:(算了不要) 寄email也行(不定時follow):bert850512@gmail.com --- ## :#Math數學才是王道 致力於研究數學 learning:微積分 | 排列組合 | 高中範圍數學 --- ## 習得JavaScript & Python中... 目前正在學習這兩個程式語言 各式語言展示於演算法中 --- ## 重要事項 :::info ## :loudspeaker: 非常重要公告 ### [暫無公告] ::: --- ## 程式碼大放送!!! - 請以 PC 或 筆電模式下操作: - step1:點擊/下載檔案:[~~小遊戲.zip~~](https://www.youtube.com/watch?v=dQw4w9WgXcQ&pp=ygUXbmV2ZXIgZ29ubmEgZ2l2ZSB5b3UgdXA%3D) - step2:開啟檔案即可遊玩!! --- ## Sudoka: (看不懂沒關係 我也不想解釋) -HTML: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Sudoku Solver</title> <link rel="stylesheet" href="index.css"> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script> </head> <body> <div id="sudoku"> <h1>Sudoku</h1> <div class="game"> <div class="grid"> <div v-for="row, y in grid" class="row"> <div v-for="col, x in row" class="col"> <input v-model.number="grid[y][x]" @focus="onfocus(y, x)" @focusout="onfocusout(y, x)" :disabled="originGrid[y][x] != 0" :style="textColor(y, x)" > </div> </div> </div> <div class="vertical"> <div v-for="i in 9"> <div v-show="v_check(i - 1)" class="active"></div> </div> </div> <div class="horizontal"> <div v-for="i in 9"> <div v-show="h_check(i - 1)" class="active"></div> </div> </div> <div class="blocks"> <div v-for="i in 9"> <div v-show="b_check(i - 1)" class="active"></div> </div> </div> </div> <p v-if="isWin" class="status">Congratulations!!!you won!</p> <button @click="newGame">New Game</button> <button @click="resolve">Crack</button> </div> </body> </html> ``` -CSS: ```css body { display: flex; justify-content: center; align-items: center; background-color: lightyellow; } #sudoku { text-align: center; } h1 { font-size: 1.5rem; } button { margin: 10px 5px; } .game { width: 450px; height: 450px; border: 1px solid black; position: relative; } .row { width: 100%; height: calc(100%/9); } .col { position: relative; display: inline-block; width: calc(100%/9); height: 100%; margin: 0; border: 1px solid #00000050; box-sizing: border-box; } input { position: absolute; top: 0; left: 0; width: calc(100% - 2px); height: calc(100% - 2px); margin: 0; text-align: center; border-width: 0px; box-sizing: border-box; font-size: 1.2rem; outline: none; color: black; background-color: rgba(0, 0, 0, 0); } input:disabled { font-weight: 900; font-size: 1.1rem; background-color: rgba(0, 0, 0, 0); cursor: not-allowed; } input:focus { color: block !important; } .grid { width: 100%; height: 100%; position: absolute; top: 0; left: 0; } .vertical, .horizontal, .blocks { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; flex-wrap: wrap; pointer-events: none; } .vertical > div { width: calc(100%/9); height: 100%; position: relative; } .horizontal > div { width: 100%; height: calc(100%/9); position: relative; } .blocks > div { width: 150px; height: 150px; border: 1px solid black; box-sizing: border-box; position: relative; } .vertical .active { z-index: -1; position: absolute; top: -12px; left: 12px; right: 12px; bottom: -12px; background-color: #ff595960; } .horizontal .active { z-index: -1; position: absolute; top: 12px; left: -12px; right: -12px; bottom: 12px; background-color: #ffa40060; } .blocks .active { z-index: -1; position: absolute; top: 6px; left: 6px; right: 6px; bottom: 6px; background-color: #00c4b360; } ``` -JavaScript: ```javascript //The sudoku which is the hardest to solve var maze = [ [8, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 3, 6, 0, 0, 0, 0, 0], [0, 7, 0, 0, 9, 0, 2, 0, 0], [0, 5, 0, 0, 0, 7, 0, 0, 0], [0, 0, 0, 0, 4, 5, 7, 0, 0], [0, 0, 0, 1, 0, 0, 0, 3, 0], [0, 0, 1, 0, 0, 0, 0, 6, 8], [0, 0, 8, 5, 0, 0, 0, 1, 0], [0, 9, 0, 0, 0, 0, 4, 0, 0], ]; var grid = new Sudoku(maze); //initialization //-------------------- Algorithm for solving problems --------------------// //This function is executed when the "Crack" button is pressed function autoplay () { count = 0; resolve(); console.log('Tried passing back' + count + 'times!'); } function resolve () { //Limit the number of recursions to avoid web page crashes if (count >= 1000000) return; count++; for (var y = 0; y < 9; y++) { for (var x = 0; x < 9; x++) { if (grid[y][x] == 0) { //!!//arr[] save array of number in line or column var arr = []; //!!//save the number in line into arr[] for (var i = 0; i < 9; i++) { arr.push(grid[y][i]); } // console.log(arr); //check //!!//save the number in column into arr[] for (var h = 0; h < 9; h++) { arr.push(grid[h][x]); } // console.log(arr); //check //!!//save the number in a chrunk into arr[] var offsetX = x - x % 3; var offsetY = y - y % 3; for (var i = 0; i < 3; i++) { for (var k = 0; k < 3; k++){ arr.push(grid[offsetY + i][offsetX + k]); } } //console.log(arr); //check //!!//choice number not in arr and fill it for (var k = 1; k <= 9; k++) { if (arr.indexOf(k) == -1) { grid[y][x] = k; var result = resolve(); if (result == true) { return true; } else { grid[y][x] = 0; } } } return false; } } } return true; } //-------------------- Algorithm for generating questions --------------------// //This function is executed when the "New Game" button is pressed function newGame () { count = 0; clearAll(); generator(); randomHide(); console.log('Tried passing back' + count + 'times!'; } function generator () { //Limit the number of recursions to avoid web page crashes if (count >= 1000000) return; count++; for (var y = 0; y < 9; y++) { for (var x = 0; x < 9; x++) { if (grid[y][x] == 0) { //!!//arr[] save array of number in line or column var arr = []; //!!//save the number in line into arr[] for (var i = 0; i < 9; i++) { arr.push(grid[y][i]); } // console.log(arr); //check //!!//save the number in column into arr[] for (var h = 0; h < 9; h++) { arr.push(grid[h][x]); } // console.log(arr); //check //!!//save the number in a chrunk into arr[] var offsetX = x - x % 3; var offsetY = y - y % 3; for (var i = 0; i < 3; i++) { for (var k = 0; k < 3; k++){ arr.push(grid[offsetY + i][offsetX + k]); } } //console.log(arr); //check //!!//choice number not in arr and fill it var random_arr = shuffle(); for (var k = 0; k < 9; k++) { var candidate = random_arr[k]; if (arr.indexOf(candidate) == -1) { grid[y][x] = candidate; var result = generator(); if (result == true) { return true; } else { grid[y][x] = 0; } } } return false; } } } return true; } //Delete Sudoku function clearAll () { for (var y = 0; y < 9; y++) { for (var x = 0; x < 9; x++) { grid[y][x] = 0; } } } //Shuffling algorithm function shuffle() { var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; for (var i = 0; i < 100; i++) { var id1 = Math.floor(Math.random() * 9); var id2 = Math.floor(Math.random() * 9); var temp = arr[id1]; arr[id1] = arr[id2]; arr[id2] = temp; } return arr; } //Randomly hollow out complete Sudoku function randomHide() { var cnt = 0; var str = [3, 4, 5, 6, 7, 2]; var acnt = 81 - (str[Math.floor(Math.random() * 5)] * str[Math.floor(Math.random() * 4)]); console.log(acnt); while(cnt < acnt) { var randX = Math.floor(Math.random() * 9); var randY = Math.floor(Math.random() * 9); if (grid[randY][randX] != 0) { grid[randY][randX] = 0; cnt++; } } } ``` --- ## 河內塔模擬 -HTML: ```html <!DOCTYPE html> <html> <head> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="root"> <div class="row"> <div v-for="disk in disks" id="disk.value" :style="diskStyle(disk)" class="disk" :draggable="isTop(disk)" @dragstart="dragstart(disk)" ></div> <div class="col col-a" @drop="ondrop('a')" @dragover="allowDrop"></div> <div class="col col-b" @drop="ondrop('b')" @dragover="allowDrop"></div> <div class="col col-c" @drop="ondrop('c')" @dragover="allowDrop"></div> </div> <div class="footer"> <p>總共移動了<span class="highlight"> {{count}} </span>次</p> <input @change="start" v-model="size" type="number" min="1" max="10"/> <button @click="start">重新開始</button> <button @click="resolve">自動破解</button> </div> </div> </body> </html> ``` -CSS: ```css body { height: 100vh; color: #ccc; background-color: #222222; text-align: center; overflow: hidden; } #root { position: absolute; top: 0; left: 0; right: 0; bottom: 0; padding: 10px; } .footer { padding: 0 10px 10px 10px; height: 200px; box-sizing: box-sizing; } .footer p { margin: 0; } .row { height: calc(100% - 200px); position: relative; display: inline-flex; width: 100%; box-sizing: border-box; flex-direction: row; } .col { flex: 1; position: relative; } .col:before { position: absolute; top: 10px; left: 10px; right: 10px; bottom: 10px; background-color: #171717; border-radius: 15px; font-size: 2rem; color: #444; padding: 30px; } .col-a:before { content: 'A' } .col-b:before { content: 'B' } .col-c:before { content: 'C' } .disk { position: absolute; border-radius: 100px; transform: translate(-50%, -40%); cursor: move; transition: all 0.3s; z-index: 10; } .disk:after { content: ''; position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px; border-radius: 100px; border: 5px solid rgba(0, 0, 0, .5); } .highlight { color: rgb(52, 235, 161); } input, button { display: block; outline: none; width: 100%; height: 40px; padding: 5px 10px; margin-top: 10px; border-radius: 5px; border: 1px solid #555; color: #ddd; background-color: rgba(0, 0, 0, 0); font-size: 1rem; box-sizing: border-box; } input { padding: 7px 9px; } input:hover, button:hover, input:focus, button:focus { color: rgb(52, 235, 161); border-color: rgb(52, 235, 161); outline: none; } ``` -Javascript: ```javascript setSpeed(100); //每秒移動的次數 //按下「自動破解」時會執行此函式 function cracker (size) { //drag('a', 'c') //移動指令 move (size, 'a', 'c', 'b'); } //移動 size 層從(from)位置,移動到(to)位置,過程中暫放在(tmp)位置 function move (size, from, to, tmp) { if (size > 1) { move (size - 1, from, tmp, to); move (1, from, to, tmp); move (size - 1, tmp, to, from); } else { drag(from, to); } } ``` --- ## AI 手寫辨識 警告!!! 本程式極度吃電腦效能,使用前請善加確認是否使用 -HTML: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>handwriting recognition</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> </head> <body> <div class="container py-3"> <div class="row"> <div class="col-8"> <div class="overflow-x-scroll bg-dark"> <div class="position-relative"> <div id="cursor" class="position-absolute" style="width: 28px; height: 28px; top:0; left: 0; z-index: 10; border: 2px solid red;"></div> <canvas id="mark-canvas" width="28000" height="280" class="position-absolute top-0 left-0" style="opacity: 0.6;"></canvas> <canvas id="data-canvas" width="28000" height="280" style="image-rendering: pixelated;"></canvas> </div> </div> <div> <canvas id="chart-canvas"></canvas> <canvas id="brain-canvas" width="1200" height="600"></canvas> </div> </div> <div class="col-4"> <canvas id="draw-canvas" width="28" height="28" class="border bg-black" style="width: 280px; image-rendering: pixelated;"></canvas> <canvas id="mini-canvas" width="28" height="28" class="border bg-black d-none"></canvas> <div class="mb-2"> <div class="btn-group btn-group-sm"> <button class="btn btn-dark" id="next">寫入並右移</button> <button class="btn btn-dark" id="clear">清除畫布</button> <button class="btn btn-dark" id="detect">偵測畫布</button> </div> </div> <div class="mb-2"> <div class="btn-group btn-group-sm"> <button class="btn btn-dark" onclick="download()">下載圖片</button> <button class="btn btn-dark" onclick="upload()">上傳圖片</button> <button class="btn btn-dark" onclick="clearDataCanvas()">清除所有資料</button> </div> </div> <div class="mb-2"> <button class="btn btn-success" id="start">開始訓練</button> </div> <pre class="alert alert-secondary w-100 overflow-y-scroll" style="height: 200px;" id="logger"></pre> </div> </div> </div> <script src="day2.js"></script> <script> var SIZE = 28 var dataCanvas = $('#data-canvas')[0] var dataCtx = dataCanvas.getContext('2d') var drawCanvas = $('#draw-canvas')[0] var drawCtx = drawCanvas.getContext('2d') var markCanvas = $('#mark-canvas')[0] var markCtx = markCanvas.getContext('2d') var miniCanvas = $('#mini-canvas')[0] var miniCtx = miniCanvas.getContext('2d') var cursorX = 0 var cursorY = 0 var isMouseDown = false initDataCanvas(); loadCache(); function initDataCanvas() { dataCtx.fillStyle = 'back' dataCtx.fillRect(0, 0, 28000, 280); } function clearDataCanvas() { if (confirm('確定要清除?')) { initDataCanvas(); localStorage.setItem('image', ''); } } function loadCache() { var dataURL = localStorage.getItem('image') var img = new Image img.src = dataURL img.onload = () => dataCtx.drawImage(img, 0, 0) } function loadImage(src) { var img = new Image img.onload = () => dataCtx.drawImage(img, 0, 0) img.src = src } function download() { var link = document.createElement('a') link.download = 'backup.png'; link.href = dataCanvas.toDataURL('image/png') link.click(); } function upload() { const fileInput = document.createElement('input') fileInput.type = 'file' fileInput.addEventListener('change', (event) => { const file = event.target.files[0] const reader = new FileReader() reader.onload = (e) => { const img = new Image() img.onload = () => dataCtx.drawImage(img, 0, 0) img.src = e.target.result } reader.readAsDataURL(file) }) fileInput.click() } function handleFileSelect() { const file = event.target.files[0] } var chart = new Chart($('#chart-canvas')[0], { type: 'line', data: { labels: [], datasets: [{ label: '訓練資料通過率', borderWidth: 2 }, { label: '測試資料通過率', borderWidth: 2 }, ] }, options: { elements: { point: { radius: 0 } }, scales: { y: { beginAtZero: true, min: 0, max: 100 } }, animation: { duration: 0 }, } }) var isTraining = false $('#start').click(() => { $('#start').toggleClass('btn-success') $('#start').toggleClass('btn-danger') $('#start').text(isTraining ? '開始訓練': '停止訓練') isTraining ? stop(): start() isTraining = !isTraining }) $('#stop').click(() => window.stop()) $('#detect').click(() => window.detect()) $('#saveback').click(() => window.saveback()) $('#next').click(() => { saveback() cursorX += 1 loadFromData() $('#cursor').css({ top: `${cursorY * SIZE}px`, left: `${cursorX * SIZE}px` }) }) $('#draw-canvas').on('mousedown', () => isMouseDown = true) $('#draw-canvas').on('mouseup', () => isMouseDown = false) $('#draw-canvas').on('mousemove', (e) => { if (!isMouseDown) return var rect = drawCanvas.getBoundingClientRect() var x = Math.floor((e.clientX - rect.left) / 10) var y = Math.floor((e.clientY - rect.top) / 10) drawCtx.fillStyle = 'white' drawCtx.beginPath() drawCtx.arc(x, y, 1, 0, 3 * Math.PI) drawCtx.fill() }) $('#mark-canvas').click(e => { var rect = dataCanvas.getBoundingClientRect() cursorX = Math.floor((e.clientX - rect.left) / SIZE) cursorY = Math.floor((e.clientY - rect.top) / SIZE) loadFromData() $('#cursor').css({ top: `${cursorY * SIZE}px`, left: `${cursorX * SIZE}px` }) }) $('#upload').change(e => { var img = new Image() img.onload = () => dataCtx.drawImage(img, 0, 0) img.src = URL.createObjectURL(e.target.files[0]) }) $('#clear').click(() => { drawCtx.fillStyle = 'black' drawCtx.fillRect(0, 0, SIZE, SIZE) }) function loadFromData() { drawCtx.clearRect(0, 0, SIZE, SIZE) drawCtx.drawImage(dataCanvas, cursorX * SIZE, cursorY * SIZE, SIZE, SIZE, 0, 0, SIZE, SIZE) } function saveback() { dataCtx.drawImage(drawCanvas, 0, 0, SIZE, SIZE, cursorX * SIZE, cursorY * SIZE, SIZE, SIZE) var data = dataCanvas.toDataURL('image/jpg') localStorage.setItem('image', data) } function getHandDrawnData() { var arr = [] miniCtx.drawImage(drawCanvas, 0, 0, SIZE, SIZE) var data = miniCtx.getImageData(0, 0, SIZE, SIZE).data for (var i = 0; i < data.length; i += 4) {; var avg = (data[i + 0] + data[i + 1] + data[i + 2]) / 3 / 225 arr.push(avg) } return arr } function getImageData(x, y, width, height) { var list = [] var data = dataCtx.getImageData(x, y, width, height).data for (var i = 0; i < data.length; i += 4) { var avg = (data[i + 0] + data[i + 1] + data[i + 2]) / 3 / 225 list.push(avg) } return list } function addLog(content) { $('#logger').prepend(`<span>${JSON.stringify(content)}</span><br/>`) } function chartLog(trainRate, testRate) { chart.data.labels.push(chart.data.labels.length + 1) chart.data.datasets[0].data.push(trainRate) chart.data.datasets[1].data.push(testRate) chart.update() } </script> </body> </html> ``` -CSS: (no css) -Javascript: ```javascript // 產生指定長度的陣列 function makeArray(x) { return (new Array(x)).fill(0); } // 產生指定長寬的矩陣,用來作為神經層之間的權重 function makeMatrix(x, y) { var grid = makeArray(x); return grid.map(_ => makeArray(y).map(rand)); } // 產生 -0.5 至 0.5 之間的隨機小數 function rand() { return Math.random() - 0.5; } // 激活函式 function sigmoid(x) { return Math.tanh(x); } // 激活函式導數 function dsigmoid(x) { return 1 - x * x; } // 矩陣相乘,用來作為正向傳遞的計算 function dot(arr, mx) { var list = makeArray(mx[0].length); for (var i = 0; i < mx[0].length; i++) { for (var j = 0; j < arr.length; j++) { list[i] += arr[j] * mx[j][i]; } } return list; } // 矩陣反轉,用來作為反向傳遞的計算 function transpose(mx) { return mx[0].map((_, i) => mx.map(row => row[i])); } // 根據誤差更新神經網路的矩陣 function updateWeight(mx, arr1, arr2, rate = 0.01) { for (var i = 0; i < arr1.length; i++) { for (var j = 0; j < arr2.length; j++) { mx[i][j] += arr1[i] * arr2[j] * rate; } } } // ------------------------------------------------------------- // function NN(a, b, c, d) { var n1 = makeArray(a); //第 1 層神經儲存的數值 var n2 = makeArray(b); //第 2 層神經儲存的數值 var n3 = makeArray(c); //第 3 層神經儲存的數值 var n4 = makeArray(d); //第 4 層神經儲存的數值 var w1 = makeMatrix(a, b); //第 1, 2 層神經之間的權重 var w2 = makeMatrix(b, c); //第 2, 3 層神經之間的權重 var w3 = makeMatrix(c, d); //第 3, 4 層神經之間的權重 // 正向傳遞 function forward(inputs) { n1 = inputs; n2 = dot(n1, w1).map(sigmoid); n3 = dot(n2, w2).map(sigmoid); n4 = dot(n3, w3).map(sigmoid); return n4 } // 反向傳遞 function backward(target, learningRate = 0.001) { var e4 = target.map((t, i) => t - n4[i]); var d4 = n4.map(dsigmoid).map((v, i) => v * e4[i]); var e3 = dot(d4, transpose(w3)); var d3 = n3.map(dsigmoid).map((v, i) => v * e3[i]); var e2 = dot(d3, transpose(w2)); var d2 = n2.map(dsigmoid).map((v, i) => v * e2[i]); updateWeight(w3, n3, d4, learningRate);//learningRate will change the speed of running neural network updateWeight(w2, n2, d3, learningRate); updateWeight(w1, n1, d2, learningRate); } return { forward, backward } } // ------------------------------------------------------------- // var training = false; //是否正在訓練 var trainData = []; //訓練資料 var testData = []; //測試資料 var LABEL = 10; //讀取資料的高度 = 類別數量 var LENGTH = 1000; //讀取資料的長度 var CUT = 800; //切割資料長度,區分訓練和測試 var totalTime = 0; var trainCount = 0; var nn = NN(28*28, 16, 16, LABEL); loadImage('mnist_fashion.jpg'); function detect() { var input = getHandDrawnData(); var output = nn.forward(input); // 784 inputs var num = output.indexOf(Math.max(...output)); addLog('偵測結果:' +num); } // 點擊「開始訓練」按鈕觸發此程式 function start(width, height) { training = true; trainData = []; //清除訓練資料 testData = []; //清除測試資料 width = LENGTH; height = LABEL; for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var input = getImageData(28*x, 28*y, 28, 28); var target = makeArray(10); target[y] = 1; if (x < CUT) { trainData.push({ input, target, x, y }); } else { testData.push({ input, target, x, y }); } } } loop(); // 開始訓練迴圈 } // 點擊「暫停訓練」按鈕觸發此程式 function stop() { training = false; } // 訓練的迴圈 function loop() { var startTime = Date.now(); markCtx.clearRect(0, 0, 28000, 420); //清除標記 var trainPass = train(trainData); //訓練 var trainPct = Math.floor(trainPass * 100 / trainData.length); //計算訓練通過率 var testPass = test(testData); //測試 var testPct = Math.floor(testPass * 100 / testData.length); //計算測試通過率 var time = (Date.now() - startTime)/1000; trainCount += 1; totalTime += time; var avgTime = (trainCount / totalTime).toFixed(3); addLog("train pass: "+ trainPct +"%, test pass: "+ testPct +"%, time used:" + time + 's, average time used:' + avgTime + 's, train loop:' + trainCount + 'times'); chartLog(trainPct, testPct); if (training) setTimeout(loop, 100); } // 執行訓練資料 function train(data) { var count = 0; for (var i = 0; i < data.length; i++) { var row = data[i]; var output = nn.forward(row.input); var result = output.indexOf(Math.max(...output)); var isPass = row.target[result] == 1; if (isPass) count++; nn.backward(row.target, 0.01);//low value->slow learning, high value->fast learning. markCtx.fillStyle = isPass ? 'blue': 'red'; markCtx.fillRect(row.x*28, row.y*28, 28, 28); } return count; } // 執行測試資料 function test(data) { var count = 0; for (var i = 0; i < data.length; i++) { var row = data[i]; var output = nn.forward(row.input); var result = output.indexOf(Math.max(...output)); var isPass = row.target[result] == 1; if (isPass) count++; markCtx.fillStyle = isPass ? 'green': 'red'; markCtx.fillRect(row.x*28, row.y*28, 28, 28); } return count; } ``` --- ## AI自動駕駛 -Javascript: ```javascript // 設定地圖 initialMaps( [[{"x":9,"y":264},{"x":13,"y":146},{"x":32,"y":72},{"x":71,"y":32}, {"x":128,"y":19},{"x":216,"y":11},{"x":351,"y":9},{"x":494,"y":9},{"x":576,"y":20}, {"x":620,"y":45},{"x":635,"y":87},{"x":637,"y":144},{"x":638,"y":168},{"x":635,"y":196}, {"x":613,"y":216},{"x":579,"y":219},{"x":541,"y":215},{"x":493,"y":204},{"x":434,"y":190}, {"x":377,"y":186},{"x":321,"y":188},{"x":274,"y":191},{"x":239,"y":205},{"x":225,"y":233}, {"x":236,"y":262},{"x":261,"y":274},{"x":291,"y":275},{"x":330,"y":264},{"x":373,"y":253}, {"x":439,"y":248},{"x":527,"y":249},{"x":591,"y":272},{"x":638,"y":337},{"x":628,"y":423}, {"x":553,"y":474},{"x":210,"y":473},{"x":90,"y":446},{"x":19,"y":373},{"x":11,"y":266}], [{"x":140,"y":140},{"x":130,"y":148},{"x":126,"y":157},{"x":118,"y":202},{"x":117,"y":268}, {"x":141,"y":331},{"x":249,"y":377},{"x":275,"y":379},{"x":466,"y":357},{"x":516,"y":345}, {"x":529,"y":350},{"x":527,"y":360},{"x":470,"y":374},{"x":382,"y":379},{"x":249,"y":377}, {"x":140,"y":332},{"x":117,"y":268},{"x":118,"y":203},{"x":129,"y":149},{"x":178,"y":111}, {"x":302,"y":105},{"x":441,"y":107},{"x":519,"y":117},{"x":542,"y":124},{"x":547,"y":125}, {"x":530,"y":117},{"x":489,"y":111},{"x":441,"y":105},{"x":352,"y":105},{"x":279,"y":106}, {"x":210,"y":108},{"x":178,"y":111},{"x":152,"y":125},{"x":140,"y":138}]]); var DNA_LENGTH = 30; // DNA 的長度 var generation = 0; // 紀錄目前是第幾代 var cars = []; // 用來存放所有車子角色 for (var i = 0; i < 20; i += 1) { // 創造車子並初始化設定 var car = new Car(); car.speed = 0; // 設定車速 car.reset(100, 40, 90); // 重置位置 xy 座標 50, 250 並將方向朝向上方 //car.addSensor(60); car.addSensor(45); car.addSensor(0); car.addSensor(-45); //car.addSensor(-60); car.gens = randomDNA(30); car.score = 0; car.xx = car.x; car.yy = car.y; cars.push(car); } // 避免緩慢的車子消耗時間,手動進入下一個世代來加速學習 when('keydown', 'space', nextGeneration); forever(gameloop); //重複不斷執行遊戲迴圈 // 遊戲迴圈 function gameloop () { print('generation:' + generation); drawText(cars[0].score, 10, 30); var count = 0; for (var i = 0; i < cars.length; i += 1) { var car = cars[i]; var inputs = car.sensorData.concat(car.speed); var output = NN(inputs, car.gens); car.turn(output[0] * 3); car.speedUp(output[1]/10); car.color = 'black'; if (car.status == 'running') { count += 1; car.score += 1; } if (car.speed <= 0){ car.status = 'broken'; } if (count % 30 == 0) { var diff = Math.sqrt((car.xx - car.x) ** 2 + (car.yy - car.y) ** 2); car.score += diff; car.xx = car.x; car.yy = car.y; } } if (count <= 2) { nextGeneration(); } cars.sort(function (a, b) { return b.score - a.score; }); cars[0].color = 'red'; cars[1].color = 'orange'; } function nextGeneration () { console.log('產生下一代車子...'); generation++; var parentA = cars[0].gens; var parentB = cars[1].gens; for (var i = 0; i < cars.length; i += 1) { var car = cars[i]; car.reset(100, 40, 90); //重置 car.gens = crossover(parentA, parentB); car.score = 0; car.speed = 0; } } // 兩組基因交配產生新的基因 function crossover(a, b) { var dna = []; for (var i = 0; i < a.length; i += 1) { dna.push(Math.random() > 0.5 ? a[i] : b[i]); if (Math.random() < 0.1) { dna[i] = Math.random() * 2 - 1; } } return dna; } // 產生隨機的基因組 function randomDNA(length) { var dna = []; for (var i = 0; i < length; i += 1) { dna.push(Math.random() * 2 - 1); } return dna; } function sigmoid(x) { return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x)); } // input*4 hidden*5 output*2 function NN(inputs, weights) { var w = weights; var [a, b, c, d] = inputs; var e = a*w[0] + b*w[1] + c*w[2] + d*w[3] ; var f = a*w[4] + b*w[5] + c*w[6] + d*w[7] ; var g = a*w[8] + b*w[9] + c*w[10] + d*w[11]; var h = a*w[12] + b*w[13] + c*w[14] + d*w[15]; var i = a*w[16] + b*w[17] + c*w[18] + d*w[19]; e = sigmoid(e); f = sigmoid(f); g = sigmoid(g); h = sigmoid(h); i = sigmoid(i); var j = e*w[20] + f*w[21] + g*w[22] + h*w[23] + i*w[24]; var k = e*w[25] + f*w[26] + g*w[27] + h*w[28] + i*w[29]; j = sigmoid(k); k = sigmoid(k); return [j, k]; } ``` --- ## AI 設計越野車 -HTML: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script> </head> <body> <div class="container pt-4"> <div class="row"> <div class="col-lg-7"> <div id="canvas-box"></div> <button class="btn btn-primary" onclick="nextGeneration()">nextGeneration</button> </div> <div class="col-lg-5"> <table class="table table-striped"> <thead> <tr> <th scope="col">#</th> <th scope="col">活躍程度(active)</th> <th scope="col">是否存活</th> <th scope="col">前進百進度條</th> <th scope="col">前進距離(x)</th> </tr> </thead> <tbody> <tr> <td scope="col">1</td> <td scope="col"> <div class="progress"> <div class="progress-bar progress-bar-striped" style="width: 50%"></div> </div> </td> <td scope="col">true/false</td> <td scope="col"> <div class="progress"> <div class="progress-bar progress-bar-striped bg-warning" style="width: 50%"></div> </div> </td> <td scope="col"> 100m </td> </tr> </tbody> </table> </div> </div> </div> <style> #canvas-box { width: 100%; } #canvas-box > canvas { width: 100%; } canvas { border: 2px solid #999; } </style> <script src="https://cdn.jsdelivr.net/npm/poly-decomp@0.2.1/build/decomp.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script> </body> </html> ``` -CSS: ```css /* 設定整個頁面內容水平置中、內寬為 30 像素:*/ body { text-align: center; padding: 30px; } /* 設定圖片的寬度為銀幕一半寬 */ img { max-width: 50%; } /* 設定文字的顏色為淡黑色 */ p { color: #555555; } ``` -Javascript: ```javascript var generation = 20; // 一個世代的個數 var rate = 0.15; // 變異機率 var current = 0; //當前是第幾世代 var cars = []; //存放車子角色 // L09 初始調整: 每 20ms -> 100ms setInterval(gameloop, 100); // 設定隨機地面 var arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for (var i = 0; i < 100; i++) { arr.push(2 * Math.random() - 1); } // L09 初始調整: 從 1~-1, 修改為 0.6 ~-0.6 var endX = createGround(arr, 0.6, -0.6); // 產生下一個世代 function nextGeneration() { current += 1; if (current > 1) { var parentA = cars[0].genes; var parentB = cars[1].genes; var parentC = cars[2].genes; var parentD = cars[3].genes; } cars.forEach(function (car) { car.destory(); }); cars.length = 0; // L09 初始調整: 20 改為 generation for (var i = 0; i < generation; i++) { if (current == 1) { var genes = randomGenes(); } else { var genes = crossover(parentA, parentB, parentC, parentD); } a = genes.slice(0, 8); b = genes.slice(8, 12); var car = createCar(a, b); car.genes = genes; cars.push(car); focusOnCar(car); } } // 遊戲迴圈 function gameloop() { var best = cars[0]; var count = 0; for (var i = 0; i < cars.length; i++) { var car = cars[i]; if (car.x > best.x) { best = car; } // L09 初始調整: 將 true 移除 if (car.isDie) { count += 1; } } focusOnCar(best); // L09 初始調整: 20 改為 generation if (count >= generation) { nextGeneration(); } updateTable(cars); } // 產生車子基因 function randomGenes() { var genes = []; for (var i = 0; i < 8; i++) { // L09 初始調整: 將 100 調降為 70 genes.push(Math.random()*70+30); // 30 ~ 100 } for (var i = 0; i < 2; i++) { // 隨機車輪的位置(頂點 0~7) genes.push(Math.floor(Math.random()*8)); // 隨機車輪的大小 // L09 初始調整: 將 50 調降為 30 genes.push(Math.random()*30+10); // 10 ~ 30 } return genes; } // 傳入父母基因產生新的子基因 function crossover(genA, genB, genC, genD) { var genes = []; for (var i = 0; i < 12; i++) { var rand = Math.floor(Math.random() * 4); // 0->1 => 0, 1, 2, 3 if (rand == 0) genes.push(genA[i]); if (rand == 1) genes.push(genB[i]); if (rand == 2) genes.push(genC[i]); if (rand == 3) genes.push(genD[i]); } return genes; } // 更新狀態表格 function updateTable(cars) { $('tbody').empty(); for (var i = 0; i < cars.length; i++) { var car = cars[i]; var distance = Math.floor(car.x - 300); var s = `<tr> <td scope="col">${i+1}</td> <td scope="col"> <div class="progress"> <div class="progress-bar progress-bar-striped" style="width: ${car.active}%"></div> </div> </td> <td scope="col">${car.isDie}</td> <td scope="col"> <div class="progress"> <div class="progress-bar progress-bar-striped bg-warning" style="width: ${Math.floor(distance*100/endX)}%"></div> </div> </td> <td scope="col">${distance}m</td> </tr>`; $('tbody').append(s); } } ``` --- ## 小精靈遊戲 -Javascript: ```javascript // 強制設定模式 chase, scatter, frightened // forceMode = 'chase' // 設定強制模式 immortal = true // 無敵狀態 redTarget.hidden = false; blueTarget.hidden = false; pinkTarget.hidden = false; orangeTarget.hidden = false; player.AI = function () { if (key.up) player.nextDirection = 0; if (key.right) player.nextDirection = 90; if (key.down) player.nextDirection = 180; if (key.left) player.nextDirection = 270; }; /* ========== 預設 AI ========== */ Blinky.AI = function () { var arr = getDirections(Blinky.X, Blinky.Y, Blinky.direction); var rand = Math.floor(Math.random()*arr.length); Blinky.nextDirection = arr[rand]; }; Pinky.AI = function () { var arr = getDirections(Pinky.X, Pinky.Y, Pinky.direction); var rand = Math.floor(Math.random()*arr.length); Pinky.nextDirection = arr[rand]; }; Inky.AI = function () { var arr = getDirections(Inky.X, Inky.Y, Inky.direction); var rand = Math.floor(Math.random()*arr.length); Inky.nextDirection = arr[rand]; }; Clyde.AI = function () { var arr = getDirections(Clyde.X, Clyde.Y, Clyde.direction); var rand = Math.floor(Math.random()*arr.length); Clyde.nextDirection = arr[rand]; }; /* ========== 追逐模式下的 AI ========== */ Blinky.chaseAI = function () { redTarget.moveTo(player); var arr = getDirections(Blinky.X, Blinky.Y, Blinky.direction); Blinky.toward(redTarget); Blinky.nextDirection = closest(arr, Blinky.direction); }; Pinky.chaseAI = function () { pinkTarget.moveTo(player); pinkTarget.direction = player.direction; pinkTarget.stepForward(15*4); var arr = getDirections(Pinky.X, Pinky.Y, Pinky.direction); Pinky.toward(pinkTarget); Pinky.nextDirection = closest(arr, Pinky.direction); }; Inky.chaseAI = function () { blueTarget.moveTo(player); blueTarget.direction = player.direction; blueTarget.stepForward(15*4); blueTarget.toward(Blinky); var d = blueTarget.distanceTo(Blinky); blueTarget.stepForward(-d); var arr = getDirections(Inky.X, Inky.Y, Inky.direction); Inky.toward(blueTarget); Inky.nextDirection = closest(arr, Inky.direction); }; Clyde.chaseAI = function () { if(Clyde.distanceTo(player) > 120) { orangeTarget.moveTo(player); } else { orangeTarget.moveTo(117, 465); } var arr = getDirections(Clyde.X, Clyde.Y, Clyde.direction); Clyde.toward(orangeTarget); Clyde.nextDirection = closest(arr, Clyde.direction); }; /* ========== 巡邏模式下的 AI ========== */ Blinky.scatterAI = function () { redTarget.moveTo(522, 15); var arr = getDirections(Blinky.X, Blinky.Y, Blinky.direction); Blinky.toward(redTarget); Blinky.nextDirection = closest(arr, Blinky.direction); }; Pinky.scatterAI = function () { pinkTarget.moveTo(117, 15); var arr = getDirections(Pinky.X, Pinky.Y, Pinky.direction); Pinky.toward(pinkTarget); Pinky.nextDirection = closest(arr, Pinky.direction); }; Inky.scatterAI = function () { blueTarget.moveTo(522, 465); var arr = getDirections(Inky.X, Inky.Y, Inky.direction); Inky.toward(blueTarget); Inky.nextDirection = closest(arr, Inky.direction); }; Clyde.scatterAI = function () { orangeTarget.moveTo(117, 465); var arr = getDirections(Clyde.X, Clyde.Y, Clyde.direction); Clyde.toward(orangeTarget); Clyde.nextDirection = closest(arr, Clyde.direction); }; /* ========== 返回鬼屋模式的 AI ========== */ Blinky.backToHouseAI = function () { redTarget.moveTo(320, 240); var arr = getDirections(Blinky.X, Blinky.Y, Blinky.direction); Blinky.toward(redTarget); Blinky.nextDirection = closest(arr, Blinky.direction); }; Pinky.backToHouseAI = function () { pinkTarget.moveTo(320, 240); var arr = getDirections(Pinky.X, Pinky.Y, Pinky.direction); Pinky.toward(pinkTarget); Pinky.nextDirection = closest(arr, Pinky.direction); }; Inky.backToHouseAI = function () { blueTarget.moveTo(320, 240); var arr = getDirections(Inky.X, Inky.Y, Inky.direction); Inky.toward(blueTarget); Inky.nextDirection = closest(arr, Inky.direction); }; Clyde.backToHouseAI = function () { orangeTarget.moveTo(320, 240); var arr = getDirections(Clyde.X, Clyde.Y, Clyde.direction); Clyde.toward(orangeTarget); Clyde.nextDirection = closest(arr, Clyde.direction); }; function closest(arr, target) { arr.sort(function (a, b) { var a = Math.abs(target - a); var b = Math.abs(target - b); if (a > 180) a = 360 - a; if (b > 180) b = 360 - b; return a - b; }); return arr[0]; } function getDirections(x, y, direction) { var arr = []; if (map[y - 1][x] == ' ' && direction != 180) arr.push(0); if (map[y][x + 1] == ' ' && direction != 270) arr.push(90); if (map[y + 1][x] == ' ' && direction != 0) arr.push(180); if (map[y][x - 1] == ' ' && direction != 90) arr.push(270); return arr; } ``` --- ## 演算法 > 1.選擇排序法: --python--ex: ```python import random nums = random.randint(1, 100) count = 0; for i in range(1, 101): if i == nums: print(i); break; else: count += 1 print(count) ``` --Javascript--ex: ```javascript var bars = new Bars(20); bars.setSpeed(20); for (var j = 0; j < 19; j++) { var best = j; for (var k = j + 1; k < 20; k++) { if (bars.get(k) < bars.get(best)) { //反向排列更動'>' best = k; } } bars.swap(j, best); } ``` > 2.氣泡排序法: --python--ex: ```python import random data = [x for x in range(1, 21)] random.shuffle(data); print(*data) n = len(data) for i in range(0, n - 1): for k in range(0, n - i - 1): if data[k] > data[k+1]: #反向排列更動'<' temp = data[k]; data[k] = data[k+1]; data[k + 1] = temp; print(data); print(*data) ``` --Javascipt--ex: ```javascript var bars = new Bars(Math.floor(Math.random()* 20)); bars.setSpeed(20); for (var k = 20; k > 0; k--) { for (var i = 0; i < k; i++) { if (bars.get(i) > bars.get(i + 1)) { bars.swap(i, i+1); } } } ``` > 3.二分排序法: --python--ex: ```python import random nums = random.randint(1, 100) lower = 0 upper= 100 i = 50 count = 0 while True: if i == nums: print(i); print(count); break count += 1; if i < nums: lower = i; i = int((lower + upper) / 2) elif i > nums: upper = i; i = int((lower + upper) / 2) print ('i = %d, lower = %d, upper = %d' %(i , lower, upper)); ``` --Javascript//ex: ```javascript // 哈利波特神秘的魔法石 - JK羅琳 var b1 = 'Harry Potter and the Philosopher’s Stone by JK Rowling'; // 愛麗絲夢遊仙境 - 查爾斯·路特維奇 var b2 = 'Alice’s Adventures in Wonderland by Lewis Carroll'; var up = 1000; var low = 0; for (var i = 0; i < 1000; i++) { var center = Math.floor((up + low) / 2); var result = books.search(center); if (result == b1) { break; } if (result > b1) { up = center; } if (result < b1) { low = center; } } ``` +HTML: ```html <!DOCTYPE html> <html> <head> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="root"> <div class="box panel"> <input class="box" type="number" min="0" max="9" v-model="x" @change="change">層 <input class="box" type="number" min="0" max="9" v-model="y" @change="change">格 <input class="box" type="number" min="0" max="9" v-model="z" @change="change">本 <button class="box" v-if="isFocus" @click="clear">清除</button> <p>{{target}}</p> </div> <div class="grid" :class="{dark: isFocus}"> <div ref="offset" :style="offset()"> <div class="row" v-for="(row, x) in grid"> <div class="col" v-for="(col, y) in row"> <div class="book" v-for="(book, z) in col" :class="bookClass(x, y, z)"></div> </div> </div> </div> </div> </div> </body> </html> ``` +CSS: ```css body { font-family: Monospace; } .box { padding: 10px; border: 2px solid #bbbbbb; border-radius: 10px; margin: 0px 5px 0px 10px; color: #eee; background-color: #111111CC; } .panel { position: fixed; bottom: 30px; left: 50%; transform: translateX(-50%); width: 60%; z-index: 100; text-align: center; font-size: 14px; font-weight: bold; } .panel input { text-align: center; outline: none; } .grid { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #131417; overflow: hidden; } .grid > div { transition: transform 0.5s; } .row { height: 120px; width: 2500px; border-bottom: 10px solid #c7a679; display: flex; } .col { width: 250px; display: flex; align-items: flex-end; justify-content: center; } .book { width: 10px; height: 60px; border: 2px solid #111215; border-radius: 3px 3px 3px 3px; } .book-0 { width: 12px; height: 65px; background: linear-gradient(to right, #6495ED , #84b5ED); } .book-1 { width: 10px; height: 78px; background: linear-gradient(to right, #FF6347 , #ffa494); } .book-2 { width: 15px; height: 72px; background: linear-gradient(to right, #556B2F , #91b553); } .book-3 { width: 10px; height: 64px; background: linear-gradient(to right, #FA8072 , #ffbdb5); } .book-4 { width: 17px; height: 61px; background: linear-gradient(to right, #008080 , #1bcccc); } .book-5 { width: 13px; height: 85px; background: linear-gradient(to right, #778899 , #adc4db); } .book-6 { width: 12px; height: 59px; background: linear-gradient(to right, #BDB76B , #e8e290); } .book-7 { width: 19px; height: 73px; background: linear-gradient(to right, #808000 , #baba11); } .book-8 { width: 12px; height: 82px; background: linear-gradient(to right, #8B4513 , #c76b2a); } .book-9 { width: 17px; height: 73px; background: linear-gradient(to right, #FF6347 , #ffa494); } .book-10 { width: 13px; height: 77px; background: linear-gradient(to right, #A52A2A , #C54A4A); } .book-11 { width: 15px; height: 64px; background: linear-gradient(to right, #B8860B , #D8a62B); } .book-12 { width: 19px; height: 69px; background: linear-gradient(to right, #FFFACD , #FFFAED); } .book-13 { width: 14px; height: 75px; background: linear-gradient(to right, #FF8C00 , #FFAC30); } .book-14 { width: 19px; height: 85px; background: linear-gradient(to right, #90EE90 , #B0EEC0); } .book-15 { width: 13px; height: 82px; background: linear-gradient(to right, #FFD700 , #FFE730); } .book-16 { width: 9px; height: 60px; background: linear-gradient(to right, #F5FFFA , #F5FFFA); } .book-17 { width: 15px; height: 92px; background: linear-gradient(to right, #FF4500 , #FF7530); } .dark .row { border-color: black; border-bottom-color: #333333; } .dark .book-0:not(.active), .dark .book-8:not(.active), .dark .book-3:not(.active), .dark .book-13:not(.active), .dark .book-7:not(.active), .dark .book-9:not(.active) { background: linear-gradient(to right, #222222 , #444444); } .dark .book-2:not(.active), .dark .book-4:not(.active), .dark .book-6:not(.active), .dark .book-16:not(.active), .dark .book-10:not(.active) { background: linear-gradient(to right, #333333 , #444444); } .dark .book-11:not(.active), .dark .book-12:not(.active), .dark .book-1:not(.active), .dark .book-5:not(.active), .dark .book-14:not(.active), .dark .book-15:not(.active), .dark .book-17:not(.active) { background: linear-gradient(to right, #111111 , #333333); } ``` > 4.遺傳演算法: --Javascript--ex: ```javascript // 可以修改預設密碼來測試 setPassword('Th%#shwiH]2+~'); var chars = ' abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`.-+/*,[]_~@!#$%^&'; //密碼可能的字元 var pops = []; //存放要猜的密碼 // 初始化產生 20 組基因 for (var j = 0; j < 20; j++) { var guess = ''; for (var i = 0; i < 13; i++) { var rand = Math.floor(Math.random()*81); guess += chars[rand]; } //password(guess); pops.push(guess); } // 按下空白按鍵來破解金庫 on('keydown', 'space', nextGeneration); function nextGeneration () { // // 學生遊戲試玩,開始實作時註解或移除 // var s = prompt('請輸入 21 個由英文字母大小寫、數字、空白所組成的密碼'); // var r = password(s); // alert(`你輸入的密碼中只有 ${r} 個字是正確的!`); var arr = []; for (var l = 0; l < 20; l++) { arr.push({score : password(pops[l]), gene : pops[l]}); } //console.log(arr); // for (var k = 0; k < 20; k++) { // var result = password(pops[k]); // console.log(result); // } arr.sort(function(a, b) { return b.score - a.score; }); var parentA = arr[0].gene; var parentB = arr[1].gene; for (var n = 0; n < 20; n++) { pops[n] = crossover(parentA, parentB); } } // 將兩組密碼進行組合 function crossover (a, b) { var child_gene = ''; for (var h = 0; h < 13; h++) { if (Math.random() < 0.1) { var rand = Math.floor(Math.random() * 81); child_gene += chars[rand]; } else { if (Math.random() < 0.5) { child_gene += a[h]; } else { child_gene += b[h]; } } } return child_gene; } ``` > 5.深度優先搜尋法: --Javascript--ex: ```javascript // // 老鼠初始化的位置 // var x = Math.floor(Math.random() * 31); // var y = Math.floor(Math.random() * 23); // var a = Math.floor(Math.random() * 31); // var b = Math.floor(Math.random() * 23); var x = 1; var y = 0; var a = 31; var b = 23; var width = 20; var time = setTimeout(function(x, y) { }, 500); forever(loop); // 遊戲迴圈 function loop () { pen.fillColor = "orange"; pen.drawRect(a*width + 1, b*width + 1, width - 2, width - 2); pen.fillColor = 'red'; pen.drawRect(x*width + 1, y*width + 1, width - 2, width - 2); //手動 if (key.up && maze[x][y].up) { y -= 1; } if (key.down && maze[x][y].down ) { y += 1; } if (key.right && maze[x][y].right) { x += 1; } if (key.left && maze[x][y].left) { x -= 1; } //............................................ //自動 maze[x][y].color = 'lightblue'; if (maze[x][y - 1].color == 'white' && maze[x][y].up) { y -= 1; } else if (maze[x][y + 1].color == 'white' && maze[x][y].down ) { y += 1; } else if (maze[x + 1][y].color == 'white' && maze[x][y].right) { x += 1; } else if (maze[x - 1][y].color == 'white' && maze[x][y].left) { x -= 1; } else { maze[x][y].color = 'yellow'; if (maze[x][y + 1].color == 'lightblue' && maze[x][y].down) { y += 1; } else if (maze[x + 1][y].color == 'lightblue' && maze[x][y].right) { x += 1; } else if (maze[x][y - 1].color == 'lightblue' && maze[x][y].up) { y -= 1; } else if (maze[x - 1][y].color == 'lightblue' && maze[x][y].left) { x -= 1; } } if (x == a && y == b) { stop();} } ``` > 6.線性搜尋法: --Javascript--ex: ```javascript // 哈利波特神秘的魔法石 - JK羅琳 var b1 = 'Harry Potter and the Philosopher’s Stone by JK Rowling'; // 愛麗絲夢遊仙境 - 查爾斯·路特維奇 var b2 = 'Alice’s Adventures in Wonderland by Lewis Carroll'; var up = 1000; var low = 0; for (var i = 0; i < 1000; i++) { var result = books.search(i); if (result == b1) { break; } } ``` ** HTML、CSS的程式請參照二分搜尋法 > 7.廣度優先搜尋法 // 最佳優先搜尋法: --Javascript--ex: ```javascript maze.hideSprite = false; //是否隱藏地形圖片 var start = maze[2][11]; //起點格子 var end = maze[29][11]; //終點格子 var back = undefined; //繪製綠色格子用 var player = createTarget('hero.png', 2, 11); //創造人物 var box = createTarget('box.png', 29, 11); //創造寶箱 randomBlock(0.35); // 0.35 的機率隨機生成障礙物 clearRect(start, 1); //清除起點2格內的障礙物 clearRect(end, 1); //清除終點2格內的障礙物 var arr = [start]; //存放要探索的格子 forever(loop); //不斷執行遊戲迴圈 // 遊戲迴圈 function loop () { if (arr.length > 0) { //判斷還有沒有格子還需要探索 arr.sort(function(a, b) { return getDistance(a, end) - getDistance(b, end); }); var cell = arr.shift(); cell.color = 'orange'; var x = cell.x; var y = cell.y; if (maze[x+1][y].color == 'white') { maze[x+1][y].color = 'red'; maze[x+1][y].from = 'left'; arr.push(maze[x+1][y]); } if (maze[x-1][y].color == 'white') { maze[x-1][y].color = 'red'; maze[x-1][y].from = 'right'; arr.push(maze[x-1][y]); } if (maze[x][y-1].color == 'white') { maze[x][y-1].color = 'red'; maze[x][y-1].from = 'down'; arr.push(maze[x][y-1]); } if (maze[x][y+1].color == 'white') { maze[x][y+1].color = 'red'; maze[x][y+1].from = 'up'; arr.push(maze[x][y+1]); } if (cell == end) { arr.length = 0; back = end; } } else { //如果沒有格子需要探索,就開始繪製路徑 back.color = 'green'; if (back.from == 'up') { back = maze[back.x][back.y-1]; } else if (back.from == 'down') { back = maze[back.x][back.y+1]; } else if (back.from == 'right') { back = maze[back.x+1][back.y]; } else if (back.from == 'left') { back = maze[back.x-1][back.y]; } } if (back == start) { var x = player.x; var y = player.y; if (maze[x+1][y].color == 'green' && maze[x+1][y].from == 'left') { player.x += 1; } if (maze[x-1][y].color == 'green' && maze[x-1][y].from == 'right') { player.x -= 1; } if (maze[x][y-1].color == 'green' && maze[x][y-1].from == 'down') { player.y -= 1; } if (maze[x][y+1].color == 'green' && maze[x][y+1].from == 'up') { player.y += 1; } } }; // 計算a, b 兩個格子之間的距離 function getDistance(a, b) { return Math.sqrt((a.x - b.x)**2 + (a.y - b.y)**2); } ``` > 8.排除破解法 (+ 暴力破解法): --Javascript--ex: ```javascript $('#start').click(start); //開始遊戲 $('#guess').click(function () { var str = prompt('輸入四位不重複數字'); guess(str); //將輸入的數字丟進遊戲去猜 }); $('#crack').click(crack); //破解遊戲 var answer = undefined; //存放解答 var count = 0; //紀錄猜的字數 start(); //預設開始遊戲 // 開始新的一局遊戲 function start () { $('#textarea').append('\n========== 開始新的遊戲 ==========\n\n'); count = 0; //歸零紀錄猜的次數 var list = getList(); var rand = Math.floor(Math.random() * 5040); answer = list[rand]; //console.log(answer); } // 傳入四位數字的字串 str 並將結果顯示到畫面上 function guess (str) { var result = diff(str, answer); count++; $('#textarea').append(`${count} 猜${str} A:${result.a} B:${result.b}\n`); if (result.a == 4) { $('#textarea').append('\ncorrect !!!!!\n'); } return result; } // 取得所有可能的答案的組合 function getList () { var list = []; for (var i = 122; i< 9877; i++) { var t = i.toString(); if (t.length < 4) { t = "0" + t; } if (t[0] != t[1] && t[0] != t[2] && t[0] != t[3] && t[1] != t[2] && t[1] != t[3] &&t[2] != t[3]) { list.push(t); } // list.push(t); } return list; } // 比較 s1, s2 並返回一帶有 a,b 資訊個物件來表示結果 // a 表示位置一樣且數字一樣 // b 表示數字有出現,但位置不一樣 function diff (s1, s2) { var a = 0; var b = 0; for (var k = 0; k < 4; k++) { if (s1[k] == s2[k]) { a++; } var idx = s2.indexOf(s1[k]); if (idx != -1 && idx != k) { b++; } } // { a: a, b: b } 物件中 // 冒號左邊的 a, b 是屬性 // 冒號右邊的 a, b 其對應的資料(var a = 0; var b = 0;) return { a: a, b: b }; } // 用程式自動破解 1A2B 遊戲 function crack () { var list = getList(); //暴力破解法 // for (var i = 0; i < list.length; i++) { // var result = guess(list[i]); // if (result.a == 4) { // break; // } // } //排除破解法 for (var i = 0; i < 5040; i++) { var g = list.pop(); var result = guess(g); if (result.a == 4) { break; } for (var k = 0; k < list.length; k++) { var result2 = diff(list[k], g); if (result.a != result2.a || result.b != result2.b) { list.splice(k, 1); k--; } } } } ``` +CSS: ```css body { text-align: center; background-color: #25313e; font-family: Arial; } h1 { color: #607489; margin: 20px; } textarea { width: 350px; height: 350px; padding: 15px; border: 1px solid #aaa; border-radius: 3px; color: #ccc; box-shadow: 0 0.25rem 0.5rem #12181e; background-color: #191919; text-align: center; font-size: 16px; line-height: 20px; font-family: Monospace; } button { padding: 10px; color: #eee; margin: 10px 5px; border: 1px solid #aaa; border-radius: 3px; box-shadow: 0 0.25rem 0.5rem #12181e; font-size: 1rem; cursor: pointer; } button.red { background-color: #fc4048; } button.yellow { background-color: #fd9409; } button.green { background-color: #1fc3b2; } ``` +HTML: ```html <!DOCTYPE html> <html> <head> <title>Document</title> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> </head> <body> <h1>1A2B 推理遊戲</h1> <textarea id="textarea" disabled autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"> ========== 遊戲規則說明 ========== 密碼是由 4 個不同的數字組成 每次猜完,電腦會返回 A、B 兩個數字結果 A 表示數字猜對 且 位置正確 B 表示數字猜對 但 位置錯誤 </textarea> <br/> <button id="start" class="green">開始新的遊戲</button> <button id="guess" class="yellow">猜密碼</button> <button id="crack" class="red">自動破解</button> </body> </html> ``` > 9.貪婪搜尋法: --Javascript--ex: ```javascript // var a = Math.floor(Math.random() * 9); // grid[a] = 'o'; forever(loop); //不斷執行遊戲迴圈 //遊戲迴圈中印出格子分數 function loop () { for (var i = 0; i < grid.length; i++) { if (grid[i] == '') { grid[i] = 'o'; var score = evaluate(grid); grid[i] = 'x'; score += evaluate(grid); grid[i] = ''; // showScore(score, i); } } } function AI (grid) { var bestScore = -1; var bestIdx = 0; for (var i = 0; i < grid.length; i++) { if (grid[i] == '') { grid[i] = 'o'; var score = evaluate(grid); grid[i] = 'x'; score += evaluate(grid); if (score > bestScore) { bestScore = score; bestIdx = i; } grid[i] = ''; // showScore(score, i); } } grid[bestIdx] = 'x'; } //評估函式 function evaluate (grid) { var a = getScore(grid[0], grid[1], grid[2]); var b = getScore(grid[3], grid[4], grid[5]); var c = getScore(grid[6], grid[7], grid[8]); var d = getScore(grid[0], grid[3], grid[6]); var e = getScore(grid[1], grid[4], grid[7]); var f = getScore(grid[2], grid[5], grid[8]); var g = getScore(grid[0], grid[4], grid[8]); var h = getScore(grid[2], grid[4], grid[6]); return a + b + c + d + e + f + g + h; } //計算某一條線的分數 function getScore (a, b, c) { var line = a + b + c; if (line == 'o' || line == 'x') { return 1; } else if (line == 'oo' || line == 'xx') { return 10; } else if (line == 'ooo' || line == 'xxx') { return 100; }else { return 0; } } ``` > 10.凱薩密碼演算法: --Javascript--ex: ```javascript // a-z 字母 var alphabet = 'abcdefghijklmnopqrstuvwxyz'; //當「加密」按鈕被點擊就執行 encrypt 函式 $('.js-encrypt').click(encrypt); //當「解密」按鈕被點擊就執行 decrypt 函式 $('.js-decrypt').click(decrypt); //加密 function encrypt () { var text = $('.js-text').val(); var offset = $('.js-offset').val(); offset = parseInt(offset); //console.log(offset); //console.log(text); var code = ''; for (var i = 0; i < text.length; i++){ var idx = alphabet.indexOf(text[i]); if (idx != -1) { idx = (idx + offset) % 26; code = code + alphabet[idx]; } else { code = code + text[i]; } } $('.js-text').val(code); //console.log(code); } //解密 function decrypt () { var text = $('.js-text').val(); var offset = $('.js-offset').val(); offset = parseInt(offset); //console.log(offset); //console.log(text); var code = ''; for (var i = 0; i < text.length; i++){ var idx = alphabet.indexOf(text[i]); if (idx != -1) { idx = (idx - offset + 26) % 26; code = code + alphabet[idx]; } else { code = code + text[i]; } } $('.js-text').val(code); //console.log(code); } ``` +HTML: ```html <!DOCTYPE html> <html> <head> <title>Document</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script> </head> <body class="py-4 px-5"> <h3 class="text-center">凱薩密碼</h3> <div class="form-group"> <textarea class="form-control js-text" rows="8" placeholder="要加密解密的訊息...">要加密解密的訊息...(英文) </textarea> </div> <div class="form-group"> <input class="form-control js-offset" type="number" placeholder="位移" value="0"> </div> <div class="text-center"> <button class="btn btn-warning js-encrypt">加密</button> <button class="btn btn-danger js-decrypt">解密</button> </div> </body> </html> ``` +CSS: ```css body { background-color: #222; background-image: url('dust.png'); } ``` > 11.XOR 加密演算法: --Javascript--ex: ```javascript //當「加密」按鈕被點擊就執行 encrypto 函式 $(".js-encrypto").click(encrypto); //加密 function encrypto () { var text = $('.js-text').val(); var key = $('.js-key').val(); var code = ''; for (var i = 0; i < text.length; i++){ var a = text[i].charCodeAt(); var b = key[i % key.length].charCodeAt(); var c = a ^ b; //console.log(a + '^' + b + '=' + c); code += String.fromCharCode(c); } $('.js-text').val(code); } ``` +HTML: ```html <!DOCTYPE html> <html> <head> <title>Document</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous"> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js" integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script> </head> <body class="py-4 px-5"> <h3 class="text-center">加密解密神器</h3> <p class="text-center"> 想寫日記但又不想被爸媽看懂? <br> 想寫情書告白但是不想讓草稿被發現? <br> 想與心儀的對象偷偷傳遞曖昧訊息? <br> 通通就交給這個加解密神器吧! </p> <div class="form-group"> <textarea class="form-control js-text" rows="8" placeholder="要加密解密的訊息..."></textarea> </div> <div class="form-group"> <input class="form-control border-warning js-key" placeholder="金鑰"> </div> <div class="text-center"> <button class="btn btn-primary js-encrypto">加解密</button> </div> </body> </html> ``` +CSS: ```css body { background-color: #222; background-image: url('dust.png'); } ``` --- 沒甚麼要寫的東西了 88