Files
contest/other/Snake/src/Board.java
2020-12-12 00:30:34 -06:00

150 lines
4.3 KiB
Java

import java.util.Arrays;
import java.util.Locale;
import java.util.Scanner;
class SnakeSimulationException extends SnakeException
{
public SnakeSimulationException(String errorMessage)
{
super(errorMessage);
}
}
class OutsideBoundariesException extends SnakeSimulationException
{
public OutsideBoundariesException(Vector2Int position)
{
super(String.format(Locale.ENGLISH, "The snake crossed the grid boundary at (%d, %d).", position.x, position.y));
}
}
class InsideSelfException extends SnakeSimulationException
{
public InsideSelfException(Vector2Int position)
{
super(String.format(Locale.ENGLISH, "The snake crossed into itself at (%d, %d).", position.x, position.y));
}
}
public class Board
{
private final Snake snake;
private final char[][] board;
private int pelletCount;
public Board(char[][] board) throws UnfindableSnakeException
{
char[][] copyBoard = new char[15][15];
for (int y = 0; y < 15; y++)
copyBoard[y] = board[y].clone();
this.board = copyBoard;
snake = new Snake(copyBoard);
}
public static char[][] GetCharBoard(Scanner input)
{
String[] lines = new String[15];
for (int i = 0; i < 15; i++) {
String line = input.nextLine();
// Ensure at least 15 characters available to read
int left = Math.max(0, 15 - line.length());
while (left-- > 0)
line += " ";
lines[i] = line;
}
return GetCharBoard(lines);
}
public static char[][] GetCharBoard(String[] lines)
{
char[][] board = new char[15][15];
int y = 0;
for (String line : lines) {
for (int x = 0; x < 15; x++)
board[y][x] = line.charAt(x);
y++;
}
return board;
}
public void move(char movement) throws SnakeSimulationException
{
// Calculate the new snake head position and move the snake positions
Vector2Int head = snake.Head();
Vector2Int moveDelta = snake.GetDelta(movement);
snake.setPreviousMovement(moveDelta);
snake.positions.add(0, head.plus(moveDelta));
if (!snake.WithinBoundaries()) {
throw new OutsideBoundariesException(snake.Head());
} else if (snake.WithinSelf()) {
throw new InsideSelfException(snake.Head());
} else {
// Only remove the end node if it did not consume a pellet. Simulates the 'extension' of the tail naturally.
if (!Consume())
snake.positions.remove(snake.positions.size() - 1);
else
pelletCount++;
}
}
/**
* If possible, consumes a pellet at the Snake's head position. Returns a boolean signaling if it consumed a pellet.
*
* @return Returns True if the snake has consumed a pellet with the latest function execution.
*/
private boolean Consume()
{
Vector2Int head = snake.Head();
if (board[head.y][head.x] == 'F') {
board[head.y][head.x] = ' ';
return true;
}
return false;
}
public void simulate(String dataset) throws SnakeSimulationException
{
for (int i = 0; i < dataset.length(); i++) {
// System.out.println(render());
// System.out.println("---------------");
this.move(dataset.charAt(i));
}
}
/**
* @return Returns a rendered version of the Board with Snake and Pellet positions marked.
*/
public String render()
{
// Make a copy of the original board
char[][] boardCopy = new char[15][15];
for (int i = 0; i < 15; i++)
boardCopy[i] = Arrays.copyOf(this.board[i], 15);
// Mark the snake's location
for (Vector2Int position : snake.positions)
if (position.x >= 0 && position.y >= 0 && position.x < 15 && position.y < 15)
boardCopy[position.y][position.x] = 'X';
// Join the char arrays into strings
String[] render = new String[15];
for (int i = 0; i < 15; i++)
render[i] = String.valueOf(boardCopy[i]);
// Return all lines, joined by newlines
return String.join("\n", render);
}
public int getPelletCount()
{
return pelletCount;
}
}