PDA

Просмотр полной версии : Алгоритмы Работа с массивами [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);

silin
14.02.2014, 20:48
на каждом 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 круга, которые по завершению отрисовки исчезают. Объекты текущей итерации не совпадают с обьектами из предыдущей. На этом все.

silin
14.02.2014, 23:53
ну примерно так все и происходит, только смотреть надо как-то аккуратнее что ли
да, и еще одна ловушка: операции типа удаления элементов массива в цикле по индексу - при удалении все индексы смещаются, а это не всегда легко можно учесть
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 исчезает сама собой.

На самом деле костыль с функциями в цикле придуман был условно, чтобы максимально быстро передать суть требуемого алгоритма.

silin
15.02.2014, 00:43
>> потом сбивается по каким-то непонятным причинам..
думаю, по причине, что во вновь выбранной партии могут быть экземпляры с ненулевым 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
}

выполнять некие дополнительные действия. Но именно это условие дает выпадение элемента массива и непонятную ошибку.

silin
17.02.2014, 08:57
>>Но в моем случае мне просто необходимо по выполнению условия выполнять некие дополнительные действия.

в этом же 'сортировочном' цикле положите их в другой список, с которым сотворите эти доп. действия, не путаясь в индексах
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
зы. ну и повторюсь, совершенно непонятно стремление разместить логику, которая может(должна) быть 'на борту' самих объектов, в каких-то внешних циклах..

Спасибо за этот совет. Он заставил пересмотреть внутреннюю иерархию классов и методов. Теперь все намного удобнее и логичнее + нет геммора с массивами!