Я делаю для презентации лабораторной работы программу где реализован логический ИИ. Сдел её на JS.
Часть исполнения таково: есть "вход" где появляется группа пикселей "муравьев", бесцельно бродящих близ "входа" и как только на поле выложить "еду" (пиксели другого цвета), то "муравьи" идут к еде и "тащат" её на "выход".
В целом всё готово, но мне не понравилось, что "муравей" выбирает свою целевую еду слишком просто - берется следующий элемент массива, где хранятся объекты "еда". Я решил сделать так, что бы "муравей" выбирал ближайший от своей текущей координаты объект "еда".
Однако не смотря на, казалось бы, правильно (по моему мнению) написанный код, все равно ничего не выходит.
Вот функция поиска "цели" "муравья":
function checkEat(id) //Проверка на наличие еды
{
var bestTarget = "";
var t = Infinity,l = Infinity; //будущие координаты "цели"
if (!antArmy[id].antOnTheHunt) //если муравей еще не охотится
if (eatStock.length > storageCount) { //если вся "еда" еще не утащена на "выход"
for (var eatAll = 0; eatAll <= eatStock.length; eatAll++) { //идем по массиву объектов "еда"
if (eatStock[eatAll] != "returned") //если "еда" уже не утащена
if (!eatStock[eatAll].grabbed && !eatStock[eatAll].onTarget) //если "еда" не схвачена другим "муравьем"
{ //и на неё не претендует другой "муравей"...
var AntPT = getElemCoordinates(antArmy[id].name, "top"); //координаты текущего муравья
var AntPL = getElemCoordinates(antArmy[id].name, "left");
var eatPT = getElemCoordinates(eatStock[eatAll].name, "top"); //координаты текущей еды
var eatPL = getElemCoordinates(eatStock[eatAll].name, "left");
if ((Math.abs(AntPT - eatPT) + Math.abs(AntPL - eatPL)) < (t + l)) { //сравниваем сумму координат
t = eatPT; //если следующая сумма координат будет меньше ( а то есть ближе к "муравью")
l = eatPL; // то будут вписаны новые координаты ближайшего объекта
bestTarget = eatStock[eatAll].name; //пока не выберется ближайшая "еда"
}
}
}
}
alert(bestTarget); //проверка на работу (проверка не успешна)
antArmy[id].antOnTheHunt = true; //"муравей" выходит на охоту
antArmy[id].targetEat = bestTarget; //выбирает ближайшую "еду"
eatStock[bestTarget].onTarget = true; //"еда" "помечена"
storageCount++;
}
Посоветуете что-нибудь, пожалуйста? А то не смотря на дни, просиженные над этим куском кода, ошибка мне не понятна. А узнать и реализовать очень интересно (
Вот полный код всей программы. Здесь нет предыдущей вставки и она рабочая.
Правда желательно запускать не через какой-то веб редактор, а напрямую с файла, дабы не было каких-то ошибок.
var enter = false;
var exit = false;
var eat = false;
var enter_place = false;
var exit_place = false;
var eat_place = false;
var antArmy = [];
var antArmyFull = false;
var eatStock = [];
var storageCount = 0; //Подсчет кол-во отнесенной на выход еды
function ruler(command) { //подтверждает выбор инструмента. Когда пользователь кликнет на поле, ruler определит,
//что установить на поле
if (command) {
switch (command) {
case "enter":
enter_place = true;
exit_place = false;
eat_place = false;
if (enter) document.getElementById('choose').innerHTML = '"Enter" is already placed';
else document.getElementById('choose').innerHTML = '"Enter" is choosed';
break;
case "exit":
enter_place = false;
exit_place = true;
eat_place = false;
if (exit) document.getElementById('choose').innerHTML = '"Exit" is already placed';
else document.getElementById('choose').innerHTML = '"Exit" is choosed';
break;
case "eat":
enter_place = false;
exit_place = false;
eat_place = true;
if (eat) document.getElementById('choose').innerHTML = '"Eat" is already placed';
else document.getElementById('choose').innerHTML = '"Eat" is choosed';
break;
default:
alert("something wrong with function 'ruler'.");
}
}
}
function releaseAnt() { //конвеер муравьев
if (enter === true) {
while (antArmyFull === false) {
antArmy[antArmy.length] = new MakeAnt("ant" + antArmy.length);
if (antArmy.length >= 50) antArmyFull = true;
}
document.getElementById('numOfAnts').innerHTML = 'Ant army size: ' + antArmy.length + '.';
moveAnt();
}
}
function releaseEat(posX, posY){ //конвеер еды
var x = posX;
var y = posY;
var placing = eatStock.length + 60;
while (eatStock.length <= placing) {
if (x >= posX+40) {
x = posX;
y++;
}
eatStock[eatStock.length] = new PlaceEat(eatStock.length, x, y);
x++;
}
eat = true;
}
///////////////////////ANT/////////////////////////
function MakeAnt(name) { //конструктор муравья
this.name = name;
this.antOnTheHunt = false;
this.targetEat = "";
this.antGrabEat = false;
var positionOfHome = document.getElementById("enterance");
var ant_div = document.body.appendChild(document.createElement('div')); //создаем div с атррибутами
ant_div.setAttribute("id", name);
/* В качестве начальных координат используются координаты "Входа" */
ant_div.style.cssText="position:absolute;\
top:" + parseInt(positionOfHome.style.top, 10) +
";\left:" + parseInt(positionOfHome.style.left, 10) + ";";
var annt_canvas = ant_div.appendChild(document.createElement('canvas')); //создаем холст с атррибутами
annt_canvas.setAttribute("id", "a" + name);
var ant_canvas = document.getElementById("a" + name);//находим холст
var ant_context = ant_canvas.getContext("2d");//устанавливаем 2d рисование
ant_context.fillStyle = "#000000";//цвет заливки
ant_context.fillRect(0, 0, 1, 1);//создаем квадрат и заливаем
}
///////////////////////ANT MOVE////////////////////////
function moveAnt() { //управляющая выбором движения муравья функция
for (var i = 0; i < antArmy.length; i++) {
if (eat) checkEat(i);
if (!antArmy[i].antOnTheHunt && !antArmy[i].antGrabEat) {
checkMove(antArmy[i].name);
walkLikeADrunk(i); //хаотичное передвижение
}
if (exit) {
// if (!antArmy[i].antOnTheHunt) moveToTheExit(i); //Двигаться к выходу, если он существует
if (antArmy[i].antOnTheHunt && antArmy[i].antGrabEat) bringEatBack(i); //Двигаться с едой к выходу
}
if (antArmy[i].antOnTheHunt && !antArmy[i].antGrabEat) huntForEat(i); //охотится за едой
}
setTimeout("moveAnt()", 100)
}
function move(who,where,line) { //line === "left" or "top"
if (line === "left") document.getElementById(who).style.left=parseInt(document.getElementById(who).style.left)+where;
if (line === "top") document.getElementById(who).style.top=parseInt(document.getElementById(who).style.top)+where;
}
function walkLikeADrunk(id) {
var rand = Math.round(Math.random() * (4 - 1) + 1);
switch (rand) {
case 2:
move(antArmy[id].name, 1, "left");
break;
case 3:
move(antArmy[id].name, -1, "left");
break;
case 1:
move(antArmy[id].name, 1, "top");
break;
case 4:
move(antArmy[id].name, -1, "top");
break;
default:
alert("move ant error");
}
}
function huntForEat(id)
{
if (antArmy[id].targetEat !== "")
{
var eatPosTop = getElemCoordinates(antArmy[id].targetEat,"top");
var eatPosLeft = getElemCoordinates(antArmy[id].targetEat,"left");
var AntPosTop = getElemCoordinates(antArmy[id].name,"top");
var AntPosLeft = getElemCoordinates(antArmy[id].name,"left");
if (eatPosTop < AntPosTop) move(antArmy[id].name, -1, "top");
else move(antArmy[id].name, 1, "top");
if (eatPosLeft < AntPosLeft) move(antArmy[id].name, -1, "left");
else move(antArmy[id].name, 1, "left");
checkEatBorder(id);
}
}
function bringEatBack(id)
{
var AntCurrPosTop = getElemCoordinates(antArmy[id].name,"top");
var AntCurrPosLeft = getElemCoordinates(antArmy[id].name,"left");
var eatPosTop = getElemCoordinates(antArmy[id].targetEat,"top");
var eatPosLeft = getElemCoordinates(antArmy[id].targetEat,"left");
moveToTheExit(id);
var AntPastPosTop = getElemCoordinates(antArmy[id].name,"top");
var AntPastPosLeft = getElemCoordinates(antArmy[id].name,"left");
if (AntPastPosTop <= AntCurrPosTop) eatPosTop = AntPastPosTop-1;
else eatPosTop = AntPastPosTop+1;
if (AntPastPosLeft <= AntCurrPosLeft) eatPosLeft = AntPastPosLeft-1;
else eatPosLeft = AntPastPosLeft+1;
document.getElementById(antArmy[id].targetEat).style.left=eatPosLeft;
document.getElementById(antArmy[id].targetEat).style.top=eatPosTop;
}
function checkMove(name) //Проверка движения муравья, относительно положения "Входа"
{ //Если муравей не на "охоте", то он не уходит за установленные границы
var AntPosCheckTop = getElemCoordinates(name,"top");
var AntPosCheckLeft = getElemCoordinates(name,"left");
var borderLineTop = getElemCoordinates("enterance","top");
var borderLineLeft = getElemCoordinates("enterance","left");
if ((borderLineTop < AntPosCheckTop) && (borderLineLeft < AntPosCheckLeft)) {
if (((borderLineLeft + 50) < AntPosCheckLeft) || ((borderLineTop + 50) < AntPosCheckTop)) {
if (borderLineTop < AntPosCheckTop) move(name, -1, "top");
if (borderLineLeft < AntPosCheckLeft) move(name, -1, "left");
}
}
if ((borderLineTop > AntPosCheckTop) && (borderLineLeft < AntPosCheckLeft)) {
if (((borderLineLeft + 50) < AntPosCheckLeft) || ((borderLineTop - 50) > AntPosCheckTop)) {
if (borderLineTop > AntPosCheckTop) move(name, 1, "top");
if (borderLineLeft < AntPosCheckLeft) move(name, -1, "left");
}
}
if ((borderLineTop > AntPosCheckTop) && (borderLineLeft > AntPosCheckLeft)) {
if (((borderLineLeft - 50) > AntPosCheckLeft) || ((borderLineTop - 50) > AntPosCheckTop)) {
if (borderLineTop > AntPosCheckTop) move(name, 1, "top");
if (borderLineLeft > AntPosCheckLeft) move(name, 1, "left");
}
}
if ((borderLineTop < AntPosCheckTop) && (borderLineLeft > AntPosCheckLeft)) {
if (((borderLineLeft - 50) > AntPosCheckLeft) || ((borderLineTop + 50) < AntPosCheckTop)) {
if (borderLineTop < AntPosCheckTop) move(name, -1, "top");
if (borderLineLeft > AntPosCheckLeft) move(name, 1, "left");
}
}
}
function checkExitBorder(id)
{
var AntPosCheckTop = getElemCoordinates(antArmy[id].name, "top"); //позиция муравья
var AntPosCheckLeft = getElemCoordinates(antArmy[id].name, "left");
var exitLineTop = getElemCoordinates("exit", "top"); //позиция выхода
var exitLineLeft = getElemCoordinates("exit", "left");
var startLineTop = getElemCoordinates("enterance", "top"); //позиция входа
var startLineLeft = getElemCoordinates("enterance", "left"); //это нам нужно что бы возвратить муравья
if ((exitLineTop <= AntPosCheckTop) && (exitLineLeft <= AntPosCheckLeft)) {
if (((exitLineLeft + 5) > AntPosCheckLeft) && ((exitLineTop + 5) > AntPosCheckTop)) {
if (antArmy[id].antGrabEat) {
eatStock[antArmy[id].targetEat] = "returned";
antArmy[id].antOnTheHunt = false;
antArmy[id].antGrabEat = false;
}
document.getElementById(antArmy[id].name).style.top = "" + startLineTop + "px";
document.getElementById(antArmy[id].name).style.left = "" + startLineLeft + "px";
}
}
if ((exitLineTop > AntPosCheckTop) && (exitLineLeft < AntPosCheckLeft)) {
if (((exitLineLeft + 5) > AntPosCheckLeft) && ((exitLineTop - 5) < AntPosCheckTop)) {
if (antArmy[id].antGrabEat) {
eatStock[antArmy[id].targetEat] = "returned";
antArmy[id].antOnTheHunt = false;
antArmy[id].antGrabEat = false;
}
document.getElementById(antArmy[id].name).style.top = "" + startLineTop + "px";
document.getElementById(antArmy[id].name).style.left = "" + startLineLeft + "px";
}
}
if ((exitLineTop >= AntPosCheckTop) && (exitLineLeft >= AntPosCheckLeft)) {
if (((exitLineLeft - 5) < AntPosCheckLeft) && ((exitLineTop - 5) < AntPosCheckTop)) {
if (antArmy[id].antGrabEat) {
eatStock[antArmy[id].targetEat] = "returned";
antArmy[id].antOnTheHunt = false;
antArmy[id].antGrabEat = false;
}
document.getElementById(antArmy[id].name).style.top = "" + startLineTop + "px";
document.getElementById(antArmy[id].name).style.left = "" + startLineLeft + "px";
}
}
if ((exitLineTop < AntPosCheckTop) && (exitLineLeft > AntPosCheckLeft)) {
if (((exitLineLeft - 5) < AntPosCheckLeft) && ((exitLineTop + 5) > AntPosCheckTop)) {
if (antArmy[id].antGrabEat) {
eatStock[antArmy[id].targetEat] = "returned";
antArmy[id].antOnTheHunt = false;
antArmy[id].antGrabEat = false;
}
document.getElementById(antArmy[id].name).style.top = "" + startLineTop + "px";
document.getElementById(antArmy[id].name).style.left = "" + startLineLeft + "px";
}
}
}
function checkEatBorder(id)
{
var AntPosCheckTop = getElemCoordinates(antArmy[id].name,"top"); //позиция муравья
var AntPosCheckLeft = getElemCoordinates(antArmy[id].name,"left");
var eatPosTop = getElemCoordinates(antArmy[id].targetEat,"top");
var eatPosLeft = getElemCoordinates(antArmy[id].targetEat,"left");
if ((eatPosTop <= AntPosCheckTop) && (eatPosLeft <= AntPosCheckLeft)) {
if (((eatPosLeft + 2) > AntPosCheckLeft) && ((eatPosTop + 2) > AntPosCheckTop)) {
antArmy[id].antGrabEat = true;
eatStock[antArmy[id].targetEat].grabbed = true;
}
}
if ((eatPosTop > AntPosCheckTop) && (eatPosLeft < AntPosCheckLeft)) {
if (((eatPosLeft + 2) > AntPosCheckLeft) && ((eatPosTop - 2) < AntPosCheckTop)) {
antArmy[id].antGrabEat = true;
eatStock[antArmy[id].targetEat].grabbed = true;
}
}
if ((eatPosTop >= AntPosCheckTop) && (eatPosLeft >= AntPosCheckLeft)) {
if (((eatPosLeft - 2) < AntPosCheckLeft) && ((eatPosTop - 2) < AntPosCheckTop)) {
antArmy[id].antGrabEat = true;
eatStock[antArmy[id].targetEat].grabbed = true;
}
}
if ((eatPosTop < AntPosCheckTop) && (eatPosLeft > AntPosCheckLeft)) {
if (((eatPosLeft - 2) < AntPosCheckLeft) && ((eatPosTop + 2) > AntPosCheckTop)) {
antArmy[id].antGrabEat = true;
eatStock[antArmy[id].targetEat].grabbed = true;
}
}
}
/*function checkEat(id) //Проверка на наличие еды
{
var bestTarget = "";
var t = Infinity,l = Infinity;
if (!antArmy[id].antOnTheHunt)
if (eatStock.length > storageCount) {
for (var eatAll = 0; eatAll <= eatStock.length; eatAll++) {
if (eatStock[eatAll] != "returned")
if (!eatStock[eatAll].grabbed && !eatStock[eatAll].onTarget) {
var AntPT = getElemCoordinates(antArmy[id].name, "top");
var AntPL = getElemCoordinates(antArmy[id].name, "left");
var eatPT = getElemCoordinates(eatStock[eatAll].name, "top");
var eatPL = getElemCoordinates(eatStock[eatAll].name, "left");
if ((Math.abs(AntPT - eatPT) + Math.abs(AntPL - eatPL)) < (t + l)) {
t = eatPT;
l = eatPL;
bestTarget = eatStock[eatAll].name;
}
}
}
}*/
function checkEat(id) //Проверка на наличие еды
{
if (!antArmy[id].antOnTheHunt)
if (eatStock.length > storageCount) {
for (var eatAll = 0; eatAll <= eatStock.length; eatAll++) {
if (eatStock[eatAll] != "returned")
if (!eatStock[eatAll].grabbed && !eatStock[eatAll].onTarget) {
antArmy[id].antOnTheHunt = true;
antArmy[id].targetEat = eatAll;
eatStock[eatAll].onTarget = true;
storageCount++;
break;
}
}
}
}
function moveToTheExit(id)
{
var exitPosTop = getElemCoordinates("exit","top");
var exitPosLeft = getElemCoordinates("exit","left");
var AntPosTop = getElemCoordinates(antArmy[id].name,"top");
var AntPosLeft = getElemCoordinates(antArmy[id].name,"left");
checkExitBorder(id);
if (exitPosTop < AntPosTop) move(antArmy[id].name, -1, "top");
else move(antArmy[id].name, 1, "top");
if (exitPosLeft < AntPosLeft) move(antArmy[id].name, -1, "left");
else move(antArmy[id].name, 1, "left");
}
function PlaceEat(eatid, posX, posY) { //конструктор еды
this.name = eatid;
this.onTarget = false;
this.grabbed = false;
var eat_div = document.body.appendChild(document.createElement('div')); //создаем div с атррибутами
eat_div.setAttribute("id", eatid);
eat_div.style.cssText = "position:absolute;\
top:" + posY +
";\left:" + posX + ";";
var eaat_canvas = eat_div.appendChild(document.createElement('canvas')); //создаем холст с атррибутами
eaat_canvas.setAttribute("id", "eat" + eatid);
var eat_canvas = document.getElementById("eat" + eatid);//находим холст
var eat_context = eat_canvas.getContext("2d");//устанавливаем 2d рисование
eat_context.fillStyle = "#FFA500";//цвет заливки
eat_context.fillRect(0, 0, 1, 1);//создаем квадрат и заливаем
}
//Функция реагирования на "клик" пользователя.
//Если инструмент выбран...
document.addEventListener('click', function (e) {
if ((document.elementFromPoint(e.clientX, e.clientY).tagName) != "BUTTON") {
////////////////////ENTERANCE/////////////////////
if (enter_place === true) {
if (enter === false) {
var enter_div = document.body.appendChild(document.createElement('div')); //создаем div с атррибутами
enter_div.setAttribute("id", "enterance");
enter_div.style.cssText="position:absolute;\
top:" + e.pageY +
";\left:" + e.pageX + ";";
var enteer_canvas = enter_div.appendChild(document.createElement('canvas')); //создаем холст с атррибутами
enteer_canvas.setAttribute("id", "e");
var enter_canvas = document.getElementById("e");//находим холст
var enter_context = enter_canvas.getContext("2d");//устанавливаем 2d рисование
enter_context.fillStyle = "#000080";//цвет заливки
enter_context.fillRect(0, 0, 10, 10);//создаем квадрат и заливаем
enter = true;
releaseAnt();
}
}
//////////////////EXIT////////////////////////
if (exit_place === true) {
if (exit === false) {
var exit_div = document.body.appendChild(document.createElement('div')); //создаем div с атррибутами
exit_div.setAttribute("id", "exit");
exit_div.style.cssText="position:absolute;\
top:" + e.pageY +
";\left:" + e.pageX + ";";
var exiit_canvas = exit_div.appendChild(document.createElement('canvas')); //создаем холст с атррибутами
exiit_canvas.setAttribute("id", "ex");
var exit_canvas = document.getElementById("ex");//находим холст
var exit_context = exit_canvas.getContext("2d");//устанавливаем 2d рисование
exit_context.fillStyle = "#FF0000";//цвет заливки
exit_context.fillRect(0, 0, 10, 10);//создаем квадрат и заливаем
exit = true;
}
}
////////////////EAT////////////////////////
if (eat_place === true) {
releaseEat(e.pageX, e.pageY);
}
}
}, false);
function getElemCoordinates(name,side) //side = top/left
{
if (side === "top") return parseInt(document.getElementById(name).style.top, 10);
if (side === "left") return parseInt(document.getElementById(name).style.left, 10);
}
//Вызов elem.cloneNode(true) создаст «глубокую» копию элемента
//parentElem.removeChild(elem)
Ответ
if ((Math.abs(AntPT - eatPT) + Math.abs(AntPL - eatPL)) < (t + l))
Вы берете расстояние между муравьем и едой и сравниваете с абсолютными координатами другой еды, что в корне не верно.
Вам надо помнить САМО РАССТОЯНИЕ
var t=Infinity;
...
if ((Math.abs(AntPT - eatPT) + Math.abs(AntPL - eatPL)) < t)
{
t=(Math.abs(AntPT - eatPT) + Math.abs(AntPL - eatPL);
....
}
Комментариев нет:
Отправить комментарий