Wrapper untuk Kiriman Non-Jawa
CATATAN Dukungan MAP_SIZE telah ditambahkan. Jika Anda peduli, harap perbarui kiriman Anda.
Ini adalah entri wiki komunitas untuk pembungkus, dapat digunakan oleh mereka yang ingin bermain tetapi tidak suka / tidak tahu Java. Silakan gunakan, bersenang-senang, dan saya senang membantu Anda menyiapkan berbagai hal.
Sudah cukup terlambat di sini karena saya selesai, jadi coders Java lainnya, silakan lihat ini dan sarankan perbaikan. Jika Anda bisa, lakukan melalui repositori github saya dengan mengajukan masalah atau mengirimkan tambalan. Terima kasih!
Seluruh ini sedang didistribusikan dengan UNLICENSE, silakan ikuti / fork dari repositori github-nya . Kirim tambalan di sana jika Anda menemukan masalah dan saya akan memperbarui pos ini.
Contoh Saat Ini dari Pembungkus Digunakan
plannapus : WolfCollectiveMemory di R
sikat gigi : Sikat gigi dalam ECMAScript
Cara Penggunaan
Berikut ini adalah instruksi pada protokol untuk-proses komunikasi antar melalui PIPA yang telah saya tetapkan untuk Serigala jarak jauh. Catatan Saya telah melewatkan MAP_SIZE karena ini tampaknya tidak ada, terlepas dari keberadaannya dalam pernyataan masalah OP. Jika muncul, saya akan memperbarui posting ini.
CATATAN PENTING :
- Hanya satu permintaan tunggal dari proses eksternal Anda yang akan dibuat (jadi bungkus logika pemrosesan Anda dalam loop tak terbatas. Ini juga memungkinkan Anda menyimpan setiap pemrosesan dalam memori, alih-alih menggunakan disk)
- Semua komunikasi adalah proses eksternal tunggal ini melalui STDIN dan STDOUT
- Anda harus secara eksplisit menyiram semua output yang dikirim ke STDOUT, dan pastikan itu diakhiri oleh baris baru
Spesifikasi
Skrip jarak jauh didukung oleh protokol sederhana melalui kait STDIN dan STDOUT, dan dibagi menjadi inisialisasi, Pindah, dan Serang. Dalam setiap kasus komunikasi dengan proses Anda akan melalui STDIN, dan balasan diperlukan dari STDOUT. Jika balasan tidak diterima dalam 1 detik, proses Anda akan dianggap sudah mati dan pengecualian akan dilemparkan. Semua karakter akan dikodekan dalam UTF-8, untuk konsistensi. Setiap input akan diakhiri dengan karakter baris baru, dan proses Anda harus mengakhiri setiap balasan keluaran dengan baris baru juga.
PERINGATAN Pastikan untuk menyiram buffer output Anda setelah setiap penulisan, untuk memastikan pembungkus Java melihat output Anda. Gagal memerah dapat menyebabkan Serigala jarak jauh Anda gagal.
Perhatikan bahwa hanya satu proses yang akan dibuat, semua Wolves harus dikelola dalam satu proses itu. Baca terus bagaimana spec ini akan membantu.
Inisialisasi
STDIN: S<id><mapsize>
\ n
STDOUT: K<id>
\ n
<id>
: 00
atau 01
atau ... atau99
Penjelasan:
Karakter S
akan dikirim diikuti oleh dua karakter numerik 00
, 01
, ..., 99
yang menunjukkan dari 100 serigala sedang diinisialisasi. Dalam semua komunikasi di masa depan dengan serigala khusus itu, hal yang sama <id>
akan digunakan.
Setelah ID, urutan panjang variabel karakter numerik akan dikirim. Ini ukuran peta. Anda akan tahu urutan karakter numerik selesai ketika Anda mencapai baris baru ( \n
).
Untuk memastikan proses Anda hidup, Anda harus membalas dengan karakter K
diikuti oleh yang sama yang <id>
Anda terima. Balasan lain akan menghasilkan pengecualian, membunuh serigala Anda.
Gerakan
STDIN: M<id><C0><C1>...<C7><C8>
\ n
STDOUT: <mv><id>
\ n
<Cn>
: W
Atau
atau B
atau S
atauL
W
: Serigala
: Ruang Kosong
B
: Beruang
S
: Batu
L
: Singa
<mv>
: H
Atau U
atau L
atau R
atauD
H
: Pindah. TETAP
U
: Move.UP
L
: Move.LEFT
R
: Pindah. BENAR
D
: Pindah. DOWN
Penjelasan:
Karakter M
akan dikirim diikuti oleh dua karakter <id>
untuk menunjukkan Serigala mana yang perlu memilih langkah. Setelah itu, 9 karakter akan dikirim mewakili sekeliling Wolf, dalam urutan baris (baris atas, baris tengah, baris bawah dari kiri ke kanan).
Balas dengan salah satu karakter gerakan yang valid <mv>
, diikuti oleh dua digit Wolf <id>
untuk konfirmasi.
Menyerang
STDIN: A<id><C>
\ n
STDOUT: <atk><id>
\ n
<C>
: W
Atau B
atau S
atauL
<atk>
: R
Atau P
atau S
atauD
R
: Attack.ROCK
P
: Attack.PAPER
S
: Attack. SCISSORS
D
: Attack.SUICIDE
Penjelasan:
Karakter A
akan dikirim diikuti oleh dua karakter <id>
untuk menunjukkan Wolf mana yang berpartisipasi dalam serangan. Ini diikuti oleh satu karakter yang <C>
menunjukkan jenis hal yang menyerang, baik W
olf, B
telinga, S
nada, atau L
ion.
Balas dengan salah satu <atk>
karakter yang tercantum di atas, yang menunjukkan apa tanggapan Anda terhadap serangan itu, diikuti oleh dua digit <id>
untuk konfirmasi.
Dan itu saja. Tidak ada lagi untuk itu. Jika Anda kehilangan serangan, itu <id>
tidak akan pernah dikirim ke proses Anda lagi, itulah bagaimana Anda akan tahu Serigala Anda telah mati - jika putaran Pergerakan lengkap telah berlalu tanpa itu <id>
pernah dikirim.
Kesimpulan
Perhatikan bahwa pengecualian apa pun akan membunuh semua Serigala dari jenis jarak jauh Anda, karena hanya satu "Proses" yang dibuat dari serigala jarak jauh Anda, untuk semua serigala jenis Anda yang dibuat.
Dalam repositori ini Anda akan menemukan Wolf.java
file. Cari dan ganti string berikut untuk mengatur bot Anda:
Ganti <invocation>
dengan argumen baris perintah yang akan menjalankan proses Anda dengan benar.
Ganti <custom-name>
dengan nama unik untuk Wolf Anda.
Sebagai contoh, lihat repositori , di mana saya memiliki WolfRandomPython.java
yang memanggil remote contoh saya, PythonWolf.py
(a Python 3+ Wolf).
Ubah nama file menjadi Wolf<custom-name>.java
, di mana <custom-name>
diganti dengan nama yang Anda pilih di atas.
Untuk menguji Wolf Anda, kompilasi program Java ( javac Wolf<custom-name>.java
), dan ikuti instruksi Rusher untuk memasukkannya dalam program simulasi.
Penting: Pastikan untuk memberikan instruksi yang jelas dan ringkas tentang cara mengkompilasi / mengeksekusi Wolf Anda yang sebenarnya, yang mengikuti skema yang telah saya uraikan di atas.
Semoga berhasil, dan semoga alam selalu menguntungkan Anda.
Kode Pembungkus
Ingat, Anda HARUS melakukan pencarian dan mengganti yang digariskan agar ini berfungsi. Jika permohonan Anda sangat berbulu, silakan hubungi saya untuk bantuan.
Perhatikan ada main
metode dalam pembungkus ini, untuk memungkinkan pengujian "lulus / gagal" yang belum sempurna pada kotak lokal Anda. Untuk melakukannya, unduh kelas Animal.java dari proyek, dan hapus package animals;
baris dari kedua file. Ganti baris MAP_SIZE di Animal.java dengan konstanta (seperti 100). Kompilasi mereka menggunakan javac Wolf<custom-name>.java
eksekusi via java Wolf<custom-name>
.
package animals;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Remote Wolf<custom-name> wrapper class.
*/
public class Wolf<custom-name> extends Animal {
/**
* Simple test script that sends some typical commands to the
* remote process.
*/
public static void main(String[]args){
Wolf<custom-name>[] wolves = new Wolf<custom-name>[100];
for(int i=0; i<10; i++) {
wolves[i] = new Wolf<custom-name>();
}
char map[][] = new char[3][3];
for (int i=0;i<9;i++)
map[i/3][i%3]=' ';
map[1][1] = 'W';
for(int i=0; i<10; i++) {
wolves[i].surroundings=map;
System.out.println(wolves[i].move());
}
for(int i=0; i<10; i++) {
System.out.println(wolves[i].fight('S'));
System.out.println(wolves[i].fight('B'));
System.out.println(wolves[i].fight('L'));
System.out.println(wolves[i].fight('W'));
}
wolfProcess.endProcess();
}
private static WolfProcess wolfProcess = null;
private static Wolf<custom-name>[] wolves = new Wolf<custom-name>[100];
private static int nWolves = 0;
private boolean isDead;
private int id;
/**
* Sets up a remote process wolf. Note the static components. Only
* a single process is generated for all Wolves of this type, new
* wolves are "initialized" within the remote process, which is
* maintained alongside the primary process.
* Note this implementation makes heavy use of threads.
*/
public Wolf<custom-name>() {
super('W');
if (Wolf<custom-name>.wolfProcess == null) {
Wolf<custom-name>.wolfProcess = new WolfProcess();
Wolf<custom-name>.wolfProcess.start();
}
if (Wolf<custom-name>.wolfProcess.initWolf(Wolf<custom-name>.nWolves, MAP_SIZE)) {
this.id = Wolf<custom-name>.nWolves;
this.isDead = false;
Wolf<custom-name>.wolves[id] = this;
} else {
Wolf<custom-name>.wolfProcess.endProcess();
this.isDead = true;
}
Wolf<custom-name>.nWolves++;
}
/**
* If the wolf is dead, or all the wolves of this type are dead, SUICIDE.
* Otherwise, communicate an attack to the remote process and return
* its attack choice.
*/
@Override
public Attack fight(char opponent) {
if (!Wolf<custom-name>.wolfProcess.getRunning() || isDead) {
return Attack.SUICIDE;
}
try {
Attack atk = Wolf<custom-name>.wolfProcess.fight(id, opponent);
if (atk == Attack.SUICIDE) {
this.isDead = true;
}
return atk;
} catch (Exception e) {
System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
isDead = true;
return Attack.SUICIDE;
}
}
/**
* If the wolf is dead, or all the wolves of this type are dead, HOLD.
* Otherwise, get a move from the remote process and return that.
*/
@Override
public Move move() {
if (!Wolf<custom-name>.wolfProcess.getRunning() || isDead) {
return Move.HOLD;
}
try {
Move mv = Wolf<custom-name>.wolfProcess.move(id, surroundings);
return mv;
} catch (Exception e) {
System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
isDead = true;
return Move.HOLD;
}
}
/**
* The shared static process manager, that synchronizes all communication
* with the remote process.
*/
static class WolfProcess extends Thread {
private Process process;
private BufferedReader reader;
private PrintWriter writer;
private ExecutorService executor;
private boolean running;
public boolean getRunning() {
return running;
}
public WolfProcess() {
process = null;
reader = null;
writer = null;
running = true;
executor = Executors.newFixedThreadPool(1);
}
public void endProcess() {
running = false;
}
/**
* WolfProcess thread body. Keeps the remote connection alive.
*/
public void run() {
try {
System.out.println("Starting Wolf<custom-name> remote process");
ProcessBuilder pb = new ProcessBuilder("<invocation>".split(" "));
pb.redirectErrorStream(true);
process = pb.start();
System.out.println("Wolf<custom-name> process begun");
// STDOUT of the process.
reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
System.out.println("Wolf<custom-name> reader stream grabbed");
// STDIN of the process.
writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
System.out.println("Wolf<custom-name> writer stream grabbed");
while(running){
this.sleep(0);
}
reader.close();
writer.close();
process.destroy(); // kill it with fire.
executor.shutdownNow();
} catch (Exception e) {
e.printStackTrace();
System.out.println("Wolf<custom-name> ended catastrophically.");
}
}
/**
* Helper that invokes a read with a timeout
*/
private String getReply(long timeout) throws TimeoutException, ExecutionException, InterruptedException{
Callable<String> readTask = new Callable<String>() {
@Override
public String call() throws Exception {
return reader.readLine();
}
};
Future<String> future = executor.submit(readTask);
return future.get(timeout, TimeUnit.MILLISECONDS);
}
/**
* Sends an initialization command to the remote process
*/
public synchronized boolean initWolf(int wolf, int map_sz) {
while(writer == null){
try {
this.sleep(0);
}catch(Exception e){}
}
boolean success = false;
try{
writer.printf("S%02d%d\n", wolf, map_sz);
writer.flush();
String reply = getReply(5000l);
if (reply != null && reply.length() >= 3 && reply.charAt(0) == 'K') {
int id = Integer.valueOf(reply.substring(1));
if (wolf == id) {
success = true;
}
}
if (reply == null) {
System.out.println("did not get reply");
}
} catch (TimeoutException ie) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to initialize, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to initialize, %s\n", wolf, e.getMessage());
}
return success;
}
/**
* Send an ATTACK command to the remote process.
*/
public synchronized Attack fight(int wolf, char opponent) {
Attack atk = Attack.SUICIDE;
try{
writer.printf("A%02d%c\n", wolf, opponent);
writer.flush();
String reply = getReply(1000l);
if (reply.length() >= 3) {
int id = Integer.valueOf(reply.substring(1));
if (wolf == id) {
switch(reply.charAt(0)) {
case 'R':
atk = Attack.ROCK;
break;
case 'P':
atk = Attack.PAPER;
break;
case 'S':
atk = Attack.SCISSORS;
break;
case 'D':
atk = Attack.SUICIDE;
break;
}
}
}
} catch (TimeoutException ie) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to attack, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to attack, %s\n", wolf, e.getMessage());
}
return atk;
}
/**
* Send a MOVE command to the remote process.
*/
public synchronized Move move(int wolf, char[][] map) {
Move move = Move.HOLD;
try{
writer.printf("M%02d", wolf);
for (int row=0; row<map.length; row++) {
for (int col=0; col<map[row].length; col++) {
writer.printf("%c", map[row][col]);
}
}
writer.print("\n");
writer.flush();
String reply = getReply(1000l);
if (reply.length() >= 3) {
int id = Integer.valueOf(reply.substring(1));
if (wolf == id) {
switch(reply.charAt(0)) {
case 'H':
move = Move.HOLD;
break;
case 'U':
move = Move.UP;
break;
case 'L':
move = Move.LEFT;
break;
case 'R':
move = Move.RIGHT;
break;
case 'D':
move = Move.DOWN;
break;
}
}
}
} catch (TimeoutException ie) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to move, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to move, %s\n", wolf, e.getMessage());
}
return move;
}
}
}