public void Maths_LineIntersection_CorrectPoint() { Point A = new Point(0, 5); Point B = new Point(10, 5); Point C = new Point(5, 0); Point D = new Point(5, 10); Point intersectionPoint = GameMaths.LineIntersection(A, B, C, D); Assert.AreEqual(intersectionPoint.x, 5); Assert.AreEqual(intersectionPoint.y, 5); }
public String Shoot(double polarAngle, double scanAngle, int energy, String attackCode) { string bigoutput = ""; if (this.Energy < energy) { Console.WriteLine("You do not have enough energy to shoot"); return(null); } this.Energy -= energy; // cordinates of the spaceship // cordinates of the spaceship double x = this.XCoordinate; double y = this.YCoordinate; int r = this.Capacity / 100; ArrayList list = new ArrayList(); int dist = (int)Math.Round(energy / Math.Abs(Math.Sin((Math.PI - scanAngle) / 2 * Math.PI / 180.0)), 0); double xA = Math.Round(x + r * Math.Cos(polarAngle * Math.PI / 180.0), 2); double yA = Math.Round(y + r * Math.Sin(polarAngle * Math.PI / 180.0), 2); // B and C are points of the scan extremes double xB = Math.Round(xA + dist * Math.Cos((polarAngle - scanAngle * 0.5) * Math.PI / 180.0), 2); double yB = Math.Round(yA + dist * Math.Sin((polarAngle - scanAngle * 0.5) * Math.PI / 180.0), 2); double xC = Math.Round(xA + dist * Math.Cos((polarAngle + scanAngle * 0.5) * Math.PI / 180.0), 2); double yC = Math.Round(yA + dist * Math.Sin((polarAngle + scanAngle * 0.5) * Math.PI / 180.0), 2); Point a, b, c; a = new Point(xA, yA); b = new Point(xB, yB); c = new Point(xC, yC); // get a list of the planets and spacehsips // check if they are inside the triangle ABC // or if the sides of the triangle cu the spaceships (as a circle) var dict = this.SpaceshipsInsideWithShadow(a, b, c); foreach (KeyValuePair <Spaceship, double> kvp in dict) { Console.WriteLine("You attacked " + ((Spaceship)(kvp.Key)).Name + " with ratio " + kvp.Value); } foreach (KeyValuePair <Spaceship, double> kvp in dict) { Console.WriteLine("You attacked " + ((Spaceship)(kvp.Key)).Name + " with ratio " + kvp.Value); Spaceship ship = kvp.Key; list.Add(ship); double x_coord = ship.XCoordinate; double y_coord = ship.YCoordinate; int other_radius = ship.Capacity / 100; double ratio; // ratio of the energy with which we are attacking // if the spaceship is inside the shoot array' if (GameMaths.IsInside(a, b, c, new Point(x_coord, y_coord))) { // B'C' is parallel to BC, we need the the slope and the other spaceship coordinates to find the equation and distance of B'C' double slope = (yB - yC) / (xB - xC); // find an equation of the type y = slope * x + b_ // aim: find out another point on B'C' double b_ = y_coord - slope * x_coord; double x_new_point = 1; // random, doesn't matter double y_new_point = slope * x_new_point + b_; Point b_prime = GameMaths.LineIntersection(a, b, new Point(x_coord, y_coord), new Point(x_new_point, y_new_point)); Point c_prime = GameMaths.LineIntersection(a, c, new Point(x_coord, y_coord), new Point(x_new_point, y_new_point)); double dist_b_c_prime = GameMaths.Distance2Points(b_prime, c_prime); // multiple cases depending on where the spaceship lies on the line if (GameMaths.DistanceToLine(GameMaths.LineEquation(a, b), x_coord, y_coord) < other_radius) // other spaceship is closer to AB, and extends outside { double distance_to_ab = GameMaths.DistanceToLine(GameMaths.LineEquation(a, b), x_coord, y_coord); double dist_to_add; double b_o_dist = distance_to_ab * Math.Sin(((Math.PI - scanAngle) / 2) * Math.PI / 180.0); if (dist_b_c_prime - b_o_dist >= other_radius) { dist_to_add = other_radius; } else { dist_to_add = dist_b_c_prime - b_o_dist; } ratio = (dist_to_add + b_o_dist) / dist_b_c_prime; } else if (GameMaths.DistanceToLine(GameMaths.LineEquation(a, c), x_coord, y_coord) < other_radius) { double distance_to_ac = GameMaths.DistanceToLine(GameMaths.LineEquation(a, c), x_coord, y_coord); double dist_to_add; double c_o_dist = distance_to_ac * Math.Sin(((Math.PI - scanAngle) / 2) * Math.PI / 180.0); if (dist_b_c_prime - c_o_dist >= other_radius) { dist_to_add = other_radius; } else { dist_to_add = dist_b_c_prime - c_o_dist; } ratio = (dist_to_add + c_o_dist) / dist_b_c_prime; } else { // spaceship is on the line equally distributed if (2 * other_radius < dist_b_c_prime) { ratio = (2 * other_radius) / dist_b_c_prime; } else { ratio = 1; } } ratio += dict[ship]; ratio /= 2; ratio *= (StringDistance.Compute(ship.Code, attackCode) / 16.0 + 1) / 2.0; bigoutput += this.Attack(ship, (int)(Math.Round((energy * ratio), 0))); } // if the other spacehsip center is outside of the shoot triangle else if (GameMaths.ContainsSpaceship(a, b, c, new Point(x_coord, y_coord), other_radius)) // && this.UserId != ship.UserId) { // B'C' is parallel to BC, we need the the slope and the other spaceship coordinates to find the equation and distance of B'C' double slope = (yB - yC) / (xB - xC); // find an equation of the type y = slope * x + b // aim: find out another point on B'C' double b_ = y_coord - slope * x_coord; double x_new_point = 1; // random, doesn't matter double y_new_point = slope * x_new_point + b_; Point b_prime = GameMaths.LineIntersection(a, b, new Point(x_coord, y_coord), new Point(x_new_point, y_new_point)); Point c_prime = GameMaths.LineIntersection(a, c, new Point(x_coord, y_coord), new Point(x_new_point, y_new_point)); double dist_b_c_prime = GameMaths.Distance2Points(b_prime, c_prime); ratio = (other_radius - GameMaths.SmallestDistance(a, b, c, new Point(x_coord, y_coord), other_radius)) / dist_b_c_prime; ratio += dict[ship]; ratio /= 2; ratio *= (StringDistance.Compute(ship.Code, attackCode) / 16.0 + 1) / 2.0; bigoutput += this.Attack(ship, (int)(Math.Round((energy * ratio), 0))); } } return(bigoutput); }
/* * * Helper function to compute the not shadowed spaceships after a scan or attack * * returns a dictionary mapping the spaceship to a real ratio (the relative portion of the spaceship that is visible in the scan, shoot * */ public Dictionary <Spaceship, double> SpaceshipsInsideWithShadow(Point a, Point b, Point c) { Spaceship[] sp = ElasticSearchCommands.searchAll().ToArray(); // double represents the shadows Dictionary <Spaceship, double> list = new Dictionary <Spaceship, double>(); var lines = new ArrayList(); lines.Add(new Line(b, c)); var x = this.XCoordinate; var y = this.YCoordinate; var dict = new SortedDictionary <double, Spaceship>(); for (int i = 0; i < sp.Length; i++) { double x_coord = sp[i].XCoordinate; double y_coord = sp[i].YCoordinate; if ((GameMaths.ContainsSpaceship(a, b, c, new Point(x_coord, y_coord), sp[i].Capacity / 100) || GameMaths.IsInside(a, b, c, new Point(x_coord, y_coord))) && this.Name != sp[i].Name) //&& sp[i].Name!="Owen") { double dist = GameMaths.Distance2Points(new Point(x, y), new Point(x_coord, y_coord)); while (dict.ContainsKey(dist)) { dist += 0.2; } dict.Add(dist, sp[i]); } } // find the true non-shadowed spaceships foreach (KeyValuePair <double, Spaceship> kvp in dict) { Spaceship ship = kvp.Value; Point p1, p2; // projections of the tangents to the circle onto BC line Point[] points = GameMaths.PointsOfTangentToCircle(a, new Point(ship.XCoordinate, ship.YCoordinate), ship.Capacity / 100); p1 = points[0]; p2 = points[1]; // get intersection between AP1 and BC (projection of A on BC through a point tangent to the circle/spaceship) points[0] = GameMaths.LineIntersection(a, points[0], b, c); points[1] = GameMaths.LineIntersection(a, points[1], b, c); Array.Sort(points); p1 = points[0]; p2 = points[1]; if (p1 == null || p2 == null) { continue; } int i = 0, j = 0; Boolean found1 = false; Boolean found2 = false; //find where the projections of the points on BC found would sit on the line BC // the points l1,l2 are looking for where p1 sits // the poiints n1, n2 are looking for where p2 sits // modifications in the intervals is necessary // delete all lines between p1 and p2 while (!(found1 && found2)) { // fetch the ith line if (!found1 && i < lines.Count) { Line line = (Line)lines[i]; Point l1 = line.a, l2 = line.b; if (p1.CompareTo(l1) > 0) { if (p1.CompareTo(l2) < 0) { // l1 < p1 < l2 // found the interval where p1 lies, it is not shadowed, so add the spacehsip found1 = true; // check if p1 and p2 are on the same interval if (p2.CompareTo(l1) > 0 && p2.CompareTo(l2) < 0) { list.Add(ship, GameMaths.Distance2Points(p1, p2)); found2 = true; Point aux = ((Line)lines[i]).b; ((Line)lines[i]).b = p1; lines.Insert(i + 1, new Line(p2, aux)); } else { list.Add(ship, GameMaths.Distance2Points(p1, ((Line)lines[i]).b)); ((Line)lines[i]).b = p1; j = i + 1; } } else { // p1 will sit in the next intervals i++; } } else { // p1 lies in an area outside of the lines array, which means it is shadowed // mark l1 as found, but don't add this spaceship to the scanned ones found1 = true; } } if (!found2 && j < lines.Count) { Line line = (Line)lines[j]; Point n1 = line.a, n2 = line.b; if (p2.CompareTo(n1) > 0) { if (p2.CompareTo(n2) < 0) { // n1 < p2 < n2 // found the interval where p2 lies found2 = true; if (list.ContainsKey(ship)) { list[ship] += GameMaths.Distance2Points(((Line)lines[j]).a, p2); } else { list.Add(ship, GameMaths.Distance2Points(((Line)lines[j]).a, p2)); } // restrict the interval for future lookups ((Line)lines[i]).a = p2; } else { // p2 will sit in the next intervals if (found1) { if (list.ContainsKey(ship)) { list[ship] += GameMaths.Distance2Points(((Line)lines[j]).a, ((Line)lines[j]).b); } else { list.Add(ship, GameMaths.Distance2Points(((Line)lines[j]).a, ((Line)lines[j]).b)); } lines.RemoveAt(j); // delete all intervals in between p1 and p2 } else { j++; } } } else { // p2 lies in an area outside of the lines array, which means it is shadowed // mark l1 as found, but don't add this spaceship to the scanned ones found2 = true; } } if (i >= lines.Count) { found1 = true; } if (j >= lines.Count) { found2 = true; } } if (list.ContainsKey(ship)) { list[ship] = list[ship] / GameMaths.Distance2Points(p1, p2); } } return(list); }