initial commit
This commit is contained in:
commit
807034a634
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
### IntelliJ IDEA ###
|
||||||
|
out/
|
||||||
|
!**/src/main/**/out/
|
||||||
|
!**/src/test/**/out/
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
bin/
|
||||||
|
!**/src/main/**/bin/
|
||||||
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
85
src/Bot.java
Normal file
85
src/Bot.java
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
public abstract class Bot {
|
||||||
|
|
||||||
|
// Ein Bot ist ein Programm, das sich mit einem Server verbindet und
|
||||||
|
// mit diesem kommuniziert. Der Server sendet dem Bot eine Zeichenkette,
|
||||||
|
// die das Spielfeld repräsentiert. Der Bot sendet dem Server ein Zeichen,
|
||||||
|
// das die nächste Bewegung des Bots repräsentiert.
|
||||||
|
|
||||||
|
|
||||||
|
private final String host; // Hostname oder IP-Adresse des Servers
|
||||||
|
private final int port; // Port des Servers
|
||||||
|
|
||||||
|
protected Bot(String[] args) {
|
||||||
|
host = args.length > 0 ? args[0] : "localhost";
|
||||||
|
port = args.length > 1 ? Integer.parseInt(args[1]) : 63187;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diese Methode stellt die Verbindung zum Server her und startet die
|
||||||
|
// Kommunikation mit dem Server. Die Methode wird von der main-Methode
|
||||||
|
// aufgerufen.
|
||||||
|
protected void run() {
|
||||||
|
try (Socket socket = new Socket()) {
|
||||||
|
socket.connect(new InetSocketAddress(host, port));
|
||||||
|
OutputStream out = socket.getOutputStream();
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
View view = new View();
|
||||||
|
while (true) {
|
||||||
|
view.read(in);
|
||||||
|
view.print();
|
||||||
|
try {
|
||||||
|
char ch = nextMove(view);
|
||||||
|
out.write(ch);
|
||||||
|
}
|
||||||
|
catch (Exception e) { break; }
|
||||||
|
}
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diese Methode ermittelt den nächsten Zug des Bots. Sie wird von der
|
||||||
|
// run-Methode aufgerufen, nachdem der Server das Spielfeld gesendet hat.
|
||||||
|
// Subklassen müssen diese Methode implementieren.
|
||||||
|
abstract protected char nextMove(View view) throws Exception;
|
||||||
|
|
||||||
|
// Diese Klasse repräsentiert das Spielfeld. Sie wird von der run-Methode
|
||||||
|
// verwendet, um das Spielfeld zu lesen und auszugeben.
|
||||||
|
// Subklassen können diese Klasse verwenden, um das Spielfeld zu analysieren.
|
||||||
|
public static class View {
|
||||||
|
protected String data;
|
||||||
|
protected int width;
|
||||||
|
|
||||||
|
// Diese Methode liest das Spielfeld vom Server.
|
||||||
|
private void read(BufferedReader in) throws IOException {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
data = in.readLine();
|
||||||
|
if (data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sb.append(data);
|
||||||
|
width = data.length();
|
||||||
|
for (int i = 1; i < width; ++i) {
|
||||||
|
sb.append(in.readLine());
|
||||||
|
}
|
||||||
|
data = sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diese Methode gibt das Spielfeld aus.
|
||||||
|
protected void print() {
|
||||||
|
if (data == null || width < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0, len = data.length(); i < len; i += width) {
|
||||||
|
System.out.println(data.substring(i, i + width));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
140
src/CollectBot.java
Normal file
140
src/CollectBot.java
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
public class CollectBot extends SmartBot {
|
||||||
|
|
||||||
|
private int maxNumberOfTilesToMove = 15;
|
||||||
|
|
||||||
|
private int tilesMoved;
|
||||||
|
|
||||||
|
private char directionBias;
|
||||||
|
|
||||||
|
private final Stack<Character> moves;
|
||||||
|
|
||||||
|
protected CollectBot(String[] args) {
|
||||||
|
super(args);
|
||||||
|
tilesMoved = 0;
|
||||||
|
directionBias = LEFT;
|
||||||
|
moves = new Stack<Character>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Bot bot = new CollectBot(args);
|
||||||
|
bot.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected char nextMove(View view) throws Exception {
|
||||||
|
char move = '^';
|
||||||
|
|
||||||
|
// Search larger areas after a time
|
||||||
|
if (moves.size() != 0 && moves.size() % 100 == 0 && maxNumberOfTilesToMove <=30) {
|
||||||
|
maxNumberOfTilesToMove += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for Gems
|
||||||
|
int turn = scanView(view);
|
||||||
|
if (turn == 3) {
|
||||||
|
tilesMoved++;
|
||||||
|
// Change up direction after not encountering anything for a while
|
||||||
|
if (tilesMoved >= maxNumberOfTilesToMove) {
|
||||||
|
tilesMoved = 0;
|
||||||
|
move = switchBias(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tilesMoved = 0;
|
||||||
|
move = switch (turn) {
|
||||||
|
case -1 -> LEFT;
|
||||||
|
case 0 -> FORWARD;
|
||||||
|
case 1 -> RIGHT;
|
||||||
|
default -> move;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
moves.push(move);
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* This Method can be either used to detect potential spiral collision paths or to periodically change the direction bias
|
||||||
|
* @param numberOfTurns The number of turns that should be equal
|
||||||
|
* @return true, if the last n turns were equal in the given distance covered
|
||||||
|
*/
|
||||||
|
private boolean evaluateNumberOfEqualTurns(int numberOfTurns) {
|
||||||
|
if (this.moves.isEmpty() || this.moves.size() < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Stack<Character> moves = (Stack<Character>) this.moves.clone();
|
||||||
|
int numberOfEqualTurns = 0;
|
||||||
|
int distanceCovered = 0;
|
||||||
|
char directionToCompare = '#';
|
||||||
|
while (numberOfEqualTurns <= numberOfTurns && !moves.isEmpty()) {
|
||||||
|
char lastMove = moves.pop();
|
||||||
|
if (lastMove == FORWARD) {
|
||||||
|
distanceCovered++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfEqualTurns == 0) {
|
||||||
|
numberOfEqualTurns++;
|
||||||
|
directionToCompare = lastMove;
|
||||||
|
} else {
|
||||||
|
if (lastMove != directionToCompare) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
numberOfEqualTurns++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numberOfEqualTurns == 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Changes up the direction bias every two turns which achieves a rough zig-zag pattern
|
||||||
|
* @return the next direction bias
|
||||||
|
*/
|
||||||
|
protected char switchBias(boolean forcedSwitch) {
|
||||||
|
if(!evaluateNumberOfEqualTurns(2) && !forcedSwitch) {
|
||||||
|
return directionBias;
|
||||||
|
}
|
||||||
|
directionBias = switch (directionBias) {
|
||||||
|
case LEFT -> {
|
||||||
|
directionBias = RIGHT;
|
||||||
|
yield RIGHT;
|
||||||
|
}
|
||||||
|
case RIGHT -> {
|
||||||
|
directionBias = LEFT;
|
||||||
|
yield LEFT;
|
||||||
|
}
|
||||||
|
default -> directionBias;
|
||||||
|
};
|
||||||
|
return directionBias;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected char switchBias() {
|
||||||
|
return switchBias(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int scanView(View view) {
|
||||||
|
if (view.data.contains("@")) {
|
||||||
|
int stone = view.data.indexOf("@") + 1;
|
||||||
|
|
||||||
|
// Check Front:
|
||||||
|
switch (stone) {
|
||||||
|
case 3, 8:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If possible, prefer direction Bias
|
||||||
|
if (directionBias == LEFT) {
|
||||||
|
switch (stone) {
|
||||||
|
case 11, 12: return -1; // left
|
||||||
|
case 14, 15: return 1; // right
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (stone) {
|
||||||
|
case 14, 15: return 1; // right
|
||||||
|
case 11, 12: return -1; // left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
29
src/DummyBot.java
Normal file
29
src/DummyBot.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class DummyBot extends SmartBot {
|
||||||
|
|
||||||
|
Random random;
|
||||||
|
|
||||||
|
protected DummyBot(String[] args) {
|
||||||
|
super(args);
|
||||||
|
random = new Random();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Bot bot = new DummyBot(args);
|
||||||
|
bot.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected char nextMove(View view) throws Exception {
|
||||||
|
int move = random.nextInt(0, 7);
|
||||||
|
return switch (move) {
|
||||||
|
case 1,2,3 -> FORWARD;
|
||||||
|
case 4 -> LEFT;
|
||||||
|
case 5 -> RIGHT;
|
||||||
|
case 6 -> SHOOT;
|
||||||
|
default -> 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
67
src/EscapeBot.java
Normal file
67
src/EscapeBot.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
public class EscapeBot extends Bot {
|
||||||
|
|
||||||
|
int unitsMoved;
|
||||||
|
|
||||||
|
int unitsToMove;
|
||||||
|
|
||||||
|
int timesTurned;
|
||||||
|
|
||||||
|
protected EscapeBot(String[] args) {
|
||||||
|
super(args);
|
||||||
|
unitsMoved = 0;
|
||||||
|
unitsToMove = 5;
|
||||||
|
timesTurned = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Bot bot = new EscapeBot(args);
|
||||||
|
bot.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected char nextMove(View view) throws Exception {
|
||||||
|
//boolean found = false;
|
||||||
|
|
||||||
|
if (unitsMoved % 5 == 0) {
|
||||||
|
char c = checkView(view);
|
||||||
|
switch (c) {
|
||||||
|
case '0': break;
|
||||||
|
case '1': throw new Exception("found!");
|
||||||
|
default: return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unitsMoved < unitsToMove) {
|
||||||
|
unitsMoved++;
|
||||||
|
return '^';
|
||||||
|
} else if (unitsMoved == unitsToMove) {
|
||||||
|
unitsMoved = 0;
|
||||||
|
timesTurned++;
|
||||||
|
|
||||||
|
if (timesTurned % 2 == 0) {
|
||||||
|
unitsToMove += 5;
|
||||||
|
}
|
||||||
|
return '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
private char checkView(View view) {
|
||||||
|
if (view.data.contains("o")) {
|
||||||
|
int spaceship = view.data.indexOf("o") + 1;
|
||||||
|
if (spaceship == 13) {
|
||||||
|
return '1';
|
||||||
|
} else if (spaceship <= 10) {
|
||||||
|
return '^';
|
||||||
|
} else if (spaceship >= 15) {
|
||||||
|
return 'v';
|
||||||
|
} else if (spaceship%5 < 3) {
|
||||||
|
return '<';
|
||||||
|
} else if (spaceship%5 > 3) {
|
||||||
|
return '>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
}
|
163
src/RumbleBot.java
Normal file
163
src/RumbleBot.java
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class RumbleBot extends SmartBot {
|
||||||
|
|
||||||
|
private int tilesToMove;
|
||||||
|
|
||||||
|
private int escapeMove;
|
||||||
|
|
||||||
|
private final Random random;
|
||||||
|
|
||||||
|
private final int[] leftVectorIndizes = new int[] {36,37,38,39};
|
||||||
|
private final int[] rightVectorIndizes = new int[] {23,24,25,26};
|
||||||
|
private final int[] frontVectorIndizes = new int[] {4,13,22,31};
|
||||||
|
|
||||||
|
protected RumbleBot(String[] args) {
|
||||||
|
super(args);
|
||||||
|
this.random = new Random();
|
||||||
|
this.escapeMove = 0;
|
||||||
|
this.tilesToMove = random.nextInt(5, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Bot bot = new RumbleBot(args);
|
||||||
|
bot.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected char nextMove(View view) throws Exception {
|
||||||
|
char move = FORWARD;
|
||||||
|
|
||||||
|
// if (tilesToMove >= tilesMoved) {
|
||||||
|
// tilesMoved = 0;
|
||||||
|
// tilesToMove = random.nextInt(5, 15);
|
||||||
|
// move = directionBias;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (escapeMove != 0) {
|
||||||
|
escapeMove--;
|
||||||
|
return FORWARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for enemies
|
||||||
|
Enemy enemy = evaluateEnemy(view);
|
||||||
|
if (enemy != null) {
|
||||||
|
move = calculateOptimalMove(view, enemy);
|
||||||
|
escapeMove = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (directionBlocked(view,FORWARD)) {
|
||||||
|
if (directionBlocked(view,RIGHT)) {
|
||||||
|
move = LEFT;
|
||||||
|
} else {
|
||||||
|
move = RIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Enemy evaluateEnemy(View view) {
|
||||||
|
int enemyPos;
|
||||||
|
if (view.data.contains("^")) {
|
||||||
|
enemyPos = view.data.indexOf('^');
|
||||||
|
} else if (view.data.contains("v")) {
|
||||||
|
enemyPos = view.data.indexOf('v');
|
||||||
|
} else if (view.data.contains("<")) {
|
||||||
|
enemyPos = view.data.indexOf('<');
|
||||||
|
} else if (view.data.contains(">")) {
|
||||||
|
enemyPos = view.data.indexOf('>');
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Enemy(enemyPos + 1, view.data.charAt(enemyPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean directionBlocked(View view, char direction) {
|
||||||
|
if (direction == FORWARD) {
|
||||||
|
for (int i = 4; i < 32; i+=9) {
|
||||||
|
if (view.data.charAt(i) == 'X') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (direction == LEFT) {
|
||||||
|
for (int i = 36; i < 40; i++) {
|
||||||
|
if (view.data.charAt(i) == 'X') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (direction == RIGHT) {
|
||||||
|
for (int i = 41; i < 45; i++) {
|
||||||
|
if (view.data.charAt(i) == 'X') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private char calculateOptimalMove(View view, Enemy enemy) {
|
||||||
|
int pos = enemy.position;
|
||||||
|
char dir = enemy.direction;
|
||||||
|
|
||||||
|
|
||||||
|
// Top Sector
|
||||||
|
if (pos <= 18) {
|
||||||
|
// Left Half
|
||||||
|
if (pos % 9 < 5) {
|
||||||
|
return !directionBlocked(view,RIGHT) ? RIGHT : SHOOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right Half
|
||||||
|
else if (pos % 9 > 5) {
|
||||||
|
return !directionBlocked(view,LEFT) ? LEFT : SHOOT;
|
||||||
|
}
|
||||||
|
// Center
|
||||||
|
else {
|
||||||
|
return SHOOT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom Sector
|
||||||
|
if (pos >= 24) {
|
||||||
|
// Left or Right Half
|
||||||
|
if (pos % 9 != 5) {
|
||||||
|
return !directionBlocked(view,FORWARD) ? FORWARD : randomDirection(view);
|
||||||
|
}
|
||||||
|
// Center
|
||||||
|
else {
|
||||||
|
return randomDirection(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left or Right
|
||||||
|
return randomDirection(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char randomDirection(View view) {
|
||||||
|
int rand = random.nextInt(0, 1);
|
||||||
|
char dir = rand == 0 ? '<' : '>';
|
||||||
|
return !directionBlocked(view,dir) ? dir : flipDirection(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char flipDirection(char direction) {
|
||||||
|
return switch (direction) {
|
||||||
|
case RIGHT -> LEFT;
|
||||||
|
case LEFT -> RIGHT;
|
||||||
|
case FORWARD -> BACKWARD;
|
||||||
|
default -> FORWARD;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Enemy {
|
||||||
|
final int position;
|
||||||
|
final char direction;
|
||||||
|
|
||||||
|
public Enemy(int position, char direction) {
|
||||||
|
this.position = position;
|
||||||
|
this.direction = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
src/SmartBot.java
Normal file
28
src/SmartBot.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
public abstract class SmartBot extends Bot {
|
||||||
|
|
||||||
|
protected static final char FORWARD = '^';
|
||||||
|
protected static final char BACKWARD = 'v';
|
||||||
|
protected static final char LEFT = '<';
|
||||||
|
protected static final char RIGHT = '>';
|
||||||
|
protected static final char SHOOT = 'f';
|
||||||
|
|
||||||
|
protected int tilesMoved;
|
||||||
|
|
||||||
|
protected final Stack<Character> moves;
|
||||||
|
|
||||||
|
|
||||||
|
protected SmartBot(String[] args) {
|
||||||
|
super(args);
|
||||||
|
this.tilesMoved = 0;
|
||||||
|
this.moves = new Stack<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected char nextMove(View view) throws Exception {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
199
src/SnakeBot.java
Normal file
199
src/SnakeBot.java
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
public class SnakeBot extends SmartBot {
|
||||||
|
|
||||||
|
private int maxNumberOfTilesToMove = 15;
|
||||||
|
|
||||||
|
private int tilesMoved;
|
||||||
|
|
||||||
|
private int tailLength;
|
||||||
|
|
||||||
|
private int escapeSequence;
|
||||||
|
|
||||||
|
private char directionBias;
|
||||||
|
|
||||||
|
private final Stack<Character> moves;
|
||||||
|
|
||||||
|
protected SnakeBot(String[] args) {
|
||||||
|
super(args);
|
||||||
|
tilesMoved = 0;
|
||||||
|
tailLength = 0;
|
||||||
|
escapeSequence = 0;
|
||||||
|
directionBias = LEFT;
|
||||||
|
moves = new Stack<Character>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Bot bot = new SnakeBot(args);
|
||||||
|
bot.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected char nextMove(View view) throws Exception {
|
||||||
|
char move = '^';
|
||||||
|
|
||||||
|
// Avoid potential spiral paths
|
||||||
|
if (evaluateNumberOfEqualTurns(3, tailLength)) {
|
||||||
|
moves.push(switchBias());
|
||||||
|
System.out.println("Potential Spiral detected. Next Move: " + directionBias);
|
||||||
|
escapeSequence = 2;
|
||||||
|
return directionBias;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Way must be free
|
||||||
|
if (!checkFrontCollisions(view)) {
|
||||||
|
escapeSequence = 1;
|
||||||
|
moves.push(switchBias());
|
||||||
|
System.out.println("Collision ahead. Next Move: " + directionBias);
|
||||||
|
|
||||||
|
return directionBias;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape after potential collision or spiral turn loops
|
||||||
|
if (escapeSequence != 0) {
|
||||||
|
switch (escapeSequence) {
|
||||||
|
case 1:
|
||||||
|
escapeSequence = 0;
|
||||||
|
moves.push(FORWARD);
|
||||||
|
return FORWARD;
|
||||||
|
case 2:
|
||||||
|
escapeSequence = 1;
|
||||||
|
moves.push(switchBias());
|
||||||
|
return directionBias;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search larger areas after a time
|
||||||
|
if (moves.size() != 0 && moves.size() % 100 == 0 && maxNumberOfTilesToMove <=30) {
|
||||||
|
maxNumberOfTilesToMove += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for Gems
|
||||||
|
int turn = scanView(view);
|
||||||
|
if (turn == 3) {
|
||||||
|
tilesMoved++;
|
||||||
|
// Change up direction after not encountering anything for a while
|
||||||
|
if (tilesMoved >= maxNumberOfTilesToMove) {
|
||||||
|
tilesMoved = 0;
|
||||||
|
move = switchBias(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tilesMoved = 0;
|
||||||
|
move = switch (turn) {
|
||||||
|
case -1 -> LEFT;
|
||||||
|
case 0 -> FORWARD;
|
||||||
|
case 1 -> RIGHT;
|
||||||
|
default -> move;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
moves.push(move);
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* This Method can be either used to detect potential spiral collision paths or to periodically change the direction bias
|
||||||
|
* @param numberOfTurns The number of turns that should be equal
|
||||||
|
* @param maxDepth The distance in wich the turns must have occurred to be considered
|
||||||
|
* @return true, if the last n turns were equal in the given distance covered
|
||||||
|
*/
|
||||||
|
private boolean evaluateNumberOfEqualTurns(int numberOfTurns, int maxDepth) {
|
||||||
|
if (this.moves.isEmpty() || this.moves.size() < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Stack<Character> moves = (Stack<Character>) this.moves.clone();
|
||||||
|
int numberOfEqualTurns = 0;
|
||||||
|
int distanceCovered = 0;
|
||||||
|
char directionToCompare = '#';
|
||||||
|
while (numberOfEqualTurns <= numberOfTurns && distanceCovered <= maxDepth && !moves.isEmpty()) {
|
||||||
|
char lastMove = moves.pop();
|
||||||
|
if (lastMove == FORWARD) {
|
||||||
|
distanceCovered++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfEqualTurns == 0) {
|
||||||
|
numberOfEqualTurns++;
|
||||||
|
directionToCompare = lastMove;
|
||||||
|
} else {
|
||||||
|
if (lastMove != directionToCompare) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
numberOfEqualTurns++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numberOfEqualTurns == 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean evaluateNumberOfEqualTurns(int numberOfTurns) {
|
||||||
|
return evaluateNumberOfEqualTurns(numberOfTurns, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Changes up the direction bias every two turns which achieves a rough zig-zag pattern
|
||||||
|
* @return the next direction bias
|
||||||
|
*/
|
||||||
|
protected char switchBias(boolean forcedSwitch) {
|
||||||
|
if(!evaluateNumberOfEqualTurns(2) && !forcedSwitch) {
|
||||||
|
return directionBias;
|
||||||
|
}
|
||||||
|
directionBias = switch (directionBias) {
|
||||||
|
case LEFT -> {
|
||||||
|
directionBias = RIGHT;
|
||||||
|
yield RIGHT;
|
||||||
|
}
|
||||||
|
case RIGHT -> {
|
||||||
|
directionBias = LEFT;
|
||||||
|
yield LEFT;
|
||||||
|
}
|
||||||
|
default -> directionBias;
|
||||||
|
};
|
||||||
|
return directionBias;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected char switchBias() {
|
||||||
|
return switchBias(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkFrontCollisions(View view) {
|
||||||
|
return view.data.charAt(2) != '*' &&
|
||||||
|
view.data.charAt(7) != '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkSideCollisions(View view, int side) {
|
||||||
|
if (side == -1) {
|
||||||
|
return view.data.charAt(11) != '*';
|
||||||
|
} else if (side == 1) {
|
||||||
|
return view.data.indexOf(13) != '*';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int scanView(View view) {
|
||||||
|
if (view.data.contains("@")) {
|
||||||
|
int stone = view.data.indexOf("@") + 1;
|
||||||
|
|
||||||
|
// Check Front:
|
||||||
|
switch (stone) {
|
||||||
|
case 3:
|
||||||
|
tailLength++;
|
||||||
|
return 0;
|
||||||
|
case 8:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If possible, prefer direction Bias
|
||||||
|
if (directionBias == LEFT) {
|
||||||
|
switch (stone) {
|
||||||
|
case 11, 12: return checkSideCollisions(view, -1)? -1 : 3; // left
|
||||||
|
case 14, 15: return checkSideCollisions(view, 1)? 1 : 3; // right
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (stone) {
|
||||||
|
case 14, 15: return checkSideCollisions(view, 1)? 1 : 3; // right
|
||||||
|
case 11, 12: return checkSideCollisions(view, -1)? -1 : 3; // left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user