8 queens problem - actionscript-3

I am trying to solve the 8 queens problem (where you select a space and it will put down 8 queens so that none of them will hit each other) but i am having trouble making the chess board.
right now i have this
var chessBoard:Array = new Array();
chessBoard["row1"] = [1,0,1,0,1,0,1,0];
chessBoard["row2"] = [0,1,0,1,0,1,0,1];
chessBoard["row3"] = [1,0,1,0,1,0,1,0];
chessBoard["row4"] = [0,1,0,1,0,1,0,1];
chessBoard["row5"] = [1,0,1,0,1,0,1,0];
chessBoard["row6"] = [0,1,0,1,0,1,0,1];
chessBoard["row7"] = [1,0,1,0,1,0,1,0];
chessBoard["row8"] = [0,1,0,1,0,1,0,1];
and i need to know two things
a) will i be able to use this for the problem (will i be able to have it check if any queens will collide by its array coordinates)
b) how do i draw the squares on the chess board to correspond with the numbers

var chessBoard:Array = new Array();
// Setup the array
for(var i:int = 0; i < 4; i++)
{
chessBoard.push(new Array(1,0,1,0,1,0,1,0));
chessBoard.push(new Array(0,1,0,1,0,1,0,1));
}
// Size of the tile
var tileSize:int = 20;
function createChessBoard():void
{
// Itterate through the "chessBoard"-array
for(var i:int = 0; i < chessBoard.length; i++)
{
// Itterate through the arrays in the "chessBoard"-array
for(var j:int = 0; j < chessBoard[i].length; j++)
{
// Create new tile
var tile:Sprite = new Sprite();
// Create the color variable and check to see what value to put
// in it dependingin the value of the current itteration - 1 or 0
var tileColor:int = chessBoard[i][j] * 0xffffff;
// Tile-coloring-setup-thingie-routine
tile.graphics.beginFill(tileColor);
tile.graphics.drawRect(0, 0, tileSize, tileSize);
tile.graphics.endFill();
// Tile positioning
tile.x = j * tileSize;
tile.y = i * tileSize;
// Adding tile to the displaylist
addChild(tile);
}
}
}
// Run function
createChessBoard();

You can assume that cell is black when sum of its coordinates is odd and white if even:
function getColor(x, y) {
return (x + y) % 2 == 0 ? 0 : 1;
}
// or even
function getColor(x, y) {
return (x + y) % 2;
}

You could start with creating a Square class, this would enable you to give specific properties to each Square. You want to avoid having two pieces on one square for instance, you want to set the color, also you would need to know the coordinates such as a1, c4 etc...
To draw your Chessboard, you could create rows of Squares.
private function squares:Array = [];
private function addRow( black:Boolean , _y:int , rowName:String ):void
{
for( var i:int ; i < 8 ; ++i )
{
var sq:Square = new Square();
//alternate colors
if( black )
sq.color = 0;
else
sq.color = 0xffffff;
black = !black;
sq.x = i* sq.width;
sq.y = _y;
//save square Chess coordinates
sq.coord = {letter: rowName , number: i + 1}
addChild(sq);
//add the Square instance to an Array for further reference
squares.push( sq );
}
}
Then simply add the rows
private function createBoard():void
{
var black:Boolean;
var letters:Array = [ a , b , c , d , e , f , g , h ]
for( var i:int ; i < 8 ; ++i )
{
addRow( black , i * squareSize , letters[i] );
black = !black;
}
}
To add a Queen to a specific Square instance , use the squares Array.

Related

How to Save positions for 3 objects in Array to make random position between each other by AS3?

How to Save positions for 3 objects in Array to make random position between each other by AS3?
import flash.geom.Point;
var arry:Point = new Point();
arry[0] = arry[78,200];
arry[1] = arry[217,200];
arry[2] = arry[356,200];
//object called b1
b1.x = arry[0][0];
b1.y = arry[0][1];
//object called b2
b2.x = arry[1][0];
b2.y = arry[1][1];
//object called b3
b3.x = arry[2][0];
b3.y = arry[2][1];
//make objects swap positions between each other
var rand:Number = (Math.random()*arry.length);
//output to see random position [[78,200],[217,200],[356,200]]
trace(arry);
to get random with tween like this... https://www.youtube.com/watch?v=8m_m64plQ6E
At compile time you should get this Error I suppose : "ReferenceError: Error #1069"
Here is a way to store the positions (like in the link you provided from youtube) :
import flash.geom.Point;
var squareWidth:uint = 40;
var squareHeight:uint = 40;
var marginX:uint = 100;
var marginY:uint = 75;
var spacer:uint = 10;
var positions:Vector.<Point > = new Vector.<Point > (9);
function setPositions(v:Vector.<Point>):void {
var count:uint = 0;
var posx:uint;
var posy:uint;
for (var i = 0; i < 3; i ++)
{
for (var j = 0; j < 3; j ++)
{
posx = (j * squareWidth) + (spacer * j) + marginX;
posy = (i * squareHeight) + (spacer * i) + marginY;
v[count] = new Point(posx,posy);
count++;
}
}
}
setPositions(positions);
trace(positions);
// output :
// (x=100, y=75),(x=150, y=75),(x=200, y=75),(x=100, y=125),(x=150, y=125),(x=200, y=125),(x=100, y=175),(x=150, y=175),(x=200, y=175)
So here you have nine Points to place the clips like in the video.
You just have to add a function to swap the nine boxes stored in another Vector.
In your case.
For 3 positions do the following if I understand your question.
import flash.geom.Point;
var positions:Vector.<Point> = new Vector.<Point>(3);
var p1:Point = new Point(78,200);
var p2:Point = new Point(217,200);
var p3:Point = new Point(356,200);
positions[0] = p1;
positions[1] = p2;
positions[2] = p3;
trace(positions);
// output : (x=78, y=200),(x=217, y=200),(x=356, y=200)
So, you're still unclear!
Your issue is to find a random position?
This may help you if this is the problem you're facing :
import flash.geom.Point;
var positions:Vector.<Point > = new Vector.<Point > (3);
var numbers:Vector.<uint> = new Vector.<uint>();
var numbersAllowed:uint = 3;
var rndNmbrs:Vector.<uint> = new Vector.<uint>(3);;
var p1:Point = new Point(78,200);
var p2:Point = new Point(217,200);
var p3:Point = new Point(356,200);
positions[0] = p1;
positions[1] = p2;
positions[2] = p3;
trace(positions);
function populateRndNmbrs(n:uint):void {
for (var i:uint = 0; i < n; i++)
{
numbers[i] = i;
}
}
populateRndNmbrs(numbersAllowed);
function populateRandomNumbers(n:uint):void
{
var rnd:uint;
for (var i:uint = 0; i < n; i++)
{
rnd = numbers[Math.floor(Math.random() * numbers.length)];
for (var j:uint = 0; j < numbers.length; j++)
{
if (rnd == numbers[j])
{
numbers.splice(j,1);
}
}
rndNmbrs[i] = rnd;
}
}
populateRandomNumbers(numbersAllowed);
trace("rndNmbrs = " + rndNmbrs);
for (var i:uint = 0; i < numbersAllowed; i++)
{
trace("b"+ (i+1) + ".x = " + positions[rndNmbrs[i]].x);
trace("b"+ (i+1) + ".y = " + positions[rndNmbrs[i]].y);
// In place of trace, you should place the boxes at those random positions.;
}
//output:
//(x=78, y=200),(x=217, y=200),(x=356, y=200)
//rndNmbrs = 2,0,1
//b1.x = 356
//b1.y = 200
//b2.x = 78
//b2.y = 200
//b3.x = 217
//b3.y = 200
Is that what you want? Or do you want to know how to create a motion effect?
I'm not sure about what you really need...
This will help you to place all the boxes in a random position.
You may do this like here bellow, and add a function to check if the random positions are not the same.
With only 3 MovieClips, you will often have the same random positions as long they're stored in the "positions Vector"
var squares:Vector.<MovieClip> = new Vector.<MovieClip>(3);
function populateMCs(target:DisplayObjectContainer,n:uint):void{
for (var i:uint = 0; i < n; i++){
squares[i] = target["b"+(i+1)];
}
}
function swapMCs():void{
for (var i:uint=0; i<squares.length; i++){
squares[i].x = positions[rndNmbrs[i]].x;
squares[i].y = positions[rndNmbrs[i]].y;
}
}
populateMCs(this,numbersAllowed);
swapMCs();
I give you a last example to get a motion effect in AS3.
I'm not a translator AS2 -> AS3 and a video is not the best way to show your code :(
This will make your boxes move smoothly, but not the way you want.
Now, you have to learn AS3 and try to make the job by yourself.
Then, if you have another issue, just ask clearly what you want.
var friction:Number = 0.15;
setDestination(squares[0],squares[0].x,350,friction);
setDestination(squares[1],squares[1].x,350,friction);
setDestination(squares[2],squares[2].x,350,friction);
squares[0].addEventListener(Event.ENTER_FRAME,moveClip);
squares[1].addEventListener(Event.ENTER_FRAME,moveClip);
squares[2].addEventListener(Event.ENTER_FRAME,moveClip);
function setDestination(mc:MovieClip,x:uint,y:uint,friction:Number):void{
mc.destinx = x;
mc.destiny = y;
mc.f = friction;
}
function moveClip(e:Event):void{
var mc:MovieClip = e.target as MovieClip;
trace(mc.name)
mc.speedx = (mc.destinx - mc.x);
mc.speedy = (mc.destiny - mc.y);
mc.x += mc.speedx*mc.f;
mc.y += mc.speedy*mc.f;
if((Math.floor(mc.speedx)<1) && (Math.floor(mc.speedy)<1)){
mc.removeEventListener(Event.ENTER_FRAME,moveClip);
trace("STOP MOVE FOR " + mc.name);
}
}

How To Create An Array of Movie Clip with number

I have multi movieclips in my stage and they have instanceName e.g. k1,k2,... . I want to createar=[k1,k2,k3,k4, ...].
var i: int;
var ar: Array = new Array();
for (i = 1; i < 5; i++)
{
ar[i-1] = ["k" + i];
}
trace(ar);
ar[1].x = 100;
But the end of code does not perform.
What you want to do is to create an array of MovieClips, but instead of it you create an array of Arrays of Strings. To achieve your goal, you need to find an instance of a clip on stage by its name. Here is how you can try to do that:
const array:Array = new Array();
for(var i:int = 0; i < 5; i++) {
const childName:String = "k" + (i + 1);
const myMovieClip:MovieClip = stage.getChildByName(childName) as MovieClip;
array.push(myMovieClip);
}

removeChild is removing all my Movie clips

I am making a tool which obscures an image with squares. What I want to happen is to have a bouncing ball which hits the squares and makes them disappear. However, the removeChild command isn't working right. I set it up to populate the image with empty movie clips and colorize them. However, when I click the square, I am running into problems with the parent/child. I keep running into this error. "The supplied DisplayObject must be a child of the caller." I cannot think of a good way to assign the eventListeners to each individual squares. I'm sure it is obvious. Here is my code. Thank you in advance
EDIT:If I get it to work, it deletes all instances of the square, not just the one I clicked.
Here is my code
var mc:MovieClip = bgIMG;
var bd:BitmapData = new BitmapData(mc.width,mc.height);
bd.draw(mc);
var _img:Bitmap = new Bitmap(bd);
var _imgNodes:Array = [];
var _tiledImg:MovieClip = container_tiled_img;
var pad:int = 0;
var rows:int = 10;
var cols:int = 10;
var zero:Point = new Point();
createImgNodeGrid(rows, cols, pad);
pixelateNodes(_imgNodes);
function removeMC(e:MouseEvent)
{//removes the movie clip
trace(e.currentTarget.x);
stage.removeChild(e.currentTarget.parent.parent);
}
function pixelateNodes(nodes:Array = null):void
{
for each (var node:Bitmap in nodes)
{
node.bitmapData.fillRect(node.bitmapData.rect, avgColor(node.bitmapData));
}
}
function avgColor(src:BitmapData):uint
{
var A:Number = 0;
var R:Number = 0;
var G:Number = 0;
var B:Number = 0;
var idx:Number = 0;
var px:Number;
for (var x:int = 0; x < src.width; x++)
{
for (var y:int = 0; y < src.height; y++)
{
px = src.getPixel32(x,y);
A += px >> 24 & 0xFF;
R += px >> 16 & 0xFF;
G += px >> 8 & 0xFF;
B += px & 0xFF;
idx++;
}
}
A /= idx;
R /= idx;
G /= idx;
B /= idx;
return A << 24 | R << 16 | G << 8 | B;
}
function createImgNodeGrid(rows:int = 1, cols:int = 1, pad:Number = 0):void
{
var w:Number = _img.width / rows;
var h:Number = _img.height / cols;
var numNodes:int = rows * cols;
_imgNodes = [];
var nodeCount:int = 0;
for (var i:int = 0; i < rows; i++)
{
for (var j:int = 0; j < cols; j++)
{
// get area of current image node
var sourceRect:Rectangle = new Rectangle(i * w, j * h, w, h);
// copy bitmap data of current image node
var tempBd:BitmapData = new BitmapData(w,h,true);
tempBd.copyPixels(_img.bitmapData, sourceRect, zero);
// place image node bitmap data into sprite
var imgNode:Bitmap = new Bitmap(tempBd);
imgNode.x = i * (w + pad);
imgNode.y = j * (h + pad);
// store each image node
//_imgNodes.push(imgNode);
_imgNodes[nodeCount++] = imgNode;
// add each image node to the stage
_tiledImg.addChild(imgNode);
_tiledImg.addEventListener(MouseEvent.CLICK,removeMC);
}
}
}
The problem you have is your are adding the event to the parent of the node(_tiledImg).
function createImgNodeGrid(rows:int = 1, cols:int = 1, pad:Number = 0):void
{
var w:Number = _img.width / rows;
var h:Number = _img.height / cols;
var numNodes:int = rows * cols;
_imgNodes = [];
var nodeCount:int = 0;
for (var i:int = 0; i < rows; i++)
{
for (var j:int = 0; j < cols; j++)
{
// get area of current image node
var sourceRect:Rectangle = new Rectangle(i * w, j * h, w, h);
// copy bitmap data of current image node
var tempBd:BitmapData = new BitmapData(w,h,true);
tempBd.copyPixels(_img.bitmapData, sourceRect, zero);
// place image node bitmap data into sprite
var imgNode:Bitmap = new Bitmap(tempBd);
imgNode.x = i * (w + pad);
imgNode.y = j * (h + pad);
// store each image node
//_imgNodes.push(imgNode);
_imgNodes[nodeCount++] = imgNode;
// you need a container since you can not attach event listeners to a BitMap
var sprite:Sprite = new Sprite()
sprite.mouseChildren = false;
sprite.addEventListener(MouseEvent.CLICK,removeMC);
sprite.addChild(imgNode);
// add each image node to the stage
_tiledImg.addChild(sprite);
// _tiledImg.addEventListener(MouseEvent.CLICK,removeMC);
}
}
}
function removeMC(e:MouseEvent)
{
var target:Sprite = event.currentTarget as Sprite;
target.parent.removeChild(target)
}
If I am following correctly, you are trying to remove an imgNode on MouseClick. If that is the case, you should change removeMC function to this:
function removeMC(e:MouseEvent)
{
//removes the movie clip
trace(e.target);
_tiledImg.removeChild(event.currentTarget);
}
Also, you shouldn't add the listener within the for loop, but instead add it outside of the for loops (since you are just adding the listener to _tiledImg and that doesn't change in the for loops).
A easy way to always remove a child from the right parent is to do as following
function removeMC(e:MouseEvent)
{
//removes the movie clip
var target:Sprite = event.currentTarget as Sprite;
target.parent.removeChild(target)
}

AS3 which item in an array has the lower value?

I’m trying to make a game like tower defence in AS3 and currently cant find solution to check which item in an array has the lower value of distance between enemy and turret, in order to choose which enemy to attack first.
I'm really stuck with this problem and asking for your help.
Here is a short code:
var enemyArray:Array = new Array();
var turretArray:Array = new Array();
addEventListener(Event.EnterFrame, loop);
// adding enemies
for(var i:int=0; i<3; i++){
var enemy:Enemy = new Enemy();
...
...
enemyArray.push(enemy);
addChild(enemy);
}
// adding turret
for(var t:int=0; t<2; t++){
var turret:Turret = new Turret();
...
...
turret.destinationX = 0;
turret.destinationY = 0;
turret.distance = 0;
turretArray.push(turret);
addChild(turret);
}
// loop
function loop(event:Event):void{
for(var j:int=enemyArray.length-1; j>=0; j--){
for(var k:int=turretArray.length-1; k>=0; k--){
// getting destination
turretArray[k].destinationX = turretArray[k].x - enemyArray[j].x;
turretArray[k].destinationY = turretArray[k].y - enemyArray[j].y;
// getting distance between turret and enemy
turretArray[k].distance = Math.sqrt(turretArray[k].destinationX*turretArray[k].destinationX+turretArray[k].destinationY*turretArray[k].destinationY);
// here i need to get min value from all turrets distance
}
}
}
Looks like you just need to be keeping track of the lowest value you've found as you go rather than overwriting it every time (if I've understood your code, correctly).
// loop
function loop(event:Event):void{
for(var k:int=turretArray.length-1; k>=0; k--)
{
turretArray[k].distance = -1;
for(var j:int=enemyArray.length-1; j>=0; j--)
{
var dx = turretArray[k].x - enemyArray[j].x;
var dy = turretArray[k].y - enemyArray[j].y;
var dist = Math.sqrt(dx * dx + dy * dy);
if(dist < turretArray[k].distance || turretArray[k].distance < 0)
{
turretArray[k].distance = dist;
turretArray[k].destinationX = dx;
turretArray[k].destinationY = dy;
}
}
}
}
Here, we store the initial distance value found in turretArray[k].distance, and only overwrite that if we find a lower one. We set it to -1 each time so we can tell if it's been set, yet, or not.
This is the equation you want:
http://www.mathopenref.com/coorddist.html
sqrt( (turret1X - turret2x)^2 + (turret1Y - turret2Y)^2 )

AS3: Random Point on Irregular Shape

I have a MovieClip holding an irregular shape such as this one:
I need to generate a random point on this shape.
I can use brute force by generating points within the bounding box and then hitTesting to see if they reside on the irregular shape. However, I'm sure there's a more efficient way to tackle this problem.
What is the most efficient way to generate a random point on an irregular shape?
You mentioned hitTest, but I assume you meant hitTestPoint().
If so, a function go get the random points you mention, would look a bit like this:
function getRandomPointsInClip(target:MovieClip,numPoints:int):Vector.<Point>{
var points:Vector.<Point> = new Vector.<Point>(numPoints,true);
var width:Number = target.width,height:Number = target.height;
for(var i:int = 0; i < numPoints ; i++){
var point:Point = new Point(target.x+Math.random() * width,target.y+Math.random() * height);
if(target.hitTestPoint(point.x,point.y,true)) points[i] = point;//is the random coord inside ?
else i = i-1;//nope, go back one step - > retry above until it is inside
}
return points;
}
The other I hinted at in my comment involves looping through non transparent pixels in a bitmap data of your object. This method would insure you don't have many duplicates, as opposed to the previous method, but it also means, you have less control over the number of points created and there's extra memory used for creating the bitmap. Still, for documentation purposes, here is the function:
function getGridPointsInClip(target:MovieClip,res:int,offset:Number = 3):Vector.<Point>{
var points:Vector.<Point> = new Vector.<Point>();
var x:int,y:int,alpha:int,w:int = int(target.width),h:int = int(target.height);
var bmd:BitmapData = new BitmapData(w,h,true,0x00FFFFFF);bmd.draw(target);
var pixels:Vector.<uint> = bmd.getVector(bmd.rect),numPixels:int = w*h;
for(var i:int = 0; i < numPixels; i+=res) {
x = i%bmd.width;
y = int(i/bmd.width);
alpha = pixels[i] >>> 24;
if(alpha > 0) points.push(new Point(x+random(-offset,offset),y+random(-offset,offset)));
}
return points;
}
function random(from:Number,to:Number):Number {
if (from >= to) return from;
var diff:Number = to - from;
return (Math.random()*diff) + from;
}
And here'a very basic test:
var pts:Vector.<Point> = getRandomPointsInClip(mc,300);
//var pts:Vector.<Point> = getGridPointsInClip(mc,100,4);
for(var i:int = 0 ; i < pts.length; i++) drawCircle(pts[i].x,pts[i].y,3,0x009900);
function getRandomPointsInClip(target:MovieClip,numPoints:int):Vector.<Point>{
var points:Vector.<Point> = new Vector.<Point>(numPoints,true);
var width:Number = target.width,height:Number = target.height;
for(var i:int = 0; i < numPoints ; i++){
var point:Point = new Point(target.x+Math.random() * width,target.y+Math.random() * height);
if(target.hitTestPoint(point.x,point.y,true)) points[i] = point;//is the random coord inside ?
else i = i-1;//nope, go back one step - > retry above until it is inside
}
return points;
}
function getGridPointsInClip(target:MovieClip,res:int,offset:Number = 3):Vector.<Point>{
var points:Vector.<Point> = new Vector.<Point>();
var x:int,y:int,alpha:int,w:int = int(target.width),h:int = int(target.height);
var bmd:BitmapData = new BitmapData(w,h,true,0x00FFFFFF);bmd.draw(target);
var pixels:Vector.<uint> = bmd.getVector(bmd.rect),numPixels:int = w*h;
for(var i:int = 0; i < numPixels; i+=res) {
x = i%bmd.width;
y = int(i/bmd.width);
alpha = pixels[i] >>> 24;
if(alpha > 0) points.push(new Point(x+random(-offset,offset),y+random(-offset,offset)));
}
return points;
}
function random(from:Number,to:Number):Number {
if (from >= to) return from;
var diff:Number = to - from;
return (Math.random()*diff) + from;
}
function drawCircle(x:Number,y:Number,radius:Number,color:uint):void{
graphics.lineStyle(1,color);
graphics.drawCircle(x-radius,y-radius,radius);
}
HTH
If you think of some non-blob like shapes, it's clear the check random pixel, try again method isn't really a good way. The bounding box area could be huge compared to the shape area.
What you could do to improve the effectiveness is getting a vector of the BitmapData of the shape. It should contain all pixels of the bounding box. Update - it would be nice now if we could pick a random point, and remove it from the vector if it isn't inside the shape. Unfortunately the vector only contains the pixels' colour, not the position which is implicit and only correct if we don't change the vector's length. Since we don't need to know the actual colour, we can omit all transparent pixels and store an inside pixel's position as it's value in the vector. This way we don't need to create a new object for each pixel of the shape (that would be quite expensive!).
var v:Vector.<uint> shapeBoxBitmap.getVector(shapeBoxBitmap.rect);
var pixelNum:int = v.length;
for(var i:uint = 0; i < pixelNum; i++) {
if( v[i] && 0xFF000000 == 0) { // transparent pixel, outside off shape
v.splice(i,1);
} else {
v[i] = i;
}
}
//get random point
var randomPixel:int = v[Math.floor(Math.random()*v.length)];
var point:Point = new Point(randomPixel%shapeBitmap.width,int(randomPixel/shapeBitmap.width));