클레어 보이
AbleDogs에 맞도록 업데이트 된 코드
우후! 넷캣을 이겼다! 이 미래 예측 팩을 만들기 위해 약간의 수정으로 기존 코드 (신용 정보를 Geobits!)를 확장했습니다. 먹이가 어디로 움직일지를 아는 포식자를 능가하는 것은 없습니다!
내가 한 두 가지 테스트에서 내 팩은 항상 Netcats에 대해 이겼습니다. 그러나 근처에 다른 먹이가 너무 많으면 예측이 실패하므로 다른 팩이 없으면 성능이 좋지 않습니다.
아마도 나는 처음 몇 천 번의 턴 동안 먹이 수를 줄이기 위해 CivilizedBeasts의 트릭을 포함시킬 수 있습니다.
5.21 분 후에 완료
Clairvoyant (1) : 9270 턴 : 100 점
EcoCamel.pl (3) : 턴 8118 : 점수 80
넷캣 (0) : 턴 6111 : 64 점
RubyVultures.rb (5) : 턴 4249 : 점수 51
RubySpiders.rb (4) : Turn 3495 : Score 40
CivilizedBeasts (2) : 3176 턴 : 32 점
체이서 팩 (6) : Turn 2492 : Score 25
내 팩 이름에서 내가 사용하는 전략 = D를 알아야합니다.
편집 :
- 같은 먹이를 쫓지 않도록 업데이트 된 팩 관리 시스템
- 먹이의 수가 적을 때 방황 과정을 개선하십시오 (이는 승리에 중요합니다!).
이전 버전이 막 났을 때 특별한 경우를 개선하십시오.
- 포식자 감지 알고리즘의 버그를 수정했습니다 (현재는 정확합니다).
- 먹이
flock[ALIGN]
요소 포함
- 음식이 부족한 경우 먹이 하나를 애완 동물로 유지하십시오
- 팩이 먹이를 모을 수있는 굴을 만듭니다
- 근처의 포식자를 유혹하여 우리의 먹이를 쫓아 가십시오.
나는 각 팩이 먹는 먹이의 수를 세었습니다. 결과는 다음과 같습니다.
Clairvoyant (1)는 9270 회전 (0.099 먹이 / 턴)으로 916 먹이를 소비했습니다.
EcoCamel.pl (3)은 8118 턴에서 73 마리의 먹이를 소비했습니다 (0.009 마리의 먹이 / 턴)
Netcats (0)는 6111 턴 (0.092 프레이 / 턴)에서 563 개의 먹이를 소비했습니다.
RubyVultures.rb (5)는 4249 번의 턴에서 77 마리의 먹이를 소비했습니다 (0.018 마리의 먹이 / 턴)
RubySpiders.rb (4)는 3495 턴에서 293 마리의 먹이를 소비했습니다 (0.084 마리의 먹이 / 턴)
CivilizedBeasts (2)는 3176 턴에 10 마리의 먹이를 소비했습니다 (0.003 마리의 먹이 / 턴)
ChaserPack (6)은 2492 번의 회전에서 43 개의 먹이를 소비했습니다 (0.017 개의 먹이 / 턴)
내 팩은 매우 공격적이며 RubySpiders와 마찬가지로 Netcats의 먹이를 훔쳐서 얻은 916 카운트의 대부분입니다.
EcoCamel의 중앙 낙타로 인해 CivilizedBeasts가 유실되었습니다.
그리고 EcoCamel (배고픔 500)은 매우 효율적이며, 끝까지 살아남기에 충분합니다.
또한이 업데이트 된 Clairvoyant를 통해 게임은 거의 10,000 회전에 도달하지 못합니다.
코드:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.TreeSet;
public class Clairvoyant extends GenericPack {
private static final double MAX_SPEED = 6.1;
private TreeSet<Animal> foods = new TreeSet<Animal>(new AnimalComparator());
private TreeSet<Animal> predators = new TreeSet<Animal>(new AnimalComparator());
private XY abattoirCorner;
private double abattoirRadius = 100;
private MyMember[] myMembers = new MyMember[100];
public class AnimalComparator implements Comparator<Animal>{
@Override
public int compare(Animal arg0, Animal arg1) {
if(arg0.x < arg1.x){
return -1;
} else if (arg0.x > arg1.x){
return 1;
} else {
if(arg0.y < arg1.y){
return -1;
} else if(arg0.y > arg1.y){
return 1;
} else {
return 0;
}
}
}
}
public class MyMember extends Member{
public XY target;
public XY herdPos;
public double herdRadius;
public boolean mayEat;
public XY pos;
public ArrayList<MyAnimal> closestPreys;
public boolean outdated;
public MyMember(int id) {
super(id);
this.pos = new XY(x, y);
closestPreys = new ArrayList<MyAnimal>();
mayEat = true;
outdated = true;
}
public MyMember(Member member){
super(member.id);
this.pos = new XY(x, y);
closestPreys = new ArrayList<MyAnimal>();
mayEat = true;
outdated = true;
}
public MyMember(Member member, Animal target){
super(member.id);
this.target = new XY(target.x, target.y);
this.pos = new XY(x, y);
closestPreys = new ArrayList<MyAnimal>();
mayEat = true;
outdated = true;
}
public void reset(Member me){
x = me.x;
y = me.y;
pos = new XY(x, y);
closestPreys.clear();
mayEat = true;
outdated = true;
}
}
public class MyAnimal extends Animal{
public ArrayList<MyMember> chasers;
public XY pos;
public boolean resolved;
public MyAnimal(double x, double y){
super(x, y);
pos = new XY(x, y);
chasers = new ArrayList<MyMember>();
resolved = false;
}
public MyAnimal(Animal ani){
super(ani.x, ani.y);
pos = new XY(x, y);
chasers = new ArrayList<MyMember>();
resolved = false;
}
}
public static void main(String[] args){
new Clairvoyant().run();
}
public Clairvoyant(){
for(int i=0; i<100; i++){
nextIdx[i] = 0;
}
int cornerIdx = (int)Math.floor(Math.random()*4);
switch (cornerIdx){
case 0: abattoirCorner = new XY(0,0); break;
case 1: abattoirCorner = new XY(500,0); break;
case 2: abattoirCorner = new XY(500,500); break;
case 3: abattoirCorner = new XY(0,500); break;
}
}
@Override
public void respond(){
updateData();
goToTarget();
}
private void updateData(){
for(int i=0; i<100; i++){
if(myMembers[i]!=null){
myMembers[i].pos = null;
}
}
foods.clear();
predators.clear();
for(Member me: members){
foods.addAll(me.foods);
predators.addAll(me.others);
predators.add(new Animal(me.x, me.y));
if(myMembers[me.id] != null){
myMembers[me.id].reset(me);
} else {
myMembers[me.id] = new MyMember(me);
}
}
for(int i=0; i<100; i++){
if(myMembers[i]!=null && myMembers[i].pos == null){
myMembers[i] = null;
}
}
TreeSet<MyAnimal> closestPreys = new TreeSet<MyAnimal>(new AnimalComparator());
for(int i=0; i<100; i++){
if (myMembers[i]==null) continue;
MyMember me = myMembers[i];
ArrayList<Animal> animals = findClosest(foods, me.pos, members.size());
boolean first = true;
for(Animal ani: animals){
MyAnimal myAni = new MyAnimal(ani);
if(closestPreys.contains(ani)){
myAni = closestPreys.ceiling(myAni);
} else {
closestPreys.add(myAni);
}
if(first){
myAni.chasers.add(me);
first = false;
}
me.closestPreys.add(myAni);
}
}
performMatching();
for(int i=0; i<100; i++){
if (myMembers[i] == null) continue;
MyMember me = myMembers[i];
if(!me.outdated) continue;
if(me.closestPreys.size() == 0) continue;
MyAnimal closestPrey = me.closestPreys.get(0);
if(closestPrey.resolved) continue;
if(closestPrey.chasers.size() > 1){
MyMember hungriest = me;
MyMember closest = me;
for(MyMember otherMe: closestPrey.chasers){
if(sqDist(closestPrey.pos, otherMe) < sqDist(closestPrey.pos, closest)){
closest = otherMe;
}
if(otherMe.hunger < hungriest.hunger){
hungriest = otherMe;
}
}
if(hungriest.hunger > 200){ // Nobody's critically hungry, the closest takes the prey
closest.target = closestPrey.pos;
closest.mayEat = true;
closest.herdPos = abattoirCorner;
closest.herdRadius = abattoirRadius;
closest.outdated = false;
} else {
if(hungriest == closest){
closest.target = closestPrey.pos;
closest.mayEat = true;
closest.herdPos = abattoirCorner;
closest.herdRadius = abattoirRadius;
closest.outdated = false;
} else {
closest.target = closestPrey.pos;
closest.mayEat = false;
closest.herdPos = hungriest.pos;
closest.herdRadius = 0;
closest.outdated = false;
hungriest.target = closestPrey.pos;
hungriest.mayEat = true;
hungriest.herdPos = abattoirCorner;
hungriest.herdRadius = 10;
hungriest.outdated = false;
}
}
closestPrey.resolved = true;
} else {
me.target = closestPrey.pos;
me.herdPos = abattoirCorner;
me.herdRadius = abattoirRadius;
me.mayEat = true;
me.outdated = false;
}
}
for(int i=0; i<100; i++){
if (myMembers[i] == null) continue;
MyMember me = myMembers[i];
if(me.outdated){
me.target = null;
me.outdated = false;
}
}
}
private void goToTarget(){
for(Member me: members){
MyMember mem = myMembers[me.id];
if(mem.target == null){
wander(me, 2*(me.id%2)-1);
continue;
} else {
nextIdx[me.id] = 0;
XY[] nearestHostile = new XY[100];
for(Animal other: me.others){
XY otherPos = new XY(other.x, other.y);
boolean isMember = false;
for(Member otherMember: members){
if(other.x==otherMember.x && other.y==otherMember.y){
isMember = true;
break;
}
}
if(!isMember){
if(nearestHostile[me.id] == null || XY.sqDistance(mem.pos, otherPos) < XY.sqDistance(mem.pos, nearestHostile[me.id])){
nearestHostile[me.id] = otherPos;
}
}
}
// Go towards the target by predicting its next position
XY target = predictNextPos(mem.target, me);
me.dx = (target.x - me.x);
me.dy = (target.y - me.y);
// Try to herd the target to our abattoir if this member is not too hungry
// and if there is no other hostile predator who is closer to the target than us
// This will make the other hostile predator to keep targeting this target, while
// it is certain that we will get the target.
// This is a win situation for us, since it will make the other predator wasting his turn.
if((me.hunger <= 200 && XY.sqDistance(mem.target, mem.pos) > 400) || me.hunger <= 50 ||
(nearestHostile[me.id] != null && Math.sqrt(XY.sqDistance(mem.target, nearestHostile[me.id])) < Math.sqrt(XY.sqDistance(mem.target, mem.pos)))){
continue;
}
// Don't eat if not threatened nor hungry
if(me.hunger > 50 && (nearestHostile[me.id] == null ||
Math.sqrt(XY.sqDistance(mem.target, nearestHostile[me.id])) > Math.sqrt(XY.sqDistance(mem.target, mem.pos)) + 6)){
mem.mayEat = false;
}
// Herd to abattoir corner
double distFromHerd = Math.sqrt(XY.sqDistance(target, mem.herdPos));
XY oppositeAbattoirCorner = new XY(500-abattoirCorner.x, 500-abattoirCorner.y);
double distFromOpposite = Math.sqrt(XY.sqDistance(target, oppositeAbattoirCorner));
if((me.dx*me.dx+me.dy*me.dy > 64 && distFromHerd > mem.herdRadius && distFromOpposite > abattoirRadius)
|| (preyCount < 5*predCount)){
double herdDistance = 4*(distFromHerd-mem.herdRadius)/(Island.SIZE-mem.herdRadius);
if(!mem.mayEat) herdDistance = 4;
XY gradient = target.minus(abattoirCorner);
me.dx += gradient.x*herdDistance/distFromHerd;
me.dy += gradient.y*herdDistance/distFromHerd;
}
}
}
}
private void performMatching(){
for(int i=0; i<100; i++){
if (myMembers[i] == null) continue;
MyMember me = myMembers[i];
if(me.closestPreys.size()==0) continue;
MyAnimal closestPrey = me.closestPreys.get(0);
if(closestPrey.chasers.size() > 1){
resolveConflict(closestPrey);
}
}
}
private void resolveConflict(MyAnimal prey){
ArrayList<MyMember> chasers = prey.chasers;
MyMember winner = null;
double closestDist = Double.MAX_VALUE;
for(MyMember me: chasers){
if(sqDist(prey.pos, me) < closestDist){
closestDist = sqDist(prey.pos, me);
winner = me;
}
}
for(int i=chasers.size()-1; i>=0; i--){
MyMember me = chasers.get(i);
if(me!=winner){
me.closestPreys.get(0).chasers.remove(me);
me.closestPreys.add(me.closestPreys.remove(0));
me.closestPreys.get(0).chasers.add(me);
}
}
}
private Animal findClosest(Collection<Animal> preys, XY me){
Animal target = null;
double cDist = Double.MAX_VALUE;
double x, y, sqDist;
for (Animal food : preys) {
x = food.x - me.x;
y = food.y - me.y;
sqDist = x * x + y * y + Double.MIN_NORMAL;
if (sqDist < cDist) {
cDist = sqDist;
target = food;
}
}
return target;
}
private ArrayList<Animal> findClosest(Collection<Animal> preys, XY me, int num){
ArrayList<Animal> result = new ArrayList<Animal>();
for(Animal food: preys){
int addIdx = -1;
for(int i=0; i<num && i<result.size(); i++){
Animal regFood = result.get(i);
if(sqDist(me, food) < sqDist(me, regFood)){
addIdx = i;
break;
}
}
if(addIdx == -1){
result.add(food);
} else {
result.add(addIdx, food);
}
if(result.size() > num){
result.remove(num);
}
}
return result;
}
private Member findClosestToTarget(Collection<Member> members, Animal target){
Member member = null;
double cDist = Double.MAX_VALUE;
double x, y, sqDist;
for (Member me : members) {
x = me.x - target.x;
y = me.y - target.y;
sqDist = x * x + y * y + Double.MIN_NORMAL;
if (sqDist < cDist) {
cDist = sqDist;
member = me;
}
}
return member;
}
private static final XY[] CHECKPOINTS = new XY[]{
new XY(49.5,49.5),
new XY(450.5,49.5),
new XY(450.5,100),
new XY(49.5,100),
new XY(49.5,150),
new XY(450.5,150),
new XY(450.5,200),
new XY(49.5,200),
new XY(49.5,250),
new XY(450.5,250),
new XY(450.5,300),
new XY(49.5,300),
new XY(49.5,350),
new XY(450.5,350),
new XY(450.5,400),
new XY(49.5,400),
new XY(49.5,450.5),
new XY(450.5,450.5)};
private int[] nextIdx = new int[100];
private int advanceIdx(int idx, int sign, int amount){
return sign*(((Math.abs(idx)+CHECKPOINTS.length-1+sign*amount) % CHECKPOINTS.length) + 1);
}
private void wander(Member me, int sign) {
if(preyCount > 20*predCount){
if (me.dx == 0 && me.dy == 0) {
me.dx = 250 - me.x;
me.dy = 250 - me.y;
return;
}
double lx, ly, px, py;
lx = me.dx / 4;
ly = me.dy / 4;
boolean dir = Math.random() < 0.5 ? true : false;
px = dir ? ly : -ly;
py = dir ? -lx : lx;
me.dx += px;
me.dy += py;
} else {
if(nextIdx[me.id]==0){
XY farthest = new XY(2000,2000);
int farthestIdx = -1;
for(int i=0; i<CHECKPOINTS.length; i++){
if(sign*sqDist(CHECKPOINTS[i], me) > sign*sqDist(farthest, me)){
farthest = CHECKPOINTS[i];
farthestIdx = i+1;
}
}
nextIdx[me.id] = farthestIdx*sign;
for(Member mem: members){
if(mem.id == me.id) continue;
if(nextIdx[mem.id]==nextIdx[me.id]){
nextIdx[me.id] = advanceIdx(nextIdx[me.id], sign, 5);
}
}
}
if(sqDist(CHECKPOINTS[Math.abs(nextIdx[me.id])-1],me) < 1){
nextIdx[me.id] = advanceIdx(nextIdx[me.id], sign, 1);
}
me.setDirection(CHECKPOINTS[Math.abs(nextIdx[me.id])-1].x-me.x,
CHECKPOINTS[Math.abs(nextIdx[me.id])-1].y-me.y);
}
}
private double sqDist(XY me, Animal target){
double dx = me.x-target.x;
double dy = me.y-target.y;
return dx*dx + dy*dy + Double.MIN_NORMAL;
}
private double sqDist(XY me, Member target){
double dx = me.x-target.x;
double dy = me.y-target.y;
return dx*dx + dy*dy + Double.MIN_NORMAL;
}
private double sqDist(Animal target, Member me){
double dx = me.x-target.x;
double dy = me.y-target.y;
return dx*dx + dy*dy + Double.MIN_NORMAL;
}
private List<Animal> getNeighbors(double radius, XY pos, Collection<Animal> candidates) {
List<Animal> neighbors = new ArrayList<Animal>();
for(Animal neighbor: candidates){
if(sqDist(pos, neighbor) < radius * radius){
neighbors.add(neighbor);
}
}
return neighbors;
}
final double[] weights = { 1, 1, 0.96, 2, 4 };
double weightSum;
static final int ALIGN = 0;
static final int SEPARATE = 1;
static final int COHESION = 2;
static final int FLEE = 3;
static final int WALL = 4;
static final int VISIBLE = 30;
static final int VISIBLE_PRED = 50;
private HashMap<Member, List<Animal>> prevPreys = new HashMap<Member, List<Animal>>();
private XY matchPreys(List<Animal> prevs, List<Animal> curs, XY prey){
XY result = new XY();
double sqDist = 0;
Animal candidate;
XY otherPos;
for(Animal otherPrey: curs){
otherPos = new XY(otherPrey.x, otherPrey.y);
sqDist = XY.sqDistance(prey, otherPos);
if(sqDist > VISIBLE * VISIBLE)
continue;
candidate = findClosest(getNeighbors(6, otherPos, prevs), prey);
if(candidate == null){
return null;
}
result.add(otherPos.x-candidate.x, otherPos.y-candidate.y);
}
return result;
}
private XY predictNextPos(XY prey, Member me) {
List<Animal> preys = getNeighbors(VISIBLE_PRED, prey, foods);
List<Animal> preds = getNeighbors(VISIBLE, prey, predators);
XY flock[] = new XY[weights.length];
for (int i = 0; i < weights.length; i++)
flock[i] = new XY();
double dx, dy, dist, sqDist;
for (Animal otherPrey : preys) {
sqDist = XY.sqDistance(prey, new XY(otherPrey.x, otherPrey.y));
if(sqDist > VISIBLE * VISIBLE)
continue;
dx = otherPrey.x - prey.x;
dy = otherPrey.y - prey.y;
flock[COHESION].add(dx*sqDist, dy*sqDist);
flock[SEPARATE].add(-dx*(1d/sqDist), -dy*(1d/sqDist));
flock[ALIGN].add(new XY(prey.x-me.x,prey.y-me.y));
}
if(sqDist(prey, me) < 400){
if(prevPreys.get(me) == null){
prevPreys.put(me, preys);
} else {
XY flockAlign = matchPreys(prevPreys.get(me), preys, prey);
if(flockAlign == null){
prevPreys.put(me , null);
} else {
flock[ALIGN] = flockAlign;
prevPreys.put(me, preys);
}
}
}
flock[ALIGN].unitize().multiply(5);
flock[COHESION].unitize().multiply(5);
flock[SEPARATE].unitize().multiply(5);
for (Animal predator : preds){
flock[FLEE].add(prey.x-predator.x, prey.y-predator.y);
}
dx = Island.CENTER.x - prey.x;
dy = Island.CENTER.y - prey.y;
dist = Math.max(Math.abs(dx), Math.abs(dy));
if(dist > 240){
flock[WALL].x = dx * dist;
flock[WALL].y = dy * dist;
flock[WALL].unitize().multiply(5);
}
XY vec = new XY();
vec.x = 0;
vec.y = 0;
for (int i = 0; i < flock.length; i++) {
flock[i].multiply(weights[i]);
vec.add(flock[i]);
}
limitSpeed(vec);
return vec.add(prey);
}
private XY limitSpeed(XY move) {
if (move.x*move.x+move.y*move.y > MAX_SPEED*MAX_SPEED)
move.unitize().multiply(MAX_SPEED);
return move;
}
}