非Java提交的包装器
注意已添加MAP_SIZE支持。如果您愿意,请相应地更新您的提交。
这是用于包装程序的社区Wiki条目,可供那些想玩但不喜欢/不了解Java的人使用。请使用它,玩得开心,我们很乐意帮助您进行设置。
当我结束时,这已经很晚了,因此其他Java编码人员请仔细研究并提出改进建议。如果可以,请通过我的github存储库提交问题或提交补丁来这样做。谢谢!
这一切都随UNLICENSE一起分发,请从github存储库中关注/分叉。如果您发现问题,请在此处提交补丁,我将更新此帖子。
当前使用的包装器示例
plannapus:R中的WolfCollectiveMemory
牙刷:ECMAScript中的牙刷
如何使用
以下是我为远程狼定义的通过PIPES进行进程间通信的协议说明。注意我跳过了MAP_SIZE,因为它似乎不存在,尽管它存在于OP的问题陈述中。如果确实出现,我将更新此帖子。
重要提示:
- 将仅对外部进程进行一次调用(因此将处理逻辑包裹在无限循环中。这也使您可以将所有处理保留在内存中,而不是使用磁盘)
- 所有通信都通过STDIN和STDOUT到此单个外部过程
- 您必须显式刷新发送到STDOUT的所有输出,并确保它是换行符终止的
规格
远程脚本通过STDIN和STDOUT挂钩由简单协议支持,并分为初始化,移动和攻击。在每种情况下,都将通过STDIN与您的过程进行通信,并且需要STDOUT进行答复。如果在1秒钟内未收到答复,则将认为您的进程已死,并且将引发异常。为了保持一致,所有字符都将以UTF-8编码。每个输入将以换行符终止,并且您的进程也应以换行符终止每个输出答复。
警告确保每次写入后都刷新输出缓冲区,以确保Java包装程序可以看到您的输出。未能刷新可能导致您的远程Wolf失败。
请注意,将只创建一个进程,所有狼必须在该进程内进行管理。继续阅读本规范将如何提供帮助。
初始化
STDIN: S<id><mapsize>
\ n
标准输出: K<id>
\ n
<id>
: 00
或01
或...或99
说明:
的字符S
将被发送后跟两个数字字符00
,01
,...,99
指示哪个100条狼被初始化。在与该特定狼的所有将来通信中,<id>
将使用相同的狼。
在ID之后,将发送可变长度的数字字符序列。这是地图的大小。到达换行符(\n
)后,数字字符的序列将结束。
为确保您的过程仍然有效,您必须在回复时输入字符,K
然后加上<id>
收到的字符。其他任何答复都会导致异常,杀死您的狼。
运动
STDIN: M<id><C0><C1>...<C7><C8>
\ n
标准输出: <mv><id>
\ n
<Cn>
: W
或
或B
或S
或L
W
:狼
:空的空间
B
:熊
S
:石头
L
:狮子
<mv>
: H
或U
或L
或R
或D
H
:移动。保持
U
:移动
L
:移动。左
R
:向右移动
D
:下移
说明:
M
将发送该角色,后跟两个角色,<id>
以指示哪个狼需要选择一个举动。之后,将按行顺序(从最左边到最右边,从上排,中排,下排)发送9个字符来表示Wolf的周围环境。
用有效的运动角色之一回复<mv>
,然后是狼的两位数字<id>
进行确认。
攻击
STDIN: A<id><C>
\ n
标准输出: <atk><id>
\ n
<C>
: W
或B
或S
或L
<atk>
: R
或P
或S
或D
R
:攻击摇滚
P
: Attack.PAPER
S
: Attack.SCISSORS
D
: Attack.SUICIDE
说明:
A
将发送该角色,后跟两个角色,<id>
以指示哪个狼参与了攻击。这之后是一个字符,<C>
指示攻击的是哪种类型的东西,包括W
olf,B
耳朵,S
音调或L
离子。
使用<atk>
上面列出的字符之一进行答复,指示您对攻击的反应,然后是两位数<id>
以进行确认。
就是这样。没有更多了。如果您输掉了一次攻击,那么该攻击<id>
将永远不会再发送到您的进程,这就是您将知道狼已经死的方式-如果经过完整的运动回合而<id>
没有被发送出去。
结论
请注意,任何异常都将杀死您的远程类型的所有狼,因为对于您创建的所有类型的狼,仅由远程狼构造一个“进程”。
在此存储库中,您将找到Wolf.java
文件。搜索并替换以下字符串以设置您的机器人:
用<invocation>
将正确执行过程的命令行参数替换。
用<custom-name>
您的狼的唯一名称替换。
例如,请查看存储库,该存储库中有WolfRandomPython.java
一个调用我的示例远程库PythonWolf.py
(Python 3+ Wolf)。
将文件重命名为Wolf<custom-name>.java
,其中<custom-name>
将替换为您在上面选择的名称。
要测试Wolf,请编译Java程序(javac Wolf<custom-name>.java
),然后按照Rusher的说明将其包括在仿真程序中。
重要提示:请务必按照我上面概述的方案,就如何编译/执行实际的Wolf 提供清晰,简洁的说明。
祝您好运,大自然永远都对您有利。
包装代码
请记住,您必须进行搜索并替换一下概述才能正常工作。如果您的调用特别麻烦,请与我联系以获取帮助。
请注意main
,此包装器中有一种方法,可以在本地机器上进行基本的“通过/失败”测试。为此,请从项目中下载Animal.java类,然后package animals;
从两个文件中删除该行。用一些常量(例如100)替换Animal.java中的MAP_SIZE行。使用javac Wolf<custom-name>.java
execute 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;
}
}
}