/* * SnakeBot. * Eine weitere wichtige Funktion des Rovers ist es, Gesteinsproben zu sammeln. * Interessante Steine sind im Scan mit einem @ gekennzeichnet. * Mit jeder aufgesammelten Gesteinsprobe wird an den Rover ein Wagen angehängt, der zukünftig hinter dem Rover mitgezogen wird. * Die Wagen sind im Scan mit * zu identifizieren. * Vorsicht: fährt der Rover in einen Wagen, ist er schwer beschädigt und kann keine weiteren Steine mehr sammeln. * Sie können Ihre Implementierung wieder testen mit: * docker run --rm -p 63187:63187 mediaeng/bots snakes * 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“. */ public class SnakeBot extends Bot{ String moves = ""; private int spiralNumber = 0; private boolean goesForward = true; private boolean ignoreStones = false; public static void main(String[] args) { 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) { 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); if(nextMove == '^' && view.data.charAt(frontCellIndex) == '*'){ nextMove = (countCollectedStonesLeft(view) <= countCollectedStonesRight(view)) ? '<' : '>'; ignoreStones = true; } if(countUncollectedStones(view) > 1) ignoreStones = true; if(countCollectedStones(view) <= 2 && countUncollectedStones(view) <= 1) ignoreStones = false; if(isStoneNearby(view)){ nextMove = goToNearbyStone(view); } 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) == '@'; 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); if(view.data.charAt(frontCellIndex) == '@') return '^'; if(view.data.charAt(leftCellIndex) == '@') return '<'; if(view.data.charAt(rightCellIndex) == '@') return '>'; return 0; } private void resetMoves() { moves = ""; spiralNumber = 0; } private int countUncollectedStones(View view) { int count = 0; for (char c : view.data.toCharArray()) { if (c == '@') count++; } return count; } private int countCollectedStonesLeft(View view) { int[] leftSide = generateLeftSideArray(view.width); int stones = 0; for (int cellIndex : leftSide) { if(view.data.charAt(cellIndex) == '*') stones++; } 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++; } return stones; } private int countCollectedStones(View view) { int count = 0; for (char c : view.data.toCharArray()) { if (c == '*') count++; } return count; } private char goToStone(View view) { int rowDifference = findStoneRow(view) - (view.width / 2); return rowDifference < 0 ? '^' : '<'; } private int findStoneRow(View view) { return view.data.indexOf('@') / view.width; } private char walkBySpiral(View view) { if (moves.isEmpty()) { spiralNumber++; moves += "^".repeat(view.width * spiralNumber) + ">" + "^".repeat(view.width * spiralNumber) + ">"; } char nextMove = moves.charAt(0); moves = moves.substring(1); return nextMove; } private int calculateCharIndexFromCoordinates(int width, int x, int y){ return width * y + x; } private int[] generateLeftSideArray(int sideLength) { int[] leftStones = new int[sideLength / 2 * sideLength]; int index = 0; for (int row = 0; row < sideLength; row++) { for (int col = 0; col < sideLength / 2; col++) { leftStones[index++] = row * sideLength + col; } } return leftStones; } private int[] generateRightSideArray(int sideLength) { int[] rightStones = new int[sideLength / 2 * sideLength]; int index = 0; for (int row = 0; row < sideLength; row++) { for (int col = (sideLength / 2) + 1; col < sideLength; col++) { rightStones[index++] = row * sideLength + col; } } return rightStones; } private char walkByColumns(View view) { if(moves.isEmpty()){ moves = "^".repeat(28); moves += (goesForward ? ">" + "^".repeat(view.width) + ">" : "<" + "^".repeat(view.width) + "<"); goesForward = !goesForward; } char nextMove = moves.charAt(0); moves = moves.substring(1); return nextMove; } }