Skip to content

Commit

Permalink
fixes #9 : Il y a maintenant un défenseur, qui cherche les snaffles p…
Browse files Browse the repository at this point in the history
…rès de mon but, et un attaquant, qui les envoie chez l'adversaire.

Le code est souple, MAIS il y a de gros problèmes de détermination des snaffles cibles : le calcul de distance des snaffles n'est pas convergeant.
  • Loading branch information
Riduidel committed Nov 29, 2016
1 parent 2972641 commit af3e522
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 20 deletions.
70 changes: 70 additions & 0 deletions libs/lib-2d/src/main/java/org/ndx/codingame/lib2d/Line.java
@@ -1,5 +1,6 @@
package org.ndx.codingame.lib2d;

import java.util.ArrayList;
import java.util.Collection;

import org.ndx.codingame.lib2d.base.AbstractPoint;
Expand Down Expand Up @@ -215,4 +216,73 @@ public Collection<ContinuousPoint> intersectionWith(Circle circle) {
public boolean intersectsWith(Circle circle) {
return circle.intersectsWith(this);
}


public Collection<ContinuousPoint> intersectionWith(Line line) {
Collection<ContinuousPoint> returned = new ArrayList<>();
double a = coeffs.a,
b = coeffs.b,
c = coeffs.c,
d = line.coeffs.a,
e = line.coeffs.b,
f = line.coeffs.c
;
if(e*a!=b*d) {
if(coeffs.isHorizontalLine()) {
/*
* a*x+b*y+c = 0
* d*x+e*y+f = 0
*
* a*x = -(b*y+c)
* d*x = -(e*y+f)
*
* x = -(b*y+c)/a
* x = -(e*y+f)/d
*
* (b*y+c)/a=(e*y+f)/d
*
* d*(b*y+c)=a*(e*y+f)
*
* d*b*y+d*c=a*e*y+a*f
*
* (d*b-a*e)*y=a*f-d*c
*
* y=(a*f-d*c)/(d*b-a*e)
*/
double y = (a*f-d*c)/(d*b-a*e);
if(!line.coeffs.isHorizontalLine()) {
returned.add(new ContinuousPoint(line.coeffs.computeXFromY(y), y));
}
} else {
/*
* a*x+b*y+c = 0
* d*x+e*y+f = 0
*
* b*y = -(a*x+c)
* e*y = -(d*x+f)
*
* y = -(a*x+c)/b
* y = -(d*x+f)/e
*
* (a*x+c)/b = (d*x+c)/e
* e*(a*x+c) = b*(d*x+f)
*
* e*a*x+e*c = b*d*x+b*c
* (e*a-b*d)*x = b*f-e*c
* x = (b*f-e*c)/(e*a-b*d)
*/
double x = (b*f-e*c)/(e*a-b*d);
if(line.coeffs.isVerticalLine()) {
returned.add(new ContinuousPoint(x, coeffs.computeYFromX(x)));
} else {
returned.add(new ContinuousPoint(x, line.coeffs.computeYFromX(x)));
}
}
}
return returned;
}

public boolean intersectsWith(Line line) {
return !intersectionWith(line).isEmpty();
}
}
25 changes: 25 additions & 0 deletions libs/lib-2d/src/main/java/org/ndx/codingame/lib2d/Segment.java
Expand Up @@ -44,4 +44,29 @@ public boolean contains(ContinuousPoint point) {
public Collection<ContinuousPoint> intersectionWith(Circle circle) {
return super.intersectionWith(circle).stream().filter(this::contains).collect(Collectors.toSet());
}

@Override
public Collection<ContinuousPoint> intersectionWith(Line line) {
return super.intersectionWith(line).stream()
.filter(p ->
p.x>=Math.min(first.x, second.x) && p.x<=Math.max(first.x, second.x)
&&
p.y>=Math.min(first.y, second.y) && p.y<=Math.max(first.y, second.y)
)
.collect(Collectors.toList());
}

public Collection<ContinuousPoint> intersectionWith(final Segment segment) {
return intersectionWith((Line) segment).stream()
.filter(p ->
p.x>=Math.min(segment.first.x, segment.second.x) && p.x<=Math.max(segment.first.x, segment.second.x)
&&
p.y>=Math.min(segment.first.y, segment.second.y) && p.y<=Math.max(segment.first.y, segment.second.y)
)
.collect(Collectors.toList());
}

public boolean intersectsWith(Segment segment) {
return !intersectionWith(segment).isEmpty();
}
}
Expand Up @@ -26,6 +26,8 @@ public class LineTest {
ContinuousPoint at_45_degrees = tested.pointAtAngle(first, 45, 1, PointBuilder.DEFAULT);
assertThat(at_45_degrees.x).isEqualTo(1/sqrt(2), within(Algebra.ZERO));
assertThat(at_45_degrees.y).isEqualTo(1+1/sqrt(2), within(Algebra.ZERO));
Line intersecting = from(0, 0).lineTo(2, 2);
assertThat(tested.intersectionWith(intersecting)).contains(at(1.0, 1));
}

@Test public void can_compute_infos_on_vertical_line() {
Expand All @@ -39,6 +41,8 @@ public class LineTest {
assertThat(tested.project(at(0.0, 0))).isEqualTo(at(1, 0));
assertThat(tested.symetricOf(at(0.0, 0))).isEqualTo(at(2, 0));
assertThat(tested.pointAtNTimes(2)).isEqualTo(at(1, 2));
Line intersecting = from(0, -1).lineTo(0, 1);
assertThat(tested.intersectionWith(intersecting)).isEmpty();
}

@Test public void can_compute_infos_on_vertical_reverse_line() {
Expand Down
Expand Up @@ -74,7 +74,7 @@ private static void chooseCaptain(Status status, List<Wizard> myTeam) {
} else {
if(status.getCaptain()==myCaptain.id) {
// we change captain only when really deserved
if(Math.abs(myCaptain.position.x-wingman.position.x)<Wizard.RADIUS) {
if(Math.abs(myCaptain.position.x-wingman.position.x)<Wizard.RADIUS*2) {
myCaptain.setAttacking(true);
}
}
Expand Down
Expand Up @@ -61,6 +61,10 @@ private <Type extends Entity> Map<ContinuousPoint, Type> getPositionsOf(Class<Ty
return (Map<ContinuousPoint, Type>) positionsOf.get(type);
}

public Collection<Snaffle> getSnaffles() {
return getCollectionOf(Snaffle.class);
}

public Snaffle findBestSnaffleFor(ContinuousPoint position) {
return getPositionsOf(Snaffle.class).get(position.findNearestDistance2(getPositionsOf(Snaffle.class).keySet()));
}
Expand All @@ -74,12 +78,7 @@ public Collection<Wizard> getAllWizards() {
}

public Snaffle findBestSnaffleFor(Wizard wizard) {
SortedMap<ContinuousPoint, Snaffle> snaffles = null;
if(wizard.isAttacking()) {
snaffles = getSnafflesSortedByDistanceTo(wizard.getAttackedGoal().pointAtNTimes(0.5));
} else {
snaffles = getSnafflesSortedByDistanceTo(wizard.getDefendedGoal().pointAtNTimes(0.5));
}
SortedMap<ContinuousPoint, Snaffle> snaffles = sortSnafflesFor(wizard);
SortedMap<ContinuousPoint, Snaffle> goodOnes = snaffles.headMap(wizard.position);
ContinuousPoint key = null;
if(goodOnes.isEmpty()) {
Expand All @@ -105,6 +104,16 @@ public Snaffle findBestSnaffleFor(Wizard wizard) {
return snaffles.get(key);
}

public SortedMap<ContinuousPoint, Snaffle> sortSnafflesFor(Wizard wizard) {
SortedMap<ContinuousPoint, Snaffle> snaffles = null;
if(wizard.isAttacking()) {
snaffles = getSnafflesSortedByDistanceTo(wizard.getAttackedGoal().pointAtNTimes(0.5));
} else {
snaffles = getSnafflesSortedByDistanceTo(wizard.getDefendedGoal().pointAtNTimes(0.5));
}
return snaffles;
}

private SortedMap<ContinuousPoint, Snaffle> getSnafflesSortedByDistanceTo(ContinuousPoint goalCenter) {
final Map<ContinuousPoint, Snaffle> snaffles = getPositionsOf(Snaffle.class);
SortedMap<ContinuousPoint, Snaffle> sorted = new TreeMap<>(new AbstractPoint.PositionByDistanceTo(goalCenter));
Expand Down
Expand Up @@ -27,17 +27,19 @@ public int compare(Entity o1, Entity o2) {
}

public final ContinuousPoint position;
public final ContinuousPoint speed;
public final Vector direction;
public final int id;
private Map<Double, Circle> circles = new TreeMap<>();
public Entity(int id, double x, double y, double vx, double vy) {
this.id = id;
position = new ContinuousPoint(x, y);
speed = new ContinuousPoint(vx, vy);
direction = Geometry.from(position).vectorOf(vx, vy);
}

public Circle getCircle() {
return getExtendedCircle(getRadius());
return getCircle(getRadius());
}

protected abstract double getRadius();
Expand All @@ -48,7 +50,7 @@ public boolean isBetween(Wizard wizard, Segment goal) {
return (int) Math.signum(position.getX()-wizard.position.getX())!=(int) Math.signum(position.getX()-goal.first.getX());
}

public Circle getExtendedCircle(Double radius) {
public Circle getCircle(Double radius) {
if(!circles.containsKey(radius)) {
circles.put(radius, Geometry.from(position).cirleOf(radius));
}
Expand Down
Expand Up @@ -79,7 +79,7 @@ private String throwInDirectionOf(List<Entity> entities, Segment goal) {
Iterator<Entity> entity = toAvoid.iterator();
while(entity.hasNext() && found) {
Entity tested = entity.next();
found = !obstacleFinder.intersectsWith(tested.getExtendedCircle(tested.getRadius()+Snaffle.RADIUS*2));
found = !obstacleFinder.intersectsWith(tested.getCircle(tested.getRadius()+Snaffle.RADIUS*2));
}
}
angle+=5;
Expand Down
@@ -0,0 +1,7 @@
package org.ndx.codingame.fantastic.spells;

public class AccioStatus extends SpellStatus {
public AccioStatus() {
super(6);
}
}
@@ -0,0 +1,10 @@
package org.ndx.codingame.fantastic.spells;

import org.ndx.codingame.fantastic.status.StatusElement;

public class ObliviateStatus extends SpellStatus implements StatusElement {

public ObliviateStatus() {
super(3);
}
}
@@ -1,19 +1,50 @@
package org.ndx.codingame.fantastic.spells;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import org.ndx.codingame.fantastic.entities.Bludger;
import org.ndx.codingame.fantastic.entities.Entities;
import org.ndx.codingame.fantastic.entities.Entity;
import org.ndx.codingame.fantastic.entities.Snaffle;
import org.ndx.codingame.fantastic.entities.Wizard;
import org.ndx.codingame.fantastic.status.MagicStatus;
import org.ndx.codingame.fantastic.status.Status;
import org.ndx.codingame.lib2d.Segment;
import org.ndx.codingame.lib2d.continuous.ContinuousPoint;

public enum Spell {
FLIPENDO(20) {
},
ACCIO(20) {
@Override
public SpellContext shouldCastThat(Status status, Wizard wizard, Entities entities) {
if(!wizard.isAttacking()) {
AccioStatus spellStatus = status.get(AccioStatus.class);
if(spellStatus==null) {
spellStatus = new AccioStatus();
status.set(spellStatus);
}
final Collection<Snaffle> snaffles = entities.sortSnafflesFor(wizard).values();
return snaffles.stream()
.filter(s -> {
Segment expected = new Segment(s.position,
new ContinuousPoint(s.position.x+s.speed.x*2, s.position.y+s.speed.y*2));
return expected.intersectsWith(wizard.getDefendedGoal());
})
.findFirst()
.map(s -> new SpellContext(s))
.orElse(SpellContext.NO);
}
return SpellContext.NO;
}

@Override
public String cast(Status status, SpellContext context) {
status.get(AccioStatus.class).applyOn(context.entity);
return super.cast(status, context);
}
},
PETRIFICUS(10) {
},
Expand All @@ -23,22 +54,35 @@ public enum Spell {
*/
@Override
public SpellContext shouldCastThat(Status status, Wizard wizard, Entities entities) {
ObliviateStatus obliviated = status.get(ObliviateStatus.class);
if(obliviated==null) {
obliviated = new ObliviateStatus();
status.set(obliviated);
}
for(Bludger b : entities.getBludgers()) {
List<Wizard> myTeamisNearBludger = entities.getAllWizards().stream()
.sorted(new Entity.ByDistanceTo(b))
.limit(2)
.filter(w -> w.teamId==status.getTeam())
.collect(Collectors.toList());
if(myTeamisNearBludger.size()==2) {
System.err.println(String.format("The two nearest wizards of Bludger %s are mine !", b));
if(myTeamisNearBludger.get(0).position.distance2To(b.position)<1000) {
System.err.println(String.format("And one is definitely too near"));
return new SpellContext(b);
if(!obliviated.isAppliedOn(b)) {
List<Wizard> myTeamisNearBludger = entities.getAllWizards().stream()
.sorted(new Entity.ByDistanceTo(b))
.limit(2)
.filter(w -> w.teamId==status.getTeam())
.collect(Collectors.toList());
if(myTeamisNearBludger.size()==2) {
System.err.println(String.format("The two nearest wizards of Bludger %s are mine !", b));
if(myTeamisNearBludger.get(0).position.distance2To(b.position)<1000) {
System.err.println(String.format("And one is definitely too near"));
return new SpellContext(b);
}
}
}
}
return SpellContext.NO;
}

@Override
public String cast(Status status, SpellContext context) {
status.get(ObliviateStatus.class).applyOn(context.entity);
return super.cast(status, context);
}
};

private int required;
Expand Down
@@ -0,0 +1,43 @@
package org.ndx.codingame.fantastic.spells;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.ndx.codingame.fantastic.entities.Entity;
import org.ndx.codingame.fantastic.status.StatusElement;

public class SpellStatus implements StatusElement {
private Map<Entity, Integer> entities = new HashMap<>();

private final int duration;

public SpellStatus(int duration) {
super();
this.duration = duration;
}

public void applyOn(Entity entity) {
entities.put(entity, duration);
}

public boolean isAppliedOn(Entity entity) {
return entities.containsKey(entity);
}

@Override
public void advanceOneTurn() {
List<Entity> list = new ArrayList<>(entities.keySet());
for (Entity entity : list) {
int durationOf = entities.get(entity);
if(durationOf>1) {
entities.put(entity, durationOf-1);
} else {
entities.remove(entity);
}
}
}


}

0 comments on commit af3e522

Please sign in to comment.