Выбрать случайные элементы из массива без повторов?

Редактировать: я не могу поверить, что я не поймал это раньше. Оказывается, моей проблемой было повторное объявление моих первых переменных снова и снова, по сути, начиная программу заново, а не продолжая ее. Чтобы исправить это, я заменил первые две строки на это:

if (initialized === undefined) {
    trace("INITIALIZING");
    var MCs = [];
    var lastPos = "intializer";
    var initialized = 1;
}

Теперь это работает как шарм. Я чувствую себя нубом для этого; извините всех, чье время я потратил впустую. Я бы опубликовал это как ответ на свой собственный вопрос, но он не позволит мне, так как я все еще новичок.


Исходное сообщение следует:

Я пытаюсь сделать вспышку, которая будет случайным образом выбирать рекламу, воспроизводить ее, а затем случайным образом воспроизводить другую. Для этого мне удалось перетасовать массив, а затем gotoAndPlay-написать метку в первом элементе массива, а затем удалить этот элемент. В конце каждого объявления gotoAndPlay(1); со всем основным кодом, находящимся в первом кадре. Если массив пуст, он перестраивает и переставляет его.

Проблема в том, что я не хочу повторять какие-либо объявления, пока они не пройдут через все из них; Я думаю, что у меня есть это, но я не уверен. Кроме того, я не хочу, чтобы последний элемент в массиве был таким же, как первый в новом, поэтому одно и то же объявление не будет отображаться дважды подряд. Я пытаюсь заставить его определить, соответствует ли элемент, который он только что использовал, тому, который он собирается использовать, и переставить, если это произойдет, но в моем тестировании он по-прежнему иногда показывает одно и то же объявление дважды подряд.

Я, очевидно, делаю что-то не так, но, будучи совершенно новым для ActionScript3 (и на самом деле для прошивки), у меня много проблем с определением, что это такое. Вот что у меня сейчас:

var MCs = [];
var lastPos = "intializer";

if (MCs.length == 0) {
    MCs = reset();
    if (lastPos == MCs[0]) {
        while (lastPos == MCs[0]) {
            MCs = reset();
        }
    }
}
if (MCs.length > 0) {
    lastPos = MCs[0];
    MCs.splice(0,1);
    gotoAndPlay(lastPos+"MC");
}

function reset(){
    var PrepMCs = new Array("Image1", "Image2", "Image3");
    var WorkMCs = new Array(PrepMCs.length);

    var randomPos:Number = 0;
    for (var i:int = 0; i < WorkMCs.length; i++)
    {
        randomPos = int(Math.random() * PrepMCs.length);
        WorkMCs[i] = PrepMCs.splice(randomPos, 1)[0];
    }
    return WorkMCs;
}

Лично я бы предпочел сделать это с помощью JavaScript, HTML и изображений; это было бы действительно просто. Но по причинам хостинга /CMS я не имею никакого контроля, я ограничен одним файлом или одним блоком кода; Я не могу ничего разместить снаружи, что, насколько я могу судить, делает Flash лучшим выбором для этого.

Любая помощь будет принята с благодарностью, спасибо! Если я сделал что-то ужасно, ужасно неправильно, и это удивительно, что это вообще работает, не стесняйтесь сказать мне!

редактировать: это только что пришло мне в голову, это прекрасно, если второй запуск в том же порядке, что и первый запуск, и т. д. Главное, это должно быть случайным. Это, вероятно, гораздо проще реализовать.

редактировать 2: MASSIVE DERP ЗДЕСЬ. Каждый раз, когда он работает, он повторно инициализирует MCs а также lastPos... другими словами, это тасуется каждый раз и начинается заново. Что я должен исследовать, так это как запустить строку кода, только если переменная еще не инициализирована.

3 ответа

Явно воровал у @32bitKid, это моя версия.

Основная проблема, с которой я столкнулся при его решении - это идея "толкание / сращивание". Насколько это возможно, я люблю создавать один раз и использовать повторно. Сокращение и рост массивов громоздки, даже если они эффективны.

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

Кстати, мне нравится, что он предотвращает повторение предыдущего пункта ("почти пустой").

Итак, вот еще один метод:

package
{

    public class RandomizedList
    {
        private var _items:Array;
        private var idxs:Array;
        private var rnd:int;
        private var priorItemIdx:int;
        private var curIdx:int;

        public function RandomizedList(inarr:Array)
        {
            items = inarr;
        }

        private function initRandomize():void
        {
            idxs = new Array();

            //Fisher-Yates initialization (http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle):
            idxs[i] = 0;
            for (var i:int = 1; i < items.length; i++)
            {
                rnd = int(Math.random() * (i + 1));
                idxs[i] = idxs[rnd];
                idxs[rnd] = rnd;
            }

            curIdx = 0;
            priorItemIdx = -1;
        }

        private function randomize():void
        {
            var tempint:int;
            //Fisher-Yates (http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle):
            for (var i:int = items.length; i >= 1; i--)
            {
                rnd = int(Math.random() * (i + 1));
                tempint = idxs[i];
                idxs[i] = idxs[rnd];
                idxs[rnd] = tempint;
            }

            curIdx = 0;
        }

        public function next():void
        {
            if (curIdx >= idxs.length)
            {
                randomize();
            }

            if (items.length > 1 && priorItemIdx == idxs[curIdx])
            {
                curIdx++;
            }

            priorItemIdx = idxs[curIdx++];
            return items[priorItemIdx];
        }

        public function get items():Array
        {
            return _items;
        }

        public function set items(value:Array):void
        {
            _items = value;
            initRandomize();
        }
    }
}

Я бы использовал такой служебный класс, чтобы абстрагировать желаемое поведение:

import flash.text.TextField;

class Randomizer {

    private var unused:Array = [];
    private var used:Array;

    public function Randomizer(playList:Array) {
        used = playList;
    }

    public function next():* {
        // If almost empty, refill the unused array
        if(unused.length <= 1) refill();

        // Get the first item off the playList
        var item:* = unused.shift();

        // Shove it into the bucket
        used.push(item); 

        // return it back
        return item;
    }

    public function refill():void {
        var i:int;
        // Fisher-Yates shuffle to refill the unused array
        while(used.length > 0) {
            i = Math.floor(Math.random() * used.length)
            unused.push(used.splice(i,1)[0])
        }
    }
}

Обратите внимание, что он пополняет unused массив, когда unused В массиве по-прежнему есть один элемент, что делает невозможным повторение последнего результата дважды подряд. Это вернет каждый элемент один раз перед циклом и никогда не будет повторять один и тот же элемент дважды.

Вы бы использовали это, говоря что-то вроде:

var ads:Randomizer = new Randomizer(["Image1", "Image2", "Image3"]);
ads.next(); // will return something
ads.next(); // will return something
ads.next(); // will return something
ads.next(); // will return something
// Keep going into infinity...

Здесь есть небольшой тестовый пример этого кода.

Посмотрите, имеет ли это смысл

//create your array of all your ad names/frame labels
var PrepMCs:Array = new Array("Image1", "Image2", "Image3");

var shuffledMCs:Array = [];

//store the name of the last played ad in this var
var lastAdPlayed:String;

//shuffle the array
shuffleArray(PrepMCs);


function shuffleArray(arrayToShuffle:Array):void {  
//clear the array
shuffledMCs = [];

var len:int = arrayToShuffle.length;

for(var i:int = 0; i<len; i++) {
shuffledMCs[i] = arrayToShuffle.splice(int(Math.random() * (len - i)), 1)[0];
}

//test to see if the new first ad is the same as the last played ad
if (lastAdPlayed == shuffledMCs[0]) {
//reshuffle
    shuffleArray(PrepMCs);
} else {

lastAdPlayed = [0];

trace(shuffledMCs);

playAds();
}    

}



//after each ad has played, call this function
function playAds():void {

if (shuffledMCs.length > 0) {

    gotoAndPlay(shuffledMCs[0]);
    shuffledMCs.splice(0,1);

} else {
    //array is empty so we have played all the ads
    shuffleArray(PrepMCs);
}

}
Другие вопросы по тегам