从数组中选择无重复的随机元素?

时间:2012-04-26 18:49:12

标签: arrays actionscript-3 flash flash-cs5 shuffle

编辑:我简直不敢相信我没有赶上这个。事实证明我的问题是一遍又一遍地重新声明我的第一个变量,基本上是重新启动程序而不是继续它。为了解决这个问题,我用这个替换了前两行:

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 HERE。每次运行时,它都会重新初始化MCslastPos ...换句话说,它每次都会随机播放并重新开始。我应该研究的是如果尚未初始化变量,如何只运行一行代码。

3 个答案:

答案 0 :(得分:1)

从@ 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();
        }
    }
}

答案 1 :(得分:0)

我会使用这样的实用程序类来抽象出我想要的行为:

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...

此代码有一个小测试示例here

答案 2 :(得分:-1)

看看这是否有意义

//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);
}

}