Глюки с рекурсией
Народ, подскажите пожалуйста кто чем может! Есть такая вот проблема, что в скрипте, который я тут выкладываю, присутствует рекурсивная функция, исследующая значения в массиве и определяющая совпадения со случайным получаемым значением в этой функции. В целом, сценарий направлен на создание игры "Пятнашки".
Глюк такой, что когда я вставляю строчные выражения внутрь функции, никак на прямую не связанные с логикой функции и не влияющие на её работу, то мой сценарий начинает нормально работать и не допускает повторения значений в результирующем массиве. Они только лишь для вывода отчетов по этапам работы функции и в окончательном варианте не нужны. НО как только функция лишается этих выражений с отчетом, то сразу же наблюдается повторное попадание совпадающих значений в массив. 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.. это конечно редко будет по теории вероятности, но будет... |
Часовой пояс GMT +3, время: 04:15. |