Related
first question ever here...
I am coding a simple 3-card poker hand evaluator and am having problems finding/extracting multiple "straights" (sequential series of values) from an array of values.
I need to extract and return EVERY straight the array possibly has. Here's an example:
(assume array is first sorted numerically incrementing)
myArray = [1h,2h,3c,3h,4c]
Possible three-value sequences are:
[1h,2h,3c]
[1h,2h,3h]
[2h,3c,4c]
[2h,3h,4c]
Here is my original code to find sequences of 3, where the array contains card objects with .value and .suit. For simplicity in this question I just put "2h" etc here:
private var _pokerHand = [1h,2h,3c,3h,4c];
private function getAllStraights(): Array
{
var foundStraights:Array = new Array();
for (var i: int = 0; i < (_handLength - 2); i++)
{
if ((_pokerHand[i].value - _pokerHand[i + 1].value) == 1 && (_pokerHand[i + 1].value - _pokerHand[i + 2].value) == 1)
{
trace("found a straight!");
foundStraights.push(new Array(_pokerHand[i], _pokerHand[i + 1], _pokerHand[i + 2]));
}
}
return foundStraights;
}
but it of course fails when there are value duplicates (like the 3's above). I cannot discard duplicates because they could be of different suits. I need every possible straight as in the example above. This allows me to run the straights through a "Flush" function to find "straight flush".
What array iteration technique am I missing?
This is an interesting problem. Given the popularity of poker games (and Flash) I'm sure this has been solved many times before, but I couldn't find an example online. Here's how I would approach it:
Look at it like a path finding problem.
Begin with every card in the hand as the start of a possible path (straight).
While there are possible straights:
Remove one from the list.
Find all the next valid steps, (could be none, or up to 4 following cards with the same value), and for each next valid step:
If it reaches the goal (completes a straight) add it to a list of found straights.
Otherwise add the possible straight with the next step back to the stack.
This seems to do what you want (Card object has .value as int):
private function getAllStraights(cards:Vector.<Card>, straightLength:uint = 3):Vector.<Vector.<Card>> {
var foundStraights:Vector.<Vector.<Card>> = new <Vector.<Card>>[];
var possibleStraights:Vector.<Vector.<Card>> = new <Vector.<Card>>[];
for each (var startingCard:Card in cards) {
possibleStraights.push(new <Card>[startingCard]);
}
while (possibleStraights.length) {
var possibleStraight:Vector.<Card> = possibleStraights.shift();
var lastCard:Card = possibleStraight[possibleStraight.length - 1];
var possibleNextCards:Vector.<Card> = new <Card>[];
for (var i:int = cards.indexOf(lastCard) + 1; i < cards.length; i++) {
var nextCard:Card = cards[i];
if (nextCard.value == lastCard.value)
continue;
if (nextCard.value == lastCard.value + 1)
possibleNextCards.push(nextCard);
else
break;
}
for each (var possibleNextCard:Card in possibleNextCards) {
var possibleNextStraight:Vector.<Card> = possibleStraight.slice().concat(new <Card>[possibleNextCard]);
if (possibleNextStraight.length == straightLength)
foundStraights.push(possibleNextStraight);
else
possibleStraights.push(possibleNextStraight);
}
}
return foundStraights;
}
Given [1♥,2♥,3♣,3♥,4♣] you get: [1♥,2♥,3♣], [1♥,2♥,3♥], [2♥,3♣,4♣], [2♥,3♥,4♣]
It gets really interesting when you have a lot of duplicates, like [1♥,1♣,1♦,1♠,2♥,2♣,3♦,3♠,4♣,4♦,4♥]. This gives you:
[1♥,2♥,3♦], [1♥,2♥,3♠], [1♥,2♣,3♦], [1♥,2♣,3♠], [1♣,2♥,3♦], [1♣,2♥,3♠], [1♣,2♣,3♦], [1♣,2♣,3♠], [1♦,2♥,3♦], [1♦,2♥,3♠], [1♦,2♣,3♦], [1♦,2♣,3♠], [1♠,2♥,3♦], [1♠,2♥,3♠], [1♠,2♣,3♦], [1♠,2♣,3♠], [2♥,3♦,4♣], [2♥,3♦,4♦], [2♥,3♦,4♥], [2♥,3♠,4♣], [2♥,3♠,4♦], [2♥,3♠,4♥], [2♣,3♦,4♣], [2♣,3♦,4♦], [2♣,3♦,4♥], [2♣,3♠,4♣], [2♣,3♠,4♦], [2♣,3♠,4♥]
I haven't checked this thoroughly but it looks right at a glance.
I have a little problem with my flash game. My array of birds (obstacles) everytime when they reach let's say x -800 they respawn at the starting position in everytime at random place in an array and it works well.
BUT
Every time it loops, birds 1 by 1 stacks at the first position of an array. It is weird.
public function setUpBirds() {
for (var i:int = 0 ;i< 10; i++) {
var mcClip:Bird = new Bird();
var yVal:Number = (Math.ceil(Math.random()*100));
birds.push(mcClip);
birds[i].x = 100 * i;
birds[i].y = yVal * i;
birdsContainer.addChild(mcClip);
}
}
private function moveBirds(event:Event):void {
birdsContainer.x = birdsContainer.x -10;
if (birdsContainer.x == -500) {
birdsContainer.x = 500;
setUpBirds();
}
}
Any ideas?
Everytime your birdsContainer has an x of 500, you call setUpBirds(), so let's step though and look at what's happening: (explained with code comments injected into your code)
First time setUpBirds runs:
for (var i:int = 0 ;i< 10; i++) {
//a new bird is created 10 times
var mcClip:Bird = new Bird();
var yVal:Number = (Math.ceil(Math.random()*100));
//you add it to the array
birds.push(mcClip);
//birds[1] properly refers to the item you just pushed into the array
birds[i].x = 100 * i;
birds[i].y = yVal * i;
birdsContainer.addChild(mcClip);
}
First time through, everything is great, your birds array has 10 items in it now.
Now, second time the function runs:
for (var i:int = 0 ;i< 10; i++) {
//create 10 more new birds (in addition to the last ones)
var mcClip:Bird = new Bird();
var yVal:Number = (Math.ceil(Math.random()*100));
//add to the array (which already has 10 items in it)
birds.push(mcClip); //so if i is 5, the item you just pushed is at birds[14]
//birds[i] will refer to a bird you created the first time through
//eg bird[0] - bird[9] depending on `i`, but really you want bird[10] = bird[19] this time around
birds[i].x = 100 * i; //your moving the wrong bird
birds[i].y = yVal * i;
//the new birds you create, will have an x/y of 0
//since birds[i] doesn't refer to these new birds
birdsContainer.addChild(mcClip);
}
Now you see the problem? your birds array now has 20 items in it, so you are now referencing the wrong item in the array.
To fix this, just set the x/y on the mcClip var instead of the array, or do birds[birds.length-1].x = 100 * i to use the last item added to the array.
On a side note, your performance is going to get pretty bad pretty fast creating 10 new birds all the time. You need to get rid of those old birds if you're constantly creating new ones.
Seems like what you probably WANT to do is just reposition the existing birds every loop, so that would look something like this:
for (var i:int = 0 ;i< 10; i++) {
//check if there is NOT a bird already at this position in the array
if(birds.length <= i || !birds[i]){
//no bird yet, so create it and add it and push it
var mcClip:Bird = new Bird();
birds.push(mcClip);
birdsContainer.addChild(mcClip);
}
//now set the position of the bird
var yVal:Number = (Math.ceil(Math.random()*100));
birds[i].x = 100 * i;
birds[i].y = yVal * i;
}
This way, you only ever creating 10 birds and you are just resetting the y position of those birds every loop.
Hey guys so i am developing a Game and i have an Array that keeps track of my 5 movie clips that are added to the stage by the array. I have a Player movie clip as well so the Player movie clip is Hittesting with all the 5 diamond movie clips which are added to the stage like so:
private var nPoints:Number = 5;..........
public function addPointsToStage():void
{
for (var i = 0; i < nPoints; i++)
{
trace(aPointsArray.length);
points = new mcGainPoints();
stage.addChild(points);
points.x = startPoint.x + (xSpacing * i);
points.y = startPoint.y - (ySpacing * i);
aPointsArray.push(points);
}
}
Now when the Player comes in contact with all the 5 movie clips everything works fine and the output for the array looks like this:
0
1
2
3
4
Then it continues to the next level.
But say that my Player doesnt hit any of the 5 movie clips or only hits a couple of them, when the next level is started the output looks like this:
5
6
7
8
9
and when the next level is started weird things start happening like points start adding to the highscore by themselves.
I think the problem is that im not destroying the array holding the 5 movie clips correctly this is the code i use to start the next level and destroy the array:
if(player.hitTestObject(mcGoal_1))
{
//Remove all points from array/stage
for (var i:int = 0; i < aPointsArray.length; i++)
{
if (aPointsArray[i].parent)
{
parent.removeChild(aPointsArray[i]);
}
startNextLevel();
}
The mcGoal_1 is the object of the game so if the player hits the goal_1 then destroy all array objects on screen and start next level. This is the startnextlevel function.
private function startNextLevel():void
{
//add points to next stage
addPointsToStage();
}
So can you see why when the next level starts the array isnt reset back to 01234? I think thats why the game has that bug of randomly adding points. Please any help will be appreciated
//Remove all points from array/stage
for (var i:int = 0; i < aPointsArray.length; i++)
if (aPointsArray[i].parent)
parent.removeChild(aPointsArray[i]);
// just one statement, no braces
aPointsArray.length=0; // clear the array itself, not just
// points from display list!
startNextLevel(); // now start level
An incorrect order of correct statements leads to a disaster. Always check your code flow, what executes now and what then, and how many times.
It doesn't look like you're removing anything from the array.
You can use a combination of .indexOf() and .splice() to remove items from an array:
function removeMc(clip:MovieClip):void
{
if(clip.parent) clip.parent.removeChild(clip);
// Also remove from array.
var index:int = aPointsArray.indexOf(clip);
aPointsArray.splice(index, 1);
}
It might also be worth simply emptying the array when you startNextLevel():
private function startNextLevel():void
{
aPointsArray.length = 0;
//add points to next stage
addPointsToStage();
}
Just assign your array to null value. so that array will start from begining whenever you require. i hope the following code code would helps you.
var nPoints:Number = 5;
var points:poin;
var aPointsArray:Array;
var startPoint:Number = 0;
var xSpacing:Number = 20;
var ySpacing:Number = 20;
addPointsToStage();
function addPointsToStage():void
{
aPointsArray = null;
aPointsArray = new Array();
for (var i:int = 0; i < 6; i++)
{
trace(aPointsArray.length);
points = new poin();
addChild(points);
points.x = 100+ (xSpacing * i);
points.y = 200 - (ySpacing * i);
aPointsArray.push(points);
}
}
I have problem with this array thing I am doing. U can just plug in the code and run.
I need to have 2 things display out of the same array and which ever is picked gets kickedout from the array and stashed into another one.
One of the 2 things that are displaying out is picked at random and the other one goes in order it was put in.
So the logic I applied, or tried applying and is not working very well is..
Once the 2 things display out and if u pick the index count, no numbers change since the index count becomes subtracted by one, so the object after it gets pushed up.
but if the random choice is picked the index count moves up by one since it needs to keep moving...
The error i get is this:
TypeError: Error #2007: Parameter child must be non-null.
at flash.display::DisplayObjectContainer/addChild()
at Level3Torture_fla::MainTimeline/civilizedorder()[Level3Torture_fla.MainTimeline::frame1:87]
at Level3Torture_fla::MainTimeline/goNext()[Level3Torture_fla.MainTimeline::frame1:114]
at Level3Torture_fla::MainTimeline/switchpic()[Level3Torture_fla.MainTimeline::frame1:79]
This is the Code:
import flash.sampler.NewObjectSample;
import flash.display.Sprite;
import flash.events.MouseEvent;
var eating_breakfast:Sprite;
var walking:Sprite;
var swimming:Sprite;
var art:Sprite;
var choices:Array = new Array ();
//Sprite Creation
eating_breakfast = new Sprite ();
eating_breakfast.graphics.beginFill(0xE39D43);
eating_breakfast.graphics.drawRect(0,0,50,50);
eating_breakfast.graphics.endFill();
eating_breakfast.x = 50;
eating_breakfast.y = 50;
walking = new Sprite ();
walking.graphics.beginFill(0xC3266C);
walking.graphics.drawRect(0,0,50,50);
walking.graphics.endFill();
walking.x = 100;
walking.y = 100;
swimming = new Sprite ();
swimming.graphics.beginFill(0x48AFD1);
swimming.graphics.drawRect(0,0,50,50);
swimming.graphics.endFill();
swimming.x = 150;
swimming.y = 150;
art = new Sprite ();
art.graphics.beginFill(0xafdb44);
art.graphics.drawRect(0,0,50,50);
art.graphics.endFill();
art.x = 200;
art.y = 200;
//adding sprites into array
choices.push( eating_breakfast);
choices.push(walking);
choices.push(swimming);
choices.push(art);
var indexcount = 0;
var randomize:Number;
var storageArray: Array = new Array ();
civilizedorder();
randomizedorder();
this.addEventListener(MouseEvent.CLICK,switchpic);
//pick the target generated object
function switchpic(t:MouseEvent)
{
//for index count
if (t.target == choices[indexcount])
{
storageArray.push(choices[indexcount]);
removeChild(choices [indexcount]);
removeChild(choices [randomize]);
choices.splice(indexcount,1);
goNext();
};
// for randomize
if (t.target == choices[randomize])
{
storageArray.push(choices[randomize]);
removeChild(choices [indexcount]);
removeChild(choices [randomize]);
choices.splice(randomize,1);
indexcount++;
trace("The Index count is" + indexcount);
goNext();
}
}
//generates the index count object
function civilizedorder()
{
addChild(choices [indexcount]);
choices[indexcount].x = 300;
}
trace("The number of choices in the choice array is " + choices.length);
//generates the randomized object
function randomizedorder()
{
randomize = Math.floor(Math.random() * choices.length);
trace("the random number is" + randomize);
if (randomize == indexcount )
{
randomizedorder();
}
else
{
addChild(choices [randomize]);
}
}
//EDIT
function goNext()
{
trace("The storagearray has " + (storageArray.length));
if (choices.length < 0 || choices.length > 0)
{
if (indexcount > choices.length-1)
{
indexcount = choices.length - 1;
}
civilizedorder();
randomizedorder();
}
}
It is giving me a new error now. It's called StackOverflow. I am not entirely sure what is going wrong now.
EDIT: To add a conditional and check if you will be out of bounds for adding a child in this array, try this:
if(indexcount <= choices.length){
addChild(choices [indexcount]);
}
Try commenting out the splicing in the switchpic() method. That or re-add those values/sprite instances to the array.
I think that you've sliced from the "choices" array twice in the switchpic() method, and never actually add to the array ever again. So you'll eventually end up with an empty choices array. Hence the error.
In the second conditional, if (t.target == choices[randomize]), you increment indexcount, and then call goNext() which regenerates the randomize value to not equal the indexcount, but also tries to re-add a child sprite.
This could cause an array of 4 items to become 2 items, and then, possibly, randomize = 0, indexcount = 1. In the second pass, you might have an array of 0 items, with randomize = 0, indexcount = 1 and the error to occur.
Here's the flow, I imagine:
It looks like you're clicking on an instance of a sprite.
Then it calls switchpic(), which executes:
...
choices.splice(indexcount,1);
...
and then goNext()
which calls civilizedorder()
which executes:
...
addChild(choices [indexcount]);
...
you should check indexcount is never outside of 0-3 range.
in function goNext(), change the code as follows:
function goNext()
{
trace("The storagearray has " + (storageArray.length));
if(choices.length <> 0)
{
if(indexcount > choices.length-1)
indexcount = choices.length-1;
civilizedorder();
randomizedorder();
}
}
I'm wondering if it is possible to reset / reload / reconstruct an array order?
I'm making this "Space Invaders" game and the enemy's need to restart to it's position when the game is being restarted. When I shoot down the enemy's and reset my game, the enemy's I've killed keep being gone.
So here's some of the code responsible:
var spiderArray:Array = new Array(enemyField.enemy1,enemyField.enemy2,
enemyField.enemy3,enemyField.enemy4,
enemyField.enemy5,enemyField.enemy6,
enemyField.enemy7,enemyField.enemy8,
enemyField.enemy9,enemyField.enemy10,
enemyField.enemy11,enemyField.enemy12,
enemyField.enemy13,enemyField.enemy14,
enemyField.enemy15,enemyField.enemy16,
enemyField.enemy17,enemyField.enemy18,
enemyField.enemy19,enemyField.enemy20,
enemyField.enemy21,enemyField.enemy22,
enemyField.enemy23,enemyField.enemy24,
enemyField.enemy25,enemyField.enemy26,
enemyField.enemy27,enemyField.enemy28,
enemyField.enemy29,enemyField.enemy30,
enemyField.enemy31,enemyField.enemy32,
enemyField.enemy33,enemyField.enemy34,
enemyField.enemy35,enemyField.enemy36,
enemyField.enemy37,enemyField.enemy38,
enemyField.enemy39,enemyField.enemy40,
enemyField.enemy41,enemyField.enemy42,
enemyField.enemy43,enemyField.enemy44,
enemyField.enemy45,enemyField.enemy46,
enemyField.enemy47,enemyField.enemy48,
enemyField.enemy49,enemyField.enemy50,
enemyField.enemy51,enemyField.enemy52,
enemyField.enemy53,enemyField.enemy54,
enemyField.enemy55,enemyField.enemy56,
enemyField.enemy57,enemyField.enemy58,
enemyField.enemy59,enemyField.enemy60,
enemyField.enemy61,enemyField.enemy62,
enemyField.enemy63,enemyField.enemy64,
enemyField.enemy65,enemyField.enemy66);
Now the place where the enemy's are being killed:
function enemyHitTest():void {
//for each of the three spiders
for(var i:int = 0; i < spiderArray.length; i++) {
//the each of the six bullets
for(var j:int = 0; j < 6; j++) {
//don't consider bullets that aren't in play:
if(bulletArray[j].y > SpelerMC.y) continue;
if(spiderArray[i].hitTestObject(bulletArray[j])) {
score += 10;
scoreTxt.text = score.toString();
trace("Invader " + i + " neergeschoten!");
spiderArray[i].parent.removeChild(spiderArray[i]);
bulletArray[j].x = j * 70 + 100;
bulletArray[j].y = 595;
}
}
}
Now I think I need to put some sort of theArray.pop(); or something, but don't know how to use it, but I need to place it in this function:
function startGame() {
trace("Start het spel opnieuw...");
gameTimer.addEventListener(TimerEvent.TIMER, onTick);
gameTimer.start();
enemyField.x = 400;
enemyField.y = 160;
SpelerMC.x = 83;
SpelerMC.y = 531;
}
Please help me! Have been searching for 5 hours already. Thanks in advance!
to remove element number i use array.splice(i, 1); ( http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html#splice().com/en_US/FlashPlatform/reference/actionscript/3/Array.html#splice%28%29) but keep in mind that array.length will decrease
to reset the array just invoke spidersArray = new Array(enemyField.enemy1, etc) again
UPDATE
in in the enemyHitTest function i changed the removing condition to if(enemyArray[i].visible && enemyArray[i].hitTestObject(laserArray[j])) and enemyArray[i].parent.removeChild(enemyArray[i]); to enemyArray[i].visible = false;
and added
function respawnEnemies():void{
for(var i:int = 0; i < enemyArray.length; i++) {
enemyArray[i].visible = true;
}
}
to call it from startGame
full code here
upd 2
so the problem was not in resetting the array but in the fact that your enemyField and its' enemies were added to stage manually and removed programmatically so there was no code to call to bring them back
if all your instances should be preserved - e.g. you generate all actors at the beginning and later all of them are reused (at the new game) you can set an array of them and on each start game make a copy and remove "dead" enemies from the copied array
also better option is to use a vector e.g.
var enemies:Vector.<Enemy> = Vector.<Enemy>([]);//in brackets references to the instances of Enemy class
var inGame:Vector.<Enemy> = enemies.concat();
also 5hrs of research? please be patient and try harder,
best regards