|
|
@@ -10,169 +10,178 @@ |
|
|
|
* Für diese Funktion wird am 7.2.24 in einer gemeinsamen Arena mit allen Teams des Jahrgangs ein Wettbewerb durchgeführt. |
|
|
|
* Die besten acht Teams qualifizieren sich für die Königsdisziplin „Rumble“. |
|
|
|
*/ |
|
|
|
|
|
|
|
import java.util.Random; |
|
|
|
|
|
|
|
public class SnakeBot extends Bot{ |
|
|
|
private String moves = ""; |
|
|
|
private int spiralNumber = 0; |
|
|
|
boolean frontIsBlocked, backIsBlocked, leftIsBlocked, rightIsBlocked, trapped; |
|
|
|
private char previousTurn = '<'; |
|
|
|
private int spiralFactor = 1; |
|
|
|
private char spiralDirection = '>'; |
|
|
|
private boolean goesForward = true; |
|
|
|
private boolean ignoreStones = false; |
|
|
|
public static void main(String[] args) { |
|
|
|
Bot snakeBot = new SnakeBot(args); |
|
|
|
snakeBot.run(); |
|
|
|
Bot SnakeBot = new SnakeBot(args); |
|
|
|
SnakeBot.run(); |
|
|
|
} |
|
|
|
|
|
|
|
protected SnakeBot(String[] args) { |
|
|
|
super(args); |
|
|
|
} |
|
|
|
//@TODO: find a better way to avoid collected stones |
|
|
|
//@TODO: find a better way to collect stones |
|
|
|
protected char nextMove(View view) { |
|
|
|
|
|
|
|
protected char nextMove(View view) throws Exception { |
|
|
|
boolean stoneDetected = view.data.contains("@"); |
|
|
|
char nextMove; |
|
|
|
nextMove = (stoneDetected && !ignoreStones) ? goToStone(view) : walkBySpiral(view); |
|
|
|
|
|
|
|
int centerCoordinateOfView = view.width / 2; |
|
|
|
int frontCellIndex = calculateCharIndexFromCoordinates(view.width, centerCoordinateOfView, centerCoordinateOfView - 1); |
|
|
|
checkBarriers(view); |
|
|
|
|
|
|
|
if(nextMove == '^' && view.data.charAt(frontCellIndex) == '*'){ |
|
|
|
nextMove = (countCollectedStonesLeft(view) <= countCollectedStonesRight(view)) ? '<' : '>'; |
|
|
|
ignoreStones = true; |
|
|
|
} |
|
|
|
nextMove = stoneDetected ? goToStone(view) : walkBySpiral(view); |
|
|
|
|
|
|
|
if(countUncollectedStones(view) > 1) ignoreStones = true; |
|
|
|
if(countCollectedStones(view) <= 2 && countUncollectedStones(view) <= 1) ignoreStones = false; |
|
|
|
|
|
|
|
if(isStoneNearby(view)){ |
|
|
|
nextMove = goToNearbyStone(view); |
|
|
|
} |
|
|
|
nextMove = checkMove(nextMove); |
|
|
|
|
|
|
|
saveMove(nextMove); |
|
|
|
return nextMove; |
|
|
|
} |
|
|
|
|
|
|
|
private boolean isStoneNearby(View view){ |
|
|
|
int centerCoordinateOfView = view.width / 2; |
|
|
|
int frontCellIndex = calculateCharIndexFromCoordinates(view.width, centerCoordinateOfView, centerCoordinateOfView - 1); |
|
|
|
int leftCellIndex = calculateCharIndexFromCoordinates(view.width, centerCoordinateOfView - 1, centerCoordinateOfView); |
|
|
|
int rightCellIndex = calculateCharIndexFromCoordinates(view.width, centerCoordinateOfView + 1, centerCoordinateOfView); |
|
|
|
|
|
|
|
boolean stoneIsInFront = view.data.charAt(frontCellIndex) == '@'; |
|
|
|
boolean stoneIsOnTheLeft = view.data.charAt(leftCellIndex) == '@'; |
|
|
|
boolean stoneIsOneTheRight = view.data.charAt(rightCellIndex) == '@'; |
|
|
|
private void checkBarriers(View view) throws Exception { |
|
|
|
int centerCoordinates = view.width / 2; |
|
|
|
int centerIndex = getCharIndexFromCoordinates(view.width, centerCoordinates, centerCoordinates); |
|
|
|
|
|
|
|
return stoneIsInFront || stoneIsOnTheLeft || stoneIsOneTheRight; |
|
|
|
} |
|
|
|
|
|
|
|
private char goToNearbyStone(View view){ |
|
|
|
int centerCoordinateOfView = view.width / 2; |
|
|
|
int frontCellIndex = calculateCharIndexFromCoordinates(view.width, centerCoordinateOfView, centerCoordinateOfView - 1); |
|
|
|
int leftCellIndex = calculateCharIndexFromCoordinates(view.width, centerCoordinateOfView - 1, centerCoordinateOfView); |
|
|
|
int rightCellIndex = calculateCharIndexFromCoordinates(view.width, centerCoordinateOfView + 1, centerCoordinateOfView); |
|
|
|
int frontIndex = getCharIndexFromCoordinates(view.width, centerCoordinates, centerCoordinates - 1); |
|
|
|
int backIndex = getCharIndexFromCoordinates(view.width, centerCoordinates, centerCoordinates + 1); |
|
|
|
int leftIndex = centerIndex - 1; |
|
|
|
int rightIndex = centerIndex + 1; |
|
|
|
|
|
|
|
if(view.data.charAt(frontCellIndex) == '@') return '^'; |
|
|
|
if(view.data.charAt(leftCellIndex) == '@') return '<'; |
|
|
|
if(view.data.charAt(rightCellIndex) == '@') return '>'; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
frontIsBlocked = view.data.charAt(frontIndex) == '*'; |
|
|
|
backIsBlocked = view.data.charAt(backIndex) == '*'; |
|
|
|
leftIsBlocked = view.data.charAt(leftIndex) == '*'; |
|
|
|
rightIsBlocked = view.data.charAt(rightIndex) == '*'; |
|
|
|
trapped = frontIsBlocked && backIsBlocked && leftIsBlocked && rightIsBlocked; |
|
|
|
|
|
|
|
private void resetMoves() { |
|
|
|
moves = ""; |
|
|
|
spiralNumber = 0; |
|
|
|
if (trapped) { |
|
|
|
Exception trappedException = new Exception("Snake is trapped"); |
|
|
|
System.err.println(trappedException.getMessage()); |
|
|
|
throw trappedException; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private int countUncollectedStones(View view) { |
|
|
|
int count = 0; |
|
|
|
|
|
|
|
for (char c : view.data.toCharArray()) { |
|
|
|
if (c == '@') count++; |
|
|
|
private char checkMove(char move) throws Exception { |
|
|
|
if (frontIsBlocked) { |
|
|
|
resetMovesSequence(); |
|
|
|
if (leftIsBlocked) move = '>'; |
|
|
|
else if (rightIsBlocked) move = '<'; |
|
|
|
else if (previousTurn == '<') move = '>'; |
|
|
|
else if (previousTurn == '>') move = '<'; |
|
|
|
else { |
|
|
|
Exception invalidTurnException = new Exception("The previous turn was neither '<' nor '>'."); |
|
|
|
System.err.println(invalidTurnException.getMessage()); |
|
|
|
throw invalidTurnException; |
|
|
|
} |
|
|
|
} |
|
|
|
return count; |
|
|
|
return move; |
|
|
|
} |
|
|
|
|
|
|
|
private int countCollectedStonesLeft(View view) { |
|
|
|
int[] leftSide = generateLeftSideArray(view.width); |
|
|
|
int stones = 0; |
|
|
|
for (int cellIndex : leftSide) { |
|
|
|
if(view.data.charAt(cellIndex) == '*') stones++; |
|
|
|
private void saveMove(char move) { |
|
|
|
if (move == '<' || move == '>') { |
|
|
|
previousTurn = move; |
|
|
|
} |
|
|
|
return stones; |
|
|
|
} |
|
|
|
|
|
|
|
private int countCollectedStonesRight(View view) { |
|
|
|
int[] rightSide = generateRightSideArray(view.width); |
|
|
|
int stones = 0; |
|
|
|
for (int cellIndex : rightSide) { |
|
|
|
if(view.data.charAt(cellIndex) == '*') stones++; |
|
|
|
private char walkBySpiral(View view) { |
|
|
|
if (moves.isEmpty()) { |
|
|
|
spiralFactor++; |
|
|
|
moves += "^".repeat(view.width * spiralFactor) + spiralDirection + "^".repeat(view.width * spiralFactor) + spiralDirection; |
|
|
|
} |
|
|
|
return stones; |
|
|
|
char nextMove = moves.charAt(0); |
|
|
|
moves = moves.substring(1); |
|
|
|
return nextMove; |
|
|
|
} |
|
|
|
|
|
|
|
private int countCollectedStones(View view) { |
|
|
|
int count = 0; |
|
|
|
private char walkByColumns(View view) { |
|
|
|
if(moves.isEmpty()){ |
|
|
|
int min = 10; |
|
|
|
int max = 100; |
|
|
|
|
|
|
|
Random random = new Random(); |
|
|
|
int steps = random.nextInt((max - min) + 1) + min; |
|
|
|
//int steps = 32 - view.width; |
|
|
|
|
|
|
|
for (char c : view.data.toCharArray()) { |
|
|
|
if (c == '*') count++; |
|
|
|
moves = "^".repeat(steps); |
|
|
|
moves += (goesForward ? ">" + "^".repeat(view.width) + ">" : "<" + "^".repeat(view.width) + "<"); |
|
|
|
goesForward = !goesForward; |
|
|
|
} |
|
|
|
return count; |
|
|
|
char nextMove = moves.charAt(0); |
|
|
|
moves = moves.substring(1); |
|
|
|
return nextMove; |
|
|
|
} |
|
|
|
|
|
|
|
private char goToStone(View view) { |
|
|
|
resetMovesSequence(); |
|
|
|
|
|
|
|
int rowDifference = findStoneRow(view) - (view.width / 2); |
|
|
|
return rowDifference < 0 ? '^' : '<'; |
|
|
|
} |
|
|
|
int[] frontIndexes = getFrontIndexes(view); |
|
|
|
int[] leftIndexes = getLeftIndexes(view); |
|
|
|
int[] rightIndexes = getRightIndexes(view); |
|
|
|
|
|
|
|
private int findStoneRow(View view) { |
|
|
|
return view.data.indexOf('@') / view.width; |
|
|
|
} |
|
|
|
for (int index : frontIndexes) { |
|
|
|
if (view.data.charAt(index) == '@' && view.data.charAt(index + view.width) != '*' && !frontIsBlocked) return '^'; |
|
|
|
} |
|
|
|
|
|
|
|
private char walkBySpiral(View view) { |
|
|
|
if (moves.isEmpty()) { |
|
|
|
spiralNumber++; |
|
|
|
moves += "^".repeat(view.width * spiralNumber) + ">" + "^".repeat(view.width * spiralNumber) + ">"; |
|
|
|
for (int index : leftIndexes) { |
|
|
|
if (view.data.charAt(index) == '@' && view.data.charAt(index + 1) != '*' && !leftIsBlocked) return '<'; |
|
|
|
} |
|
|
|
char nextMove = moves.charAt(0); |
|
|
|
moves = moves.substring(1); |
|
|
|
return nextMove; |
|
|
|
} |
|
|
|
|
|
|
|
private int calculateCharIndexFromCoordinates(int width, int x, int y){ |
|
|
|
return width * y + x; |
|
|
|
for (int index : rightIndexes) { |
|
|
|
if (view.data.charAt(index) == '@' && view.data.charAt(index - 1) != '*' && !rightIsBlocked) return '>'; |
|
|
|
} |
|
|
|
|
|
|
|
return '^'; |
|
|
|
} |
|
|
|
|
|
|
|
private int[] generateLeftSideArray(int sideLength) { |
|
|
|
int[] leftStones = new int[sideLength / 2 * sideLength]; |
|
|
|
private int[] getLeftIndexes(View view) { |
|
|
|
int center = view.width / 2; |
|
|
|
int[] leftIndexes = new int[center]; |
|
|
|
int index = 0; |
|
|
|
|
|
|
|
for (int row = 0; row < sideLength; row++) { |
|
|
|
for (int col = 0; col < sideLength / 2; col++) { |
|
|
|
leftStones[index++] = row * sideLength + col; |
|
|
|
} |
|
|
|
for (int col = 0; col < center; col++) { |
|
|
|
leftIndexes[index++] = getCharIndexFromCoordinates(view.width, col, center); |
|
|
|
} |
|
|
|
|
|
|
|
return leftStones; |
|
|
|
return leftIndexes; |
|
|
|
} |
|
|
|
|
|
|
|
private int[] generateRightSideArray(int sideLength) { |
|
|
|
int[] rightStones = new int[sideLength / 2 * sideLength]; |
|
|
|
private int[] getRightIndexes(View view) { |
|
|
|
int center = view.width / 2; |
|
|
|
int[] rightIndexes = new int[center]; |
|
|
|
int index = 0; |
|
|
|
|
|
|
|
for (int row = 0; row < sideLength; row++) { |
|
|
|
for (int col = (sideLength / 2) + 1; col < sideLength; col++) { |
|
|
|
rightStones[index++] = row * sideLength + col; |
|
|
|
} |
|
|
|
for (int col = center + 1; col < view.width; col++) { |
|
|
|
rightIndexes[index++] = getCharIndexFromCoordinates(view.width, col, center); |
|
|
|
} |
|
|
|
|
|
|
|
return rightStones; |
|
|
|
return rightIndexes; |
|
|
|
} |
|
|
|
|
|
|
|
private char walkByColumns(View view) { |
|
|
|
if(moves.isEmpty()){ |
|
|
|
moves = "^".repeat(28); |
|
|
|
moves += (goesForward ? ">" + "^".repeat(view.width) + ">" : "<" + "^".repeat(view.width) + "<"); |
|
|
|
goesForward = !goesForward; |
|
|
|
private int[] getFrontIndexes(View view) { |
|
|
|
int center = view.width / 2; |
|
|
|
int[] frontIndexes = new int[center]; |
|
|
|
int index = 0; |
|
|
|
|
|
|
|
for (int row = 0; row < center; row++) { |
|
|
|
frontIndexes[index++] = getCharIndexFromCoordinates(view.width, center, row); |
|
|
|
} |
|
|
|
char nextMove = moves.charAt(0); |
|
|
|
moves = moves.substring(1); |
|
|
|
return nextMove; |
|
|
|
|
|
|
|
return frontIndexes; |
|
|
|
} |
|
|
|
|
|
|
|
private int getCharIndexFromCoordinates(int width, int x, int y) { |
|
|
|
return width * y + x; |
|
|
|
} |
|
|
|
|
|
|
|
private void resetMovesSequence() { |
|
|
|
moves = ""; |
|
|
|
System.out.println("Previous spiralNumber: " + spiralFactor + ". Resetting."); |
|
|
|
spiralFactor = 1; |
|
|
|
spiralDirection = (spiralDirection == '>') ? '<' : '>'; |
|
|
|
goesForward = true; |
|
|
|
} |
|
|
|
} |