Просмотр полной версии : Алгоритмы Работа с массивами [UPDATE]
australian incognito
14.02.2014, 18:17
Задам вопрос в контексте недавно созданной темы: http://www.flasher.ru/forum/showthread.php?t=206574
Ниже описан применяемый мной алгоритм, но главный вопрос: почему при трейсе 'rand num' не совпадают с 'res num'? Как сделать, чтобы совпадали и логика, заложенная ниже работала верно?
import flash.events.Event;
var objNum:Number = 10;
var objArr:Array = new Array();
var enabledObjArr:Array = new Array();
var prevObjArr:Array = new Array();
//
var entFrParam:Number = 0;
var entFrParamMax:Number = 60;
function mainFunc(e:Event):void
{
var i:int;
//
if (entFrParam++ == entFrParamMax)
{
trace("\n\n///////// rand num:")
//
entFrParam = 0;
//
prevObjArr = getRandElements(objArr,4,prevObjArr);
//
for (i = 0; i < prevObjArr.length; i++)
{
//trace(prevObjArr[i].name)
enabledObjArr.push(prevObjArr[i]);
//
trace(prevObjArr[i].name);
}
trace("///////// res num:")
}
//
for (i = 0; i < enabledObjArr.length; i++)
{
process(enabledObjArr[i], 60);
//
if (enabledObjArr[i].degree >= 360)
{
trace(enabledObjArr[i].name);
//
enabledObjArr.shift();
}
}
}
function getRandElements(arr:Array, n:int, exclude:Array):Array
{
var i:int;
var tmp:Array = arr.concat();
var res:Array = [];
// убираем исключаемые
for (i = 0; i < exclude.length; i++)
{
tmp.splice(tmp.indexOf(exclude[i]), 1);
}
// выбираем из оставшихся рандомно
for (i = 0; i < n; i++)
{
var rnd:int = Math.random() * tmp.length;
res.push(tmp[rnd]);
tmp.splice(rnd, 1);
}
// возвращаем нужный массив
return res;
}
function process(obj:Object, speed:Number)
{
obj.degree += speed;
}
for (var i = 0; i < objNum; i++)
{
objArr[i] = new Object();
objArr[i].name = i;
objArr[i].degree = 0;
}
//
this.addEventListener(Event.ENTER_FRAME, mainFunc);
на каждом 60м такте вы генерите выборку prevObjArr и все ее элементы добавляете в enabledObjArr
на каждом же такте каждому элементу enabledObjArr увеличиваем degree и при достижении этим degree значения 360 смотрим трейс этого элемента, удаляя при этом первый элемент enabledObjArr
ну т.е. где-то до шестого такта (degree<360) мы не видим никакго трейса, а потом видим некий сумбур, организованный с помощью enabledObjArr.shift() в цикле, а дальше снова ничего не видим ( enabledObjArr пуст) до следующего 60го такта..
что за "логика" тут реализована и почему эти трейсы должны совпадать не оч. понятно
australian incognito
14.02.2014, 22:45
Предполагаемая логика следующая:
есть некий массив objArr на 10 обьектов
с итерацией в 60 кадров мы делаем из него рандомную выборку на 4 обьекта (исключая совпадение с 4-мя объектами предыдущей итерации). 4 этих объекта мы помещаем в массив enabledObjArr, чтобы можно было проводить с ними дальнейшие манипуляции.
с итерацией в 1 кадр мы наращиваем параметр degree каждого из инициализированных обьектов из массива enabledObjArr до 360 с некоторой заданной скоростью (в нашем случае 60)
по достижению параметром degree отметки в 360 мы удаляем обьект из массива enabledObjArr, тем самым исключив наращивание параметра.
удаляется нарощенный до 360 обьект с помощью shift, т.к. первым достигнет 360 именно тот обьект, который был добавлен первым в массив (тут я могу ошибаться, но вроде как это очевидно).
так почему же должны совпадать выводы трейсом rand num и res num?
Первое (rand num) нам показывает случайную выборку из 4 чисел в нужной последовательности, которые мы активировали в п. 2. Допустим это обьекты № 3, 7, 1, 5.
По моей логике у обьекта №3 у первого из четырех параметр degree начнет прирост и соответственно у него же первым достигнет 360. Соответственно он первым и должен быть удален из массива и выведен первым в res num.
Так это задумывалось.
Спасибо тем, кто осилил это длинное обьяснение.
Добавлено через 9 минут
Еще хочу добавить более цельную концепцию того, что бы я хотел видеть по итогу.
Предположим есть 10 обьектов. Каждый при инициализации отрисовывает круг с некоторой скоростью.
При 60 fps задача такая: каждую секунду из 10 обьектов выбирать 4 (не пересекающихся с объектами прошлой итерации) и наращивать в них угол до 360 градусов (т.е. по-сути, отрисовывать круг). На этом все, как только круг отрисован, обьекты можно опять обнулять (градусы = 0) и ждать следующей операции по инициализации 4 рандомных обьектов. Получается каждую секунду мы отрисовываем 4 из 10 круга, которые по завершению отрисовки исчезают. Объекты текущей итерации не совпадают с обьектами из предыдущей. На этом все.
ну примерно так все и происходит, только смотреть надо как-то аккуратнее что ли
да, и еще одна ловушка: операции типа удаления элементов массива в цикле по индексу - при удалении все индексы смещаются, а это не всегда легко можно учесть
function mainFunc(e:Event):void
{
var i:int;
if (entFrParam++ == entFrParamMax)
{
trace("------60----prevObjArr:")
entFrParam = 0;
prevObjArr = getRandElements(objArr, 4, prevObjArr);
enabledObjArr = prevObjArr.concat();
for (i = 0; i < prevObjArr.length; i++)
{
trace(prevObjArr[i].name);
}
}
if (!enabledObjArr.length) return;
trace("------1-----enabledObjArr:")
for (i = 0; i < enabledObjArr.length; i++)
{
trace(enabledObjArr[i].name);
}
for (i = 0; i < enabledObjArr.length; i++)
{
process(enabledObjArr[i], 60);
if (enabledObjArr[i].degree >= 360)
{
enabledObjArr.splice(i--, 1);
}
}
}
зы
ну и, конечно, разруливать функционал объектов какими-то внешними функциями в циклах это, имхо, путь к вывиху мозга..
насоздавал, а дальше когда надо и кого надо запустил, все остальное объект в состоянии решить и сделать сам:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Main extends Sprite
{
private var objNum:Number = 10;
private var objArr:Array = [];
private var prevObjArr:Array = [];
public function Main():void
{
for (var i:int = 0; i < objNum; i++)
{
var obj:Obj = new Obj(i);
obj.x = 100 + Math.random() * 200;
obj.y = 100 + Math.random() * 200;
objArr.push(obj);
addChild(obj);
}
var timer:Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, timer_timer);
timer.start();
}
private function timer_timer(e:TimerEvent):void
{
prevObjArr = getRandElements(objArr, 4, prevObjArr);
trace( "prevObjArr : " + prevObjArr );
for (var i:int = 0; i < prevObjArr.length; i++)
{
prevObjArr[i].start();
}
}
private function getRandElements(arr:Array, n:int, exclude:Array):Array
{
var i:int;
var tmp:Array = arr.concat();
var res:Array = [];
// убираем исключаемые
for (i = 0; i < exclude.length; i++)
{
tmp.splice(tmp.indexOf(exclude[i]), 1);
}
// выбираем из оставшихся рандомно
for (i = 0; i < n; i++)
{
var rnd:int = Math.random() * tmp.length;
res.push(tmp[rnd]);
tmp.splice(rnd, 1);
}
// возвращаем нужный массив
return res;
}
}
}
import flash.display.Sprite;
import flash.events.Event;
//////////////////
class Obj extends Sprite
{
public var degree:Number = 0;
public var id:int;
public var speed:Number = 0.2;
public var radius:Number = 10;
public function Obj(id:int)
{
super();
this.id = id;
}
public function start():void
{
degree = 0;
graphics.clear();
graphics.lineStyle(0);
graphics.moveTo(radius * Math.cos(degree), radius * Math.sin(degree));
addEventListener(Event.ENTER_FRAME, process);
}
private function process(e:Event):void
{
degree += speed;
graphics.lineTo(radius * Math.cos(degree), radius * Math.sin(degree));
if (degree >= 2 * Math.PI)
{
// останавливаем
removeEventListener(Event.ENTER_FRAME, process);
// ну и что-там еще надо..
graphics.clear();
}
}
override public function toString():String
{
return "obj_" + id;
}
}
australian incognito
15.02.2014, 00:21
ну примерно так все и происходит, только смотреть надо как-то аккуратнее что ли
function mainFunc(e:Event):void
{
var i:int;
if (entFrParam++ == entFrParamMax)
{
trace("------60----prevObjArr:")
entFrParam = 0;
prevObjArr = getRandElements(objArr, 4, prevObjArr);
enabledObjArr = prevObjArr.concat();
for (i = 0; i < prevObjArr.length; i++)
{
trace(prevObjArr[i].name);
}
}
if (!enabledObjArr.length) return;
trace("------1-----enabledObjArr:")
for (i = 0; i < enabledObjArr.length; i++)
{
trace(enabledObjArr[i].name);
}
for (i = 0; i < enabledObjArr.length; i++)
{
process(enabledObjArr[i], 60);
if (enabledObjArr[i].degree >= 360)
{
enabledObjArr.splice(i--, 1);
}
}
}
При подмене моей функции на вашу, все держится неплохо 2-3 цикла, потом сбивается по каким-то непонятным причинам... Как будто часть объектов массива enabledObjArr исчезает сама собой.
На самом деле костыль с функциями в цикле придуман был условно, чтобы максимально быстро передать суть требуемого алгоритма.
>> потом сбивается по каким-то непонятным причинам..
думаю, по причине, что во вновь выбранной партии могут быть экземпляры с ненулевым degree или что-то в этом роде..., отслеживать такие штуки в этих циклах с динамическими объектами как-то безидейно совсем
вот так, может быть
private function mainFunc(e:Event):void
{
var i:int;
if (entFrParam++ == entFrParamMax)
{
trace("------60----prevObjArr:")
entFrParam = 0;
prevObjArr = getRandElements(objArr, 4, prevObjArr);
enabledObjArr = prevObjArr.concat();
for (i = 0; i < prevObjArr.length; i++)
{
prevObjArr[i].degree = 0;
trace(prevObjArr[i].name);
}
}
if (!enabledObjArr.length) return;
trace("------1-----enabledObjArr:")
var tmp:Array = [];
for (i = 0; i < enabledObjArr.length; i++)
{
trace(enabledObjArr[i].name);
process(enabledObjArr[i], 60);
if (enabledObjArr[i].degree < 360)
{
tmp.push(enabledObjArr[i]);
}
}
enabledObjArr = tmp;
}
UPD. плюс удаление из массива в цикле по его индексу, это чаще всего головоломка, которую легче обойти, чем решать
australian incognito
17.02.2014, 02:09
>>
думаю, по причине, что во вновь выбранной партии могут быть экземпляры с ненулевым degree или что-то в этом роде..., отслеживать такие штуки в этих циклах с динамическими объектами как-то безидейно совсем
Беда в том, что в моей рабочей версии кода - параметр degree наращивается вновь созданному классу Circle, у которого параметр degree по дефолту нулевой... Я бы и рад показать рабочую версию, но там слишком много не относящегося к вопросу кода, без которого не будет работать ничего. Базовую версию в первом посте я написал как "выжимку" нужного кода для того, чтобы не быть совсем абстрактным... Так вот уже на первой итерации у меня 360 градусов второй обьект никогда не достигает, он как будто вообще не создавался. А 4-й достигает 360, но с отставанием в один кадр (возможно, это результат исчезновения второго обьекта, но далеко не факт).
Вы красиво обошли подсчет угла переопределением нужного массива и обратным сравнением вот тут:
if (enabledObjArr[i].degree < 360)
{
tmp.push(enabledObjArr[i]);
}
Но в моем случае мне просто необходимо по выполнению условия
if (enabledObjArr[i].degree >= 360)
{
//// some code
}
выполнять некие дополнительные действия. Но именно это условие дает выпадение элемента массива и непонятную ошибку.
>>Но в моем случае мне просто необходимо по выполнению условия выполнять некие дополнительные действия.
в этом же 'сортировочном' цикле положите их в другой список, с которым сотворите эти доп. действия, не путаясь в индексах
var tmp:Array = [];
var tmp1:Array = [];
for (i = 0; i < enabledObjArr.length; i++)
{
process(enabledObjArr[i], 60);
if (enabledObjArr[i].degree < 360)
{
tmp.push(enabledObjArr[i]);
}else
{
tmp1.push(enabledObjArr[i]);
}
}
Добавлено через 12 минут
зы. ну и повторюсь, совершенно непонятно стремление разместить логику, которая может(должна) быть 'на борту' самих объектов, в каких-то внешних циклах..
australian incognito
23.02.2014, 01:00
зы. ну и повторюсь, совершенно непонятно стремление разместить логику, которая может(должна) быть 'на борту' самих объектов, в каких-то внешних циклах..
Спасибо за этот совет. Он заставил пересмотреть внутреннюю иерархию классов и методов. Теперь все намного удобнее и логичнее + нет геммора с массивами!
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.