調整された細菌
私は手遅れではないことを願っています。
私のテストでは、他の対戦相手に勝ちます(そして常にそれらをすべて殺すことによって)、そしてそれが自分自身に直面するならば、戦いは決して終わらないでしょう、戦略が強い証拠です。
シングルセルの場合、以前の状態を記憶できますが、自分の立場を利用して異なる動作をすることができます!=)
これにより、細菌が仕切りとムーバーに分割され、そうすることで、防御ラインを維持しながら、最前線だけでなくより多くの細菌が有用になります。
また、特定の敵に集中するように攻撃を調整し、敵がより速く殺されるようにします(これは、HPに焦点を当てた他の単一セルに直面するためです)。
ボード上のセルの数によって検出されるゲーム中盤では、彼らはそれらを打ち負かすことによって敵の領域に押し込もうとします。これが重要な戦略です。
これは現在、他のすべての対戦相手と比較して最高の成長率を持っていますが、開始が遅いため、これは大規模なアリーナでうまく機能します。
で実行する java CoordinatedBacteria
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
public class CoordinatedBacteria {
public static final int MAX_HP = 6;
public static final int MAX_ENERGY = 6;
public static final int ACIDITY = 0;
// given arena state and cell stats, return an action string (e.g., "ATTACK NW 2", "DIVIDE S")
public static String decide(final Arena arena, Point cell, int hp, int energy) {
// empty and corpses are free for movement and division
final Point2D enemyCenter = arena.getCenterOf("x");
final Point2D ourCenter = arena.getCenterOf("o");
final int moverPos = (enemyCenter.x <= ourCenter.x || enemyCenter.y <= ourCenter.y) ? (arena.width+arena.height+1)%2 : 1;
final int attackPos = (enemyCenter.x <= ourCenter.x || enemyCenter.y <= ourCenter.y) ? (arena.width+arena.height)%2 : 1;
int selfCount = arena.count("o");
boolean isMidWay = selfCount > (arena.width*arena.height/2-1);
if(!isMidWay){
if(enemyCenter.x < ourCenter.x){
enemyCenter.x = 0;
enemyCenter.y = 0;
ourCenter.x = arena.width;
ourCenter.y = arena.height;
} else {
enemyCenter.x = arena.width;
enemyCenter.y = arena.height;
ourCenter.x = 0;
ourCenter.y = 0;
}
}
ArrayList<Point> nearbyEmpty = arena.getAdjacentMatches(cell, ".");
Collections.sort(nearbyEmpty, new Comparator<Point>(){
@Override
public int compare(Point o1, Point o2) {
Double score1 = arena.getAdjacentMatches(o1, ".").size()
+ arena.getAdjacentMatches(o1, "c").size()
+ arena.getAdjacentMatches(o1, "x").size()
- arena.getAdjacentMatches(o1, "o").size()
+ distance(o1.x, o1.y, enemyCenter.x, enemyCenter.y)*100;
Double score2 = arena.getAdjacentMatches(o2, ".").size()
+ arena.getAdjacentMatches(o2, "c").size()
+ arena.getAdjacentMatches(o2, "x").size()
- arena.getAdjacentMatches(o2, "o").size()
+ distance(o1.x, o1.y, enemyCenter.x, enemyCenter.y)*100;
return Double.compare(score2, score1);
}
});
ArrayList<Point> nearbyEnemies = arena.getAdjacentMatches(cell, "x");
Collections.sort(nearbyEnemies, new Comparator<Point>(){
@Override
public int compare(Point o1, Point o2) {
Integer score1 = (arena.getAdjacentMatches(o1, ".").size()
+ arena.getAdjacentMatches(o1, "c").size()
- arena.getAdjacentMatches(o1, "x").size()
+ arena.getAdjacentMatches(o1, "o").size())
*10
+ (isAtBoundary(o1, arena)?1000:0)
+ (o1.x + o1.y + attackPos + 1)%2;
Integer score2 = (arena.getAdjacentMatches(o2, ".").size()
+ arena.getAdjacentMatches(o2, "c").size()
- arena.getAdjacentMatches(o2, "x").size()
+ arena.getAdjacentMatches(o2, "o").size())
*10
+ (isAtBoundary(o2, arena)?1000:0)
+ (o2.x + o2.y + attackPos + 1)%2;
return Integer.compare(score2, score1);
}
});
ArrayList<Point> nearbyCorpses = arena.getAdjacentMatches(cell, "c");
Collections.sort(nearbyCorpses, new Comparator<Point>(){
@Override
public int compare(Point o1, Point o2) {
Integer score1 = arena.getAdjacentMatches(o1, "x").size()
- arena.getAdjacentMatches(o1, "o").size();
Integer score2 = arena.getAdjacentMatches(o2, "x").size()
- arena.getAdjacentMatches(o2, "o").size();
return Integer.compare(score1, score2);
}
});
ArrayList<Point> nearbyFriends = arena.getAdjacentMatches(cell, "o");
for(Point empty: nearbyEmpty){
if(nearbyFriends.size()>=2 && energy >= 1 && arena.getAdjacentMatches(empty, "x").size()==3 && isAtBoundary(empty, arena)){
return "MOVE "+arena.getDirection(cell, empty);
}
}
for(Point empty: nearbyCorpses){
if(nearbyFriends.size()>=2 && energy >= 1 && arena.getAdjacentMatches(empty, "x").size()==3 && isAtBoundary(empty, arena)){
return "MOVE "+arena.getDirection(cell, empty);
}
}
if ((cell.x+cell.y)%2 == moverPos && energy >= 1 && energy <= 5){
if(nearbyEmpty.size()>0){
Point foremost = nearbyEmpty.get(0);
if(nearbyFriends.size() >= 4){
return "MOVE "+arena.getDirection(cell, foremost);
}
}
if(nearbyCorpses.size() > 0) {
Point corpse = nearbyCorpses.get(0);
return "EAT " + arena.getDirection(cell, corpse);
}
if(energy > 0 && nearbyEnemies.size() > 0) {
int attackStrength = Math.min(energy, 3);
Point enemy = nearbyEnemies.get(0);
return "ATTACK " + arena.getDirection(cell, enemy) + " " + attackStrength;
}
if(nearbyFriends.size() >= 4 && nearbyEmpty.size() > 0){
Point movePoint = getBestPointToDivide(arena, nearbyEmpty);
return "MOVE " + arena.getDirection(cell, movePoint);
}
}
if(energy >= 5 && nearbyEmpty.size() > 0) {
Point divisionPoint = getBestPointToDivide(arena, nearbyEmpty);
if(energy == MAX_ENERGY && nearbyFriends.size() >= 5
&& distance(enemyCenter.x, enemyCenter.y, cell.x, cell.y) > distance(enemyCenter.x, enemyCenter.y, divisionPoint.x, divisionPoint.y)){
return "MOVE " + arena.getDirection(cell, divisionPoint);
}
return "DIVIDE " + arena.getDirection(cell, divisionPoint);
}
if(nearbyCorpses.size() > 0) {
Point corpse = nearbyCorpses.get(0);
if (energy < MAX_ENERGY){
return "EAT " + arena.getDirection(cell, corpse);
} else {
return "DIVIDE " + arena.getDirection(cell, corpse);
}
}
if(energy >= 5 && nearbyCorpses.size() > 0) {
Point divisionPoint = getBestPointToDivide(arena, nearbyCorpses);
if(energy == MAX_ENERGY && nearbyFriends.size() >= 5
&& distance(enemyCenter.x, enemyCenter.y, cell.x, cell.y) < distance(enemyCenter.x, enemyCenter.y, divisionPoint.x, divisionPoint.y)){
return "MOVE " + arena.getDirection(cell, divisionPoint);
}
return "DIVIDE " + arena.getDirection(cell, divisionPoint);
}
// if at least one adjacent enemy, attack if possible
if(energy > 0 && nearbyEnemies.size() > 0) {
int attackStrength = Math.min(energy, 3);
Point enemy = nearbyEnemies.get(0);
return "ATTACK " + arena.getDirection(cell, enemy) + " " + attackStrength;
}
return "REST";
}
public static boolean isAtBoundary(Point point, Arena arena){
return point.x==0 || point.x==arena.width-1 || point.y==0 || point.y==arena.height-1;
}
public static double distance(double x1, double y1, double x2, double y2){
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
public static Point getBestPointToDivide(Arena arena, List<Point> nearbyEmpty){
Point result = null;
double minDist = 100000;
List<Point> mostEmpty = new ArrayList<Point>();
int max = -1000;
List<Point> neighbor = nearbyEmpty;
for(Point point: neighbor){
int emptyNeighborScore = arena.getAdjacentMatches(point, ".").size()
+ arena.getAdjacentMatches(point, "c").size()
+ arena.getAdjacentMatches(point, "x").size()
- arena.getAdjacentMatches(point, "o").size();
if(emptyNeighborScore > max){
mostEmpty = new ArrayList<Point>();
mostEmpty.add(point);
max = emptyNeighborScore;
} else if(emptyNeighborScore == max){
mostEmpty.add(point);
}
}
for(Point point: mostEmpty){
Point2D enemyCenter = arena.getCenterOf("x");
double dist = Math.pow(point.x-enemyCenter.x, 2) + Math.pow(point.y-enemyCenter.y, 2);
if(dist < minDist){
minDist = dist;
result = point;
}
}
return result;
}
public static void main(String[] args) throws IOException {
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
String firstLine;
firstLine = br.readLine();
if(firstLine.equals("BEGIN")) {
System.out.println(MAX_HP + " " + MAX_ENERGY + " " + ACIDITY);
} else {
String[] dimensions = firstLine.split(" ");
int width = Integer.parseInt(dimensions[0]);
int height = Integer.parseInt(dimensions[1]);
Point[][] arena = new Point[height][];
String input;
int lineno = 0;
while(!(input=br.readLine()).equals("")) {
char[] charList = input.toCharArray();
arena[lineno] = new Point[width];
for(int i=0; i<charList.length; ++i) {
arena[lineno][i] = new Point(i, lineno, charList[i]);
}
lineno++;
}
String[] stats = br.readLine().split(" ");
int x = Integer.parseInt(stats[0]);
int y = Integer.parseInt(stats[1]);
int hp = Integer.parseInt(stats[2]);
int energy = Integer.parseInt(stats[3]);
Arena arenaObj = new Arena(arena, width, height);
System.out.print(decide(arenaObj, arenaObj.get(x,y), hp, energy));
}
}
public static class Arena {
public Point[][] array;
public HashMap<String, String> c2d;
public int height;
public int width;
public Arena(Point[][] array, int width, int height) {
this.array = array;
this.width = width;
this.height = height;
this.c2d = new HashMap<String, String>();
this.c2d.put("0,0", "-");
this.c2d.put("0,-1", "N");
this.c2d.put("0,1", "S");
this.c2d.put("1,0", "E");
this.c2d.put("-1,0", "W");
this.c2d.put("-1,-1", "NW");
this.c2d.put("1,-1", "NE");
this.c2d.put("-1,1", "SW");
this.c2d.put("1,1", "SE");
}
// get the character at x,y
// or return empty string if out of bounds
public Point get(int x, int y) {
if(y < 0 || y >= this.array.length){
return null;
}
Point[] row = this.array[y];
if(x < 0 || x >= row.length) {
return null;
}
return row[x];
}
// get arraylist of Points for each adjacent space that matches the target string
public ArrayList<Point> getAdjacentMatches(Point p, String match) {
ArrayList<Point> result = new ArrayList<Point>();
for(int i=-1; i<=1; ++i) {
for(int j=-1; j<=1; ++j) {
Point found = this.get(p.x+i, p.y+j);
if((i!=0 || j!=0) && found != null && found.symbol.equals(match)) {
result.add(found);
}
}
}
return result;
}
public ArrayList<Point> getAdjacents(Point p){
ArrayList<Point> result = new ArrayList<Point>();
for(int i=-1; i<=1; ++i) {
for(int j=-1; j<=1; ++j) {
Point found = this.get(p.x+i, p.y+j);
if((i!=0 || j!=0) && found != null) {
result.add(found);
}
}
}
return result;
}
public int count(String sym){
int result = 0;
for(int y=0; y<array.length; y++){
for(int x=0; x<array[y].length; x++){
Point cur = this.get(x, y);
if(cur!=null && cur.symbol.equals(sym)){
result++;
}
}
}
return result;
}
// get the direction string from point 1 to point 2
public String getDirection(Point p1, Point p2) {
int dx = p2.x - p1.x;
int dy = p2.y - p1.y;
dx = Math.abs(dx) / (dx==0?1:dx);
dy = Math.abs(dy) / (dy==0?1:dy);
return this.c2d.get(dx + "," + dy);
}
public Point2D getCenterOf(String sym){
Point2D result = new Point2D(0,0);
int count = 0;
for(int y=0; y<array.length; y++){
for(int x=0; x<array[y].length; x++){
if(this.get(x,y).symbol.equals(sym)){
result.x += x;
result.y += y;
count++;
}
}
}
result.x /= count;
result.y /= count;
return result;
}
}
public static class Point {
int x, y;
String symbol;
public Point(int x, int y, String sym) {
this.x=x;
this.y=y;
this.symbol=sym;
}
public Point(int x, int y, char sym){
this(x, y, ""+sym);
}
}
public static class Point2D{
double x,y;
public Point2D(double x, double y){
this.x = x;
this.y = y;
}
}
}
'node c:/cell/cell_template.js'
に指定する必要があるように、各引数のように完全に実行可能なコマンドを指定する必要があります'java CellTemplate'
。チャレンジテキストでこれを明確にします。それでも問題が解決しない場合は、私たち(および技術的な問題を抱えている他の人)が、たった今作ったチャットルームでこの議論を続けることができます。