GÜNCELLEME: isSuicidal (), uçak sınıfına eklendi; bu, bir uçağın duvarlarla geri dönüşü olmayan bir çarpışma rotasında olup olmadığını kontrol etmenizi sağlar !!
UPDATE: updateCoolDown (), simulateMove () öğesinden ayrıldı
GÜNCELLEME: Sparr tarafından yazılan , test edilmeyen Java olmayan giriş sarmalayıcısı, yorumları görün
GÜNCELLEME Zove Games Bu KOTH için harika bir 3D görselleştirici yazdı , işte PredictAndAVoid ile savaşan bir shitty youtube videosu .
Plane sınıfının simulateMove () işlevi hafifçe değiştirildi, böylece artık soğumayı güncelleştirmiyor, çekimden sonra bunun için yeni updateCoolDown () işlevini kullanın. Yeni isSuicidal (), bir uçağın ölüme kadar uçması gerekiyorsa true değerini döndürür, düşmanın hareketlerini budamak ve duvarlara çarpmamak için kullanın. Güncellenmiş kodu almak için, sadece Controller ve Plane sınıflarını github repo'dakilerle değiştirin.
Açıklama
Bu zorluğun amacı, başka bir yarışmacı tarafından iki uçağa karşı karşıya gelecek olan iki dövüş uçağını kodlamak . Her fırsatta bir boşluk hareket ettirir ve çekim yapma şansınız olur. İşte bu kadar basit.
Neredeyse ...
Arena ve olası hareketler
Arena uzayda duvarlı 14x14x14. Yarışmacı 1'in uçakları (0,5,0) ve (0,8,0) lokasyonlarında ve yarışmacı 2'nin uçakları (13,5,13) ve (13,8,13) 'de başlar. Tüm uçaklar en yakın oldukları dikey duvarlardan yatay olarak uzaklaşarak başlarlar.
Artık uçaklar uçtuğunuzdan ve helikopterler olmadığınızdan, sadece isteğinizde yön değiştiremezsiniz veya hareket etmeyi durduramazsınız, bu nedenle her uçağın bir yönü vardır ve her dönüşünde bir kiremit bu yönde hareket edecektir.
Mümkün olan yönler şunlardır: Kuzey (N), Güney (S), Doğu (E), Batı (K), Yukarı (U) ve Aşağı (D) ve bu altı maddenin herhangi bir mantıksal birleşimidir. NS ekseninin x eksenine tekabül ettiği yerde, WE ila y ve DU ila z. NW, SU ve NED, olası yön örnekleri olarak akla geliyor; UD, geçersiz bir kombinasyonun harika bir örneğidir.
Elbette uçaklarınızın yönünü değiştirebilirsiniz, ancak bir sınırlama var, yönünüzü sadece en fazla 45 dereceyle değiştirebilirsiniz. Bunu görselleştirmek için rubik küpünüzü alın (bir tanesine sahip olduğunuzu biliyorum) ve 26 dış küçük küpün hepsinin olası yönler olduğunu hayal edin (bir harf yönü yüzler, iki harf yönü kenar ve üç harf yönü köşelerdir). Küçük bir küple temsil edilen bir yöne doğru yöneliyorsanız, kendinize dokunan her bir küpün yönünü değiştirebilirsiniz (çapraz olarak dokunan sayımlar, ancak yalnızca göze dokunarak, küpten dokunmayanlar).
Tüm uçaklar hangi yöne değiştirmek istediklerini belirttikten sonra, bunu yaparlar ve aynı anda bir karoyu hareket ettirirler.
Geçerli bir yönde hareket etmeyi de tercih edebilirsiniz ancak yönünüzü hareket ettiğiniz yöne değiştirmek yerine gittiğiniz yöne doğru uçmaya devam edin. Bu, bir köşeden dönen bir araba ile araba değiştirme şeritleri arasındaki farka benzer.
Çekim ve ölmek
Her turda en fazla bir kez atış yapabilirsiniz ve aynı zamanda hangi yöne uçacağınıza karar verdiğinizde ve uçağınızı (ve dolayısıyla da silahınızı) aynı yöne işaret edip etmemek istediğinize karar vermeniz gerekir. Mermi uçak hareket ettikten hemen sonra vuruldu. Çekimden sonra bir tur soğukkanlı, üçüncü turda tekrar gitmek için iyi bir insansınız. Sadece uçtuğunuz yönde çekim yapabilirsiniz. Bir mermi anlıktır ve duvara ya da uçağa çarpana kadar düz bir çizgide uçar.
Yön değiştirmenin yanı sıra 'şerit değiştirme' şeklini de dikkate alarak, bu, önünüzde ayrıca bazı çapraz, tek çizgiler halinde 3x3 satırlık bir sütunu tehdit edebileceğiniz anlamına gelir.
Bir uçağa çarparsa, bu uçak ölür ve derhal tahtadan kaybolur (çünkü tamamen patlar ya da bir şey). Mermiler en fazla yalnızca bir uçağa çarpabilir. Mermiler aynı anda vurulur, böylece iki uçak birbirini vurabilir. İki mermi havada olsa çarpışamaz (üzgünüm, biliyorum).
Bununla birlikte iki uçak çarpışabilir (aynı küpte sona ererse ve aynı düzlemde bitmeden birbirini geçerse DEĞİL) ve bu her iki uçağın da ölmesine (ve tamamen patlamaya) neden olabilir. Ayrıca uçağın söz konusu ölmesine ve hareketlerini düşünmek için köşeye konmasına neden olacak duvara uçabilirsiniz. Çarpışmalar çekim yapmadan önce ele alınır.
Denetleyiciyle iletişim
Java ve diğer dillerdeki girişleri kabul edeceğim. Girişiniz java içindeyse, STDIN aracılığıyla giriş alırsınız ve STDOUT aracılığıyla çıkar.
Girişiniz java içindeyse, girişiniz aşağıdaki sınıfı genişletmelidir:
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();
}
Bu sınıfın yarattığı örnek tüm yarışma boyunca devam eder, böylece değişkenlerde saklamak istediğiniz verileri saklayabilirsiniz. Daha fazla bilgi için koddaki yorumları okuyun.
Ayrıca size aşağıdaki yardımcı sınıfları sağladım:
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) {}
}
Bu sınıfların örneklerini oluşturabilir ve işlevlerinden herhangi birini istediğiniz kadar kullanabilirsiniz. Bu yardımcı sınıflar için tam kodu burada bulabilirsiniz .
İşte girişinizin nasıl görünebileceğine bir örnek (Umarım benden daha iyi yaparsınız, bu uçaklarla yapılan maçların çoğu duvardan kaçma çabalarına rağmen duvarda uçuyorlar.):
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 turnuvaya diğer girişlerle birlikte katılacak, bu nedenle en son bitirirseniz, en azından DumbPlanes'ten daha iyisini yapmamak sizin suçunuz.
Kısıtlamalar
KOTH wiki'de belirtilen kısıtlamalar geçerlidir:
- Denetleyiciyle, çalışma zamanıyla veya diğer gönderilerle bağlantı kurma girişimleri diskalifiye edilir. Tüm başvurular sadece verdikleri girdi ve depolama ile çalışmalıdır.
- Botlar, belirli diğer botları yenmek veya desteklemek için yazılmamalıdır. (Bu nadir durumlarda istenebilir, ancak bu zorluğun temel bir kavramı değilse, daha iyi göz ardı edilir.)
- Makul miktarda kaynakla denemeler yapmak için çok fazla zaman veya bellek kullanan gönderileri diskalifiye etme hakkını saklı tutarım.
- Bir bot, bilerek veya kazayla, mevcut olanla aynı stratejiyi uygulamamalıdır.
Gönderiminizi test etme
Controller kodunu buradan indirin . Gönderinizi Something.java olarak ekleyin. Düzleminiz için girişleri [] ve [] adlarına dahil etmek için Controller.java öğesini değiştirin. Her şeyi bir Eclipse projesi olarak veya ile derleyin javac -d . *.java
, sonra Controller'ı çalıştırın java Planes/Controller
. Yarışma günlüğü test.txt
sonunda bir çetele ile olacaktır . matchUp()
İki düzlemi de birbirine karşı sadece iki düzlemde test etmek için argüman olarak da çağırabilirsiniz .
Dövüşü kazanmak
Dövüşün galibi, en son uçağı uçan olandır, 100 turdan sonra hala 1 takımdan fazla kalanlar varsa, en fazla uçak kalan takım kazanır. Eğer bu eşitse, berabere biter.
Puanlama ve rekabet
Bir sonraki resmi turnuva, mevcut ödül tükendiğinde oynanacak.
Her giriş (en az) en az 100 kez birbirleriyle savaşacak, her maçın galibi 100'den en fazla kazananlar ve 2 puan kazanacaksınız. Çekiliş durumunda, her iki girişe 1 puan verilir.
Yarışmanın galibi en çok puan alan yarışmacı. Çekiliş halinde kazanan, çizilen kayıtlar arasında bir maçta kazanandır.
Girişlerin sayısına bağlı olarak, Girişler arasındaki dövüşlerin miktarı önemli ölçüde artabilir, ilk turnuvadan sonra 2-4 en iyi girişi seçebilirim ve daha fazla dövüşe sahip girişimler arasında elit bir turnuva ayarlayabilirim (ve muhtemelen daha fazla tur). kavga)
(ön) Skor tahtası
Yine heyecan verici bir turnuvada ikinci sırada yer alan yeni bir girişimiz var , Crossfire gibi PredictAndAvoid hariç herkes için fotoğraf çekmek zor. Bu turnuvanın her uçak kümesi arasında yalnızca 10 kavga ile yapıldığını ve bunun nasıl gerçekleştiğinin tamamen doğru bir sunumunun olmadığını unutmayın.
----------------------------
¦ 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 dışı sargının çıktılarına bir örnek:
NEW CONTEST 14 20
14x14x14 arenada yeni bir yarışmanın başladığını ve dövüş başına 20 tur içereceğini gösteriyor.
NEW OPPONENT 10
yeni bir rakiple karşı karşıya olduğunu ve bu rakiple 10 kez mücadele edeceğini gösterir.
NEW FIGHT 5 3 2
mevcut rakibe karşı yeni bir mücadelenin başladığını, bu rakibe şimdiye kadar 5 kez savaştığını, 3 kazanarak ve 2 kavga kaybettiklerini gösteriyor
ROUNDS LEFT 19
mevcut savaşta 19 tur kaldığını gösteriyor
NEW TURN
Dövüşün bu turu için dört uçağın tümünde veri almak üzere olduğunuzu gösterir.
alive 13 8 13 N 0
alive 13 5 13 N 0
dead 0 0 0 N 0
alive 0 8 0 S 0
Bu dört satır, her iki uçağınızın da canlı olduğunu, sırasıyla [13,8,13] ve [13,5,13] koordinatlarında, her ikisinin de sıfır bekleme süresi olan Kuzeye dönük olduğunu gösterir. İlk düşman uçağı öldü, ikincisi ise canlı, [0,8,0] 'da ve sıfır bekleme süresiyle güneye bakıyor.
Bu noktada, programınız aşağıdakine benzer iki satır çıkmalıdır:
NW 0 1
SU 1 0
Bu, ilk uçağınızın geçerli yönünden dönmeden ve mümkün olduğunda çekim yapmadan Kuzeybatı'ya gideceğini gösterir. İkinci uçağınız SouthUp'a doğru ilerliyor, çekim yapmıyor, SouthUp'a bakıyor.
Şimdi ROUNDS LEFT 18
bunu NEW TURN
vb. Takip edersiniz . Bu, birisi kazanana veya raunt zaman aşımına uğrayana kadar devam eder, bu noktada NEW FIGHT
, önce a ile gösterilen güncellenmiş dövüş sayısı ve skorlarıyla başka bir çizgi alırsınız NEW OPPONENT
.