mirror of
https://github.com/Xevion/contest.git
synced 2025-12-06 01:14:36 -06:00
finished Snake class-based program
This commit is contained in:
1
other/Snake/.gitignore
vendored
Normal file
1
other/Snake/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.idea/**
|
||||
11
other/Snake/Snake.iml
Normal file
11
other/Snake/Snake.iml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
18
other/Snake/out/production/Snake/snake2.dat
Normal file
18
other/Snake/out/production/Snake/snake2.dat
Normal file
@@ -0,0 +1,18 @@
|
||||
F F
|
||||
F F
|
||||
F
|
||||
F
|
||||
|
||||
F F
|
||||
|
||||
|
||||
|
||||
XXX F
|
||||
|
||||
|
||||
F F
|
||||
|
||||
F
|
||||
2
|
||||
UROOOUOOLOOOOOOUOOOO
|
||||
UOOOOOOOOOOOOOOOOOOO
|
||||
0
other/Snake/out/production/Snake/snake2.out
Normal file
0
other/Snake/out/production/Snake/snake2.out
Normal file
149
other/Snake/src/Board.java
Normal file
149
other/Snake/src/Board.java
Normal file
@@ -0,0 +1,149 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
107
other/Snake/src/Snake.java
Normal file
107
other/Snake/src/Snake.java
Normal file
@@ -0,0 +1,107 @@
|
||||
import java.util.ArrayList;
|
||||
|
||||
class UnfindableSnakeException extends SnakeException {
|
||||
UnfindableSnakeException(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public class Snake
|
||||
{
|
||||
public ArrayList<Vector2Int> positions;
|
||||
private Vector2Int previousMovement = GetDelta('R');
|
||||
|
||||
public Snake(char[][] board) throws UnfindableSnakeException
|
||||
{
|
||||
Vector2Int head = null;
|
||||
// Find head of the snake - lazily using problem constraints
|
||||
for (int y = 0; y < 15; y++) {
|
||||
for (int x = 15 - 1; x >= 0; x--) {
|
||||
if (board[y][x] == 'X') {
|
||||
if (head == null)
|
||||
head = new Vector2Int(x, y);
|
||||
board[y][x] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the head was find, build the Snake's known positions
|
||||
if (head != null) {
|
||||
positions = new ArrayList<>();
|
||||
positions.add(head);
|
||||
positions.add(new Vector2Int(head.x - 1, head.y));
|
||||
positions.add(new Vector2Int(head.x - 2, head.y));
|
||||
} else {
|
||||
throw new UnfindableSnakeException("Could not find Snake head within the provided Grid.");
|
||||
}
|
||||
}
|
||||
|
||||
public Snake(ArrayList<Vector2Int> positions)
|
||||
{
|
||||
this.positions = positions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the current length of the snake
|
||||
*/
|
||||
public int Length()
|
||||
{
|
||||
return positions.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Returns the 'head' (first) node in the snake.
|
||||
*/
|
||||
public Vector2Int Head() { return positions.get(0); }
|
||||
|
||||
|
||||
/**
|
||||
* @return Returns he 'tail' (last) node in the snake.
|
||||
*/
|
||||
public Vector2Int Tail() { return positions.get(positions.size() - 1); }
|
||||
|
||||
public Vector2Int GetDelta(char movement) {
|
||||
switch (movement) {
|
||||
case 'U':
|
||||
return new Vector2Int(0, -1);
|
||||
case 'D':
|
||||
return new Vector2Int(0, 1);
|
||||
case 'L':
|
||||
return new Vector2Int(-1, 0);
|
||||
case 'R':
|
||||
return new Vector2Int(1, 0);
|
||||
case 'O':
|
||||
return previousMovement;
|
||||
default:
|
||||
return new Vector2Int();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether or not the Snake's head is within the game's boundaries.
|
||||
*/
|
||||
public boolean WithinBoundaries()
|
||||
{
|
||||
Vector2Int head = positions.get(0);
|
||||
return head.x >= 0 && head.y >= 0 && head.x < 15 && head.y < 15;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns true if the Snake's body positions overlap onto itself
|
||||
*/
|
||||
public boolean WithinSelf() {
|
||||
Vector2Int head = Head();
|
||||
|
||||
// Iterate along each previous node in the snake and check if it has moved into itself
|
||||
for (int i = 1; i < positions.size(); i++)
|
||||
if (head.equals(positions.get(i)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setPreviousMovement(Vector2Int previousMovement)
|
||||
{
|
||||
this.previousMovement = previousMovement;
|
||||
}
|
||||
}
|
||||
3
other/Snake/src/Snake2.java
Normal file
3
other/Snake/src/Snake2.java
Normal file
@@ -0,0 +1,3 @@
|
||||
public class Snake2
|
||||
{
|
||||
}
|
||||
51
other/Snake/src/SnakeRunner.java
Normal file
51
other/Snake/src/SnakeRunner.java
Normal file
@@ -0,0 +1,51 @@
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static java.lang.System.out;
|
||||
|
||||
class SnakeException extends Exception
|
||||
{
|
||||
public SnakeException(String errorMessage)
|
||||
{
|
||||
super(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SnakeRunner
|
||||
{
|
||||
public static void main(String[] args) throws UnfindableSnakeException, FileNotFoundException
|
||||
{
|
||||
// Read board input
|
||||
Scanner input = new Scanner(new File("./src/snake2.dat"));
|
||||
char[][] charBoard = Board.GetCharBoard(input);
|
||||
|
||||
// Read datasets
|
||||
String[] datasets = new String[input.nextInt()];
|
||||
input.nextLine();
|
||||
for (int i = 0; i < datasets.length; i++)
|
||||
datasets[i] = input.nextLine();
|
||||
|
||||
// Simulate each dataset
|
||||
int i = 0;
|
||||
for (String dataset : datasets) {
|
||||
Board board = new Board(charBoard);
|
||||
boolean success = true;
|
||||
try {
|
||||
// out.println(dataset);
|
||||
board.simulate(dataset);
|
||||
} catch (SnakeSimulationException e) {
|
||||
// out.printf("Could not fully simulate dataset %s...%n", i);
|
||||
// e.printStackTrace();
|
||||
out.println("GAME OVER");
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success)
|
||||
out.printf("%d Pellets%n", board.getPelletCount());
|
||||
|
||||
out.println(board.render());
|
||||
}
|
||||
}
|
||||
}
|
||||
23
other/Snake/src/Vector2Int.java
Normal file
23
other/Snake/src/Vector2Int.java
Normal file
@@ -0,0 +1,23 @@
|
||||
public class Vector2Int
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
public Vector2Int() {
|
||||
this(0, 0);
|
||||
}
|
||||
|
||||
public Vector2Int(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Vector2Int plus(Vector2Int other)
|
||||
{
|
||||
return new Vector2Int(this.x + other.x, this.y + other.y);
|
||||
}
|
||||
|
||||
public boolean equals(Vector2Int other) {
|
||||
return this.x == other.x && this.y == other.y;
|
||||
}
|
||||
}
|
||||
18
other/Snake/src/snake2.dat
Normal file
18
other/Snake/src/snake2.dat
Normal file
@@ -0,0 +1,18 @@
|
||||
F F
|
||||
F F
|
||||
F
|
||||
F
|
||||
|
||||
F F
|
||||
|
||||
|
||||
|
||||
XXX F
|
||||
|
||||
|
||||
F F
|
||||
|
||||
F
|
||||
2
|
||||
UROOOUOOLOOOOOOUOOOO
|
||||
UOOOOOOOOOOOOOOOOOOO
|
||||
0
other/Snake/src/snake2.out
Normal file
0
other/Snake/src/snake2.out
Normal file
Reference in New Issue
Block a user