Commit 207adb5b authored by Magnus Schjølberg's avatar Magnus Schjølberg
Browse files

Add test code for JUnit5 and JavaFX

parent cbe0d512
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Text?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="of10.lf.GameController">
<children>
<GridPane prefHeight="400.0" prefWidth="400.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="600.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="330.0" vgrow="ALWAYS" />
<RowConstraints maxHeight="70.0" minHeight="70.0" prefHeight="70.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Pane fx:id="board" prefHeight="200.0" prefWidth="600.0" GridPane.rowIndex="0">
</Pane>
<Pane maxHeight="75.0" minHeight="75.0" prefHeight="75.0" prefWidth="600.0" GridPane.rowIndex="1">
<children>
<Button layoutX="100.0" layoutY="5.0" mnemonicParsing="false" onMouseClicked="#handleUp" prefWidth="60.0" text="Up" />
<Button layoutX="100.0" layoutY="40.0" mnemonicParsing="false" onMouseClicked="#handleDown" prefWidth="60.0" text="Down" />
<Button layoutX="30.0" layoutY="40.0" mnemonicParsing="false" onMouseClicked="#handleLeft" prefWidth="60.0" text="Left" />
<Button layoutX="170.0" layoutY="40.0" mnemonicParsing="false" onMouseClicked="#handleRight" prefWidth="60.0" text="Right" />
<Button layoutX="507.0" layoutY="5.0" mnemonicParsing="false" onMouseClicked="#handleLoad" text="Load" />
<Button layoutX="507.0" layoutY="40.0" mnemonicParsing="false" onMouseClicked="#handleSave" text="Save" />
<TextField fx:id="filename" layoutX="334.0" layoutY="27.0" prefHeight="27.0" prefWidth="160.0" promptText="save_file" text="save_file" />
<Text layoutX="334.0" layoutY="23.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Filename:" />
<Text fill="RED" layoutX="334.0" layoutY="66.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Filen finnes ikke" visible="false" fx:id="fileNotFoundMessage"/>
</children>
</Pane>
</children>
</GridPane>
</children>
</AnchorPane>
package of13.kode;
import java.util.ArrayList;
import java.util.List;
public class Game {
private Tile[][] board;
private ArrayList<Tile> snake;
private boolean isGameOver = false;
private boolean isGameWon = false;
public Game(int width, int height) {
board = new Tile[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
board[y][x] = new Tile(x, y);
}
}
}
public void createSnake(List<Tile> tiles) {
if (snake != null) {
throw new IllegalStateException("Snake already created");
}
for (Tile tile : tiles) {
tile.setSnake();
}
snake = new ArrayList<>(tiles);
}
public boolean isTile(int x, int y) {
return 0 <= x && x < getWidth() && 0 <= y && y < getHeight();
}
public Tile getTile(int x, int y) {
if (!isTile(x, y)) {
throw new IllegalArgumentException("Not a valid tile");
}
return board[y][x];
}
public int getHeight() {
return board.length;
}
public int getWidth() {
return board[0].length;
}
public boolean isGameOver() {
return isGameOver;
}
public boolean isGameWon() {
return isGameWon;
}
public void setGameOver() {
isGameOver = true;
}
public void setGameWon() {
isGameWon = true;
}
private boolean canMove(int dx, int dy) {
if (snake == null || Math.abs(dx) + Math.abs(dy) > 1 || isGameOver() || isGameWon()) {
return false;
}
int x = snake.get(0).getX() + dx;
int y = snake.get(0).getY() + dy;
return isTile(x, y) && (!getTile(x, y).hasCollision() || getTile(x, y) == snake.get(snake.size() - 1));
}
private void move(int dx, int dy) {
if (!canMove(dx, dy)) {
throw new IllegalStateException("Not a valid move");
}
Tile targetTile = getTile(snake.get(0).getX() + dx, snake.get(0).getY() + dy);
if (targetTile.isGoal()) {
isGameWon = true;
}
if (!targetTile.isFruit()) {
snake.get(snake.size() - 1).setAir();
snake.remove(snake.size() - 1);
}
snake.add(0, targetTile);
snake.get(0).setSnake();
if (isGameWon) {
return;
}
while (snakeInAir()) {
isGameOver = false;
for (Tile tile : snake) {
if (!isTile(tile.getX(), tile.getY() + 1)) {
isGameOver = true;
}
}
if (isGameOver) {
break;
}
for (Tile tile : snake) {
tile.setAir();
}
ArrayList<Tile> newSnake = new ArrayList<>();
for (Tile tile : snake) {
Tile newTile = getTile(tile.getX(), tile.getY() + 1);
newTile.setSnake();
newSnake.add(newTile);
}
snake = newSnake;
}
}
private boolean snakeInAir() {
for (Tile tile : snake) {
if (isTile(tile.getX(), tile.getY() + 1) && getTile(tile.getX(), tile.getY() + 1).isGround()) {
return false;
}
}
return true;
}
public boolean isSnakeHead(Tile tile) {
return snake != null && tile == snake.get(0);
}
public void moveUp() {
move(0, -1);
System.out.println(this);
}
public void moveDown() {
move(0, 1);
System.out.println(this);
}
public void moveLeft() {
move(-1, 0);
System.out.println(this);
}
public void moveRight() {
move(1, 0);
System.out.println(this);
}
public List<Tile> getSnake() {
return new ArrayList<>(snake);
}
@Override
public String toString() {
String representation = "";
if (isGameWon()) {
representation = "You Won!";
} else if (isGameOver()) {
representation = "You Lost!";
}
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
if (snake != null && snake.get(0) == getTile(x, y)) {
representation = representation + "8";
} else {
representation = representation + getTile(x, y).toString();
}
}
representation = representation + "\n";
}
return representation;
}
}
package of13.kode;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class GameApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage primaryStage) throws IOException {
primaryStage.setTitle("Snakebird");
primaryStage.setScene(new Scene(FXMLLoader.load(getClass().getResource("Game.fxml"))));
primaryStage.show();
}
}
package of13.kode;
import javafx.fxml.FXML;
import javafx.scene.text.Text;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import java.io.FileNotFoundException;
import java.util.Arrays;
public class GameController {
private Game game;
private SaveHandler saveHandler = new SaveHandler();
@FXML
Pane board;
@FXML
TextField filename;
@FXML
Text fileNotFoundMessage;
@FXML
public void initialize() {
game = new Game(16, 12);
game.getTile(6, 11).setGround();
game.getTile(7, 11).setGround();
game.getTile(8, 11).setGround();
game.getTile(6, 10).setGround();
game.getTile(7, 10).setGround();
game.getTile(8, 10).setGround();
game.getTile(9, 10).setGround();
game.getTile(6, 9).setGround();
game.getTile(7, 9).setGround();
game.getTile(8, 9).setGround();
game.getTile(9, 9).setGround();
game.getTile(6, 8).setGround();
game.getTile(8, 6).setGround();
game.getTile(10, 6).setGround();
game.getTile(5, 5).setGround();
game.getTile(5, 6).setFruit();
game.getTile(9, 6).setFruit();
game.getTile(8, 3).setGoal();
game.createSnake(Arrays.asList(game.getTile(9, 8), game.getTile(8, 8)));
createBoard();
drawBoard();
}
private void createBoard() {
board.getChildren().clear();
for (int y = 0; y < game.getHeight(); y++) {
for (int x = 0; x < game.getWidth(); x++) {
Pane tile = new Pane();
tile.setTranslateX(x * 20);
tile.setTranslateY(y * 20);
tile.setPrefWidth(20);
tile.setPrefHeight(20);
board.getChildren().add(tile);
}
}
}
private String getTileColor(Tile tile) {
if (game.isSnakeHead(tile)) {
return "#1db121";
} else if (tile.isSnake()) {
return "#24d628";
} else if (tile.isGround()) {
return "#a26f42";
} else if (tile.isFruit()) {
return "#e5303a";
} else if (tile.isGoal()) {
return "#f6ec5a";
}
return "#7bcaf2";
}
@FXML
void handleUp() {
game.moveUp();
drawBoard();
}
@FXML
void handleDown() {
game.moveDown();
drawBoard();
}
@FXML
void handleLeft() {
game.moveLeft();
drawBoard();
}
@FXML
void handleRight() {
game.moveRight();
drawBoard();
}
private String getFilename() {
String filename = this.filename.getText();
if (filename.isEmpty()) {
filename = "save_file";
}
return filename;
}
@FXML
void handleSave() {
try {
saveHandler.save(getFilename(), game);
fileNotFoundMessage.setVisible(false);
} catch (FileNotFoundException e) {
fileNotFoundMessage.setVisible(true);
}
}
@FXML
void handleLoad() {
try {
game = saveHandler.load(getFilename());
fileNotFoundMessage.setVisible(false);
} catch (FileNotFoundException e) {
fileNotFoundMessage.setVisible(true);
}
createBoard();
drawBoard();
}
private void drawBoard() {
for (int y = 0; y < game.getHeight(); y++) {
for (int x = 0; x < game.getWidth(); x++) {
board.getChildren().get(y * game.getWidth() + x).setStyle("-fx-background-color: " + getTileColor(game.getTile(x, y)));
}
}
if (game.isGameWon()) {
Text wonText = new Text();
wonText.setText("You Won!");
wonText.setFill(Color.GREEN);
wonText.setStyle("-fx-font-size: 40px;");
wonText.setTranslateX(((double) game.getWidth() * 20) / 2 - 80);
wonText.setTranslateY(((double) game.getHeight() * 20) / 2);
board.getChildren().add(wonText);
} else if (game.isGameOver()) {
Text lostText = new Text();
lostText.setText("You Lost!");
lostText.setStyle("-fx-font-size: 40px;");
lostText.setFill(Color.RED);
lostText.setTranslateX(((double) game.getWidth() * 20) / 2 - 80);
lostText.setTranslateY(((double) game.getHeight() * 20) / 2);
board.getChildren().add(lostText);
}
}
}
package of13.kode;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class SaveHandler {
public final static String SAVE_FOLDER = "src/main/java/of13/saves/";
public void save(String filename, Game game) throws FileNotFoundException {
try (PrintWriter writer = new PrintWriter(getFilePath(filename))) {
writer.println(game.getWidth());
writer.println(game.getHeight());
writer.println(game.isGameOver());
writer.println(game.isGameWon());
for (int y = 0; y < game.getHeight(); y++) {
for (int x = 0; x < game.getWidth(); x++) {
writer.print(game.getTile(x, y).getType());
}
}
writer.println();
writer.println(game.getSnake().size());
for (Tile tile : game.getSnake()) {
writer.print(tile.getX());
writer.print(" ");
writer.println(tile.getY());
// Eventuelt
//writer.printf("%d %d\n", tile.getX(), tile.getY());
}
}
}
public Game load(String filename) throws FileNotFoundException {
try (Scanner scanner = new Scanner(new File(getFilePath(filename)))) {
int width = scanner.nextInt();
int height = scanner.nextInt();
Game game = new Game(width, height);
if (scanner.nextBoolean()) {
game.setGameOver();
}
if (scanner.nextBoolean()) {
game.setGameWon();
}
scanner.nextLine();
String board = scanner.next();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
char symbol = board.charAt(y * width + x);
game.getTile(x, y).setType(symbol);
}
}
int snakeLength = scanner.nextInt();
List<Tile> snake = new ArrayList<>();
for (int i = 0; i < snakeLength; i++) {
snake.add(game.getTile(scanner.nextInt(), scanner.nextInt()));
}
game.createSnake(snake);
return game;
}
}
public static String getFilePath(String filename) {
return SAVE_FOLDER + filename + ".txt";
}
}
package of13.kode;
public class Tile {
private char type = 'a';
private int x;
private int y;
public Tile(int x, int y) {
this.x = x;
this.y = y;
}
public void setType(char symbol) {
if ("asgf@s".indexOf(symbol) == -1) {
throw new IllegalArgumentException("Not a valid state");
}
type = symbol;
}
public char getType() {
return type;
}
public void setAir() {
type = 'a';
}
public void setSnake() {
type = 's';
}
public void setGround() {
type = 'g';
}
public void setFruit() {
type = 'f';
}
public void setGoal() {
type = '@';
}
public boolean isAir() {
return type == 'a';
}
public boolean isSnake() {
return type == 's';
}
public boolean isGround() {
return type == 'g';
}
public boolean isFruit() {
return type == 'f';
}
public boolean isGoal() {
return type == '@';
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean hasCollision() {
return isGround() || isSnake();
}
@Override
public String toString() {
switch (type) {
case 'g':
return "#";
case '@':
return "@";
case 's':
return "O";
case 'f':
return "*";
case 'a':