Глюки с рекурсией
Народ, подскажите пожалуйста кто чем может! Есть такая вот проблема, что в скрипте, который я тут выкладываю, присутствует рекурсивная функция, исследующая значения в массиве и определяющая совпадения со случайным получаемым значением в этой функции. В целом, сценарий направлен на создание игры "Пятнашки".
Глюк такой, что когда я вставляю строчные выражения внутрь функции, никак на прямую не связанные с логикой функции и не влияющие на её работу, то мой сценарий начинает нормально работать и не допускает повторения значений в результирующем массиве. Они только лишь для вывода отчетов по этапам работы функции и в окончательном варианте не нужны. НО как только функция лишается этих выражений с отчетом, то сразу же наблюдается повторное попадание совпадающих значений в массив. script.js ( обратить внимание на рекурсивную функцию getCubeCoords(), если в ней убрать или закомментировать все строки, где встречается переменная otchet1, то все будет плохо :(, а именно, может быть не с первого раза, но со второго или третьего раза обновления страницы, появятся совпадающие значения в массиве cubeMap, что пагубно отражается на расстановке квадратов в выделенном для них поле field):
var fieldSize = 16;
var cubeMap = [];
var otchet1 = '<table border="1">\n'
+ '<tr><td>№<\/td><td>Выбранные координаты<\/td><td>Результат<\/td><td>Окончательные координаты<\/td><\/tr>';
genCubeMap();
otchet1 += '<\/table>';
function genCubeMap(){
var reqX, reqY;
for (var i=0; i < fieldSize; i++){
getCubeCoords();
}
function getCubeCoords(){
reqX = parseInt(Math.random()*4);
reqY = parseInt(Math.random()*4);
otchet1 += '<tr><td>'+ (i+1) +'<\/td><td>'+ reqX +':'+ reqY +'<\/td>';
var zanyato = false;
for (var n=0; n < i+1; n++){
if (cubeMap[n] && cubeMap[n][1] == reqX && cubeMap[n][2] == reqY){
zanyato = true;
break;
}
}
if (zanyato !== false){
otchet1 += '<td>заняты квадратом №'+ (n+1) +'<\/td><td> <\/td><\/tr>\n';
getCubeCoords();
return;
} else {
otchet1 += '<td>Свободны<\/td><td>'+ reqX +':'+ reqY +'<\/td><\/tr>\n';
}
cubeMap[i] = [i<fieldSize-1 ? i+1 : null, reqX, reqY, '|'];
}
}
function placeCubs(){
for (var i=0; i < fieldSize-1; i++){
this['cube'+(i+1)].style.left = cubeMap[i][1]*53 +'px';
this['cube'+(i+1)].style.top = cubeMap[i][2]*53 +'px';
}
}
var d = document;
var field, cube1, cube2, cube3, cube4, cube5, cube6, cube7, cube8, cube9, cube10, cube11, cube12, cube13, cube14, cube15;
var info, info2;
window.onload = function(){
info = d.getElementById('info');
info2 = d.getElementById('info2');
field = d.getElementById('field');
cube1 = d.getElementById('cube1');
cube2 = d.getElementById('cube2');
cube3 = d.getElementById('cube3');
cube4 = d.getElementById('cube4');
cube5 = d.getElementById('cube5');
cube6 = d.getElementById('cube6');
cube7 = d.getElementById('cube7');
cube8 = d.getElementById('cube8');
cube9 = d.getElementById('cube9');
cube10 = d.getElementById('cube10');
cube11 = d.getElementById('cube11');
cube12 = d.getElementById('cube12');
cube13 = d.getElementById('cube13');
cube14 = d.getElementById('cube14');
cube15 = d.getElementById('cube15');
placeCubs();
info.innerHTML = otchet1;
}
default.css :
body {
background: #fff;
color: #000;
margin: 5px;
padding-top: 1px;
}
#info {
position: absolute;
font: normal 12px Arial;
}
#info2 {
position: absolute;
right: 0;
}
#field {
border: 1px solid #000;
width: 211px; height: 211px;
padding: 1px;
margin: 100px auto 0;
background: #FFF;
}
#field div {
width: 50px; height: 50px;
border: 1px solid #000;
margin: 0 -52px -52px 0;
background: #566DFF;
text-align: center;
font: bold 38px Arial;
position: relative;
cursor: pointer;
}
index.html : <?xml version="1.0"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>JavaScript - "Пятнашки"</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" type="text/css" href="./default.css" /> <script type="text/javascript" src="./script.js"></script> </head> <body> <div id="info"> </div> <div id="info2"> </div> <div id="field"> <div id="cube1">1</div> <div id="cube2">2</div> <div id="cube3">3</div> <div id="cube4">4</div> <div id="cube5">5</div> <div id="cube6">6</div> <div id="cube7">7</div> <div id="cube8">8</div> <div id="cube9">9</div> <div id="cube10">10</div> <div id="cube11">11</div> <div id="cube12">12</div> <div id="cube13">13</div> <div id="cube14">14</div> <div id="cube15">15</div> </div> </body> </html> Никак не могу взять в толк в чем здесь проблема. ХЕЛП! :) |
очень странно тут у вас.. функция placeCubs, разберем для начала ее..
this['cube'+(i+1)].style.left = cubeMap[i][1]*53 +'px'; что это?? this - это window. а window, это не массив. это объект this['cube'+(i+1)] - этого быть не может!! вот массив cubeMap[i][1] - что это?? на момент пока вы его вызвайте - он пустой!! разумеется будет ошибка!! используйте фаербаг!!! чтобы его вызвать в хроме нажмите f12, там будет вкладка console. туда и будут сыпаться ваши ошибки |
field = d.getElementById('field');
cube1 = d.getElementById('cube1');
cube2 = d.getElementById('cube2');
cube3 = d.getElementById('cube3');
cube4 = d.getElementById('cube4');
cube5 = d.getElementById('cube5');
cube6 = d.getElementById('cube6');
cube7 = d.getElementById('cube7');
cube8 = d.getElementById('cube8');
cube9 = d.getElementById('cube9');
cube10 = d.getElementById('cube10');
cube11 = d.getElementById('cube11');
cube12 = d.getElementById('cube12');
cube13 = d.getElementById('cube13');
cube14 = d.getElementById('cube14');
cube15 = d.getElementById('cube15');
это все нафига? один раз нашли фиелд и хватит field = d.getElementById('field'); дальше можно делать так: cube1 = field.children[0]; cube2 = field.children[1]; cube3 = field.children[2]; ... ну и дальше в таком духе. а можно так массивом и хранить |
Ну, во первых, с ошибками у меня тут все в порядке :) Все проверено и сбоев нет благодаря отличному инструменту Web Developer для Firefox!
Во вторых, этот this в функции placeCubs() действительно содержит объект окна, но вот интересная штука - кроме этого он содержит еще и все переменные, которые были созданы раньше обращения к этому объекту в такой форме, в виде массива с ассоциативными ключами, которые соответствуют именам этих переменных! Вот статья по этой теме! В третьих, спасибо за совет насчет field.children[0]..., действительно это слегка уменьшает код и при этом работает! Я действительно не знал, что можно так делать :) В четвертых, элемент массива cubeMap[i][1] в 43 строке скрипта не пустой, так как при загрузке сценария в браузер запускается функция genCubeMap() с локальной рекурсивной функцией внутри, которая создает значения в массиве cubeMap в виде массива 2ого уровня с рядом значений в 37 строке скрипта. Затем, после срабатывания события window.onload запускается функция placeCubs(), которая начинает обращаться к массиву cubeMap, в котором уже присутствуют 16 элементов с индексами с 0 по 15, из которых задействуются 15 элементов с индексами с 0 по 14. Эта функция расставляет имеющиеся в HTML документе блоки с id="cube1" и до "cube15", с помощью свойств стиля left и top, в соответствии со значениями, помещенными рекурсивной функцией getCubeCoords() в массив cubeMap[i] с индексами [1] и [2], т.е. эти значения оказываются в cubeMap[i][1] и cubeMap[i][2] позициях и, по сути, являются координатами месторасположения каждого конкретного блока внутри поля field. Надеюсь, я понятно объяснил? :) |
сори.. эт я протупил.. объяснили понятно. вот только ошибка все равно есть в js.посмотрите свой код еще раз, где то не хватает скобок закрывающих (1 шт). может когда копировали не докопировали..))
|
а отчет вам зачем?
вот эта байда: var otchet1 = '<table border="1">\n' + '<tr><td>№<\/td><td>Выбранные координаты<\/td><td>Результат<\/td><td>Окончательные координаты<\/td><\/tr>'; otchet1 += '<\/table>'; я так понял для отладки? честно говоря я наверное материться буду. вот почти каждому отвечающему говорю одно и тоже!! есть фаербаг для этого!! у вас фаерфокс я так понял? это тогда устанавливать его надо. для установки надо скачать, попробуйте здесь: https://addons.mozilla.org/ru/firefox/addon/firebug/ в хроме он идет стандартно, устанавливать не надо. если хтите погуглите.. и после установки для вызова фаербага нажимайте f12, там есть вкладка консоль, чтобы туда сыпать сообщения вместо вашего: otchet1 += '<td>заняты квадратом №'+ (n+1) +'<\/td><td> <\/td><\/tr>\n'; нужно прописать: console.log('заняты квадратом №'+ (n+1)); |
Цитата:
|
так, давайте еще раз. если нет текстовых переменных то у вас не правильно формируется cubeMap.
cubeMap[i] = [i<fieldSize-1 ? i+1 : null, reqX, reqY, '|']; в дальнейшем используется только индексы 1 (reqX) и 2 (reqY) индекс 0 и 4 не используются.. на них можно не смотреть? |
да, можно не смотреть...
|
вот немного переписал функцию:
function genCubeMap()
{
var reqX, reqY;
var zanyato = false;
for (var i=0; i < fieldSize; i++)
{
do
{
zanyato = false;
reqX = parseInt(Math.random()*4);
if (reqX == 4) reqX = 3;
reqY = parseInt(Math.random()*4);
if (reqY == 4) reqY = 3;
for (var n=0; n < i+1; n++)
{
if (cubeMap[n] && cubeMap[n][1] == reqX && cubeMap[n][2] == reqY)
{
zanyato = true;
break;
}
}
}
while (zanyato);
cubeMap[i] = [i<fieldSize-1 ? i+1 : null, reqX, reqY, '|'];
}
}
я большой противник рекурсий. лучше рекурсию заменить на цикл. и метод random принимает значения от 0 до 1. т.е. вам нужен диапазон от 0 до 3. если при вашем подходе рандом выдаст 1.. и умножить на 4, то получится 4.. это конечно редко будет по теории вероятности, но будет... |
Опаньки 8) Math.random() оказывается может выдать и max value 1 ? Хм... это интересно :) Спасибо, проверим...
|
аа. не вру, 1 не вкл
|
Тэээкс :) Чудесным образом всё теперь работает правильно! Однако понять бы еще почему :) Огромное спасибо, вы маг и волшебник! Я буду разбираться :)
|
| Часовой пояс GMT +3, время: 17:53. |