How to determine valid chess moves? [closed] - chess

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am trying to understand the algorithms behind determining valid moves for each chess piece. The specific issue I am having is determining when a piece cannot move past a certain point because it is being blocked by a piece of its own colour or is able to take a piece of the opposite colour but cannot move past that point.
The simple algorithms I have for each piece are:
Valid King move, if the piece moves from (X1, Y1) to (X2, Y2), the
move is valid if and only if |X2-X1|<=1 and |Y2-Y1|<=1.
Valid Bishop move, if the piece moves from (X1, Y1) to (X2, Y2), the
move is valid if and only if |X2-X1|=|Y2-Y1|.
Valid Rook move, if the piece moves from (X1, Y1) to (X2, Y2), the
move is valid if and only if X2=X1 or Y2=Y1.
Valid Queen move, a queen's move is valid if it is either a valid
bishop or rook move.
Valid Knight move, if the piece moves from (X1, Y1) to (X2, Y2), the
move is valid if and only if (|X2-X1|=1 and |Y2-Y1|=2) or (|X2-X1|=2
and |Y2-Y1|=1).
Valid Pawn move, if the piece moves from (X1, Y1) to (X2, Y2), the
move is valid if and only if X2=X1 and Y2-Y1=1 (only for a white
pawn).
Any advice would be appreciated.

You need to take the board state into account for that.
I think the common way to do it would be checking if each cell on the path is empty or not.
public enum PieceColor { Black, White }
public interface IBoard
{
bool IsEmpty(int x, int y);
PieceColor GetPieceColor(int x, int y);
}
IBoard board;
bool BishopCanMove(PieceColor bishopColor, int fromX, int fromY, int toX, int toY)
{
int pathLength = Mathf.Abs(toX - fromX);
if (pathLength != Mathf.Abs(toY - fromY)) return false; // Not diagonal
// Also validate if the coordinates are in the 0-7 range
// Check all cells before the target
for (int i = 1; i < pathLength; i++)
{
int x = fromX + i;
int y = fromY + i;
if(board.IsEmpty(x, y)) continue; // No obstacles here: keep going
else return false; // Obstacle found before reaching target: the move is invalid
}
// Check target cell
if (board.IsEmpty(toX, toY)) return true; // No piece: move is valid
// There's a piece here: the move is valid only if we can capture
return board.GetPieceColor(toX, toY) == bishopColor;
}
The IBoard interface is there just to show the point. You should have a board state exposing those informations in some way.

Related

Collision response for rectangles

I've been working on a physics engine for about a week now, being stuck for several days trying to work out how to resolve collisions.
My problem is that if there's a box stuck in the middle of 2 other boxes, or between a box and a wall, my application will get stuck in a while loop. It wont resolve the collisions.
This is my code (note: if collision is right side, it means that object A is colliding against object B with its right side. Distance is negative because the objects are inside eachother, and it's in x or y axis depending on side of collision. If you need more code, for example the collision class, which is simply a container of the 2 objects, i can provide that.):
edit: Code edited with new way of dealing with collisions:
//Move colliding objects so they don't collide anymore.
while (getCollidingAmount(objectVector)){
for (int i = 0; i < objectVector.size(); i++){
PhysicsObject* A = objectVector[i];
if (objectVector[i]->getPhysicsType() != PhysicsType::staticT && A->_collision.size() > 0){
Collision collision = A->_collision[A->getDeepestPenetrationCollisionIndex(A->_collision)];
PhysicsObject* B = collision.getObject();
switch (collision.getSide()){
case SideOfCollision::left:
case SideOfCollision::top:
//Opposite velocity
if (A->_saveVelocity.x < 0 && B->_saveVelocity.x > 0){
long double percentageOfVelocity = std::min(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x)) /
std::max(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x));
A->_position.x -= percentageOfVelocity*collision.getVectorPenetration().x;
A->_position.y -= percentageOfVelocity*collision.getVectorPenetration().y;
}
else{
A->_position.x -= collision.getVectorPenetration().x;
A->_position.y -= collision.getVectorPenetration().y;
}
break;
case SideOfCollision::right:
case SideOfCollision::bottom:
//Opposite velocity
if (A->_saveVelocity.x > 0 && B->_saveVelocity.x < 0){
long double percentageOfVelocity = 1 - std::min(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x)) /
std::max(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x));
A->_position.x -= percentageOfVelocity*collision.getVectorPenetration().x;
A->_position.y -= percentageOfVelocity*collision.getVectorPenetration().y;
}
else{
A->_position.x -= collision.getVectorPenetration().x;
A->_position.y -= collision.getVectorPenetration().y;
}
break;
}
updateCollisions(objectVector);
}
}
}
Update
Something wrong with my trigonometry in bottom and top collisions:
sf::Vector2<long double> Collision::getVectorPenetration() const{
long double x;
long double y;
long double velX = _object->getVelocity().x;
long double velY = _object->getVelocity().y;
long double angle = atan2(velY, velX);
if (_side == SideOfCollision::left || _side == SideOfCollision::right){
x = getDistance();
y = x * tan(angle);
return sf::Vector2<long double>(x, y);
}
else if (_side == SideOfCollision::top || _side == SideOfCollision::bottom){
y = getDistance();
x = y / tan(angle);
return sf::Vector2<long double>(x, y);
}
}
Update 2
Thanks to Aiman, i solved my issue. Updated my collisionResponse code aswell to match my new way of dealing with collisions. I'm having another issue now where gravity makes it so i can't move in X direction when touching another object. If anyone familiar with this issue wants to give any tips to solve it, i appreciate it :).
Update 3
So it seems gravity is not actually the problem since i can swap gravity to the x axis, and then be able to slide boxes along the walls. There seems to still be something wrong with the trigonometry.
I can think of many ways to approach the problem.
1-**The more complicated one is to **introduce friction. Here is how I'd implement it, though this is untested and there is a chance I missed something in my train of thought.
Every shape gets a friction constant, and according to those your objects slide when they collide.
First, you need to get the angle that is perpendicular to your surface. To do this, you just get the arctan of the the surface's normal slope. The normal is simply -1/m, where m is the slope of your surface (which you is the ratio/quotient of how much the surface extends in y to/by how much it extends in x). Let's call this angle sNormal for "surface normal". We may also need sAngle-"surface angle" for later (you find that by arctan(m)). There remains some ambiguity in the angle that has to do with whether you're talking about the 'front' or the 'back' of the surface. You'll have to deal with that manually.
Next, you need the angle of the trajectory your object flies in, which you already know how to find (atan2(y,x)). We'll call this angle oAngle for "object's surface angle". Next, you calculate deltaAngle = sNormal - oAngle. This angle represents how much momentum was not blocked completely by the surface. A deltaAngle of 0 means all momentum is gone, and a value of PI/2 or 90 means the 2 surfaces are in parallel touching each other not blocking any momentum at all. Anything in between, we interpolate:
newSpeed = objectSpeed * deltaAngle/(PI/2);
newVelocity.x = cos(sAngle) * objectSpeed;
newVelocity.y = sin(sAngle) * objectSpeed;
Now this assumes 0 friction. If we let a friction of 1 be the maximum friction which doesn't allow the object to "slide", we modify the newSpeed before we apply the newVelocity values, like so: newSpeed *= (1-friction);.
And there we have it! Just give your platform a friction value of less than 1 and your box will be able to slide. If you're dealing with upright boxes, then the surface angle is PI for top wall, 0 for the bottom, PI/2 for the right and -PI/2 for the left wall.
2-The simpler option is to subtract gravity from the object's y-velocity in the solver's calculation.

I need an equation for equal movement along an ellipse

i am programing something like planets moving around the Sun, and to move planets i am using a function
CGPointMake(object.center.x + 1, sqrt(75*75*150*150 - 75*75*(object.center.x - 300)*(object.center.x - 300))/150 + 150)
using eliptic equation where a = 150, b = 75, p = 300, q = 150, but when object closes to x = around 450 its speed rises, i guess that is because of pitagora because the path its passes is c = sqrt((x-x0)^2*(y-y0)^2)
i notice my c is always around 0.5, but when it gets on the end of x domain it rises up to 0.8 so i need either a programatic or mathematical solution to make object move at same speed around an eliptic curve
Thank you!
If you want the real thing
then the planets closer to the primary focus point (center of mass of stellar system ... very close to star) are moving faster so use Kepler's equation here: C++ implementation of mine. Do not forget to check out all the sub-links in that answer you can find there everything you need.
If you want constant speed instead
Then use parametric ellipse equation
x(a)=x0+rx*cos(a)
y(a)=y0+ry*sin(a)
where a is angle <0,2.0*PI> (x0,y0) is the ellipse center and (rx,ry) are the ellipse semi axises (radii).
if a is incremented with constant speed then the area increase is constant so the a is the mean circular angle not the visual on ellipse !!! For more info look here:
Issue with ellipse angle calculation and point calculation
[edit1] as MartinR pointed out the speed is not constant
so here is approximation with his formula for speed. Ellipse is axis aligned defined by x0,y0,rx,ry (rx>=ry) the perimeter aproximation l:
h=(rx-ry)/(rx+ry); h*=3.0*h; l=M_PI*(rx+ry)*(1.0+(h/(10.0+sqrt(4.0-h))));
if you want to have n chunks of equal sized steps along the perimeter then
l/=n;
initial computations:
double x0,y0,rx,ry,n,l,h;
x0=Form1->ClientWidth>>1; // center is centered on form
y0=Form1->ClientHeight>>1;
rx=200; // semiaxises rx>=ry !!!
ry=75;
n=40.0; // number of chunks per ellipse (1/speed)
//l=2.0*M_PI*sqrt(0.5*((rx*rx)+(ry*ry))); // not accurate enough
h=(rx-ry)/(rx+ry); h*=3.0*h; l=M_PI*(rx+ry)*(1.0+(h/(10.0+sqrt(4.0-h)))); // this is more precise
l/=n; // single step size in units,pixels,or whatever
first the slow bruteforce attack (black):
int i;
double a,da,x,y,xx,yy,ll;
a=0.0;
x=x0+rx*cos(a);
y=y0+ry*sin(a);
for (i=n;i>0;i--)
{
xx=x; yy=y;
for (da=a;;)
{
a+=0.001;
x=x0+rx*cos(a);
y=y0+ry*sin(a);
ll=sqrt(((xx-x)*(xx-x))+((yy-y)*(yy-y)));
if (ll>=l) break;
} da=a-da;
scr->MoveTo(5.0+50.0*a,5.0);
scr->LineTo(5.0+50.0*a,5.0+300.0*da);
scr->MoveTo(x0,y0);
scr->LineTo(xx,yy);
scr->LineTo(x ,y );
ll=sqrt(((xx-x)*(xx-x))+((yy-y)*(yy-y)));
scr->TextOutA(0.5*(x+xx)+20.0*cos(a),0.5*(y+yy)+20.0*sin(a),floor(ll));
}
Now the approximation (Blue):
a=0.0; da=0;
x=x0+rx*cos(a);
y=y0+ry*sin(a);
for (i=n;i>0;i--)
{
scr->MoveTo(5.0+50.0*a,5.0+300.0*da);
xx=rx*sin(a);
yy=ry*cos(a);
da=l/sqrt((xx*xx)+(yy*yy)); a+=da;
scr->LineTo(5.0+50.0*a,5.0+300.0*da);
xx=x; yy=y;
x=x0+rx*cos(a);
y=y0+ry*sin(a);
scr->MoveTo(x0,y0);
scr->LineTo(xx,yy);
scr->LineTo(x ,y );
ll=sqrt(((xx-x)*(xx-x))+((yy-y)*(yy-y)));
scr->TextOutA(0.5*(x+xx)+40.0*cos(a),0.5*(y+yy)+40.0*sin(a),floor(ll));
}
This is clean ellipse step (no debug draws)
a=???; // some initial angle
// point on ellipse
x=x0+rx*cos(a);
y=y0+ry*sin(a);
// next angle by almost constant speed
xx=rx*sin(a);
yy=ry*cos(a);
da=l/sqrt((xx*xx)+(yy*yy)); a+=da;
// next point on ellipse ...
x=x0+rx*cos(a);
y=y0+ry*sin(a);
Here the output of comparison bruteforce and approximation:
[edit2] little precision boost
a,da=???; // some initial angle and step (last)
x=x0+rx*cos(a);
y=y0+ry*sin(a);
// next angle by almost constant speed
xx=rx*sin(a+0.5*da); // use half step angle for aproximation ....
yy=ry*cos(a+0.5*da);
da=l/sqrt((xx*xx)+(yy*yy)); a+=da;
// next point on ellipse ...
x=x0+rx*cos(a);
y=y0+ry*sin(a);
the half step angle in approximation lead to much closer result to bruteforce attack
Hmm...
You could fake something like this very easily with SpriteKit. N.B. your entire app doesn't have to use SpriteKit. You can fairly easily put an SKView into a non-SpriteKit app.
Anyway...
Create your planet...
SKSpritNode *planet = [SKSpritNode spriteNodeWithImageNamed:#"mars"];
[solarSystemView addChild:planet];
Create your elliptical path...
UIBezierPath *ellipse = [UIBezierPath bezierPathWithOvalInRect:/*your rect*/]; //or create it any other way.
Create an action...
SKAction *singleOrbit = [SKAction followPath:ellipse.CGPath speed:10];
SKAction *orbit = [SKAction repeatActionForever:singleOrbit];
Run the action...
[planet runAction:orbit];

Center coordinate of a coordinate region

I have 2 coordinates, a top left and a bottom right. I would like to find the center point of the region. Right now I have the following method to calculate it. The center point is way off. When I call the method with
[self.map setRegionTopLeft: CLLocationCoordinate2DMake(21.57524, -157.984514)
bottomRight: CLLocationCoordinate2DMake(21.309766, -157.80766)
animated:YES];
It should center on the island of Oahu in the State of Hawaii, USA. I found this math here so I'm not sure whats going on.
Code A - This is way off. It's not putting me anywhere near the island.
- (CLLocationCoordinate2D)centerPointFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight
{
CLLocationCoordinate2D centerPoint;
centerPoint.longitude = (topLeft.longitude + bottomRight.longitude) / 2;
if (fabs(bottomRight.longitude - topLeft.longitude) > 180)
{
if (centerPoint.longitude > 0)
{
centerPoint.longitude = centerPoint.longitude + 180;
} else {
centerPoint.longitude = centerPoint.longitude - 180;
}
}
centerPoint.latitude = asin((sin(bottomRight.latitude) + sin(topLeft.latitude))/2);
return centerPoint;
}
I've also, originally, tried this method. Its just what popped in my head when I thought center of a rectangle. If gets me a lot closer to what the center should be - I can see the island - but its still off.
Code B - Original code I tried. This is much closer to what I expected but still off.
- (CLLocationCoordinate2D)centerPointFromRegionTopLeft:(CLLocationCoordinate2D)topLeft
bottomRight:(CLLocationCoordinate2D)bottomRight
{
CLLocationCoordinate2D centerPoint;
centerPoint.latitude = ((topLeft.latitude + bottomRight.latitude) / 2);
centerPoint.longitude = ((topLeft.longitude + bottomRight.longitude) / 2);
return centerPoint;
}
So given a coordinate region (topLeft, bottomRight) how to I get the center coordinate? The idea is I should be able to give any 2 coordinates and get the center coordinate.
Update* Code B works. I had my topLeft and bottomRight wrong. Code A puts me very south and a little east of where it should.
You need the middle of L(longitude) and B(latitude). For B the problem is around the pole, but as you set it, you simply can't "put the cap on the pole", so, really no problems here.
Middle(B1,B2)=(B1+B2)/2.
But L is much worse. L can jump from -179 to -179. And another problem : the middle of (-179,+179) should be 180, and middle(-1,+1) should be 0. I.e., we should always choose middle along shorter way between opposite points, not around the whole Earth.
We should move the zero meridian so, that the difference between L1,L2 will be smaller, than 180, make normal middle of them and then return the zero meridian back.
Let L1
if L2-L1>180, let's choose L2 for the new zero meridian.
shift=L2
L2=L2-shift, L1=L1+360-shift. Now, notice, L1-L2<180!
LmShifted=(L1+L2)/2
Lm=LmShifted+shift.
If we'll take these formulas together, we'll have:
Lm=(L1-L2+360)/2+L2
if L2-L1<180, Lm=(L1+L2)/2
The problem is when L2-L1=180. In this case you have two opposite meridians, dividing the Earth in two, and for the role of the middle both "quarter" meridian, to the right and to the left, fit. It's up to you, what to choose.

How can i calculate the opposite point if i have a point and a center? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I have a center point and i know point 1, now i want to calculate point 2 which is in the opposite direction, but have another lenght. Also i know the lenght from the center point to point 2, but it is not on the same vector as Point 1 to center is. Imagine the dotted line has another angle as the image shows.
Point 2 should be on the same vector as is Point 1. In other words, Point 1 to Point 2 should be a straight line which pass trough the center.
I hope some one can help me.
Thank you very much in advance.
This will work:
Code assumes collinear points, in a 2D plane, defined as Cartesian coordinates
In Java:
class GoGo {
public static void main (String[] args) {
double[] center = new double[] { 4.0,3.0 };
double[] point1 = new double[] { 8.0,4.0 };
double[] point2 = getPoint2(center,point1,4.0);
System.out.print("X: " + point2[0] + " Y: " +point2[1]);
}
public static double[] getPoint2(double[] center, double[] point1, double distance) {
//assumes Points = double[2] { xValue, yValue }
double[] point2 = new double[2];
double changeInX = point1[0] - center[0]; // get delta x
double changeInY = point1[1] - center[1]; // get delta y
double distanceCto1 = Math.pow( // get distance Center to point1
(Math.pow(changeInX,2.0) + Math.pow(changeInY,2.0))
,0.5);
double distanceRatio = distance/distanceCto1;// ratio between distances
double xValue = distanceRatio * changeInX; // proportional change in x
double yValue = distanceRatio * changeInY; // proportional change in y
point2[0] = center[0] - xValue; // normalize from center
point2[1] = center[0] - yValue; // normalize from center
return point2; // and return
}
}
I wrote this in Java because it is my preferred language and you didn't specify a language you needed the answer in . If you have a different language preference, I can attempt to port the code to your preferred language (assuming I know it).
CODE GIVEN BY: Marcello Stanisci
In Objective C:
- (CGPoint) getOppositePointAtCenter2:(CGPoint)center fromPoint:(CGPoint)point oppositeDistance:(double)oppositeDistance {
CGPoint vector = CGPointMake(point.x - center.x, point.y - center.y);
double distanceCenterToPoint1 = pow(pow(vector.x, 2) + pow(vector.y, 2), 0.5);
double distanceRatio = oppositeDistance / distanceCenterToPoint1;
double xValue = distanceRatio * vector.x;
double yValue = distanceRatio * vector.y;
return CGPointMake(center.x - xValue, center.y - yValue);
}

Graphics - How may I know if a line is visible onscreen taking account its width

I'm doing some core graphics, and I wonder how I may know if a line will have some parts of it visible on screen.
Let's take a line going from x-5, y3 to x2, y-7. If it's 1 pixel wide, nothing will be displayed onscreen. If it's 15 pixels wide, some parts of it will be displayed.
How may I check that ?
If you have lines only you can work with the function below. Otherwise I would recommend to go through the whole length of your line and create in a specific distance an square of the line width size and check if it is inside your view. An example: If you have a line from x0y0 to x7y0. You would go to x1y0 create a square of your draw line size (in this example 15) and see if this overlaps your screen. Next go to x2y0 and so on. The advantage is it will even work with bezier curves (a little wiki information how bezier work will be enough).
// EDIT: (made a little bezier check function, should work, but haven't tested) And I don't think its more performance efficient to check each line before drawing:
- (void)bezierWithStart:(CGPoint)start cp1:(CGPoint)cp1 cp2:(CGPoint)cp2 end:(CGPoint)end withWidth:(float)wid {
for (float i = 0.0; i<=1.0; i+=0.05) { // how many steps
CGPoint chk1 = CGPointMake(start.x+((cp1.x-start.x)*i), start.y+((cp1.y-start.y)*i));
CGPoint chk2 = CGPointMake(cp1.x+((cp2.x-cp1.x)*i), cp1.y+((cp2.y-cp1.y)*i));
CGPoint chk3 = CGPointMake(cp2.x+((end.x-cp2.x)*i), cp2.y+((end.y-cp2.y)*i));
CGPoint chk4 = CGPointMake(chk1.x+((chk2.x-chk1.x)*i), chk1.y+((chk2.y-chk1.y)*i));
CGPoint chk5 = CGPointMake(chk2.x+((chk3.x-chk2.x)*i), chk2.y+((chk3.y-chk2.y)*i));
CGPoint cPoint = CGPointMake(chk4.x+((chk5.x-chk4.x)*i), chk4.y+((chk5.y-chk4.y)*i));
CGRect drawLine = CGRectMake(cPoint.x-(wid/2), cPoint.y-(wid/2), wid, wid);
// check if rect is in view
}
}
// EDIT end
But now lets go to the simple line function:
- (void)testLine:(CGPoint)fp toSecond:(CGPoint)sp withWidth:(float)wid {
float xratio = sp.x - fp.x;
float yratio = sp.y - fp.y;
double a = sqrt(((wid*wid)*(xratio*xratio))/((yratio*yratio)+(xratio*xratio)));
a/=2; // because line width goes in both direction
double b = (yratio/xratio)*a;
if ((xratio<0.0 && yratio<0.0) || (xratio>0.0 && yratio>0.0))b*=-1;
CGPoint diffFrom1 = CGPointMake(fp.x+a, fp.y+b);
CGPoint diffTo1 = CGPointMake(sp.x+a, sp.y+b);
a*=-1;
b*=-1;
CGPoint diffFrom2 = CGPointMake(fp.x+a, fp.y+b);
CGPoint diffTo2 = CGPointMake(sp.x+a, sp.y+b);
}
you will get 4 points. 2 lines, one above and one below the original line, half the size of your draw width. The calculation behind is to get the draw direction and for that the difference to the original line. But for those who want to get into it, heres my pre calculation: