UPDATE: isSuicidal () telah ditambahkan ke kelas pesawat, ini memungkinkan Anda untuk memeriksa apakah sebuah pesawat berada di jalur tabrakan yang tidak dapat diubah dengan dinding !!
UPDATE: updateCoolDown () dipisahkan dari simulateMove ()
PEMBARUAN: pembungkus entri non-Jawa, ditulis oleh Sparr , tersedia untuk pengujian, lihat komentar
UPDATE Zove Games Telah menulis visualisator 3D yang mengagumkan untuk KOTH ini, berikut adalah video youtube buruk dari PredictAndAVoid yang memerangi PredictAndAVoid.
Fungsi simulateMove () dari kelas Plane sedikit dimodifikasi sehingga tidak memperbarui pendinginan lagi, gunakan fungsi updateCoolDown () baru untuk itu, setelah pemotretan. IsSuicidal () yang baru mengembalikan true jika sebuah pesawat pasti akan mati, menggunakannya untuk memangkas pergerakan musuh dan menghindari menabrak tembok. Untuk mendapatkan kode yang diperbarui, cukup ganti kelas Controller dan Plane dengan yang ada di repo github.
Deskripsi
Tujuan dari tantangan ini adalah untuk mengkodekan dua pesawat dogfighting yang akan berhadapan dengan dua pesawat oleh kontestan lain. Setiap belokan Anda bergerak satu ruang dan memiliki kesempatan untuk menembak. Itu dia, sesederhana itu.
Hampir saja...
Arena dan kemungkinan gerakan
Arena adalah 14x14x14 berdinding di ruang angkasa. pesawat dari kontestan 1 mulai di lokasi (0,5,0) dan (0,8,0) dan di kontestan 2 di (13,5,13) dan (13,8,13). Semua pesawat memulai dengan terbang secara horizontal menjauh dari dinding vertikal yang paling dekat dengannya.
Sekarang karena Anda menerbangkan pesawat dan bukan helikopter, Anda tidak bisa hanya mengubah arah sesuka hati atau bahkan berhenti bergerak, sehingga setiap pesawat memiliki arah dan akan memindahkan satu ubin ke arah itu setiap belokan.
Arah yang mungkin adalah: Utara (N), Selatan (S), Timur (E), Barat (W), Atas (U) dan Bawah (D) dan kombinasi logis dari keenam itu. Dimana sumbu NS berhubungan dengan sumbu x, WE ke y dan DU ke z. NW, SU dan NED muncul dalam pikiran sebagai contoh kemungkinan arah; UD adalah contoh bagus kombinasi yang tidak valid.
Anda tentu saja dapat mengubah arah pesawat Anda, tetapi ada batasannya, Anda hanya dapat mengubah arah Anda paling banyak 45 derajat. Untuk memvisualisasikan ini, ambil kubus rubik Anda (saya tahu Anda punya satu) dan bayangkan semua 26 kubus kecil luar adalah arah yang mungkin (satu arah huruf adalah wajah, dua arah huruf adalah tepi dan tiga arah huruf adalah sudut). Jika Anda menuju ke arah yang diwakili oleh kubus kecil, Anda dapat mengubah arah ke setiap kubus yang menyentuh milik Anda (menyentuh angka secara diagonal, tetapi hanya menyentuh secara kasat mata, yang tidak menyentuh kubus).
Setelah semua pesawat menunjukkan ke arah mana mereka ingin berubah, mereka melakukannya dan memindahkan satu ubin secara bersamaan.
Anda juga dapat memilih untuk bergerak ke arah yang valid tetapi tetap terbang ke arah yang Anda tuju, sebagai gantinya mengubah arah Anda ke arah yang Anda pindahkan. Ini analog dengan perbedaan antara mobil yang melaju di tikungan dan jalur ganti mobil.
Menembak dan sekarat
Anda dapat menembak paling banyak sekali per putaran dan ini harus diputuskan pada saat yang sama Anda memutuskan ke arah mana untuk terbang dan apakah Anda ingin menjaga pesawat Anda (dan dengan ekstensi, pistol Anda) menunjuk ke arah yang sama atau tidak. Peluru ditembak tepat setelah pesawat Anda bergerak. Ada pendinginan satu putaran setelah memotret, pada putaran ketiga, Anda baik untuk pergi lagi. Anda hanya bisa menembak ke arah yang Anda terbangi. Peluru itu instan dan terbang dalam garis lurus hingga menyentuh dinding atau pesawat.
Mempertimbangkan cara Anda dapat mengubah arah dan juga 'mengubah jalur', ini berarti bahwa Anda dapat mengancam sebuah kolom hingga 3x3 baris di depan Anda di samping beberapa garis tunggal diagonal.
Jika menabrak pesawat, pesawat ini mati dan segera menghilang dari papan (karena benar-benar meledak atau apa). Peluru hanya bisa mengenai satu pesawat paling banyak. Peluru ditembak secara bersamaan, sehingga dua pesawat bisa saling menembak. Dua peluru tidak bisa bertabrakan di udara (sedih, saya tahu).
Namun dua pesawat dapat bertabrakan (jika mereka berakhir di kubus yang sama dan BUKAN jika mereka saling bersilangan tanpa berakhir di pesawat yang sama), dan ini mengakibatkan kedua pesawat sekarat (dan benar-benar meledak). Anda juga dapat terbang ke dinding yang akan mengakibatkan pesawat dalam pertanyaan sekarat dan diletakkan di sudut untuk memikirkan tindakannya. Tabrakan ditangani sebelum menembak.
Komunikasi dengan pengontrol
Saya akan menerima entri dalam java dan juga bahasa lain. Jika entri Anda ada di java, Anda akan mendapatkan input melalui STDIN dan akan menampilkan melalui STDOUT.
Jika entri Anda di java, entri Anda harus memperluas kelas berikut:
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();
}
Mesin virtual yang dibuat dari kelas itu akan bertahan sepanjang seluruh kompetisi, sehingga Anda dapat menyimpan data apa pun yang ingin Anda simpan dalam variabel. Baca komentar dalam kode untuk informasi lebih lanjut.
Saya juga memberi Anda kelas pembantu berikut:
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) {}
}
Anda dapat membuat instance dari kelas-kelas ini dan menggunakan salah satu fungsinya sebanyak yang Anda suka. Anda dapat menemukan kode lengkap untuk kelas pembantu ini di sini .
Berikut ini contoh tampilan entri Anda (Mudah-mudahan Anda akan melakukan lebih baik daripada yang saya lakukan, sebagian besar pertandingan dengan pesawat ini berakhir dengan mereka terbang ke dinding, meskipun upaya terbaik mereka untuk menghindari dinding.):
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 akan bergabung dengan turnamen bersama dengan entri lainnya, jadi jika Anda berakhir terakhir, itu adalah kesalahan Anda sendiri karena tidak setidaknya melakukan lebih baik daripada DumbPlanes.
Batasan
Batasan yang disebutkan dalam wiki KOTH berlaku:
- Setiap upaya untuk mengutak-atik controller, runtime, atau kiriman lainnya akan didiskualifikasi. Semua pengiriman hanya dapat bekerja dengan input dan penyimpanan yang diberikan.
- Bot tidak boleh ditulis untuk mengalahkan atau mendukung bot lain yang spesifik. (Ini mungkin diinginkan dalam kasus yang jarang terjadi, tetapi jika ini bukan konsep inti dari tantangan, itu lebih baik disingkirkan.)
- Saya berhak untuk mendiskualifikasi pengiriman yang menggunakan terlalu banyak waktu atau memori untuk menjalankan uji coba dengan sumber daya yang masuk akal.
- Bot tidak boleh menerapkan strategi yang sama persis dengan yang sudah ada, sengaja atau tidak sengaja.
Menguji kiriman Anda
Unduh kode Pengendali dari sini . Tambahkan kiriman Anda sebagai Something.java. Ubah Controller.java untuk memasukkan entri untuk pesawat Anda dalam entri [] dan nama []. Kompilasi semuanya sebagai proyek Eclipse atau dengan javac -d . *.java
, lalu jalankan Controller dengan java Planes/Controller
. Log kontes akan berada di test.txt
, dengan papan skor di akhir. Anda juga dapat menelepon matchUp()
langsung dengan dua entri sebagai argumen untuk hanya menguji dua pesawat terhadap satu sama lain.
Memenangkan pertarungan
Pemenang pertarungan adalah orang yang memiliki pesawat terakhir yang terbang, jika setelah 100 putaran, masih ada lebih dari 1 tim yang tersisa, tim dengan pesawat terbanyak yang menang. Jika ini sama, itu seri.
Penilaian dan kompetisi
Turnamen resmi berikutnya akan berjalan ketika hadiah saat ini habis.
Setiap entri akan memperjuangkan setiap entri lainnya (setidaknya) 100 kali, pemenang setiap pertandingan adalah yang dengan kemenangan terbanyak dari 100 dan akan diberikan 2 poin. Dalam hal pengundian, kedua entri diberikan 1 poin.
Pemenang kompetisi adalah yang paling banyak poin. Dalam hal pengundian, pemenangnya adalah orang yang menang dalam pertandingan di antara entri yang diundi.
Tergantung pada jumlah entri, Jumlah perkelahian antar entri dapat meningkat secara signifikan, saya mungkin juga memilih 2-4 entri terbaik setelah turnamen pertama dan mengatur turnamen elit antara entri tersebut dengan lebih banyak pertarungan (dan mungkin lebih banyak putaran per pertarungan)
(pendahuluan) Papan Skor
Kami memiliki entri baru yang dengan kuat mengambil posisi kedua di turnamen menarik lainnya , sepertinya Crossfire sangat sulit untuk ditembak untuk semua orang kecuali untuk PredictAndAvoid. Perhatikan bahwa turnamen ini dijalankan dengan hanya 10 pertarungan antara setiap set pesawat dan karenanya tidak ada representasi yang sepenuhnya akurat tentang bagaimana keadaan.
----------------------------
¦ 1. PredictAndAvoid: 14 ¦
¦ 2. Crossfire: 11 ¦
¦ 3. Weeeeeeeeeeee: 9 ¦
¦ 4. Whirligig: 8 ¦
¦ 4. MoveAndShootPlane: 8 ¦
¦ 6. StarFox: 4 ¦
¦ 6. EmoFockeWulf: 2 ¦
¦ 7. DumbPlanes: 0 ¦
----------------------------
Berikut adalah contoh output dari pembungkus non-Jawa:
NEW CONTEST 14 20
menunjukkan bahwa kontes baru akan dimulai, di arena 14x14x14, dan itu akan melibatkan 20 putaran per pertandingan.
NEW OPPONENT 10
menunjukkan bahwa Anda menghadapi lawan baru, dan bahwa Anda akan melawan lawan ini 10 kali
NEW FIGHT 5 3 2
menunjukkan bahwa pertarungan baru melawan lawan saat ini mulai, bahwa Anda telah bertarung lawan ini 5 kali sejauh ini, menang 3 dan kalah 2 perkelahian
ROUNDS LEFT 19
menunjukkan ada 19 putaran tersisa dalam pertarungan saat ini
NEW TURN
menunjukkan bahwa Anda akan menerima data untuk keempat pesawat untuk ronde pertarungan ini
alive 13 8 13 N 0
alive 13 5 13 N 0
dead 0 0 0 N 0
alive 0 8 0 S 0
Keempat garis ini menunjukkan bahwa kedua pesawat Anda masih hidup, masing-masing pada koordinat [13,8,13] dan [13,5,13], keduanya menghadap ke Utara, keduanya dengan cooldown nol. Pesawat musuh pertama sudah mati, dan yang kedua masih hidup, pada [0,8,0] dan menghadap ke selatan dengan nol cooldown.
Pada titik ini program Anda harus menampilkan dua baris yang mirip dengan yang berikut:
NW 0 1
SU 1 0
Ini menunjukkan bahwa pesawat pertama Anda akan melakukan perjalanan ke NorthWest, tanpa berbalik dari posisinya saat ini, dan memotret jika mampu. Pesawat kedua Anda akan melakukan perjalanan SouthUp, berbalik menghadap SouthUp, bukan menembak.
Sekarang Anda ROUNDS LEFT 18
diikuti oleh NEW TURN
dll. Ini berlanjut sampai seseorang menang atau ronde habis, pada titik mana Anda mendapatkan NEW FIGHT
garis lain dengan jumlah dan skor pertarungan yang diperbarui, mungkin didahului oleh a NEW OPPONENT
.
sumber
Jawaban:
Baku tembak
Ide awal saya adalah untuk menembak pesawat musuh dengan kedua pesawat saya pada saat yang sama, tetapi saya tidak bisa menyelesaikannya ... Jadi di sini adalah pesawat yang mencoba untuk menjauh dari dinding dan keluar dari jangkauan tembak dari musuh. Pesawat tidak boleh bertabrakan atau menembak pesawat yang ramah.
Sunting: metode ini
possibleHits
selalu mengembalikan 0, setelah memperbaikinya dan menambahkan beberapa perbaikan kecil, kinerjanya lebih baik dari sebelumnya.sumber
sumber
Dogfight 3D Visualizer
Saya menulis visualisasi kecil dan cepat untuk tantangan ini. File kode dan jar ada di repo github saya: https://github.com/Hungary-Dude/DogfightVisualizer
Dibuat menggunakan libGDX ( http://libgdx.com ). Saat ini UI sangat buruk, saya melakukan ini dengan cepat.
Saya baru belajar cara menggunakan Git dan Gradle jadi tolong beri komentar jika saya melakukan kesalahan
Menjalankan
dist/dogfight.bat
ataudist/dogfight.sh
untuk melihat DumbPlanes beraksi!Untuk membangun dari sumber, Anda memerlukan Gradle ( http://gradle.org ) dan integrasi Gradle untuk IDE Anda, jika Anda memilikinya. Kemudian klon repo dan jalankan
gradlew desktop:run
. Semoga Gradle akan mengimpor semua perpustakaan yang diperlukan. Kelas utamanya adalahzove.koth.dogfight.desktop.DesktopLauncher
.Berjalan tanpa mengimpor
Salin semua file kelas pesawat ke
dist/
. Kemudian, jalankandist/desktop-1.0.jar
dengan perintah ini:Saya akan memperbarui karena sumber untuk pengontrol Planes diperbarui, tetapi untuk memperbarui diri Anda, Anda perlu menambahkan beberapa kode
Planes.Controller
. Lihat github readme untuk info tentang ini.Berikut screenshotnya:
Jika Anda memiliki pertanyaan atau saran, tinggalkan komentar di bawah ini!
sumber
plane.transform.setToTranslation(new Vector3(point3d.x-6.5f,point3d.y-6.5f,point3d.z-6.5f))
Tidak ada pesawat tampaknya keluar dari batas jadi saya ragu ada sesuatu yang salahEmoFockeWulf
Dia kembali. Dia membuat dirinya kelaparan hingga 224 byte. Dia tidak tahu bagaimana akhirnya dia seperti ini.
sumber
Weeeeeeeeeeee - 344 byte setelah menghapus spasi putih
Apakah loop mengagumkan dan hal-hal. Tidak dapat kehilangan jika Anda melakukan loop.
EDIT: ternyata ketika pesawat saya mulai sebagai tim 2, mereka langsung menabrak dinding. Saya pikir saya sudah memperbaikinya sekarang. Semoga.
sumber
new Type[]{item1, item2, ...}
dalam hal ini yang Anda milikireturn new Move[]{new Move(d,z,a),new Move(d,z,a^=z)};
Pindahkan-dan-Tembak pesawat
Menghindari dinding dengan mencari ketika itu dekat dengan dinding & berputar, menembak ketika itu bisa.
Penafian: Saya sama sekali bukan programmer Java, jadi jika saya mengacaukan semuanya, perbaiki untuk saya!
sumber
you may only change your angle by 45 degrees
sedikit.new Direction(wayToGo.get(currentDirection))
tidak akan berfungsi karena lupa dilemparkan ke String. wayToGo.put setelah bidang juga tidak valid, letakkan di blok {wayToGo.put (blah); blah;} atau di konstruktor.Komidi putar
Kedua pesawat mengarah ke tengah (ish), lalu putar sambil menembak sesering mungkin. Satu dari tiga sumbu dipilih per pertarungan, dan pasangan selalu berputar di sekitar sumbu yang sama dalam arah yang berlawanan.
sumber
DumbPlanes
DumbPlanes berusaha sangat keras untuk tidak terbang ke dinding, tetapi mereka tidak terlalu pintar tentang hal itu dan biasanya akhirnya menabrak dinding. Mereka juga menembak sesekali, kalau saja mereka tahu apa yang mereka tembak.
sumber
Starfox (WIP - belum berfungsi):
Dia tidak benar-benar memanfaatkan semua gerakan yang tersedia. Tapi dia memang mencoba menembak jatuh musuh dan tidak menabrak tembok.
sumber
Bahaya
Ditulis dengan Python dan antarmuka dengan pembungkus kode non-Jawa yang ditulis oleh Sparr.
Apakah semua matematika dengan Python murni dan sepenuhnya tidak dioptimalkan. Agak lambat.
Sangat dapat dikonfigurasi dan diperluas.
Sangat baik terhadap pengiriman sebelumnya. Menang 2: 1 untuk setiap orang yang kalah
Crossfire
atauPredictAndAvoid
, dan menang 98% dari semua pertarungan melawan pesaing lainnya.Termasuk alat visualisasi opsional sendiri:
Berjuang
Crossfire
/PredictAndAvoid
, dengan peringkat zona bahaya eponymous divisualisasikan dalam volume sekitarnya:Divisualisasikan menggunakan
nipy_spectral
Divisualisasikan colourmap darimatplotlib
. Koordinat yang lebih berbahaya ditampilkan menggunakan warna yang mendekati merah / putih dalam spektrum elektromagnetik, dan digambar dengan titik-titik yang lebih besar.Bahaya: Biru <Hijau <Kuning <Merah <Abu-abu Cerah
Kinerja:
1000 putaran dengan delapan algoritma lainnya di papan peringkat:
Kode:
sumber