...省略... <script> var TMan = new N6LTimerMan(); //タイマーマネージャー var rate = 2; var img = new Array(); var readed = [false, false, false]; var answer = new Array(); var answercost = 1e12; var answerhcost = 1e12; var wanswer = new Array(); var wanswercost = 1e12; var wanswerhcost = 1e12; var data; var elm; var ctx; var movefrm = 4; var anifrm0 = 4; var anifrm1 = 32; var anispan = 4; var tipsize = 8; var maxdep = 120; var coleps = 5; var eps = 5e-14; var tipmapsize = [480 / 8, 320 / 8]; var overthink = 10000; var think = 0; var rethink = 1.5; var rtd = 0; var rep = 0; var sdep = 0; var rew = 6; var nrep = 0; var bto = false; var wthink = 0; var wrethink = 1.5; var wrtd = 0; var wrep = 0; var wsdep = 0; var wrew = 6; var wnrep = 0; var wbto = false; var rearway; var tipcost = [ [64, [0, 255, 0]], [256, [0, 128, 0]], [1024, [192, 192, 0]], [8, [160, 128, 32]], [8, [128, 128, 128]] ]; var movedir = [ [[1, 0], 1, [0,7,1,6,2,5,3,4]], [[1, 1], 1.414214, [1,0,2,7,3,6,4,5]], [[0, 1], 1, [2,1,3,0,4,7,5,6]], [[-1, 1], 1.414214, [3,2,4,1,5,0,6,7]], [[-1, 0], 1, [4,3,5,2,6,1,7,0]], [[-1, -1], 1.414214, [5,4,6,3,7,2,0,1]], [[0, -1], 1, [6,5,7,4,0,3,1,2]], [[1, -1], 1.414214, [7,6,0,5,1,4,2,3]] ]; class Kuro { constructor() { this.frm = 0; this.pos = [160, 265]; this.tgt = [160, 265]; this.route = new Array(); this.nowroute = 0; this.state = 0; this.size = 32; } } class Col { constructor(r, g, b, a) { this.r = 0; this.g = 0; this.b = 0; this.a = 0; if(isNaN(a) == false){ this.r = r; this.g = g; this.b = b; this.a = a; } } } var tipmap = new Array(); var kuro = new Kuro(); function enter() { if(readed[0] == false){ img[0] = new Image(); img[0].src = "./img/astarmap.jpg"; img[0].onload = () => { readed[0] = true; analyzemap(); return; }; } if(readed[1] == false){ img[1] = new Image(); img[1].src = "./img/kuro000.png"; img[1].onload = () => { readed[1] = true; return; }; } if(readed[2] == false){ img[2] = new Image(); img[2].src = "./img/kuro001.png"; img[2].onload = () => { readed[2] = true; return; }; } elm = document.getElementById('cnv0'); ctx = elm.getContext("2d"); elm.addEventListener("click",e=>{ const rect = e.target.getBoundingClientRect(); const viewX = e.clientX - rect.left, viewY = e.clientY - rect.top; const scaleWidth = elm.clientWidth / elm.width, scaleHeight = elm.clientHeight / elm.height; const canvasX = Math.floor(viewX / scaleWidth), canvasY = Math.floor(viewY / scaleHeight); kuro.tgt = [canvasX, canvasY]; calcroute(); }); TMan.add(); Loop(0); } function Loop(id){ if(isreaded() == true){ ctx.fillStyle = "rgb(0, 0, 0)" ; ctx.strokeStyle = 'rgb(0, 0, 0)'; ctx.clearRect(0, 0, 480, 320); ctx.drawImage(img[0], 0, 0); movekuro(); drawkuro(); dispinfo(); } TMan.timer[id].setalerm(function() { Loop(id); }, 50); } function drawkuro(){ var dimg = img[1]; if((kuro.frm % anifrm0) == 0) dimg = img[2]; var dy = anispan * Math.sin((kuro.frm % anifrm1) / anifrm1 * Math.PI * 2); ctx.drawImage(dimg, kuro.pos[0] - (kuro.size / 2), kuro.pos[1] + dy - (kuro.size / 2)); } function analyzemap(){ ctx.fillStyle = "rgb(0, 0, 0)" ; ctx.strokeStyle = 'rgb(0, 0, 0)'; ctx.clearRect(0, 0, 480, 320); ctx.drawImage(img[0], 0, 0); var w = 480; var h = 320; var imgdata = ctx.getImageData(0, 0, w, h); var data = imgdata.data; var x; var y; var i; var tip; tipmap = new Array(); for(y = 0; y < h; y = y + tipsize){ for(x = 0; x < w; x = x + tipsize){ var c = getcolor(data, x, y, w, h); tip = 0; for(i = 0; i < tipcost.length; i++){ if((tipcost[i][1][0] - coleps <= c.r)&&(c.r <= tipcost[i][1][0] + coleps)&& (tipcost[i][1][1] - coleps <= c.g)&&(c.g <= tipcost[i][1][1] + coleps)&& (tipcost[i][1][2] - coleps <= c.b)&&(c.b <= tipcost[i][1][2] + coleps)){ tip = i; break; } } if((tip < 0)||(tipcost.length <= tip)) tip = 0; tipmap.push(tip); } } } function getcolor(data, x, y, w, h){ var pos = (y * w + x) * 4; var ret = new Col(); if(w * h * 4 < pos) return ret; ret.r = data[pos + 0]; ret.g = data[pos + 1]; ret.b = data[pos + 2]; ret.a = data[pos + 3]; return ret; } function movekuro(){ kuro.frm++; if(kuro.state == 0) return; if((kuro.frm % movefrm) == (movefrm - 1)) kuro.nowroute++; if(kuro.route.length - 2 < kuro.nowroute){ kuro.pos = kuro.tgt; kuro.state = 0; } else { var now = [kuro.route[kuro.nowroute][0] * tipsize, kuro.route[kuro.nowroute][1] * tipsize]; var next = [kuro.route[kuro.nowroute + 1][0] * tipsize, kuro.route[kuro.nowroute + 1][1] * tipsize]; var delta = [(next[0] - now[0]) / movefrm * (kuro.frm % movefrm), (next[1] - now[1]) / movefrm * (kuro.frm % movefrm)]; kuro.pos = [now[0] + delta[0], now[1] + delta[1]]; } } function calcroute(){ kuro.route = new Array(); kuro.nowroute = 0; var st = [Math.floor(kuro.pos[0] / tipsize), Math.floor(kuro.pos[1] / tipsize)]; var ed = [Math.floor(kuro.tgt[0] / tipsize), Math.floor(kuro.tgt[1] / tipsize)]; var wans = new Array(); wanswer = new Array(); wanswercost = 1e12; wanswerhcost = 1e12; wthink = 0; wbto = false; wrtd = -1; wnrep = -1; getnearway(st, ed); var ret; if((st[0] != nearway[0])||(st[1] != nearway[1])){ ret = serchway(wans.slice(), st, ed, 0, 0, maxdep, 0); if(ret == true){ wanswer = answer.slice(); wanswercost = answercost; wanswerhcost = answerhcost; } } var ans = new Array(); answer = new Array(); answercost = 1e12; answerhcost = 1e12; think = 0; bto = false; rtd = -1; nrep = -1; r = astar(ans.slice(), st, ed, 0, 0, maxdep, 0); ret = (ret || r); if(ret == true){ if(wanswercost < answercost){ kuro.route = wanswer.slice(); } else { kuro.route = answer.slice(); } kuro.nowroute = 0; kuro.state = 1; } return ret; } //ans:経路配列 //now:現在位置 //end:終了位置 //cost:経路コスト //hcost:推計経路コスト //maxdepth:最大ネスト深度 //depth:現在のネスト数 //answer:解答経路文字列 //answercost:解答経路コスト //ret:解決できたか? function serchway(ans, now, end, cost, hcost, maxdepth, depth){ wthink++; if((maxdepth < depth)||(overthink < wthink)){ wbto = true; return false; } var ret = false; var rrr; ans.push(now); if((now[0] == nearway[0])&&(now[1] == nearway[1])) { if((cost < wanswercost)||((wanswercost - eps < cost)&&(cost < wanswercost + eps)&&(hcost < wanswerhcost))){ wanswercost = cost; wanswerhcost = hcost; wanswer = ans.slice(); if(wrtd < 0){ wrtd = depth / rethink; if(depth - wrtd < wrew) wrtd = depth - wrew; // wbto = true; } else { rrr = depth / rethink; if(depth - rrr < wrew) rrr = depth - wrew; if(rrr < wrtd) wrtd = rrr; // wbto = true; } answer = ans.slice(); answercost = 1e12; answerhcost = 1e12; think = 0; bto = false; rtd = -1; nrep = -1; var r = astar(ans.slice(), nearway, end, cost, h, maxdepth, 0); return r; } } var i; var dir = setdir(now, nearway); for(i = 0; i < dir.length; i++){ if(wbto == true){ if(wrtd < depth){ if(overthink < wthink) return ret; } else { if((i < dir.length - 1)){ wbto = false; wthink = 0; } } } var next = [Math.floor(now[0] + movedir[dir[i]][0][0]), Math.floor(now[1] + movedir[dir[i]][0][1])]; if(isoutmap(next) == true) continue; if(isGone(ans, next) == false){ var h = heuristic(next, nearway); if(cost + h < wanswercost){ if(h < hcost) h = hcost; var crnt = tipmapsize[0] * next[1] + next[0]; var mcost = tipcost[tipmap[crnt]][0] * movedir[dir[i]][1]; var r = serchway(ans.slice(), next, end, cost + mcost, h, maxdepth, depth + 1); ret = (ret || r); } } if((depth <= wrtd)&&(i == dir.length - 1)){ rrr = depth / wrethink; if(depth - rrr < wrew) rrr = depth - wrew; if(rrr < wrtd) wrtd = rrr; wbto = true; } } return ret; } //ans:経路配列 //now:現在位置 //end:終了位置 //cost:経路コスト //hcost:推計経路コスト //maxdepth:最大ネスト深度 //depth:現在のネスト数 //answer:解答経路文字列 //answercost:解答経路コスト //ret:解決できたか? function astar(ans, now, end, cost, hcost, maxdepth, depth){ think++; if((maxdepth < depth)||(overthink < think)){ bto = true; return false; } var ret = false; var rrr; ans.push(now); if((now[0] == end[0])&&(now[1] == end[1])) { if((cost < answercost)||((answercost - eps < cost)&&(cost < answercost + eps)&&(hcost < answerhcost))){ answercost = cost; answerhcost = hcost; answer = ans.slice(); if(rtd < 0){ rtd = depth / rethink; if(depth - rtd < rew) rtd = depth - rew; // bto = true; } else { rrr = depth / rethink; if(depth - rrr < rew) rrr = depth - rew; if(rrr < rtd) rtd = rrr; // bto = true; } return true; } } var i; var dir = setdir(now, end); for(i = 0; i < dir.length; i++){ if(bto == true){ if(rtd < depth){ if(overthink < think) return ret; } else { if((i < dir.length - 1)){ bto = false; think = 0; } } } var next = [Math.floor(now[0] + movedir[dir[i]][0][0]), Math.floor(now[1] + movedir[dir[i]][0][1])]; if(isoutmap(next) == true) continue; if(isGone(ans, next) == false){ var h = heuristic(next, end); if(cost + h < answercost){ if(h < hcost) h = hcost; var crnt = tipmapsize[0] * next[1] + next[0]; var mcost = tipcost[tipmap[crnt]][0] * movedir[dir[i]][1]; var r = astar(ans.slice(), next, end, cost + mcost, h, maxdepth, depth + 1); ret = (ret || r); } } if((depth <= rtd)&&(i == dir.length - 1)){ rrr = depth / rethink; if(depth - rrr < rew) rrr = depth - rew; if(rrr < rtd) rtd = rrr; bto = true; } } return ret; } function getnearway(now, end){ var sub; var near = [-1, -1]; var nd = 1e12; var nh = 1e12; var d; var h; var x; var y; var crnt; var tip; for(y = 0; y < tipmapsize[1]; y++){ for(x = 0; x < tipmapsize[0]; x++){ crnt = tipmapsize[0] * y + x; tip = tipmap[crnt]; if((tip == 3)||(tip == 4)){ sub = [x - now[0], y - now[1]]; d = Math.sqrt(sub[0] * sub[0] + sub[1] * sub[1]); h = heuristic([x, y], end); if((d < nd)||(h < nh)&&(nd - eps < d)&&(d < nd + eps)){ nd = d; nh = h; near = [x, y]; } } } } nearway = near; } function setdir(now, end){ var sub = [Math.floor(end[0] - now[0]), Math.floor(end[1] - now[1])]; if(sub[0] == 0) sub[0] = 0; else if(sub[0] < 0) sub[0] = -1; else sub[0] = 1; if(sub[1] == 0) sub[1] = 0; else if(sub[1] < 0) sub[1] = -1; else sub[1] = 1; var i; for(i = 0; i < movedir.length; i++){ if((sub[0] == movedir[i][0][0])&&(sub[1] == movedir[i][0][1])) return movedir[i][2]; } return movedir[0][2]; } function heuristic(now, end){ var sub = [end[0] - now[0], end[1] - now[1]]; var crnt = tipmapsize[0] * now[1] + now[0]; var ret = Math.sqrt(sub[0] * sub[0] + sub[1] * sub[1]) / rate * tipcost[tipmap[crnt]][0]; return ret; } function isoutmap(pos){ if((pos[0] < 0)||(tipmapsize[0] - 1 < pos[0])||(pos[1] < 0)||(tipmapsize[1] - 1 < pos[1])) return true; return false; } function isGone(ans, now){ var i; for(i = 0; i < ans.length; i++){ if((ans[i][0] == now[0])&&(ans[i][1] == now[1])){ return true; } } return false; } function isreaded(){ for(var i = 0; i < 3; i++){ if(readed[i] == false) return false; } return true; } function dispinfo(){ var nowelm = document.getElementById('OUTTXTNOW'); var tgtelm = document.getElementById('OUTTXTTGT'); nowelm.value = Math.floor(kuro.pos[0]) + ', ' + Math.floor(kuro.pos[1]) + ' :state: ' + kuro.state; tgtelm.value = Math.floor(kuro.tgt[0]) + ', ' + Math.floor(kuro.tgt[1]); } </script> ...省略...