업데이트 : 비행기 클래스에 isSuicidal ()이 추가되었습니다. 비행기가 벽과 돌이킬 수없는 충돌 과정에 있는지 확인할 수 있습니다!
업데이트 : updateCoolDown ()이 simulateMove ()와 분리되었습니다.
업데이트 : Sparr이 작성하고 테스트에 사용할 수있는 Java 이외의 항목 래퍼
UPDATE Zove 게임 작성했습니다 멋진 3D 시각화를 ,이 KOTH 위해 여기 엿의 YouTube 동영상의 PredictAndAVoid 싸움 PredictAndAVoid의는.
Plane 클래스의 SimulateMove () 함수가 약간 수정되어 더 이상 쿨 다운을 업데이트하지 않습니다. 촬영 후 새로운 updateCoolDown () 함수를 사용하십시오. 새로운 isSuicidal ()은 비행기가 죽었을 때 참을 반환하고, 비행기를 사용하여 적의 움직임을 제거하고 벽에 부딪히지 않도록합니다. 업데이트 된 코드를 얻으려면 Controller 및 Plane 클래스를 github 리포지토리의 클래스로 바꾸십시오 .
기술
이 도전의 목표는 다른 참가자가 두 비행기와 대면하는 두 개의 공중전 비행기 를 코딩 하는 것입니다. 매 턴마다 한 칸씩 움직여서 쏠 기회가 있습니다. 그것으로 간단합니다.
거의 ..
경기장과 가능한 움직임
경기장은 공간에 14x14x14 벽으로 둘러싸여 있습니다. 참가자 1의 비행기는 (0,5,0) 및 (0,8,0) 위치에서 시작하고 참가자 2의 비행기는 (13,5,13) 및 (13,8,13)에서 시작합니다. 모든 비행기는 가장 가까운 수직 벽에서 수평으로 비행하여 시작합니다.
이제 헬리콥터가 아닌 비행기를 조종하고 있기 때문에 원하는 방향으로 변경하거나 이동을 멈출 수 없으므로 각 비행기는 방향을 가지며 매 턴마다 그 방향으로 타일 하나를 움직입니다.
가능한 방향은 North (N), South (S), East (E), West (W), Up (U) 및 Down (D) 및 이들 6 개의 논리적 조합입니다. NS 축이 x 축에 해당하는 경우 WE에서 y로, DU에서 z로. NW, SU 및 NED는 가능한 방향의 예를 떠올리게합니다. UD는 잘못된 조합의 좋은 예입니다.
물론 비행기의 방향을 변경할 수 있지만 한계는 최대 45도까지만 변경할 수 있습니다. 이것을 시각화하기 위해 루빅스 큐브를 잡고 (나는 당신이 하나 있음을 알고 있습니다) 26 개의 바깥 쪽 작은 큐브가 모두 가능한 방향이라고 생각하십시오 (한 글자 방향은 얼굴, 두 글자 방향은 가장자리, 세 글자 방향은 모서리). 작은 입방체로 표시되는 방향으로 향하고 있다면, 당신과 접촉하는 각 입방체로 방향을 바꿀 수 있습니다 (대각선으로 만지지 만 눈에 띄게 만져서 입방체를 만지지 않습니다).
모든 평면이 어떤 방향으로 변경하고 싶은지 표시 한 후에는 변경하고 한 타일을 동시에 이동합니다.
방향을 이동 한 방향으로 변경하는 대신 올바른 방향으로 이동하도록 선택했지만 진행 한 방향으로 계속 비행 할 수 있습니다. 이것은 코너를 돌고있는 차와 차가 바뀌는 차선의 차이와 유사합니다.
사격과 사망
당신은 한 라운드에 최대 한 번을 쏠 수 있으며, 어떤 방향으로 비행 할 것인지와 비행기 (및 연장에 의해 총)가 같은 방향을 향하게할지 여부를 결정할 때 동시에 결정해야합니다. 비행기가 움직이 자마자 총알이 쏜다. 촬영 후 한 차례의 쿨 다운이 있습니다. 세 번째 차례에는 다시 가십시오. 날아가는 방향으로 만 쏠 수 있습니다. 총알은 즉석에서 벽이나 비행기에 닿을 때까지 직선으로 날아갑니다.
'차선 변경'뿐만 아니라 방향을 바꿀 수있는 방법을 고려하면 대각선 앞쪽에 최대 3x3 줄의 열을 추가로 위협 할 수 있습니다.
비행기에 부딪히면이 비행기는 죽고 보드에서 즉시 사라집니다 (완전히 폭발하거나 무언가 때문에). 총알은 최대 하나의 비행기에만 맞을 수 있습니다. 총알이 동시에 발사되므로 두 비행기가 서로 쏠 수 있습니다. 두 개의 총알이 공중에서 충돌 할 수는 없습니다 (슬픈, 알아요).
그러나 두 평면이 충돌 할 수 있습니다 (동일한 큐브로 끝나고 동일한 평면에서 끝나지 않고 서로 교차하면 NOT). 벽으로 날아 가면 문제의 비행기가 죽고 그 행동에 대해 생각하기 위해 모퉁이에 놓일 수 있습니다. 충돌은 촬영 전에 처리됩니다.
컨트롤러와의 통신
Java 및 다른 언어로 된 항목을 허용합니다. 입력 항목이 java 인 경우 STDIN을 통해 입력을 받고 STDOUT을 통해 출력합니다.
항목이 java 인 경우 .your 항목은 다음 클래스를 확장해야합니다.
package Planes;
//This is the base class players extend.
//It contains the arena size and 4 plane objects representing the planes in the arena.
public abstract class PlaneControl {
// note that these planes are just for your information, modifying these doesn't affect the actual plane instances,
// which are kept by the controller
protected Plane[] myPlanes = new Plane[2];
protected Plane[] enemyPlanes = new Plane[2];
protected int arenaSize;
protected int roundsLeft;
...
// Notifies you that a new fight is starting
// FightsFought tells you how many fights will be fought.
// the scores tell you how many fights each player has won.
public void newFight(int fightsFought, int myScore, int enemyScore) {}
// notifies you that you'll be fighting anew opponent.
// Fights is the amount of fights that will be fought against this opponent
public void newOpponent(int fights) {}
// This will be called once every round, you must return an array of two moves.
// The move at index 0 will be applied to your plane at index 0,
// The move at index1 will be applied to your plane at index1.
// Any further move will be ignored.
// A missing or invalid move will be treated as flying forward without shooting.
public abstract Move[] act();
}
해당 클래스로 생성 된 인스턴스는 전체 경쟁 기간 동안 유지되므로 변수에 저장하려는 모든 데이터를 저장할 수 있습니다. 자세한 내용은 코드의 주석을 읽으십시오.
또한 다음 도우미 클래스를 제공했습니다.
package Planes;
//Objects of this class contain all relevant information about a plane
//as well as some helper functions.
public class Plane {
private Point3D position;
private Direction direction;
private int arenaSize;
private boolean alive = true;
private int coolDown = 0;
public Plane(int arenaSize, Direction direction, int x, int y, int z) {}
public Plane(int arenaSize, Direction direction, Point3D position) {}
// Returns the x coordinate of the plane
public int getX() {}
// Returns the y coordinate of the plane
public int getY() {}
// Returns the z coordinate of the plane
public int getZ() {}
// Returns the position as a Point3D.
public Point3D getPosition() {}
// Returns the distance between the plane and the specified wall,
// 0 means right next to it, 19 means at the opposite side.
// Returns -1 for invalid input.
public int getDistanceFromWall(char wall) {}
// Returns the direction of the plane.
public Direction getDirection() {}
// Returns all possible turning directions for the plane.
public Direction[] getPossibleDirections() {}
// Returns the cool down before the plane will be able to shoot,
// 0 means it is ready to shoot this turn.
public int getCoolDown() {}
public void setCoolDown(int coolDown) {}
// Returns true if the plane is ready to shoot
public boolean canShoot() {}
// Returns all positions this plane can shoot at (without first making a move).
public Point3D[] getShootRange() {}
// Returns all positions this plane can move to within one turn.
public Point3D[] getRange() {}
// Returns a plane that represents this plane after making a certain move,
// not taking into account other planes.
// Doesn't update cool down, see updateCoolDown() for that.
public Plane simulateMove(Move move) {}
// modifies this plane's cool down
public void updateCoolDown(boolean shot) {
coolDown = (shot && canShoot())?Controller.COOLDOWN:Math.max(0, coolDown - 1);
}
// Returns true if the plane is alive.
public boolean isAlive() {}
// Sets alive to the specified value.
public void setAlive(boolean alive) {}
// returns a copy of itself.
public Plane copy() {}
// Returns a string representing its status.
public String getAsString() {}
// Returns a string suitable for passing to a wrapped plane process
public String getDataString() {}
// Returns true if a plane is on an irreversable colision course with the wall.
// Use this along with simulateMove() to avoid hitting walls or prune possible emeny moves.
public boolean isSuicidal() {}
}
// A helper class for working with directions.
public class Direction {
// The three main directions, -1 means the first letter is in the direction, 1 means the second is, 0 means neither is.
private int NS, WE, DU;
// Creates a direction from 3 integers.
public Direction(int NSDir, int WEDir, int DUDir) {}
// Creates a direction from a directionstring.
public Direction(String direction) {}
// Returns this direction as a String.
public String getAsString() {}
// Returns The direction projected onto the NS-axis.
// -1 means heading north.
public int getNSDir() {}
// Returns The direction projected onto the WE-axis.
// -1 means heading west.
public int getWEDir() {}
// Returns The direction projected onto the DU-axis.
// -1 means heading down.
public int getDUDir() {}
// Returns a Point3D representing the direction.
public Point3D getAsPoint3D() {}
// Returns an array of chars representing the main directions.
public char[] getMainDirections() {}
// Returns all possible turning directions.
public Direction[] getPossibleDirections() {}
// Returns true if a direction is a valid direction to change to
public boolean isValidDirection(Direction direction) {}
}
public class Point3D {
public int x, y, z;
public Point3D(int x, int y, int z) {}
// Returns the sum of this Point3D and the one specified in the argument.
public Point3D add(Point3D point3D) {}
// Returns the product of this Point3D and a factor.
public Point3D multiply(int factor) {}
// Returns true if both Point3D are the same.
public boolean equals(Point3D point3D) {}
// Returns true if Point3D is within a 0-based arena of a specified size.
public boolean isInArena(int size) {}
}
public class Move {
public Direction direction;
public boolean changeDirection;
public boolean shoot;
public Move(Direction direction, boolean changeDirection, boolean shoot) {}
}
이 클래스의 인스턴스를 만들고 원하는만큼 함수를 사용할 수 있습니다. 이 헬퍼 클래스의 전체 코드는 여기에서 찾을 수 있습니다 .
다음은 귀하의 입장이 어떻게 보이는지에 대한 예입니다 (바람직하게 당신은 내가했던 것보다 더 잘할 것입니다.이 비행기와의 대부분의 경기는 벽을 피하려는 최선의 노력에도 불구하고 벽으로 날아가는 것으로 끝납니다).
package Planes;
public class DumbPlanes extends PlaneControl {
public DumbPlanes(int arenaSize, int rounds) {
super(arenaSize, rounds);
}
@Override
public Move[] act() {
Move[] moves = new Move[2];
for (int i=0; i<2; i++) {
if (!myPlanes[i].isAlive()) {
moves[i] = new Move(new Direction("N"), false, false); // If we're dead we just return something, it doesn't matter anyway.
continue;
}
Direction[] possibleDirections = myPlanes[i].getPossibleDirections(); // Let's see where we can go.
for (int j=0; j<possibleDirections.length*3; j++) {
int random = (int) Math.floor((Math.random()*possibleDirections.length)); // We don't want to be predictable, so we pick a random direction out of the possible ones.
if (myPlanes[i].getPosition().add(possibleDirections[random].getAsPoint3D()).isInArena(arenaSize)) { // We'll try not to fly directly into a wall.
moves[i] = new Move(possibleDirections[random], Math.random()>0.5, myPlanes[i].canShoot() && Math.random()>0.2);
continue; // I'm happy with this move for this plane.
}
// Uh oh.
random = (int) Math.floor((Math.random()*possibleDirections.length));
moves[i] = new Move(possibleDirections[random], Math.random()>0.5, myPlanes[i].canShoot() && Math.random()>0.2);
}
}
return moves;
}
@Override
public void newFight(int fightsFought, int myScore, int enemyScore) {
// Using information is for schmucks.
}
@Override
public void newOpponent(int fights) {
// What did I just say about information?
}
}
DumbPlanes는 다른 참가작과 함께 토너먼트에 참가하므로 마지막으로 종료하면 DumbPlanes보다 더 나은 성적을 거두지 못한 것은 본인의 잘못입니다.
제한 사항
KOTH 위키에 언급 된 제한 사항이 적용됩니다.
- 컨트롤러, 런타임 또는 기타 제출물을 수정하려는 시도는 실격 처리됩니다. 모든 제출물은 제공된 입력 및 저장 장치에서만 작동해야합니다.
- 봇은 다른 특정 봇을 이길 수 있도록 작성해서는 안됩니다. (드문 경우에 바람직 할 수 있지만 이것이 핵심 도전 과제 개념이 아닌 경우에는 배제하는 것이 좋습니다.)
- 충분한 양의 리소스를 사용하여 평가판을 실행하기 위해 너무 많은 시간이나 메모리를 사용하는 제출물을 실격 처리 할 권리를 보유합니다.
- 봇은 의도적으로 또는 실수로 기존 전략과 정확히 동일한 전략을 구현해서는 안됩니다.
제출 테스트
여기 에서 컨트롤러 코드를 다운로드 하십시오 . 제출물을 Something.java로 추가하십시오. 항목 [] 및 이름 []에 비행기 항목을 포함하도록 Controller.java를 수정하십시오. Eclipse 프로젝트 또는로 모든 것을 컴파일 javac -d . *.java
한 다음java Planes/Controller
. 컨테스트 로그는에 test.txt
있으며 스코어 보드는 끝에 있습니다. matchUp()
두 개의 항목을 인수로 직접 호출 하여 두 평면을 서로 테스트 할 수도 있습니다 .
싸움에서 이기다
싸움의 승자는 마지막 비행기를 비행 한 사람입니다. 100 턴 후에도 여전히 1 팀 이상 남았을 경우 가장 많은 비행기를 가진 팀이 승리합니다. 이것이 같다면 무승부입니다.
득점과 경쟁
현재 바운티가 소진되면 다음 공식 토너먼트가 진행됩니다.
각 참가작은 모든 다른 참가작 (최소한)에 100 번 싸울 것이며, 각 경기의 승자는 100 점 중 가장 많은 승리를 거둔 사람이며 2 점을받습니다. 추첨의 경우 두 항목 모두 1 점을받습니다.
경쟁의 승자가 가장 많은 점수를 얻은 사람입니다. 추첨의 경우, 우승자는 추첨 된 항목들 사이의 경기에서 승리 한 사람입니다.
출전 횟수에 따라 출전 횟수가 크게 늘어날 수 있습니다. 또한 첫 토너먼트 후 2-4 개의 최고 출전 선수를 선택하고 더 많은 시합을 가진 출전 선수들 사이에서 엘리트 토너먼트를 설정할 수도 있습니다. 싸움)
(예비) 스코어 보드
우리는 또 다른 흥미 진진한 토너먼트 에서 단연 2 위를 차지하는 새로운 참가작 을 얻었습니다. 이 토너먼트는 각 비행기 사이에서 10 번의 시합만으로 진행되었으므로 상황이 어떻게 진행되는지를 완전히 정확하게 나타내는 것은 아닙니다.
----------------------------
¦ 1. PredictAndAvoid: 14 ¦
¦ 2. Crossfire: 11 ¦
¦ 3. Weeeeeeeeeeee: 9 ¦
¦ 4. Whirligig: 8 ¦
¦ 4. MoveAndShootPlane: 8 ¦
¦ 6. StarFox: 4 ¦
¦ 6. EmoFockeWulf: 2 ¦
¦ 7. DumbPlanes: 0 ¦
----------------------------
다음은 비 Java 랩퍼의 출력 예입니다.
NEW CONTEST 14 20
14x14x14 경기장에서 새로운 컨테스트가 시작되고 있으며 전투 당 20 턴이 소요됩니다.
NEW OPPONENT 10
새로운 상대를 상대하고 있으며이 상대와 10 번 싸울 것임을 나타냅니다.
NEW FIGHT 5 3 2
는 현재 상대와의 새로운 싸움이 시작되고 있음을 나타냅니다.이 상대와 지금까지 5 번 싸워 3 번 승리하고 2 번의 전투에서 패배했음을 나타냅니다
ROUNDS LEFT 19
현재 전투에서 19 라운드가 남아 있음을 나타냅니다
NEW TURN
이 전투에서 네 비행기 모두에 대한 데이터를받을 예정임을 나타냅니다.
alive 13 8 13 N 0
alive 13 5 13 N 0
dead 0 0 0 N 0
alive 0 8 0 S 0
이 4 개의 선은 두 평면이 모두 [13,8,13] 및 [13,5,13] 좌표에서 각각 북쪽을 향하고 쿨 다운이 0 인 상태임을 나타냅니다. 첫 번째 적 비행기는 죽었고 두 번째는 [0,8,0]에 살아 있고 남쪽으로 쿨 다운이 없습니다.
이 시점에서 프로그램은 다음과 비슷한 두 줄을 출력해야합니다.
NW 0 1
SU 1 0
이것은 첫 번째 비행기가 현재 방향을 돌리지 않고 가능한 경우 발사하지 않고 노스 웨스트를 여행 함을 나타냅니다. 두 번째 비행기는 사우스 업을 여행하며 사격하지 않고 사우스 업을 향하게됩니다.
이제 당신은 등을 ROUNDS LEFT 18
따릅니다 NEW TURN
. 이것은 누군가이기거나 라운드 타임 아웃 될 때까지 계속 됩니다 .이 시점 NEW FIGHT
에서 업데이트 된 전투 횟수와 점수를 가진 다른 라인 을 얻을 수 NEW OPPONENT
있습니다.