...省略... <script> var route = [ ['A', 0, [63, 63], 3, [1, 2, [144, 40]], [2, 1, [0, 105]], [3, 1.2, [110, 100]]], ['B', 1, [224, 63], 3, [0, 2, [-1, -1]], [3, 1.2, [180, 140]], [4, 1.2, [250, 100]]], ['C', 2, [46, 152], 2, [0, 1, [-1, -1]], [5, 1, [5, 210]]], ['D', 3, [151, 143], 3, [0, 1.2, [-1, -1]], [1, 1.2, [-1, -1]], [5, 1.2, [80, 180]]], ['E', 4, [248, 165], 3, [1, 1.2, [-1, -1]], [5, 1.2, [170, 230]], [6, 1, [260, 220]]], ['F', 5, [101, 227], 4, [2, 1, [-1, -1]], [3, 1.2, [-1, -1]], [4, 1.2, [-1, -1]], [6, 2, [140, 270]]], ['G', 6, [264, 254], 2, [4, 1, [-1, -1]], [5, 2, [-1, -1]]]]; var answer = ""; var answercost = 1e12; var answerhcost = 1e12; var answerV = ""; var answercostV = 1e12; var answerhcostV = 1e12; var rate = 81; var img; var readed = false; var eps = 5e-14; var via = new Array(); var gST; var gED; var data; var elm; function calc(){ var stelm = document.getElementById('ST'); var edelm = document.getElementById('ED'); gST = Number(stelm.value.substr(6)); gED = Number(edelm.value.substr(6)); answerV = ""; answercostV = 1e12; answerhcostV = 1e12; var num = via.length; data = permutation(via, num); var dnum = data.length; var strroute = ""; var str = ""; var ret = false; var brk; var r; var i; var j; var h; var nextst; var nexted; var cost = 0; var hcost = 0; if(0 < dnum){ for(i = 0; i < dnum; i ++){ str = strroute; brk = false; cost = 0; hcost = 0; hh = 0; nextst = gST; nexted = gST; for(j = 0; j < num; j++){ nextst = nexted; nexted = data[i][j]; h = heuristic(nextst, nexted); if(cost + h < answercostV){ if(h < hcost) h = hcost; r = calcastar(nextst, nexted); ret = (ret || r); if(r == true){ if(j == 0) str = answer; else str = str + '-' + answer.substr(2); cost = cost + answercost; if(h < answerhcost) h = answerhcost; } else { brk = true; break; } } else { brk = true; break; } } if(brk) continue; nextst = nexted; nexted = gED; h = heuristic(nextst, nexted); if(cost + h < answercostV){ if(h < hcost) h = hcost; r = calcastar(nextst, nexted); ret = (ret || r); if(r == true){ cost = cost + answercost; str = str + '-' + answer.substr(2) + ":cost:" + cost.toFixed(3); if((cost < answercostV)||(answercostV - eps < cost)&&(cost < answercostV + eps)&&(h < answerhcost)){ answerV = str; answercostV = cost; answerhcostV = h; } } } } } else { str = strroute; cost = 0; hcost = 0; hh = 0; nextst = gST; nexted = gED; h = heuristic(nextst, nexted); if(cost + h < answercostV){ if(h < hcost) h = hcost; r = calcastar(nextst, nexted); ret = (ret || r); if(r == true){ cost = cost + answercost; str = answer + ":cost:" + cost.toFixed(3); if((cost < answercostV)||(answercostV - eps < cost)&&(cost < answercostV + eps)&&(h < answerhcost)){ answerV = str; answercostV = cost; answerhcostV = h; } } } } var elm = document.getElementById('OUTTXT'); if(!ret) answerV = "Can't solve."; elm.value = answerV; updatecanvas(); } function calcastar(st, ed){ answer = ""; answercost = 1e12; answerhcost = 1e12; var ret = astar("", st, ed, 0, 0, 15, 0); return ret; } //strroute:経路文字列 //now:現在位置 //end:終了位置 //cost:経路コスト //hcost:推計経路コスト //maxdepth:最大ネスト深度 //depth:現在のネスト数 //answer:解答経路文字列 //answercost:解答経路コスト //ret:解決できたか? function astar(strroute, now, end, cost, hcost, maxdepth, depth){ var ret = false; if(0 < depth) strroute = strroute + "-" + String.fromCharCode(65 + now); else strroute = String.fromCharCode(65 + now); if(now == end) { if((cost < answercost)||((answercost - eps < cost)&&(cost < answercost + eps)&&(hcost < answerhcost))){ answercost = cost; answerhcost = hcost; answer = strroute; return true; } } if(maxdepth < depth) return false; var num = route[now][3]; var i = 0; while(i < num){ var next = route[now][4+i][0]; // if(isGone(strroute, next) == false){ var h = heuristic(next, end); if(cost + h < answercost){ if(h < hcost) h = hcost; var r = astar(strroute, next, end, cost + route[now][4 + i][1], h, maxdepth, depth + 1); ret = (ret || r); } // } i++; } return ret; } function heuristic(now, end){ var p0 = route[now][2]; var p1 = route[end][2]; var sub = [p1[0] - p0[0], p1[1] - p0[1]]; var ret = Math.sqrt(sub[0] * sub[0] + sub[1] * sub[1]) / rate; return ret; } function permutation(nums, k){ var ans = []; var i; var j; if(nums.length == 0){ return ans; } if((k <= 0)||(nums.length < k)){ k = nums.length; } if(k == 1){ for(i = 0; i < k; i++){ ans[i] = [nums[i]]; } } else { for(i = 0; i < k; i++){ var parts = nums.slice(0); parts.splice(i, 1)[0]; var row = permutation(parts, k - 1); for(j = 0; j < row.length; j++){ ans.push([nums[i]].concat(row[j])); } } } return ans; } function isGone(strroute, now){ var ch; var str = strroute; while(str != ""){ ch = Number(str.charCodeAt(0) - 65); if(ch == now) return true; str = str.substr(2); } return false; } function chgdata(){ var stelm = document.getElementById('ST'); var edelm = document.getElementById('ED'); gST = Number(stelm.value.substr(6)); gED = Number(edelm.value.substr(6)); var nowelm = document.getElementById('TXTNOW'); var numelm = document.getElementById('TXTNUM'); var costelm = document.getElementById('TXTCOST'); var rateelm = document.getElementById('TXTRT'); var viaelm = document.getElementById('TXTVIA'); var lowerUpper = "A".charCodeAt(0); var upperUpper = "Z".charCodeAt(0); var lowerLower = "a".charCodeAt(0); var upperLower = "z".charCodeAt(0); var i; var j; var bbb; var work; var ch; via = new Array(); via.length = 0; var strs = viaelm.value.split('-'); for(i = 0; i < strs.length; i++){ work = Number(strs[i]); if((Number.isNaN(work))||(work < 0)||(6 < work)){ ch = strs[i].charCodeAt(0); if((lowerUpper <= ch)&&(ch <= upperUpper)){ work = Number(ch - lowerUpper); } else if((lowerLower <= ch)&&(ch <= upperLower)){ work = Number(ch - lowerLower); } } if((strs[i] != "")&&(0 <= work)&&(work <= 6)){ if((work != gST)&&(work != gED)){ bbb = true; for(j = 0; j < via.length; j++){ if(work == via[j]) bbb = false; } if(bbb) via.push(work); } } } var now = Number(nowelm.value); ch = nowelm.value.charCodeAt(0); if((lowerUpper <= ch)&&(ch <= upperUpper)){ now = Number(ch - lowerUpper); } else if((lowerLower <= ch)&&(ch <= upperLower)){ now = Number(ch - lowerLower); } if((now < 0)||(6 < now)) return; var cost = Number(costelm.value); if((Number.isNaN(cost))||(cost < 0)) return; var num = Number(numelm.value); ch = numelm.value.charCodeAt(0); work = -1; if((lowerUpper <= ch)&&(ch <= upperUpper)){ work = Number(ch - lowerUpper); } else if((lowerLower <= ch)&&(ch <= upperLower)){ work = Number(ch - lowerLower); } if(0 <= work){ num = -1; for(i = 0; i < route[now][3]; i++){ if(route[now][4 + i][0] == work){ num = i; break; } } } if((num < 0)||(route[now][3] <= num)) return; route[now][4 + num][1] = cost; for(i = 0; i < route[route[now][4 + num][0]][3]; i++){ if(route[route[now][4 + num][0]][4 + i][0] == now){ route[route[now][4 + num][0]][4 + i][1] = cost; var r = Number(rateelm.value); if(r < 0) retrun; rate = r; calc(); updatecanvas(); return; } } } function updatecanvas(){ elm = document.getElementById('cnv0'); if(!readed){ img = new Image(); img.src = "./img/astar.jpg"; img.onload = () => { readed = true; updatecanvas(); return; }; } var ctx = elm.getContext("2d"); ctx.fillStyle = "rgb(0, 0, 0)" ; ctx.strokeStyle = 'rgb(0, 0, 0)'; ctx.clearRect(0, 0, 320, 320); ctx.drawImage(img, 0, 0); var strs; var str; var now; var num; var i; var p0; var p1; for(now = 0; now < 7; now++){ num = route[now][3]; for(i = 0; i < num; i++){ if(route[now][4 + i][2][0] < 0) continue; drawcost(ctx, now, i); } } if((answerV == "")||(answerV == "Can't solve.")) return; strs = answerV.split(':'); str = strs[0]; now = Number(str.charCodeAt(0) - 65); num = now; p0 = route[now][2]; p1 = p0; ctx.beginPath(); ctx.arc(p0[0], p0[1], 10, 0, 2 * Math.PI) ; ctx.fillStyle = "rgb(32, 192, 128)" ; ctx.strokeStyle = 'rgb(32, 192, 128)'; ctx.fill(); ctx.closePath() ctx.fillStyle = "rgb(32, 128, 255)" ; ctx.strokeStyle = 'rgb(32, 128, 255)'; for(i = 0; i < via.length; i++){ ctx.beginPath(); p0 = route[via[i]][2]; p1 = p0; ctx.arc(p0[0], p0[1], 10, 0, 2 * Math.PI) ; ctx.fill(); ctx.closePath() } p0 = route[num][2]; p1 = p0; ctx.beginPath(); ctx.fillStyle = "rgb(32, 192, 128)" ; ctx.strokeStyle = 'rgb(32, 192, 128)'; ctx.lineWidth = 6; ctx.moveTo(p0[0], p0[1]); str = str.substr(2); while(str != ""){ p0 = p1; now = Number(str.charCodeAt(0) - 65); p1 = route[now][2]; ctx.lineTo(p1[0], p1[1]); str = str.substr(2); } if(Number.isNaN(p1[0]) == false){ var sub = [p1[0] - p0[0], p1[1] - p0[1]]; if((sub[0] != 0)||(sub[1] != 0)){ var th = Math.atan2(sub[1], sub[0]); var add = Math.PI / 180.0 * 150.0; var head = [30, 0]; var work0 = [head[0] * Math.cos(th + add) - head[1] * Math.sin(th + add) + p1[0], head[0] * Math.sin(th + add) + head[1] * Math.cos(th + add) + p1[1]]; var work1 = [head[0] * Math.cos(th - add) - head[1] * Math.sin(th - add) + p1[0], head[0] * Math.sin(th - add) + head[1] * Math.cos(th - add) + p1[1]]; ctx.lineTo(work0[0], work0[1]); ctx.moveTo(p1[0], p1[1]); ctx.lineTo(work1[0], work1[1]); } } ctx.moveTo(route[num][2][0], route[num][2][1]); ctx.closePath() ctx.stroke(); } function drawcost(ctx, now, i){ var cost = route[now][4 + i][1]; var pnt = route[now][4 + i][2]; ctx.font = "24px Sans-serif"; ctx.fillText(cost.toFixed(2), pnt[0], pnt[1]); } </script> ...省略...