Wrapper cho đệ trình không phải Java
LƯU Ý Hỗ trợ MAP_SIZE đã được thêm vào. Nếu bạn quan tâm, xin vui lòng cập nhật trình của bạn cho phù hợp.
Đây là mục wiki cộng đồng dành cho trình bao bọc, có thể sử dụng được bởi những người muốn chơi nhưng không thích / không biết Java. Vui lòng sử dụng nó, vui chơi và tôi rất vui khi được giúp bạn thiết lập mọi thứ.
Ở đây khá muộn vì tôi đang hoàn thiện, vì vậy các lập trình viên Java khác, vui lòng xem qua và đề xuất cải tiến. Nếu bạn có thể, hãy làm như vậy thông qua kho github của tôi bằng cách gửi một vấn đề hoặc gửi một bản vá. Cảm ơn!
Toàn bộ phần này đang được phân phối với UNLICENSE, vui lòng theo dõi / fork nó từ kho lưu trữ github của nó . Gửi các bản vá ở đó nếu bạn tìm thấy vấn đề và tôi sẽ cập nhật bài viết này.
Ví dụ hiện tại của Wrapper đang sử dụng
plannapus : WolfCollectiveMemory in R
bàn chải đánh răng : Bàn chải đánh răng trong ECMAScript
Cách sử dụng
Điều gì sau đây là các hướng dẫn về giao thức liên lạc cho quá trình giao tiếp qua PIPES mà tôi đã xác định cho Chó sói từ xa. Lưu ý Tôi đã bỏ qua MAP_SIZE vì điều này dường như không tồn tại, bất chấp sự hiện diện của nó trong tuyên bố vấn đề của OP. Nếu nó xuất hiện, tôi sẽ cập nhật bài viết này.
THÔNG BÁO QUAN TRỌNG :
- Chỉ một lệnh gọi duy nhất của quy trình bên ngoài của bạn sẽ được thực hiện (vì vậy hãy bọc logic xử lý của bạn trong một vòng lặp vô hạn. Điều này cũng cho phép bạn giữ bất kỳ xử lý nào trong bộ nhớ, thay vì sử dụng đĩa)
- Tất cả thông tin liên lạc đến quy trình bên ngoài duy nhất này thông qua STDIN và STDOUT
- Bạn phải xóa hoàn toàn tất cả đầu ra được gửi tới STDOUT và đảm bảo rằng nó được kết thúc bằng dòng mới
Đặc điểm kỹ thuật
Các tập lệnh từ xa được hỗ trợ bởi một giao thức đơn giản thông qua các móc STDIN và STDOUT, và được chia thành khởi tạo, Di chuyển và Tấn công. Trong mỗi trường hợp, giao tiếp với quy trình của bạn sẽ thông qua STDIN và cần trả lời từ STDOUT. Nếu không nhận được hồi âm trong 1 giây, quy trình của bạn sẽ được coi là đã chết và một ngoại lệ sẽ được đưa ra. Tất cả các ký tự sẽ được mã hóa theo UTF-8, để thống nhất. Mỗi đầu vào sẽ chấm dứt với một ký tự dòng mới và quá trình của bạn sẽ chấm dứt mọi trả lời đầu ra với một dòng mới.
CẢNH BÁO Hãy chắc chắn để xóa bộ đệm đầu ra của bạn sau mỗi lần ghi, để đảm bảo trình bao bọc Java nhìn thấy đầu ra của bạn. Thất bại trong việc xả nước có thể khiến Sói từ xa của bạn thất bại.
Lưu ý rằng chỉ một quy trình duy nhất sẽ được tạo, tất cả Sói phải được quản lý trong một quy trình đó. Đọc về làm thế nào thông số kỹ thuật này sẽ giúp.
Khởi tạo
STDIN: S<id><mapsize>
\ n
STDOUT: K<id>
\ n
<id>
: 00
hoặc 01
hoặc ... hoặc99
Giải trình:
Nhân vật S
sẽ được gửi sau đó là hai ký tự số 00
, 01
, ..., 99
cho thấy đó trong số 100 con sói đang được khởi tạo. Trong tất cả các giao tiếp trong tương lai với con sói cụ thể đó, điều tương tự <id>
sẽ được sử dụng.
Theo ID, một chuỗi các ký tự số có độ dài thay đổi sẽ được gửi. Đây là kích thước của bản đồ. Bạn sẽ biết chuỗi ký tự số kết thúc khi bạn đến dòng mới ( \n
).
Để đảm bảo quá trình của bạn còn sống, bạn phải trả lời với nhân vật K
theo sau giống như <id>
bạn đã nhận được. Bất kỳ câu trả lời nào khác sẽ dẫn đến một ngoại lệ, giết chết những con sói của bạn.
Phong trào
STDIN: M<id><C0><C1>...<C7><C8>
\ n
STDOUT: <mv><id>
\ n
<Cn>
: W
Hay
hay B
hay S
hayL
W
: Sói
: Không gian trống
B
: Gấu
S
: Đá
L
: Sư tử
<mv>
: H
Hay U
hay L
hay R
hayD
H
: Di chuyển.
U
: Di chuyển.UP
L
: Di chuyển.LEFT
R
: Di chuyển
D
: Di chuyển
Giải trình:
Nhân vật M
sẽ được gửi theo sau bởi hai nhân vật <id>
để cho biết Wolf cần chọn di chuyển. Theo đó, 9 ký tự sẽ được gửi đại diện cho môi trường xung quanh của Wolf, theo thứ tự hàng (hàng trên cùng, hàng giữa, hàng dưới cùng từ trái sang phải).
Trả lời bằng một trong các ký tự chuyển động hợp lệ <mv>
, theo sau là hai chữ số của Sói <id>
để xác nhận.
Tấn công
STDIN: A<id><C>
\ n
STDOUT: <atk><id>
\ n
<C>
: W
hoặc B
hoặc S
hoặcL
<atk>
: R
hoặc P
hoặc S
hoặcD
R
: Tấn công.ROCK
P
: Tấn công.PAPER
S
: Tấn công.SCISSORS
D
: Tấn công.SUICIDE
Giải trình:
Nhân vật A
sẽ được gửi theo sau bởi hai nhân vật <id>
để cho biết Wolf nào đang tham gia vào một cuộc tấn công. Tiếp theo là một nhân vật duy nhất <C>
cho biết loại vật nào đang tấn công, là W
khứu giác, B
tai, S
âm hoặc L
ion.
Trả lời với một trong các <atk>
ký tự được liệt kê ở trên, cho biết phản ứng của bạn đối với cuộc tấn công là gì, theo sau là hai chữ số <id>
để xác nhận.
Và đó là nó. Không còn gì nữa. Nếu bạn thua một cuộc tấn công, điều đó <id>
sẽ không bao giờ được gửi lại cho quá trình của bạn nữa, đó là cách bạn sẽ biết Sói của bạn đã chết - nếu một vòng Chuyển động hoàn chỉnh đã trôi qua mà không <id>
bao giờ được gửi đi.
Phần kết luận
Lưu ý rằng bất kỳ trường hợp ngoại lệ nào cũng sẽ giết tất cả Chó sói thuộc loại từ xa của bạn, vì chỉ có một "Quy trình" duy nhất được tạo ra từ con sói từ xa của bạn, cho tất cả những con sói thuộc loại bạn được tạo.
Trong kho lưu trữ này, bạn sẽ tìm thấy các Wolf.java
tập tin. Tìm kiếm và thay thế các chuỗi sau để thiết lập bot của bạn:
Thay thế <invocation>
bằng đối số dòng lệnh sẽ thực hiện đúng quy trình của bạn.
Thay thế <custom-name>
bằng một tên duy nhất cho Sói của bạn.
Để xem ví dụ về kho lưu trữ , nơi tôi có WolfRandomPython.java
điều đó gọi ví dụ từ xa của tôi, PythonWolf.py
(một Python 3+ Wolf).
Đổi tên tập tin thành Wolf<custom-name>.java
, nơi <custom-name>
được thay thế bằng tên bạn đã chọn ở trên.
Để kiểm tra Wolf của bạn, hãy biên dịch chương trình Java ( javac Wolf<custom-name>.java
) và làm theo hướng dẫn của Rizer để đưa nó vào chương trình mô phỏng.
Quan trọng: Đảm bảo cung cấp các hướng dẫn rõ ràng , ngắn gọn về cách biên dịch / thực thi Sói thực tế của bạn, theo sơ đồ mà tôi đã nêu ở trên.
Chúc may mắn, và có thể thiên nhiên sẽ có lợi cho bạn.
Mã Wrapper
Hãy nhớ rằng, bạn PHẢI thực hiện các tìm kiếm và thay thế được phác thảo để làm việc này. Nếu lời mời của bạn đặc biệt nhiều lông, xin vui lòng liên hệ với tôi để được hỗ trợ.
Lưu ý có một main
phương pháp trong trình bao bọc này, để cho phép kiểm tra "vượt qua / thất bại" thô sơ trên hộp cục bộ của bạn. Để làm như vậy, hãy tải xuống lớp Animal.java từ dự án và xóa package animals;
dòng khỏi cả hai tệp. Thay thế dòng MAP_SIZE trong Animal.java bằng một số hằng số (như 100). Biên dịch chúng bằng cách sử dụng javac Wolf<custom-name>.java
một thực thi thông qua 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;
}
}
}