Skip to content

Instantly share code, notes, and snippets.

@ProgrammerDan
Created April 11, 2014 01:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ProgrammerDan/10436886 to your computer and use it in GitHub Desktop.
Save ProgrammerDan/10436886 to your computer and use it in GitHub Desktop.
WolfToothbrush in Node.js by toothbrush, with wrapper by ProgrammerDan
var returnAttack = {
'L': 'RS',
'B': 'S',
'S': 'P',
'W': 'PRS'
};
function initialise(chunk, id) {
return 'K' + id + '\n';
};
function move(chunk, id) {
var squares = chunk.slice(3, 11);
// Idea: Move into the space if there isn't a wolf in it
// Move up
if (chunk[4] !== 'W') return 'U' + id + '\n';
// Move left
if (chunk[6] !== 'W') return 'L' + id + '\n';
// Move below
if (chunk[10] !== 'W') return 'B' + id + '\n';
// Move right
if (chunk[8] !== 'W') return 'R' + id + '\n';
// Hold the space
return 'H' + id + '\n';
};
function attack(chunk, id) {
var attack = returnAttack[chunk[3]];
if (attack.length > 1 && Math.random() > .8) {
return 'D' + id + '\n';
} else if (attack.length > 1) {
return attack[Math.floor(Math.random() * attack.length)] + id + '\n';
} else {
return attack + id + '\n';
}
};
var functions = {
'S': initialise,
'M': move,
'A': attack
};
var stdin = process.openStdin();
stdin.setEncoding('utf-8');
stdin.on('data', function(chunk) {
if (chunk.length === 0) return;
process.stdout.write(functions[chunk[0]](chunk, chunk.slice(1, 3)));
});
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 WolfToothbrush wrapper class.
*/
public class WolfToothbrush extends Animal {
/**
* Simple test script that sends some typical commands to the
* remote process.
*/
public static void main(String[]args){
WolfToothbrush[] wolves = new WolfToothbrush[100];
for(int i=0; i<10; i++) {
wolves[i] = new WolfToothbrush();
}
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 WolfToothbrush[] wolves = new WolfToothbrush[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 WolfToothbrush() {
super('W');
if (WolfToothbrush.wolfProcess == null) {
WolfToothbrush.wolfProcess = new WolfProcess();
WolfToothbrush.wolfProcess.start();
}
if (WolfToothbrush.wolfProcess.initWolf(WolfToothbrush.nWolves, MAP_SIZE)) {
this.id = WolfToothbrush.nWolves;
this.isDead = false;
WolfToothbrush.wolves[id] = this;
} else {
WolfToothbrush.wolfProcess.endProcess();
this.isDead = true;
}
WolfToothbrush.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 (!WolfToothbrush.wolfProcess.getRunning() || isDead) {
return Attack.SUICIDE;
}
try {
Attack atk = WolfToothbrush.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 (!WolfToothbrush.wolfProcess.getRunning() || isDead) {
return Move.HOLD;
}
try {
Move mv = WolfToothbrush.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 WolfToothbrush remote process");
ProcessBuilder pb = new ProcessBuilder("node toothbrush.js".split(" "));
pb.redirectErrorStream(true);
process = pb.start();
System.out.println("WolfToothbrush process begun");
// STDOUT of the process.
reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
System.out.println("WolfToothbrush reader stream grabbed");
// STDIN of the process.
writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
System.out.println("WolfToothbrush 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("WolfToothbrush 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("WolfToothbrush %d failed to initialize, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("WolfToothbrush %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("WolfToothbrush %d failed to attack, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("WolfToothbrush %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("WolfToothbrush %d failed to move, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("WolfToothbrush %d failed to move, %s\n", wolf, e.getMessage());
}
return move;
}
}
}
@ProgrammerDan
Copy link
Author

Toothbrush's post for the Wolf code-golf contest here. Go to it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment