add symlinks for marathon

This commit is contained in:
Oshgnacknak 2025-01-11 16:41:13 +01:00
parent d62aaf6a03
commit f97bf5de98
Signed by: Oshgnacknak
GPG key ID: 8CB7375654585956
127 changed files with 16 additions and 5675 deletions

1
solution/H00/src/main Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H00/src/main

View file

@ -1,121 +0,0 @@
package h00;
import fopbot.Direction;
import fopbot.Robot;
import fopbot.RobotFamily;
import fopbot.World;
/**
* Main entry point in executing the program.
*/
public class Main {
/**
* The subtask to run.
*/
public static int runToSubtask = -1;
/**
* The world speed in milliseconds.
*/
public static int delay = 300;
/**
* Main entry point in executing the program.
*
* @param args program arguments, currently ignored
*/
public static void main(String[] args) {
// This sets up the FOPBot World with a 4x4 grid. (DO NOT TOUCH)
setupWorld();
// TODO: H0.4 - Initializing FOPBot
Robot kasper = new Robot(0, 0, Direction.DOWN, 4, RobotFamily.SQUARE_BLUE);
Robot alfred = new Robot(0, 3, Direction.DOWN, 0, RobotFamily.SQUARE_GREEN);
if (runToSubtask == 0) return; // DO NOT TOUCH!
// TODO: H0.5.1 - Turning with repeated instructions
alfred.turnLeft();
alfred.turnLeft();
if (runToSubtask == 1) return; // DO NOT TOUCH!
// TODO: H0.5.2 - Turning with for-loop
int numberOfTurns = 2;
for (int i = 0; i < numberOfTurns; i++) {
alfred.turnLeft();
}
if (runToSubtask == 2) return; // DO NOT TOUCH!
// TODO: H0.5.3 - Turning with while-loop
while (!kasper.isFacingRight()) {
kasper.turnLeft();
}
if (runToSubtask == 3) return; // DO NOT TOUCH!
// TODO: H0.6.1 - Put with repeated instructions
kasper.putCoin();
kasper.move();
kasper.move();
kasper.move();
kasper.turnLeft();
if (runToSubtask == 4) return; // DO NOT TOUCH!
// TODO: H0.6.2 - Pick with repeated instructions
alfred.move();
alfred.move();
alfred.move();
alfred.pickCoin();
alfred.turnLeft();
if (runToSubtask == 5) return; // DO NOT TOUCH!
// TODO: H0.6.3 - Put with for-loop
kasper.putCoin();
int numberOfSteps = 3;
for (int i = 0; i < numberOfSteps; i++) {
kasper.move();
}
kasper.turnLeft();
if (runToSubtask == 6) return; // DO NOT TOUCH!
// TODO: H0.7.1 - Pick with while-loop
while (alfred.isFrontClear()) {
alfred.move();
}
alfred.pickCoin();
alfred.turnLeft();
if (runToSubtask == 7) return; // DO NOT TOUCH!
// TODO: H0.7.2 - Pick and put with while-loop
kasper.putCoin();
while (alfred.isFrontClear()) {
kasper.move();
alfred.move();
}
alfred.pickCoin();
alfred.turnLeft();
kasper.turnLeft();
if (runToSubtask == 8) return; // DO NOT TOUCH!
// TODO: H0.7.3 - Put with reversed for-loop
for (int i = alfred.getNumberOfCoins(); i > 0; i--) {
alfred.putCoin();
alfred.move();
}
alfred.turnLeft();
}
public static void setupWorld() {
// variable representing width/size of world
final int worldSize = 4;
// setting world size symmetrical, meaning height = width
World.setSize(worldSize, worldSize);
// speed of how fast the world gets refreshed (e.g. how fast the robot(s) act)
// the lower the number, the faster the refresh
World.setDelay(delay);
// make it possible to see the world window
World.setVisible(true);
}
}

1
solution/H00/src/test Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H00/src/test

View file

@ -1,16 +0,0 @@
package h00;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* An example JUnit test class.
*/
public class ExampleJUnitTest {
@Test
public void testAddition() {
assertEquals(2, 1 + 1);
}
}

1
solution/H01/src/main Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H01/src/main

View file

@ -1,50 +0,0 @@
package h01;
import org.tudalgo.algoutils.student.annotation.SolutionOnly;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import fopbot.Robot;
import h01.template.Families;
import h01.template.Ghost;
import h01.template.TickBased;
/**
* The {@link BlueGhost} is a {@link Robot} that looks like a blue ghost.
* It tries to move in a circle.
*/
public class BlueGhost extends Robot implements Ghost, TickBased {
/**
* Creates a new {@link BlueGhost} at the given position.
*
* @param x the x-coordinate
* @param y the y-coordinate
*/
public BlueGhost(int x, int y) {
super(x, y, Families.GHOST_BLUE);
}
/**
* Turns the robot to the right and then moves in the first direction that is
* clear.
*/
@Override
@StudentImplementationRequired("H2.1")
public void doMove() {
turnRight();
while (!isFrontClear()) {
turnLeft();
}
move();
}
/**
* Turns the robot to the right.
*
*/
@SolutionOnly
private void turnRight() {
for (int i = 0; i < 3; i++) {
turnLeft();
}
}
}

View file

@ -1,23 +0,0 @@
package h01;
import h01.template.GameControllerTemplate;
/**
* The {@link GameController} class is responsible for controlling the game.
*/
public class GameController extends GameControllerTemplate {
/**
* Creates a new {@link GameController} object and sets up the game.
*/
public GameController() {
setup();
}
/**
* Checks if the player has won the game.
*/
@Override
public boolean checkWinCondition() {
return pacman.getNumberOfCoins() == totalCoins;
}
}

View file

@ -1,16 +0,0 @@
package h01;
/**
* Main entry point in executing the program.
*/
public class Main {
/**
* Main entry point in executing the program.
*
* @param args program arguments, currently ignored
*/
public static void main(String[] args) {
new GameController().startGame();
}
}

View file

@ -1,53 +0,0 @@
package h01;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import fopbot.Robot;
import h01.template.Families;
import h01.template.Ghost;
import h01.template.TickBased;
/**
* {@link OrangeGhost} is a {@link Robot} that looks like a orange ghost.
* It tries to move in a straight line and alternates between turning left and
* right.
*/
public class OrangeGhost extends Robot implements Ghost, TickBased {
/**
* Creates a new {@link OrangeGhost} at the given position.
*
* @param x the x-coordinate
* @param y the y-coordinate
*/
public OrangeGhost(int x, int y) {
super(x, y, Families.GHOST_ORANGE);
}
private boolean leftTurnNext = false;
/**
* Moves the robot in a straight line if possible.
* If the robot cannot move forward, it turns left or right until there is no
* wall in front.
* The robot alternates between turning left and right.
*/
@Override
@StudentImplementationRequired("H2.3")
public void doMove() {
if (isFrontClear()) {
move();
return;
} else {
while (!isFrontClear()) {
if (leftTurnNext) {
turnLeft();
} else {
turnLeft();
turnLeft();
turnLeft();
}
}
leftTurnNext = !leftTurnNext;
}
}
}

View file

@ -1,74 +0,0 @@
package h01;
import org.tudalgo.algoutils.student.annotation.SolutionOnly;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import fopbot.Direction;
import fopbot.Robot;
import h01.template.Controllable;
import h01.template.Families;
import h01.template.TickBased;
/**
* {@link Pacman} is a {@link Robot} that can be controlled by the user and
* looks like Pacman.
* It can move in four directions and pick up coins.
*/
public class Pacman extends Robot implements Controllable, TickBased {
/**
* Creates a new {@link Pacman} at the given position.
*
* @param x the x-coordinate
* @param y the y-coordinate
*/
public Pacman(int x, int y) {
super(x, y, Families.PACMAN);
}
/**
* Handles the key input of the user.
* The keys 0, 1, 2, 3 represent the arrow keys up, right, down, left.
* If the key is not in this range, the method does nothing.
* If the key is in the range, the robot turns in the corresponding direction,
* moves one field and collects a coin if there is one.
*
* @param k the int value of the pressed key
*/
@Override
@StudentImplementationRequired("H1.1")
public void handleKeyInput(int k) {
if (k < 0 || k > 3) {
return;
}
if (k == 0) {
turnDirection(Direction.UP);
} else if (k == 1) {
turnDirection(Direction.RIGHT);
} else if (k == 2) {
turnDirection(Direction.DOWN);
} else {
turnDirection(Direction.LEFT);
}
if (isFrontClear()) {
move();
}
if (isOnACoin()) {
pickCoin();
}
}
/**
* Turns the robot in the given direction.
*
* @param dir the direction to turn to
*/
@SolutionOnly
private void turnDirection(Direction dir) {
while (getDirection() != dir) {
turnLeft();
}
}
}

View file

@ -1,50 +0,0 @@
package h01;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import fopbot.Robot;
import h01.template.Families;
import h01.template.Ghost;
import h01.template.TickBased;
import h01.template.Util;
/**
* The {@link PinkGhost} is a {@link Robot} that looks like a pink ghost.
* It tries to move in a random direction.
*/
public class PinkGhost extends Robot implements Ghost, TickBased {
/**
* Creates a new {@link PinkGhost} at the given position.
*
* @param x the x-coordinate
* @param y the y-coordinate
*/
public PinkGhost(int x, int y) {
super(x, y, Families.GHOST_PINK);
}
/**
* Finds in how many directions the ghost can move and then turns a random
* amount of times to the left.
* The ghost then moves forward or turns to the left until it can move forward.
*/
@Override
@StudentImplementationRequired("H2.2")
public void doMove() {
int freeLanes = 0;
for (int i = 0; i < 4; i++) {
turnLeft();
if (isFrontClear()) {
freeLanes++;
}
}
int rand = Util.getRandomInteger(1, freeLanes);
for (int i = 0; i < rand; i++) {
do {
turnLeft();
} while (!isFrontClear());
}
move();
}
}

View file

@ -1,57 +0,0 @@
package h01;
import org.tudalgo.algoutils.student.annotation.SolutionOnly;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import fopbot.Direction;
import fopbot.Robot;
import h01.template.Families;
import h01.template.Ghost;
import h01.template.TickBased;
import h01.template.Util;
/**
* The {@link RedGhost} is a {@link Robot} that looks like a red ghost.
* It tries to move in the direction of the chased robot.
*/
public class RedGhost extends Robot implements Ghost, TickBased {
private final Robot chased;
/**
* Creates a new {@link RedGhost} at the given position.
*
* @param x the x-coordinate
* @param y the y-coordinate
* @param chased the robot that is being chased
*/
public RedGhost(int x, int y, Robot chased) {
super(x, y, Families.GHOST_RED);
this.chased = chased;
}
/**
* Moves the robot in the direction of the chased robot.
*/
@Override
@StudentImplementationRequired("H2.4")
public void doMove() {
turnDirection(Util.furthestDirection(chased, this));
while (!isFrontClear()) {
turnLeft();
}
move();
}
/**
* Turns the robot in the given direction.
*
* @param dir the direction to turn to
*/
@SolutionOnly
private void turnDirection(Direction dir) {
while (getDirection() != dir) {
turnLeft();
}
}
}

View file

@ -1,5 +0,0 @@
package h01.template;
public interface Controllable {
void handleKeyInput(int k);
}

View file

@ -1,36 +0,0 @@
package h01.template;
import fopbot.RobotFamily;
import fopbot.SvgBasedRobotFamily;
import java.awt.*;
public class Families {
public static RobotFamily GHOST_ORANGE = new SvgBasedRobotFamily(
"GHOST_ORANGE",
"/robots/ghost_orange.svg",
"/robots/ghost_orange.svg",
Color.ORANGE);
public static RobotFamily GHOST_BLUE = new SvgBasedRobotFamily(
"GHOST_BLUE",
"/robots/ghost_blue.svg",
"/robots/ghost_blue.svg",
Color.BLUE);
public static RobotFamily GHOST_RED = new SvgBasedRobotFamily(
"GHOST_RED",
"/robots/ghost_red.svg",
"/robots/ghost_red.svg",
Color.RED);
public static RobotFamily GHOST_PINK = new SvgBasedRobotFamily(
"GHOST_PINK",
"/robots/ghost_pink.svg",
"/robots/ghost_pink.svg",
Color.PINK);
public static RobotFamily PACMAN = new SvgBasedRobotFamily(
"PACMAN",
"/robots/pacman.svg",
"/robots/pacman.svg",
Color.YELLOW,
270,
270);
}

View file

@ -1,378 +0,0 @@
package h01.template;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import fopbot.Coin;
import fopbot.ColorProfile;
import fopbot.GuiPanel;
import fopbot.PaintUtils;
import fopbot.Robot;
import fopbot.World;
import h01.BlueGhost;
import h01.OrangeGhost;
import h01.Pacman;
import h01.PinkGhost;
import h01.RedGhost;
/**
* A {@link GameControllerTemplate} controls the game loop and the
* {@link Robot}s and checks the win condition.
*/
public abstract class GameControllerTemplate {
/**
* The {@link Timer} that controls the game loop.
*/
private final Timer gameLoopTimer = new Timer();
/**
* The {@link GameInputHandler} that handles the input of the user.
*/
private final GameInputHandler inputHandler = new GameInputHandler();
/**
* The total umber of coins in the map.
*/
protected int totalCoins;
/**
* The {@link Robot}s that are controlled by the {@link GameControllerTemplate}.
*/
protected final ArrayList<Robot> robots = new ArrayList<>();
/**
* The {@link Pacman} {@link Robot}.
*/
protected Robot pacman;
/**
* The {@link BlueGhost} {@link Robot}.
*/
protected Robot blue;
/**
* The {@link OrangeGhost} {@link Robot}.
*/
protected Robot orange;
/**
* The {@link PinkGhost} {@link Robot}.
*/
protected Robot pink;
/**
* The {@link RedGhost} {@link Robot}.
*/
protected Robot red;
private Point ghostField = new Point(4, 4);
/**
* A {@link Map} that maps a {@link Robot} to the amount of ticks that have
* passed since the last tick action.
*/
private final Map<Robot, Integer> robotTicks = new HashMap<>();
/**
* The {@link TimerTask} that is executed every tick.
*/
private final TimerTask gameLoopTask = new TimerTask() {
@Override
public void run() {
for (final Robot robot : GameControllerTemplate.this.robots) {
if (!(robot instanceof final TickBased tb)) {
continue;
}
if (!GameControllerTemplate.this.robotTicks.containsKey(robot)) {
GameControllerTemplate.this.robotTicks.put(robot, 0);
}
if (GameControllerTemplate.this.robotTicks.get(robot) < tb.getUpdateDelay()) {
GameControllerTemplate.this.robotTicks.put(robot,
GameControllerTemplate.this.robotTicks.get(robot) + 1);
continue;
}
GameControllerTemplate.this.robotTicks.put(robot, 0);
// do tick action
if (robot instanceof final Pacman r) {
r.handleKeyInput(
GameControllerTemplate.this.inputHandler.getDirection());
} else if (robot instanceof final Ghost r) {
r.doMove();
}
}
// check win condition
if (checkWinCondition())
stopGame(true);
if (checkLoseCondition())
stopGame(false);
}
};
/**
* Gets the {@link h01.Pacman} {@link Robot}.
*
* @return the {@link h01.Pacman} {@link Robot}
*/
public Robot getPacman() {
return pacman;
}
/**
* Gets the {@link BlueGhost} {@link Robot}.
*
* @return the {@link BlueGhost} {@link Robot}
*/
public Robot getBlue() {
return blue;
}
/**
* Gets the {@link OrangeGhost} {@link Robot}.
*
* @return the {@link OrangeGhost} {@link Robot}
*/
public Robot getOrange() {
return orange;
}
/**
* Gets the {@link PinkGhost} {@link Robot}.
*
* @return the {@link PinkGhost} {@link Robot}
*/
public Robot getPink() {
return pink;
}
/**
* Gets the {@link RedGhost} {@link Robot}.
*
* @return the {@link RedGhost} {@link Robot}
*/
public Robot getRed() {
return red;
}
/**
* Starts the game loop.
*/
public void startGame() {
System.out.println("Starting game...");
this.gameLoopTimer.scheduleAtFixedRate(this.gameLoopTask, 0, 200);
}
/**
* Stops the game loop.
*/
public void stopGame(boolean won) {
this.gameLoopTimer.cancel();
endscreen(won ? Color.GREEN : Color.RED);
}
public void endscreen(Color color) {
World.getGlobalWorld().getGuiPanel().setColorProfile(
ColorProfile.DEFAULT.toBuilder()
.backgroundColorDark(Color.BLACK)
.backgroundColorLight(Color.BLACK)
.fieldColorDark(color)
.fieldColorLight(color)
.innerBorderColorLight(color)
.innerBorderColorDark(color)
.wallColorDark(Color.BLUE)
.wallColorLight(Color.BLUE)
.outerBorderColorDark(Color.BLUE)
.outerBorderColorLight(Color.BLUE)
.coinColorDark(color)
.coinColorLight(color)
.build());
World.getGlobalWorld().getGuiPanel().updateGui();
}
/**
* Sets up the game.
*/
protected void setup() {
setupWorld();
setupTheme();
setupRobots();
totalCoins = 2;// World.getHeight()*World.getWidth()-2;
setupCoins(totalCoins);
this.inputHandler.install();
}
public void setupTheme() {
World.getGlobalWorld().getGuiPanel().setColorProfile(
ColorProfile.DEFAULT.toBuilder()
.backgroundColorDark(Color.BLACK)
.backgroundColorLight(Color.BLACK)
.fieldColorDark(Color.BLACK)
.fieldColorLight(Color.BLACK)
.innerBorderColorLight(Color.BLACK)
.innerBorderColorDark(Color.BLACK)
.wallColorDark(Color.BLUE)
.wallColorLight(Color.BLUE)
.outerBorderColorDark(Color.BLUE)
.outerBorderColorLight(Color.BLUE)
.build());
}
/**
* Initializes the {@link World} and adds the {@link Robot}s to it.
*/
public void setupWorld() {
World.setSize(9, 9);
World.getGlobalWorld().setGuiPanel(new GuiPanel(World.getGlobalWorld()) {
@Override
@SuppressWarnings("UnstableApiUsage")
protected void drawCoin(final Coin c, final Graphics g, final boolean evadeRobots) {
final var g2d = (Graphics2D) g;
final var oldColor = g2d.getColor();
g2d.setColor(getColorProfile().getCoinColor());
final Rectangle2D fieldBounds = scale(PaintUtils.getFieldBounds(c, world));
final double radius = scale(5d);
g2d.fill(
new Ellipse2D.Double(
fieldBounds.getCenterX() - radius,
fieldBounds.getCenterY() - radius,
2 * radius,
2 * radius));
}
});
World.setDelay(0);
World.setVisible(true);
World.getGlobalWorld().setDrawTurnedOffRobots(false);
World.placeVerticalWall(0, 3);
World.placeVerticalWall(0, 4);
World.placeVerticalWall(0, 5);
World.placeVerticalWall(1, 2);
World.placeVerticalWall(1, 4);
World.placeVerticalWall(1, 6);
World.placeVerticalWall(2, 2);
World.placeVerticalWall(2, 3);
World.placeVerticalWall(2, 5);
World.placeVerticalWall(2, 6);
World.placeVerticalWall(3, 4);
World.placeVerticalWall(3, 7);
World.placeVerticalWall(4, 4);
World.placeVerticalWall(4, 1);
World.placeVerticalWall(5, 2);
World.placeVerticalWall(5, 3);
World.placeVerticalWall(5, 5);
World.placeVerticalWall(5, 6);
World.placeVerticalWall(6, 2);
World.placeVerticalWall(6, 4);
World.placeVerticalWall(6, 6);
World.placeVerticalWall(7, 3);
World.placeVerticalWall(7, 4);
World.placeVerticalWall(7, 5);
World.placeHorizontalWall(1, 0);
World.placeHorizontalWall(1, 1);
World.placeHorizontalWall(1, 6);
World.placeHorizontalWall(1, 7);
World.placeHorizontalWall(2, 0);
World.placeHorizontalWall(2, 7);
World.placeHorizontalWall(3, 0);
World.placeHorizontalWall(3, 2);
World.placeHorizontalWall(3, 5);
World.placeHorizontalWall(4, 1);
World.placeHorizontalWall(4, 3);
World.placeHorizontalWall(4, 6);
World.placeHorizontalWall(5, 2);
World.placeHorizontalWall(5, 5);
World.placeHorizontalWall(5, 7);
World.placeHorizontalWall(6, 0);
World.placeHorizontalWall(6, 7);
World.placeHorizontalWall(7, 0);
World.placeHorizontalWall(7, 1);
World.placeHorizontalWall(7, 6);
World.placeHorizontalWall(7, 7);
World.getGlobalWorld().setFieldColor(ghostField.x, ghostField.y, Color.YELLOW);
}
/**
* Adds the {@link Robot}s to the {@link World}.
*/
public void setupRobots() {
this.robots.add(pacman = new Pacman(4, 3));
this.robots.add(blue = new BlueGhost(ghostField.x, ghostField.y));
this.robots.add(orange = new OrangeGhost(ghostField.x, ghostField.y));
this.robots.add(pink = new PinkGhost(ghostField.x, ghostField.y));
this.robots.add(red = new RedGhost(ghostField.x, ghostField.y, pacman));
}
public void setupCoins(int numberOfCoins) {
if (numberOfCoins > World.getHeight() * World.getWidth() - 2) {
throw new IllegalArgumentException("Too many coins for this world size.");
}
ArrayList<Point> Fields = new ArrayList<>();
for (int y = 0; y < World.getHeight(); y++) {
for (int x = 0; x < World.getWidth(); x++) {
if (!((x == ghostField.x && y == ghostField.y) || x == pacman.getX() && y == pacman.getY()))
Fields.add(new Point(x, y));
}
}
for (int i = 0; i < numberOfCoins; i++) {
int randomIndex = (int) (Math.random() * Fields.size());
Point spot = Fields.remove(randomIndex);
World.putCoins(spot.x, spot.y, 1);
}
}
/**
* Checks the win condition.
*
* @return Returns true if the game is won.
*/
public abstract boolean checkWinCondition();
/**
* Checks the lose condition.
*
* @return Returns true if the game is lost.
*/
public boolean checkLoseCondition() {
boolean gameDone = pacman.getX() == orange.getX() && pacman.getY() == orange.getY();
if (pacman.getX() == blue.getX() && pacman.getY() == blue.getY()) {
gameDone = true;
}
if (pacman.getX() == pink.getX() && pacman.getY() == pink.getY()) {
gameDone = true;
}
if (pacman.getX() == red.getX() && pacman.getY() == red.getY()) {
gameDone = true;
}
return gameDone;
}
}

View file

@ -1,108 +0,0 @@
package h01.template;
import fopbot.Direction;
import fopbot.World;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A {@link GameInputHandler} handles the input of the user.
*/
public class GameInputHandler {
/**
* The {@link fopbot.Direction} to turn to. If {@code -1} the robot should not turn.
*/
private final AtomicInteger direction = new AtomicInteger(-1);
/**
* If {@code true} the robot should put a coin on the current field.
*/
private final AtomicBoolean shouldPutCoins = new AtomicBoolean(false);
/**
* If {@code true} the robot should pick a coin from the current field.
*/
private final AtomicBoolean shouldPickCoins = new AtomicBoolean(false);
/**
* Parses the inputs to a direction.
*
* @param keysPressed the keys pressed
* @return the direction or null if no direction is pressed
*/
public static Direction getDirectionFromKeysPressed(final Set<Integer> keysPressed) {
final Map<Direction, List<Integer>> directionKeys = Map.of(
Direction.UP, List.of(KeyEvent.VK_UP, KeyEvent.VK_W),
Direction.LEFT, List.of(KeyEvent.VK_LEFT, KeyEvent.VK_A),
Direction.DOWN, List.of(KeyEvent.VK_DOWN, KeyEvent.VK_S),
Direction.RIGHT, List.of(KeyEvent.VK_RIGHT, KeyEvent.VK_D)
);
final Set<Direction> pressedDirections = new HashSet<>();
for (final Direction direction : directionKeys.keySet()) {
for (final Integer key : directionKeys.get(direction)) {
if (keysPressed.contains(key)) {
pressedDirections.add(direction);
}
}
}
if (pressedDirections.size() == 1) {
return pressedDirections.iterator().next();
} else {
return null;
}
}
/**
* Installs the {@link GameInputHandler} to the {@link World}.
*/
public void install() {
World.getGlobalWorld().getInputHandler().addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(final KeyEvent e) {
updateKeysPressed();
}
@Override
public void keyPressed(final KeyEvent e) {
updateKeysPressed();
}
@Override
public void keyReleased(final KeyEvent e) {
updateKeysPressed();
}
});
}
/**
* Updates the {@link #direction}, {@link #shouldPutCoins} and {@link #shouldPickCoins} based on the pressed keys.
*/
protected void updateKeysPressed() {
this.direction.set(
Optional.ofNullable(getDirectionFromKeysPressed(World.getGlobalWorld().getInputHandler().getKeysPressed()))
.map(Enum::ordinal)
.orElse(-1)
);
this.shouldPickCoins.set(
World.getGlobalWorld().getInputHandler().getKeysPressed().contains(java.awt.event.KeyEvent.VK_SPACE)
);
this.shouldPutCoins.set(
World.getGlobalWorld().getInputHandler().getKeysPressed().contains(java.awt.event.KeyEvent.VK_R)
);
}
/**
* Returns the current {@link fopbot.Direction} to turn to. If {@code -1} the robot should not turn.
*
* @return the current {@link fopbot.Direction} to turn to. If {@code -1} the robot should not turn.
*/
public int getDirection() {
return this.direction.get();
}
}

View file

@ -1,5 +0,0 @@
package h01.template;
public interface Ghost {
void doMove();
}

View file

@ -1,15 +0,0 @@
package h01.template;
/**
* An interface that enables an object to be updated every n-th tick.
*/
public interface TickBased {
/**
* Returns the number of ticks between two updates.
*
* @return the number of ticks between two updates
*/
default int getUpdateDelay() {
return 1;
}
}

View file

@ -1,55 +0,0 @@
package h01.template;
import java.util.Random;
import fopbot.Direction;
import fopbot.Robot;
/**
* Utility class for the ghosts
*/
public class Util {
private static Random rnd = new Random();
/**
* Returns a random integer between min and max (both inclusive)
*
* @param min the minimum value
* @param max the maximum value
* @return a random integer between min and max (both inclusive)
*/
public static int getRandomInteger(int min, int max) {
return min + rnd.nextInt(max - min + 1);
}
/**
* Returns the direction in which the robot is the closest to the chaser
*
* @param pacman the robot that is being chased
* @param chaser the robot that is chasing
* @return the direction in which the robot is the closest to the chaser
*/
public static Direction furthestDirection(Robot pacman, Robot chaser) {
int px = pacman.getX();
int py = pacman.getY();
int cx = chaser.getX();
int cy = chaser.getY();
int xdelta = Math.abs(px - cx);
int ydelta = Math.abs(py - cy);
if (xdelta > ydelta) {
if (cx > px)
return Direction.LEFT;
else
return Direction.RIGHT;
} else {
if (cy > py)
return Direction.DOWN;
else
return Direction.UP;
}
}
}

View file

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
height="800px"
width="800px"
version="1.1"
id="Layer_1"
viewBox="0 0 512.001 512.001"
xml:space="preserve"
sodipodi:docname="ghost_blue.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs8" /><sodipodi:namedview
id="namedview8"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.49875"
inkscape:cx="399.33278"
inkscape:cy="400"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<path
style="fill:#555bff;fill-opacity:1"
d="M248.399,0.135C135.421,4.152,47.514,100.436,47.514,213.484V508.8c0,2.792,3.432,4.127,5.319,2.069 l57.191-62.39c3.756-4.098,10.216-4.098,13.971,0l55.336,60.365c3.858,4.209,10.493,4.209,14.35,0l55.334-60.365 c3.756-4.098,10.216-4.098,13.971,0l55.334,60.365c3.858,4.209,10.493,4.209,14.35,0l55.336-60.365 c3.756-4.098,10.216-4.098,13.971,0l57.191,62.39c1.887,2.059,5.319,0.724,5.319-2.069V208.486 C464.489,90.819,367.009-4.082,248.399,0.135z"
id="path1" />
<path
style="fill:#325ca9;fill-opacity:1"
d="M151.758,227.632c0-107.205,79.072-199.275,183.593-211.938 C308.687,4.707,279.273-0.963,248.399,0.135C135.421,4.152,47.514,100.436,47.514,213.484V508.8c0,2.792,3.432,4.127,5.319,2.069 l57.191-62.39c3.755-4.098,10.216-4.098,13.971,0l27.762,30.285V227.632H151.758z"
id="path2" />
<path
style="fill:#FFFFFF;"
d="M186.385,303.255L186.385,303.255c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-31.001,25.131-56.132,56.132-56.132l0,0c31.001,0,56.132,25.131,56.132,56.132v20.412 C242.515,278.124,217.385,303.255,186.385,303.255z"
id="path3" />
<path
style="fill:#E4EAF6;"
d="M217.002,293.049c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-18.952,9.419-35.676,23.803-45.839c-30.201,0.912-54.421,25.621-54.421,56.045v20.412c0,31.001,25.131,56.132,56.132,56.132 c12.048,0,23.184-3.831,32.327-10.292C218.139,292.98,217.579,293.049,217.002,293.049z"
id="path4" />
<path
style="fill:#82B9FF;"
d="M201.693,262.431L201.693,262.431c-11.273,0-20.412-9.138-20.412-20.412v-10.205 c0-11.273,9.138-20.412,20.412-20.412l0,0c11.273,0,20.412,9.138,20.412,20.412v10.205 C222.105,253.294,212.966,262.431,201.693,262.431z"
id="path5" />
<path
style="fill:#FFFFFF;"
d="M325.619,303.255L325.619,303.255c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-31.001,25.131-56.132,56.132-56.132l0,0c31.001,0,56.132,25.131,56.132,56.132v20.412 C381.75,278.124,356.619,303.255,325.619,303.255z"
id="path6" />
<path
style="fill:#E4EAF6;"
d="M356.236,293.049c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-18.952,9.419-35.676,23.804-45.839c-30.201,0.912-54.421,25.621-54.421,56.045v20.412c0,31.001,25.131,56.132,56.132,56.132 c12.048,0,23.184-3.831,32.327-10.292C357.374,292.98,356.814,293.049,356.236,293.049z"
id="path7" />
<path
style="fill:#82B9FF;"
d="M340.927,262.431L340.927,262.431c-11.273,0-20.412-9.138-20.412-20.412v-10.205 c0-11.273,9.138-20.412,20.412-20.412l0,0c11.273,0,20.412,9.138,20.412,20.412v10.205 C361.339,253.294,352.201,262.431,340.927,262.431z"
id="path8" />
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 512.001 512.001" xml:space="preserve">
<path style="fill:#FFA05A;" d="M248.399,0.135C135.421,4.152,47.514,100.436,47.514,213.484V508.8c0,2.792,3.432,4.127,5.319,2.069
l57.191-62.39c3.756-4.098,10.216-4.098,13.971,0l55.336,60.365c3.858,4.209,10.493,4.209,14.35,0l55.334-60.365
c3.756-4.098,10.216-4.098,13.971,0l55.334,60.365c3.858,4.209,10.493,4.209,14.35,0l55.336-60.365
c3.756-4.098,10.216-4.098,13.971,0l57.191,62.39c1.887,2.059,5.319,0.724,5.319-2.069V208.486
C464.489,90.819,367.009-4.082,248.399,0.135z"/>
<path style="fill:#F08C46;" d="M151.758,227.632c0-107.205,79.072-199.275,183.593-211.938
C308.687,4.707,279.273-0.963,248.399,0.135C135.421,4.152,47.514,100.436,47.514,213.484V508.8c0,2.792,3.432,4.127,5.319,2.069
l57.191-62.39c3.755-4.098,10.216-4.098,13.971,0l27.762,30.285V227.632H151.758z"/>
<path style="fill:#FFFFFF;" d="M186.385,303.255L186.385,303.255c-31.001,0-56.132-25.131-56.132-56.132v-20.412
c0-31.001,25.131-56.132,56.132-56.132l0,0c31.001,0,56.132,25.131,56.132,56.132v20.412
C242.515,278.124,217.385,303.255,186.385,303.255z"/>
<path style="fill:#E4EAF6;" d="M217.002,293.049c-31.001,0-56.132-25.131-56.132-56.132v-20.412
c0-18.952,9.419-35.676,23.803-45.839c-30.201,0.912-54.421,25.621-54.421,56.045v20.412c0,31.001,25.131,56.132,56.132,56.132
c12.048,0,23.184-3.831,32.327-10.292C218.139,292.98,217.579,293.049,217.002,293.049z"/>
<path style="fill:#82B9FF;" d="M201.693,262.431L201.693,262.431c-11.273,0-20.412-9.138-20.412-20.412v-10.205
c0-11.273,9.138-20.412,20.412-20.412l0,0c11.273,0,20.412,9.138,20.412,20.412v10.205
C222.105,253.294,212.966,262.431,201.693,262.431z"/>
<path style="fill:#FFFFFF;" d="M325.619,303.255L325.619,303.255c-31.001,0-56.132-25.131-56.132-56.132v-20.412
c0-31.001,25.131-56.132,56.132-56.132l0,0c31.001,0,56.132,25.131,56.132,56.132v20.412
C381.75,278.124,356.619,303.255,325.619,303.255z"/>
<path style="fill:#E4EAF6;" d="M356.236,293.049c-31.001,0-56.132-25.131-56.132-56.132v-20.412
c0-18.952,9.419-35.676,23.804-45.839c-30.201,0.912-54.421,25.621-54.421,56.045v20.412c0,31.001,25.131,56.132,56.132,56.132
c12.048,0,23.184-3.831,32.327-10.292C357.374,292.98,356.814,293.049,356.236,293.049z"/>
<path style="fill:#82B9FF;" d="M340.927,262.431L340.927,262.431c-11.273,0-20.412-9.138-20.412-20.412v-10.205
c0-11.273,9.138-20.412,20.412-20.412l0,0c11.273,0,20.412,9.138,20.412,20.412v10.205
C361.339,253.294,352.201,262.431,340.927,262.431z"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
height="800px"
width="800px"
version="1.1"
id="Layer_1"
viewBox="0 0 512.001 512.001"
xml:space="preserve"
sodipodi:docname="ghost_pink.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs8" /><sodipodi:namedview
id="namedview8"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.49875"
inkscape:cx="399.33278"
inkscape:cy="400"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<path
style="fill:#e555ff;fill-opacity:1"
d="M248.399,0.135C135.421,4.152,47.514,100.436,47.514,213.484V508.8c0,2.792,3.432,4.127,5.319,2.069 l57.191-62.39c3.756-4.098,10.216-4.098,13.971,0l55.336,60.365c3.858,4.209,10.493,4.209,14.35,0l55.334-60.365 c3.756-4.098,10.216-4.098,13.971,0l55.334,60.365c3.858,4.209,10.493,4.209,14.35,0l55.336-60.365 c3.756-4.098,10.216-4.098,13.971,0l57.191,62.39c1.887,2.059,5.319,0.724,5.319-2.069V208.486 C464.489,90.819,367.009-4.082,248.399,0.135z"
id="path1" />
<path
style="fill:#c53bd0;fill-opacity:1"
d="M151.758,227.632c0-107.205,79.072-199.275,183.593-211.938 C308.687,4.707,279.273-0.963,248.399,0.135C135.421,4.152,47.514,100.436,47.514,213.484V508.8c0,2.792,3.432,4.127,5.319,2.069 l57.191-62.39c3.755-4.098,10.216-4.098,13.971,0l27.762,30.285V227.632H151.758z"
id="path2" />
<path
style="fill:#FFFFFF;"
d="M186.385,303.255L186.385,303.255c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-31.001,25.131-56.132,56.132-56.132l0,0c31.001,0,56.132,25.131,56.132,56.132v20.412 C242.515,278.124,217.385,303.255,186.385,303.255z"
id="path3" />
<path
style="fill:#E4EAF6;"
d="M217.002,293.049c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-18.952,9.419-35.676,23.803-45.839c-30.201,0.912-54.421,25.621-54.421,56.045v20.412c0,31.001,25.131,56.132,56.132,56.132 c12.048,0,23.184-3.831,32.327-10.292C218.139,292.98,217.579,293.049,217.002,293.049z"
id="path4" />
<path
style="fill:#82B9FF;"
d="M201.693,262.431L201.693,262.431c-11.273,0-20.412-9.138-20.412-20.412v-10.205 c0-11.273,9.138-20.412,20.412-20.412l0,0c11.273,0,20.412,9.138,20.412,20.412v10.205 C222.105,253.294,212.966,262.431,201.693,262.431z"
id="path5" />
<path
style="fill:#FFFFFF;"
d="M325.619,303.255L325.619,303.255c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-31.001,25.131-56.132,56.132-56.132l0,0c31.001,0,56.132,25.131,56.132,56.132v20.412 C381.75,278.124,356.619,303.255,325.619,303.255z"
id="path6" />
<path
style="fill:#E4EAF6;"
d="M356.236,293.049c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-18.952,9.419-35.676,23.804-45.839c-30.201,0.912-54.421,25.621-54.421,56.045v20.412c0,31.001,25.131,56.132,56.132,56.132 c12.048,0,23.184-3.831,32.327-10.292C357.374,292.98,356.814,293.049,356.236,293.049z"
id="path7" />
<path
style="fill:#82B9FF;"
d="M340.927,262.431L340.927,262.431c-11.273,0-20.412-9.138-20.412-20.412v-10.205 c0-11.273,9.138-20.412,20.412-20.412l0,0c11.273,0,20.412,9.138,20.412,20.412v10.205 C361.339,253.294,352.201,262.431,340.927,262.431z"
id="path8" />
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
height="800px"
width="800px"
version="1.1"
id="Layer_1"
viewBox="0 0 512.001 512.001"
xml:space="preserve"
sodipodi:docname="ghost_red.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs8" /><sodipodi:namedview
id="namedview8"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.49875"
inkscape:cx="399.33278"
inkscape:cy="400"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<path
style="fill:#ff4040;fill-opacity:1"
d="M248.399,0.135C135.421,4.152,47.514,100.436,47.514,213.484V508.8c0,2.792,3.432,4.127,5.319,2.069 l57.191-62.39c3.756-4.098,10.216-4.098,13.971,0l55.336,60.365c3.858,4.209,10.493,4.209,14.35,0l55.334-60.365 c3.756-4.098,10.216-4.098,13.971,0l55.334,60.365c3.858,4.209,10.493,4.209,14.35,0l55.336-60.365 c3.756-4.098,10.216-4.098,13.971,0l57.191,62.39c1.887,2.059,5.319,0.724,5.319-2.069V208.486 C464.489,90.819,367.009-4.082,248.399,0.135z"
id="path1" />
<path
style="fill:#d03b3b;fill-opacity:1"
d="M151.758,227.632c0-107.205,79.072-199.275,183.593-211.938 C308.687,4.707,279.273-0.963,248.399,0.135C135.421,4.152,47.514,100.436,47.514,213.484V508.8c0,2.792,3.432,4.127,5.319,2.069 l57.191-62.39c3.755-4.098,10.216-4.098,13.971,0l27.762,30.285V227.632H151.758z"
id="path2" />
<path
style="fill:#FFFFFF;"
d="M186.385,303.255L186.385,303.255c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-31.001,25.131-56.132,56.132-56.132l0,0c31.001,0,56.132,25.131,56.132,56.132v20.412 C242.515,278.124,217.385,303.255,186.385,303.255z"
id="path3" />
<path
style="fill:#E4EAF6;"
d="M217.002,293.049c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-18.952,9.419-35.676,23.803-45.839c-30.201,0.912-54.421,25.621-54.421,56.045v20.412c0,31.001,25.131,56.132,56.132,56.132 c12.048,0,23.184-3.831,32.327-10.292C218.139,292.98,217.579,293.049,217.002,293.049z"
id="path4" />
<path
style="fill:#82B9FF;"
d="M201.693,262.431L201.693,262.431c-11.273,0-20.412-9.138-20.412-20.412v-10.205 c0-11.273,9.138-20.412,20.412-20.412l0,0c11.273,0,20.412,9.138,20.412,20.412v10.205 C222.105,253.294,212.966,262.431,201.693,262.431z"
id="path5" />
<path
style="fill:#FFFFFF;"
d="M325.619,303.255L325.619,303.255c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-31.001,25.131-56.132,56.132-56.132l0,0c31.001,0,56.132,25.131,56.132,56.132v20.412 C381.75,278.124,356.619,303.255,325.619,303.255z"
id="path6" />
<path
style="fill:#E4EAF6;"
d="M356.236,293.049c-31.001,0-56.132-25.131-56.132-56.132v-20.412 c0-18.952,9.419-35.676,23.804-45.839c-30.201,0.912-54.421,25.621-54.421,56.045v20.412c0,31.001,25.131,56.132,56.132,56.132 c12.048,0,23.184-3.831,32.327-10.292C357.374,292.98,356.814,293.049,356.236,293.049z"
id="path7" />
<path
style="fill:#82B9FF;"
d="M340.927,262.431L340.927,262.431c-11.273,0-20.412-9.138-20.412-20.412v-10.205 c0-11.273,9.138-20.412,20.412-20.412l0,0c11.273,0,20.412,9.138,20.412,20.412v10.205 C361.339,253.294,352.201,262.431,340.927,262.431z"
id="path8" />
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
height="800px"
width="800px"
version="1.1"
id="Layer_1"
viewBox="0 0 512 512"
xml:space="preserve"
sodipodi:docname="gamer-svgrepo-com.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs6" /><sodipodi:namedview
id="namedview6"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.49875"
inkscape:cx="399.66639"
inkscape:cy="400"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<g
id="g6"
transform="translate(83.607539,4.4703637e-4)"><path
style="fill:#ffd782"
d="m 209.638,244.628 129.736,-95.594 c 6.241,-4.599 7.204,-13.545 2.155,-19.428 C 301.171,82.587 238.774,55.049 170.311,63.221 81.862,73.778 10.999,145.353 1.223,233.893 c -12.937,117.155 78.443,216.313 192.983,216.313 58.996,0 111.782,-26.358 147.389,-67.889 5.021,-5.856 3.992,-14.775 -2.218,-19.35 L 209.638,267.37 c -7.661,-5.645 -7.661,-17.096 0,-22.742 z"
id="path1" /><path
style="fill:#ffc36e"
d="M 255.491,406.068 C 140.951,406.068 49.571,306.911 62.507,189.755 67.182,147.409 85.94,109.043 113.803,79.279 53.119,107.021 8.797,165.293 1.223,233.892 c -12.937,117.156 78.443,216.314 192.983,216.314 55.956,0 106.298,-23.738 141.721,-61.62 -24.506,11.197 -51.724,17.482 -80.436,17.482 z"
id="path2" /><circle
style="fill:#5b5d6e"
cx="220.689"
cy="150.06799"
r="26.483"
id="circle5" /><path
style="fill:#464655"
d="m 231.724,163.31 c -13.407,0 -24.276,-10.869 -24.276,-24.276 0,-5.134 1.614,-9.88 4.335,-13.802 -10.222,3.669 -17.577,13.351 -17.577,24.836 0,14.626 11.857,26.483 26.483,26.483 11.486,0 21.167,-7.354 24.836,-17.577 -3.921,2.72 -8.667,4.336 -13.801,4.336 z"
id="path6" /></g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

1
solution/H01/src/test Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H01/src/test

View file

@ -1,16 +0,0 @@
package h01;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* An example JUnit test class.
*/
public class ExampleJUnitTest {
@Test
public void testAddition() {
assertEquals(2, 1 + 1);
}
}

1
solution/H02/src/main Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H02/src/main

View file

@ -1,388 +0,0 @@
package h02;
import fopbot.Direction;
import fopbot.Robot;
import fopbot.RobotFamily;
import fopbot.World;
import h02.template.InputHandler;
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import java.util.Optional;
/**
* The {@link FourWins} class represents the main class of the FourWins game.
*/
public class FourWins {
private final InputHandler inputHandler = new InputHandler(this);
/**
* The width of the game board.
*/
private final int width;
/**
* The height of the game board.
*/
private final int height;
/**
* Indicates whether the game has finished.
*/
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
private boolean finished = false;
/**
* Creates a new {@link FourWins} instance with the given width and height.
*
* @param width the width of the game board
* @param height the height of the game board
*/
FourWins(final int width, final int height) {
this.width = width;
this.height = height;
}
/**
* Starts the game by setting up the world and executing the game loop.
*/
void startGame() {
setupWorld();
gameLoop();
}
/**
* Sets up the world and installs the {@link InputHandler}.
*/
void setupWorld() {
World.setSize(width, height);
World.setDelay(10);
World.setVisible(true);
inputHandler.install();
}
/**
* Validates if a given column index is within the bounds of the game board and not fully occupied.
*
* @param column The column index to validate.
* @param stones 2D array representing the game board, where each cell contains a RobotFamily color indicating the
* player that has placed a stone in that position.
* @return true if the column is within bounds and has at least one unoccupied cell; false otherwise.
*/
@StudentImplementationRequired("H2.2.1")
public static boolean validateInput(final int column, final RobotFamily[][] stones) {
return column >= 0 && column < World.getWidth() && stones[World.getHeight() - 1][column] == null;
}
/**
* Calculates the next unoccupied row index in the specified column. This row index is the next destination for a
* falling stone.
*
* @param column The column index where the stone is to be dropped.
* @param stones 2D array representing the game board, where each cell contains a RobotFamily object indicating the
* player that has placed a stone in that position.
* @return Index of the next unoccupied row index in the specified column.
*/
@StudentImplementationRequired("H2.2.2")
public static int getDestinationRow(final int column, final RobotFamily[][] stones) {
for (int row = 0; row < stones.length; row++) {
if (stones[row][column] == null) {
return row;
}
}
return -1;
}
/**
* Drops a stone into the specified column of the game board, simulating a falling animation. This method gets the
* destination row for the stone in the specified column with the `getDestinationRow` method. It creates a new Robot
* instance to represent the stone with the currentPlayer's RobotFamily in the given column and the destination row.
* After that it simulates the stone's fall by decrementing its position until it reaches the destination row. Once
* the stone reaches its destination, the method updates the stones array (a 2D array of RobotFamily colors) to
* mark the slot as occupied by the currentPlayer.
*
* @param column The column index where the stone is to be dropped.
* @param stones 2D array representing the game board, where each cell contains a RobotFamily object
* indicating the player that has placed a stone in that position.
* @param currentPlayer The RobotFamily object representing the current player dropping the stone.
*/
@StudentImplementationRequired("H2.2.2")
public static void dropStone(final int column, final RobotFamily[][] stones, final RobotFamily currentPlayer) {
// spawn stone
final Robot stone = new Robot(column, World.getHeight() - 1, Direction.DOWN, 0, currentPlayer);
// let stone fall
final int row = getDestinationRow(column, stones);
for (int currentRow = World.getHeight() - 1; currentRow > row; currentRow--) {
stone.move();
}
// turn stone up
stone.turnLeft();
stone.turnLeft();
// set slot as occupied
stones[row][column] = currentPlayer;
}
/**
* Checks if the current player has won by any condition. The conditions can be a horizontal, vertical, diagonal, or
* anti-diagonal line of at least four stones.
*
* @param stones 2D array representing the game board, where each cell contains a RobotFamily color
* indicating the player that has placed a stone in that position.
* @param currentPlayer The RobotFamily color representing the current player to check for a win.
* @return true if the current player has formed a horizontal line of at least four stones; false otherwise.
*/
@StudentImplementationRequired("H2.2.3")
public static boolean testWinConditions(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
return testWinVertical(stones, currentPlayer)
|| testWinHorizontal(stones, currentPlayer)
|| testWinDiagonal(stones, currentPlayer);
}
/**
* Checks if the current player has won by forming a horizontal line of at least consecutive four stones.
*
* @param stones 2D array representing the game board, where each cell contains a RobotFamily color
* indicating the player that has placed a stone in that position.
* @param currentPlayer The RobotFamily color representing the current player to check for a win.
* @return true if the current player has formed a horizontal line of at least four stones; false otherwise.
*/
@StudentImplementationRequired("H2.2.3")
public static boolean testWinHorizontal(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
for (int row = 0; row < World.getHeight(); row++) {
int stoneCount = 0;
for (int column = 0; column < World.getWidth(); column++) {
stoneCount = stones[row][column] == currentPlayer ? stoneCount + 1 : 0;
if (stoneCount >= 4) {
return true;
}
}
}
return false;
}
/**
* Checks if the current player has won by forming a vertical line of at least consecutive four stones.
*
* @param stones 2D array representing the game board, where each cell contains a RobotFamily color
* indicating the player that has placed a stone in that position.
* @param currentPlayer The RobotFamily color representing the current player to check for a win.
* @return true if the current player has formed a vertical line of at least four stones; false otherwise.
*/
@StudentImplementationRequired("H2.2.3")
public static boolean testWinVertical(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
for (int column = 0; column < World.getWidth(); column++) {
int stoneCount = 0;
for (int row = 0; row < World.getHeight(); row++) {
stoneCount = stones[row][column] == currentPlayer ? stoneCount + 1 : 0;
if (stoneCount >= 4) {
return true;
}
}
}
return false;
}
/**
* Checks if the current player has won by forming a diagonal line of at least consecutive four stones.
*
* @param stones 2D array representing the game board, where each cell contains a RobotFamily color
* indicating the player that has placed a stone in that position.
* @param currentPlayer The RobotFamily color representing the current player to check for a win.
* @return true if the current player has formed a diagonal line of at least four stones; false otherwise.
*/
@DoNotTouch
public static boolean testWinDiagonal(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
@SuppressWarnings("CheckStyle") final int MAX_STONES = 4;
@SuppressWarnings("CheckStyle") final int WIDTH = World.getWidth();
@SuppressWarnings("CheckStyle") final int HEIGHT = World.getHeight();
int[] direction = new int[]{1, 1};
// for every field
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
// for every direction
for (int nthDirection = 0; nthDirection < 4; nthDirection++) {
final int[] pos = {x, y};
// test for consecutive coins
int coinCount = 0; // start counting at 0
while (pos[0] >= 0 && pos[0] < WIDTH
&& pos[1] >= 0 && pos[1] < HEIGHT
&& stones[pos[1]][pos[0]] == currentPlayer) {
coinCount++; // count every stone that has currentPlayer's color
if (coinCount >= MAX_STONES) {
return true;
}
pos[0] += direction[0];
pos[1] += direction[1];
}
direction = new int[]{direction[1], -direction[0]}; // next direction (rotate by 90 deg)
}
}
}
return false;
}
/**
* Switches the player for each turn. If the current player is SQUARE_BLUE, SQUARE_RED is returned as the next
* player. If the current player is SQUARE_RED, SQUARE_BLUE is returned as the next player.
*
* @param currentPlayer The player color of the current player.
* @return The player color of the next player.
*/
@StudentImplementationRequired("H2.2.4")
public static RobotFamily nextPlayer(final RobotFamily currentPlayer) {
return currentPlayer == RobotFamily.SQUARE_BLUE ? RobotFamily.SQUARE_RED : RobotFamily.SQUARE_BLUE;
}
/**
* Displays a Message in the console and on the game board indicating the game is drawn.
*/
@StudentImplementationRequired("H2.2.4")
public void writeDrawMessage() {
inputHandler.displayDrawStatus();
// student implementation here:
System.out.println("No valid columns found. Hence, game ends with a draw.");
}
/**
* Displays a Message in the console and on the game board indicating the game is won by a player.
*
* @param winner {@link RobotFamily} of the winning player
*/
@StudentImplementationRequired("H2.2.4")
public void writeWinnerMessage(final RobotFamily winner) {
inputHandler.displayWinnerStatus(winner);
// student implementation here:
System.out.println("Player " + winner + " wins the game!");
}
/**
* Displays the winner of the game by printing the winning color in the console and filling the whole field with
* Robots of the winning color.
*
* @param winner The RobotFamily color of the winner.
*/
@StudentImplementationRequired("H2.2.4")
public static void colorFieldBackground(final RobotFamily winner) {
for (int x = 0; x < World.getWidth(); x++) {
for (int y = 0; y < World.getHeight(); y++) {
setFieldColor(x, y, winner);
}
}
}
/**
* Executes the main game loop, handling player turns, stone drops, and win condition checks. This method
* initializes the game board as a 2D array of RobotFamily colors, representing the slots that can be filled with
* players' stones. It starts with a predefined currentPlayer and continues in a loop until a win condition is met.
* Each iteration of the loop waits for player input to select a column to drop a stone into, switches the current
* player, drops the stone in the selected column, and checks for win conditions. If a win condition is met, the
* loop ends, and the winner is displayed.
*/
@StudentImplementationRequired("H2.2.4")
void gameLoop() {
final RobotFamily[][] stones = new RobotFamily[World.getHeight()][World.getWidth()];
RobotFamily currentPlayer = RobotFamily.SQUARE_BLUE;
boolean draw = false;
finished = false;
while (!finished) {
// student implementation here:
currentPlayer = nextPlayer(currentPlayer);
// wait for click in column (DO NOT TOUCH)
finished = draw = isGameBoardFull(stones);
if (draw) {
break;
}
final int column = inputHandler.getNextInput(currentPlayer, stones);
// student implementation here:
dropStone(column, stones, currentPlayer);
finished = testWinConditions(stones, currentPlayer);
}
// displaying either draw or winner (DO NOT TOUCH)
if (draw) {
writeDrawMessage();
colorFieldBackground(getDrawnRobotFamily());
} else {
writeWinnerMessage(currentPlayer);
colorFieldBackground(currentPlayer);
}
}
/**
* Executes the main game loop, handling player turns, stone drops, and win condition checks. Sets the background
* color of a field at the specified coordinates. The color is derived from the {@link RobotFamily} SQUARE_BLUE or
* SQUARE_RED.
*
* @param x the x coordinate of the field
* @param y the y coordinate of the field
* @param color the {@link RobotFamily} corresponding to the field color to set
*/
@DoNotTouch
public static void setFieldColor(final int x, final int y, final RobotFamily color) {
World.getGlobalWorld().setFieldColor(x, y, color.getColor());
}
/**
* Returns the {@link RobotFamily} which represents a drawn game.
*
* @return the {@link RobotFamily} which represents a drawn game.
*/
@DoNotTouch
@SuppressWarnings("UnstableApiUsage")
protected static RobotFamily getDrawnRobotFamily() {
return Optional.ofNullable(World.getGlobalWorld().getGuiPanel()).filter(guiPanel -> !guiPanel.isDarkMode()).map(guiPanel -> RobotFamily.SQUARE_ORANGE).orElse(RobotFamily.SQUARE_YELLOW);
}
/**
* Checks if all columns of the game board are fully occupied.
*
* @param stones 2D array representing the game board, where each cell contains a RobotFamily
* @return true if all columns of the game board are fully occupied; false otherwise.
*/
@DoNotTouch
public static boolean isGameBoardFull(final RobotFamily[][] stones) {
for (int x = 0; x < World.getWidth(); x++) {
if (FourWins.validateInput(x, stones)) {
return false;
}
}
return true;
}
/**
* Returns this instance's {@link InputHandler}.
*
* @return the input handler
*/
@DoNotTouch
public InputHandler getInputHandler() {
return inputHandler;
}
/**
* Returns {@code true} when the game is finished, {@code false} otherwise.
*
* @return whether the game is finished.
*/
public boolean isFinished() {
return finished;
}
}

View file

@ -1,218 +0,0 @@
package h02;
import fopbot.RobotFamily;
import fopbot.World;
import org.tudalgo.algoutils.student.annotation.SolutionOnly;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import static org.tudalgo.algoutils.student.io.PropertyUtils.getIntProperty;
import static org.tudalgo.algoutils.student.test.StudentTestUtils.printTestResults;
import static org.tudalgo.algoutils.student.test.StudentTestUtils.testEquals;
/**
* Main entry point in executing the program.
*/
public class Main {
/**
* Main entry point in executing the program.
*
* @param args program arguments, currently ignored
*/
public static void main(final String[] args) {
// H1
sanityChecksH211();
sanityChecksH212();
printTestResults();
// H2
sanityChecksH22();
printTestResults();
// starting game (comment out if you just want to run the tests)
final var propFile = "h02.properties";
new FourWins(
getIntProperty(propFile, "FW_WORLD_WIDTH"),
getIntProperty(propFile, "FW_WORLD_HEIGHT")
).startGame();
}
/**
* Perform sanity checks for exercise H2.1.1.
*/
@StudentImplementationRequired("H2.3")
public static void sanityChecksH211() {
// push test
final int[] newArray = OneDimensionalArrayStuff.push(new int[]{0, 1}, 2);
final int[] expectedArray = {0, 1, 2};
testEquals(expectedArray.length, newArray.length);
for (int i = 0; i < newArray.length; i++) {
testEquals(expectedArray[i], newArray[i]);
}
// calculateNextFibonacci test
int[] fibonacciArray = {0, 1};
for (int i = 0; i < 20; i++) {
fibonacciArray = OneDimensionalArrayStuff.calculateNextFibonacci(fibonacciArray);
}
testEquals(22, fibonacciArray.length);
testEquals(0, fibonacciArray[0]);
testEquals(1, fibonacciArray[1]);
for (int i = 2; i < fibonacciArray.length; i++) {
testEquals(fibonacciArray[i - 1] + fibonacciArray[i - 2], fibonacciArray[i]);
}
// fibonacci test
final int[] reference = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34};
for (int i = 0; i < 10; i++) {
testEquals(reference[i], OneDimensionalArrayStuff.fibonacci(i));
}
}
/**
* Perform sanity checks for exercise H2.1.2.
*/
@StudentImplementationRequired("H2.3")
public static void sanityChecksH212() {
// predefined simple test
final String[][] simpleTest = new String[][]{
"a b c d e f".split(" "),
"a b c d e f".split(" "),
"a b c d e f".split(" "),
};
// predefined complex test
final String[][] complexTest = new String[][]{
"a a b b c c".split(" "),
"a b c d e f".split(" "),
"a a a b b b c c c".split(" "),
};
// student implementation here:
sanityChecksH212Helper(
simpleTest,
"b",
new int[]{1, 1, 1},
1
);
sanityChecksH212Helper(
complexTest,
"b",
new int[]{2, 1, 3},
2
);
}
/**
* Helper method for sanity checks for exercise H2.1.2.
*
* @param input the input array
* @param query the query string
* @param refOcc the reference occurrences
* @param refMean the reference mean
*/
@SolutionOnly
public static void sanityChecksH212Helper(
final String[][] input,
final String query,
final int[] refOcc,
final float refMean
) {
final int[] occ = TwoDimensionalArrayStuff.occurrences(input, query);
testEquals(refOcc.length, occ.length);
for (int i = 0; i < occ.length; i++) {
testEquals(refOcc[i], occ[i]);
}
testEquals(refMean, TwoDimensionalArrayStuff.meanOccurrencesPerLine(input, query));
}
/**
* Perform sanity checks for exercise H2.2
*/
@StudentImplementationRequired("H2.4")
public static void sanityChecksH22() {
// setting world size
World.setSize(4, 5);
// predefined stones1 array
final RobotFamily[][] stones1 = {
{null, RobotFamily.SQUARE_BLUE, null, RobotFamily.SQUARE_RED},
{null, null, null, RobotFamily.SQUARE_BLUE},
{null, null, null, RobotFamily.SQUARE_RED},
{null, null, null, RobotFamily.SQUARE_BLUE},
{null, null, null, RobotFamily.SQUARE_RED},
};
// predefined stones2 array
final RobotFamily[][] stones2 = {
{RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_BLUE},
{RobotFamily.SQUARE_RED, RobotFamily.SQUARE_RED, RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_RED},
{RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_RED, RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_BLUE},
{RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_RED, RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_RED},
{RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_BLUE, RobotFamily.SQUARE_RED},
};
// student implementation here:
// H2.2.1 validateInput
final boolean isInCol1 = FourWins.validateInput(1, stones1);
final boolean isInCol3 = FourWins.validateInput(3, stones1);
testEquals(true, isInCol1);
testEquals(false, isInCol3);
// H2.2.2 getDestinationRow
final int rowCol1 = FourWins.getDestinationRow(1, stones1);
final int rowCol3 = FourWins.getDestinationRow(3, stones1);
testEquals(1, rowCol1);
testEquals(-1, rowCol3);
// H2.2.2 dropStone
FourWins.dropStone(1, stones1, RobotFamily.SQUARE_RED);
// System.out.println(Arrays.deepToString(stones1));
// System.out.println(stones1);
testEquals(RobotFamily.SQUARE_RED, stones1[1][1]);
// H2.2.3 testWinHorizontal
final boolean winRowBlue = FourWins.testWinHorizontal(stones2, RobotFamily.SQUARE_BLUE);
final boolean winRowRed = FourWins.testWinHorizontal(stones2, RobotFamily.SQUARE_RED);
testEquals(true, winRowBlue);
testEquals(false, winRowRed);
// H2.2.3 testWinVertical
final boolean winColStones2 = FourWins.testWinVertical(stones2, RobotFamily.SQUARE_BLUE);
final boolean winColStones1 = FourWins.testWinVertical(stones1, RobotFamily.SQUARE_BLUE);
testEquals(true, winColStones2);
testEquals(false, winColStones1);
// H2.2.3 testWinConditions
final boolean winStones2 = FourWins.testWinConditions(stones2, RobotFamily.SQUARE_BLUE);
final boolean winStones1 = FourWins.testWinConditions(stones1, RobotFamily.SQUARE_BLUE);
testEquals(true, winStones2);
testEquals(false, winStones1);
// H2.2.4 switchPlayer
final RobotFamily nextPlayer1 = FourWins.nextPlayer(RobotFamily.SQUARE_BLUE);
final RobotFamily nextPlayer2 = FourWins.nextPlayer(RobotFamily.SQUARE_RED);
testEquals(RobotFamily.SQUARE_RED, nextPlayer1);
testEquals(RobotFamily.SQUARE_BLUE, nextPlayer2);
// H2.2.4 colorFieldBackground, writeDrawMessage, writeWinnerMessage, gameLoop
// Test by playing
}
}

View file

@ -1,64 +0,0 @@
package h02;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
/**
* This class serves as a container for the methods that are to be implemented by the students for exercise H2.1.1.
*/
public class OneDimensionalArrayStuff {
/**
* Prevent instantiation of this utility class.
*/
private OneDimensionalArrayStuff() {
throw new IllegalStateException("This class is not meant to be instantiated.");
}
/**
* Returns a new array that is a copy of the input array with the given value appended at the end.
*
* @param array the input array
* @param value the value to append
* @return a new array that is a copy of the input array with the given value appended at the end
*/
@StudentImplementationRequired("H2.1.1")
public static int[] push(final int[] array, final int value) {
final int[] newArray = new int[array.length + 1];
//noinspection ManualArrayCopy
for (int i = 0; i < array.length; i++) {
newArray[i] = array[i];
}
newArray[array.length] = value;
return newArray;
}
/**
* Calculates the next Fibonacci number based on the given array and returns a new array with the next Fibonacci
* number appended at the end.
*
* @param array the input array containing the last two Fibonacci numbers up to the current point
* @return a new array with the next Fibonacci number appended at the end
*/
@StudentImplementationRequired("H2.1.1")
public static int[] calculateNextFibonacci(final int[] array) {
return push(array, array[array.length - 1] + array[array.length - 2]);
}
/**
* Returns the n-th Fibonacci number.
*
* @param n the index of the Fibonacci number to return
* @return the n-th Fibonacci number
*/
@StudentImplementationRequired("H2.1.1")
public static int fibonacci(final int n) {
if (n < 2) {
return n; // base case (n=0 or n=1)
}
int[] array = {0, 1};
for (int i = 2; i <= n; i++) {
array = calculateNextFibonacci(array);
}
return array[array.length - 1];
}
}

View file

@ -1,89 +0,0 @@
package h02;
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import java.util.Arrays;
/**
* This class serves as a container for the methods that are to be implemented by the students for exercise H2.1.2.
*/
public class TwoDimensionalArrayStuff {
/**
* Prevent instantiation of this utility class.
*/
private TwoDimensionalArrayStuff() {
throw new IllegalStateException("This class is not meant to be instantiated.");
}
/**
* Returns an array containing the number of occurrences of the query {@link String} in each line of the input array.
*
* @param input the input array
* @param query the query {@link String}
* @return an array containing the number of occurrences of the query {@link String} in each line of the input array
*/
@StudentImplementationRequired("H2.1.2")
public static int[] occurrences(final String[][] input, final String query) {
final int[] result = new int[input.length];
for (int row = 0; row < input.length; row++) {
for (int col = 0; col < input[row].length; col++) {
if (input[row][col].equals(query)) {
result[row]++;
}
}
}
return result;
}
/**
* Returns the mean of the input array.
*
* @param input the input array
* @return the mean of the input array
*/
@StudentImplementationRequired("H2.1.2")
public static float mean(final int[] input) {
int sum = 0;
for (final int j : input) {
sum += j;
}
return (float) sum / input.length;
}
/**
* Returns the mean number of occurrences of the query {@link String} in each line of the input array.
*
* @param input the input array
* @param query the query {@link String}
* @return the mean number of occurrences of the query {@link String} in each line of the input array
*/
@DoNotTouch
public static float meanOccurrencesPerLine(final String[][] input, final String query) {
return mean(occurrences(input, query));
}
/**
* Overload that splits the input string by lines and spaces, then calls regular meanOccurrencesPerLine.
*
* @param input the input string to split by lines and spaces
* @param query the query {@link String}
* @return the mean number of occurrences of the query {@link String} in each line of the input array
*/
@DoNotTouch
public static float meanOccurrencesPerLine(final String input, final String query) {
// filter out unwanted symbols
final String filteredInput = input.replaceAll("[^\\w\\s]", "");
// split by lines
final var processedInput = Arrays.stream(filteredInput.split("(\\r\\n|\\r|\\n)"))
// split by spaces
.map(line -> line.split("\\s"))
// collect to 2D array
.toArray(String[][]::new);
/// uncomment the following line to log processed input
// System.out.printf("Processed input: %s%n", Arrays.deepToString(processedInput));
// call regular meanOccurrencesPerLine
return meanOccurrencesPerLine(processedInput, query);
}
}

View file

@ -1,201 +0,0 @@
package h02.template;
import fopbot.RobotFamily;
import fopbot.World;
import h02.FourWins;
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.beans.PropertyChangeEvent;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
/**
* The {@link InputHandler} handles the input of the users.
*/
@DoNotTouch
public class InputHandler {
/**
* The input queue.
*/
private final BlockingDeque<Integer> inputQueue = new LinkedBlockingDeque<>();
/**
* The {@link FourWins} instance.
*/
private final FourWins fourWins;
/**
* Whether the row select mode is active.
*/
private final AtomicBoolean rowSelectMode = new AtomicBoolean(false);
/**
* The status label.
*/
private final JLabel statusLabel = new JLabel("", SwingConstants.CENTER);
/**
* Creates a new {@link InputHandler} instance.
*
* @param fourWins the {@link FourWins} instance
*/
public InputHandler(final FourWins fourWins) {
this.fourWins = fourWins;
final int padding = 4; // Padding in pixels
statusLabel.setBorder(new EmptyBorder(padding, padding, padding, padding));
}
/**
* Sets the color of the given column to the given color.
*
* @param column the column to set the color of
* @param colorSupplier the color to set
*/
private void setColumnColor(final int column, final Supplier<Color> colorSupplier) {
for (int i = 0; i < World.getHeight(); i++) {
final int finalI = i;
SwingUtilities.invokeLater(() -> World.getGlobalWorld().getField(column, finalI).setFieldColor(colorSupplier));
}
}
/**
* Executes the given action only if the game is running.
*
* @param action the action to execute
*/
private void whenGameIsRunning(final Runnable action) {
if (!fourWins.isFinished()) {
action.run();
}
}
/**
* Installs the input handler to the fopbot world.
*/
@SuppressWarnings("UnstableApiUsage")
public void install() {
final var guiPanel = World.getGlobalWorld().getGuiPanel();
final var guiFrame = World.getGlobalWorld().getGuiFrame();
World.getGlobalWorld().getInputHandler().addFieldClickListener(
e -> whenGameIsRunning(() -> addInput(e.getField().getX()))
);
World.getGlobalWorld().getInputHandler().addFieldHoverListener(e -> whenGameIsRunning(() -> {
// deselect last hovered field, if any
if (e.getPreviousField() != null) {
setColumnColor(e.getPreviousField().getX(), () -> null);
}
if (rowSelectMode.get()) {
// select current hovered field
if (e.getField() != null) {
setColumnColor(
e.getField().getX(),
() -> guiPanel.isDarkMode()
? Color.yellow
: Color.orange
);
}
}
}));
statusLabel.setFont(statusLabel.getFont().deriveFont(guiPanel.scale(20.0f)));
guiFrame.add(statusLabel, BorderLayout.NORTH);
guiFrame.pack();
guiPanel.addDarkModeChangeListener(this::onDarkModeChange);
guiPanel.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(final ComponentEvent e) {
statusLabel.setFont(
statusLabel.getFont().deriveFont(
Math.max(20f, 0.04f * Math.min(guiPanel.getWidth(), guiPanel.getHeight()))
)
);
}
});
// trigger dark mode change to set the correct color
guiPanel.setDarkMode(World.getGlobalWorld().getGuiPanel().isDarkMode());
}
/**
* Called when the dark mode changes.
*
* @param e the property change event
*/
@SuppressWarnings("UnstableApiUsage")
public void onDarkModeChange(final PropertyChangeEvent e) {
final var darkMode = (boolean) e.getNewValue();
statusLabel.setForeground(darkMode ? Color.white : Color.black);
World.getGlobalWorld().getGuiFrame().getContentPane().setBackground(darkMode ? Color.black : Color.white);
}
/**
* Adds an input to the input queue. When {@link #getNextInput(RobotFamily, RobotFamily[][])} is called, the program
* will wait until this method is called.
*
* @param input the input to add
*/
public void addInput(final int input) {
inputQueue.add(input);
}
/**
* Returns the next input from the input queue. If the input is invalid, the user will be prompted to enter a new
* input. The program will halt until a valid input is entered.
*
* @param currentPlayer the current player
* @param stones the current state of the game board
* @return the next input from the input queue
*/
public int getNextInput(final RobotFamily currentPlayer, final RobotFamily[][] stones) {
rowSelectMode.set(true);
statusLabel.setText(
"<html>Click on a column to insert a disc.<br>Current Player: %s</html>".formatted(currentPlayer.getName())
);
try {
final int input = inputQueue.take();
System.out.println("Received column input: " + input);
if (!FourWins.validateInput(input, stones)) {
System.out.println("Invalid column input, please try again.");
return getNextInput(currentPlayer, stones);
}
rowSelectMode.set(false);
return input;
} catch (final InterruptedException e) {
rowSelectMode.set(false);
throw new RuntimeException(e);
}
}
/**
* Sets a status message, saying that the game has ended in a draw.
*/
public void displayDrawStatus() {
statusLabel.setText("<html>No valid columns found. <br>Hence, game ends with a draw.</html>");
}
/**
* Sets a status message, saying that the game has ended with a winner.
*
* @param winner the winner of the game
*/
public void displayWinnerStatus(final RobotFamily winner) {
statusLabel.setText("<html>Player %s has won the game!</html>".formatted(winner.getName()));
}
/**
* Returns the {@link #statusLabel} of this {@link InputHandler}.
*
* <p>Use the {@link JLabel#getText()} method to get the current text of the label, and the
* {@link JLabel#setText(String)} method to update the text.
*
* @return the {@link #statusLabel} of this {@link InputHandler}
*/
public JLabel getStatusLabel() {
return statusLabel;
}
}

View file

@ -1,2 +0,0 @@
FW_WORLD_WIDTH = 7
FW_WORLD_HEIGHT = 6

1
solution/H02/src/test Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H02/src/test

View file

@ -1,16 +0,0 @@
package h02;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* An example JUnit test class.
*/
public class ExampleJUnitTest {
@Test
public void testAddition() {
assertEquals(2, 1 + 1);
}
}

1
solution/H03/src/main Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H03/src/main

View file

@ -1,70 +0,0 @@
package h03;
import fopbot.World;
import h03.robots.DoublePowerRobot;
import h03.robots.HackingRobot;
import h03.robots.MovementType;
import h03.robots.VersatileRobot;
/**
* Main entry point in executing the program.
*/
public class Main {
/**
* Main entry point in executing the program.
*
* @param args program arguments, currently ignored
*/
public static void main(String[] args) {
// Create a 5x5 world and make it visible
World.setSize(5, 5);
World.setVisible(true);
// Create at least one Hacking Robot with different positions and both cases for the array shift
HackingRobot hackingRobot1 = new HackingRobot(1, 1, true);
HackingRobot hackingRobot2 = new HackingRobot(2, 2, false);
// Change the type of the Hacking Robot and check the current and next type
hackingRobot1.shuffle();
System.out.println("HackingRobot1 current type: " + hackingRobot1.getType());
System.out.println("HackingRobot1 next type: " + hackingRobot1.getNextType());
hackingRobot2.shuffle();
System.out.println("HackingRobot2 current type: " + hackingRobot2.getType());
System.out.println("HackingRobot2 next type: " + hackingRobot2.getNextType());
// Create at least two Versatile Robots with both cases for coordinate exchange
VersatileRobot versatileRobot1 = new VersatileRobot(1, 2, true, false);
VersatileRobot versatileRobot2 = new VersatileRobot(3, 4, false, true);
// Change the type of the Versatile Robot until the type is DIAGONAL and check coordinates
while (versatileRobot1.getType() != MovementType.DIAGONAL) {
versatileRobot1.shuffle();
}
System.out.println("VersatileRobot1 type is DIAGONAL. x: " + versatileRobot1.getX() + ", y: " + versatileRobot1.getY());
while (versatileRobot2.getType() != MovementType.DIAGONAL) {
versatileRobot2.shuffle();
}
System.out.println("VersatileRobot2 type is DIAGONAL. x: " + versatileRobot2.getX() + ", y: " + versatileRobot2.getY());
// Create at least three Double Power Robots and change their types to get all movement types
DoublePowerRobot doublePowerRobot1 = new DoublePowerRobot(0, 0, true);
DoublePowerRobot doublePowerRobot2 = new DoublePowerRobot(1, 1, false);
DoublePowerRobot doublePowerRobot3 = new DoublePowerRobot(2, 2, true);
// Create a RobotsChallenge with previously created Double Power Robots
DoublePowerRobot[] robots = {doublePowerRobot1, doublePowerRobot2, doublePowerRobot3};
RobotsChallenge challenge = new RobotsChallenge(0, 2, robots);
// Find and display the winning Double Power Robots
DoublePowerRobot[] winners = challenge.findWinners();
System.out.println("Winning DoublePowerRobots:");
for (DoublePowerRobot winner : winners) {
if (winner != null) {
//print the winner robot's coordinates
System.out.println("Winner robot coordinates: x: " + winner.getX() + ", y: " + winner.getY());
}
}
}
}

View file

@ -1,88 +0,0 @@
package h03;
import h03.robots.DoublePowerRobot;
import h03.robots.MovementType;
/**
* The {@code RobotsChallenge} class performs a challenge between robots of the {@code DoublePowerRobot} class.
*/
public class RobotsChallenge {
private final DoublePowerRobot[] robots;
private final int goal;
private final int begin;
private final int winThreshold = 2;
/**
* Constructs a new {@code RobotsChallenge} with the specified starting position, goal, and array of robots.
*
* @param begin The starting position of the robots.
* @param goal The target coordinates.
* @param robots The array of {@code DoublePowerRobot} objects participating in the challenge.
*/
public RobotsChallenge(int begin, int goal, final DoublePowerRobot[] robots) {
this.begin = begin / 2;
this.goal = goal;
this.robots = robots;
}
/**
* Calculates the number of steps needed for a robot to reach the goal for the diagonal type.
*
* @return The number of steps required to reach the goal.
*/
public int calculateStepsDiagonal() {
return Math.abs(begin - goal);
}
/**
* Calculates the number of steps needed for a robot to reach the goal for the overstep type.
*
* @return The number of steps required to reach the goal.
*/
public int calculateStepsOverstep() {
return (Math.abs(begin - goal) % 2 == 0) ? Math.abs(begin - goal) : Math.abs(begin - goal) + 1;
}
/**
* Calculates the number of steps needed for a robot to reach the goal for the teleport type.
*
* @return The number of steps required to reach the goal.
*/
public int calculateStepsTeleport() {
return (Math.abs(begin - goal) % 2 == 0) ? Math.abs(begin - goal) / 2 : (Math.abs(begin - goal) / 2) + 2;
}
/**
* Calculates the number of steps needed for a robot to reach the goal based on its movement type.
*
* @param type The {@code MovementType} of the robot.
* @return The number of steps required to reach the goal.
*/
public int calculateSteps(MovementType type) {
return type == MovementType.DIAGONAL ? calculateStepsDiagonal() : type == MovementType.OVERSTEP ? calculateStepsOverstep() : calculateStepsTeleport();
}
/**
* Finds the winning robots in the challenge based on their movement types and the number of steps required to reach the goal.
*
* @return An array of {@code DoublePowerRobot} objects that are the winners of the challenge.
*/
public DoublePowerRobot[] findWinners() {
int winnerCount = 0;
DoublePowerRobot[] winners = new DoublePowerRobot[robots.length];
for (DoublePowerRobot robot : robots) {
int stepsFirstType = calculateSteps(robot.getType());
int stepsSecondType = calculateSteps(robot.getNextType());
int steps = Math.min(stepsFirstType, stepsSecondType);
if (steps <= winThreshold) {
winners[winnerCount] = robot;
winnerCount++;
}
}
return winners;
}
}

View file

@ -1,57 +0,0 @@
package h03.robots;
/**
* Subclass DoublePowerRobot, which inherits from the {@code HackingRobot} class and allows the robot to have two types simultaneously.
*/
public class DoublePowerRobot extends HackingRobot {
/**
* Private array doublePowerTypes containing the two types for the DoublePowerRobot.
*/
private MovementType[] doublePowerTypes = new MovementType[2];
/**
* Constructor of the DoublePowerRobot class with parameters x, y, and order.
* Initializes the robot and assigns two movement types to the robot.
*
* @param x The x-coordinate of the robot.
* @param y The y-coordinate of the robot.
* @param order If true, the movement types are shifted to the right by one index, otherwise to the left by one index.
*/
public DoublePowerRobot(int x, int y, boolean order) {
super(x, y, order);
// Assigning the two types to doublePowerTypes
doublePowerTypes[0] = getType();
doublePowerTypes[1] = getNextType();
}
/**
* Overrides the shuffle method of the superclass.
* Shuffles the robot's type a specified number of times and updates the types in doublePowerTypes.
*
* @param itNr The number of iterations to shuffle the type.
* @return True if the types have changed, false otherwise.
*/
@Override
public boolean shuffle(int itNr) {
boolean changed = super.shuffle(itNr);
// Updating the types in doublePowerTypes based on the new value of type
doublePowerTypes[0] = getType();
doublePowerTypes[1] = getNextType();
return changed;
}
/**
* Overrides the shuffle method of the superclass.
* Shuffles the robot's type until the type is different from the current type and updates the types in doublePowerTypes.
*/
@Override
public void shuffle() {
super.shuffle();
doublePowerTypes[0] = getType();
doublePowerTypes[1] = getNextType();
}
}

View file

@ -1,111 +0,0 @@
package h03.robots;
import fopbot.Robot;
import java.util.Random;
/**
* The HackingRobot class extends the Robot class and provides additional methods for movement in the grid.
* The robot can have different types of movements which can be shuffled.
*/
public class HackingRobot extends Robot {
/**
* Private array "robotTypes" containing the elements of the enumeration MovementType in reverse alphabetical order.
*/
private MovementType[] robotTypes = {MovementType.TELEPORT, MovementType.OVERSTEP, MovementType.DIAGONAL};
/**
* Private variable that contains the type of the robot.
*/
private MovementType type;
/**
* Constructs a new HackingRobot at the specified coordinates.
* The order parameter determines the initial order of the movement types.
*
* @param x The x-coordinate of the robot.
* @param y The y-coordinate of the robot.
* @param order If true, the movement types are shifted to the right by one index, otherwise to the left by one index.
*/
public HackingRobot(int x, int y, boolean order) {
super(x, y);
if (order) {
// Move elements to the right by 1 index
MovementType lastElement = robotTypes[robotTypes.length - 1];
for (int i = robotTypes.length - 1; i > 0; i--) {
robotTypes[i] = robotTypes[i - 1];
}
robotTypes[0] = lastElement;
} else {
// Move elements to the left by 1 index
MovementType firstElement = robotTypes[0];
for (int i = 0; i < robotTypes.length - 1; i++) {
robotTypes[i] = robotTypes[i + 1];
}
robotTypes[robotTypes.length - 1] = firstElement;
}
this.type = robotTypes[0];
}
/**
* Returns the current type of the robot.
*
* @return The current MovementType of the robot.
*/
public MovementType getType() {
return type;
}
/**
* Returns the movement type located 1 index to the right of the current type of the robot.
*
* @return The next MovementType of the robot.
*/
public MovementType getNextType() {
int currentIndex = -1;
for (int i = 0; i < robotTypes.length; i++) {
if (robotTypes[i] == type) {
currentIndex = i;
break;
}
}
return robotTypes[(currentIndex + 1) % robotTypes.length];
}
/**
* Generates a random number between zero (inclusive) and the specified limit (exclusive).
*
* @param limit The upper bound (exclusive) for the random number.
* @return A random integer between 0 (inclusive) and the specified limit (exclusive).
*/
public int getRandom(int limit) {
Random random = new Random();
return random.nextInt(limit);
}
/**
* Randomly changes the type of the robot a specified number of times.
*
* @param itNr The number of iterations to shuffle the type.
* @return True if the type changed after shuffling, false otherwise.
*/
public boolean shuffle(int itNr) {
MovementType previousType = this.type;
for (int i = 0; i < itNr; i++) {
int randomIndex = getRandom(robotTypes.length);
this.type = robotTypes[randomIndex];
}
return this.type != previousType;
}
/**
* Randomly changes the type of the robot until the type is different from the current type.
*/
public void shuffle() {
while (!shuffle(1)) {
}
}
}

View file

@ -1,21 +0,0 @@
package h03.robots;
/**
* The {@code MovementType} enum represents the different types of movements that a robot can perform.
*/
public enum MovementType {
/**
* Represents diagonal movement.
*/
DIAGONAL,
/**
* Represents overstepping movement.
*/
OVERSTEP,
/**
* Represents teleportation movement.
*/
TELEPORT
}

View file

@ -1,59 +0,0 @@
package h03.robots;
/**
* Subclass VersatileRobot, which inherits from the class {@code HackingRobot}.
* This robot can switch its coordinates and has specific behavior when its type is DIAGONAL.
*/
public class VersatileRobot extends HackingRobot {
/**
* Constructor of the VersatileRobot class with the parameters x, y, order, and exchange.
* Initializes the robot and optionally exchanges its coordinates.
*
* @param x The x-coordinate of the robot.
* @param y The y-coordinate of the robot.
* @param order If true, the movement types are shifted to the right by one index, otherwise to the left by one index.
* @param exchange If true, the coordinates x and y are exchanged.
*/
public VersatileRobot(int x, int y, boolean order, boolean exchange) {
super(x, y, order);
if (exchange) {
int aux = x;
setX(y);
setY(aux);
}
if (getType() == MovementType.DIAGONAL) {
setY(getX());
}
}
/**
* Overrides the shuffle method of the superclass.
* Shuffles the robot's type a specified number of times and adjusts the y-coordinate if the type is DIAGONAL.
*
* @param itNr The number of iterations to shuffle the type.
* @return True if the types have changed, false otherwise.
*/
@Override
public boolean shuffle(int itNr) {
boolean changed = super.shuffle(itNr);
if (getType() == MovementType.DIAGONAL) {
setY(getX());
}
return changed;
}
/**
* Overrides the shuffle method of the superclass.
* Shuffles the robot's type until the type is different from the current type and adjusts the y-coordinate if the type is DIAGONAL.
*/
@Override
public void shuffle() {
super.shuffle();
if (getType() == MovementType.DIAGONAL) {
setY(getX());
}
}
}

1
solution/H03/src/test Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H03/src/test

View file

@ -1,16 +0,0 @@
package h03;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* An example JUnit test class.
*/
public class ExampleJUnitTest {
@Test
public void testAddition() {
assertEquals(2, 1 + 1);
}
}

1
solution/H04/src/main Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H04/src/main

View file

@ -1,18 +0,0 @@
package h04;
import h04.template.ChessUtils;
import h04.template.GameControllerTemplate;
import h04.chesspieces.King;
public class GameController extends GameControllerTemplate {
public GameController() {
super();
setup();
}
@Override
public boolean checkWinCondition() {
final King[] kings = ChessUtils.getKings();
return (kings[0].isTurnedOff() || kings[1].isTurnedOff());
}
}

View file

@ -1,17 +0,0 @@
package h04;
import fopbot.World;
/**
* Main entry point in executing the program.
*/
public class Main {
/**
* Main entry point in executing the program.
*
* @param args program arguments, currently ignored
*/
public static void main(final String[] args) {
new GameController().startGame();
}
}

View file

@ -1,29 +0,0 @@
package h04.chesspieces;
import fopbot.Robot;
import h04.movement.DiagonalMover;
import h04.movement.MoveStrategy;
import java.awt.Point;
public class Bishop extends Robot implements ChessPiece, DiagonalMover {
private final Team team;
public Bishop(final int x, final int y, final Team team){
super(x, y, team == Team.WHITE ? Families.BISHOP_WHITE : Families.BISHOP_BLACK);
this.team = team;
}
@Override
public Team getTeam() { return team;}
@Override
public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy){strategy.move(this, dx, dy);}
@Override
public Point[] getPossibleMoveFields() {
return getDiagonalMoves();
}
}

View file

@ -1,20 +0,0 @@
package h04.chesspieces;
import h04.movement.MoveStrategy;
import java.awt.Point;
public interface ChessPiece {
Team getTeam();
int getX();
int getY();
/**
* Returns {@code true} if this robot is turned off.
*
* @return {@code true} if this robot is turned off
*/
boolean isTurnedOff();
void turnOff();
void moveStrategy(int dx, int dy, MoveStrategy strategy);
Point[] getPossibleMoveFields();
}

View file

@ -1,81 +0,0 @@
package h04.chesspieces;
import fopbot.RobotFamily;
import fopbot.SvgBasedRobotFamily;
import java.awt.Color;
public class Families {
public static RobotFamily PAWN_WHITE = new SvgBasedRobotFamily(
"PAWN_WHITE",
"/pieces/pawn_white.svg",
"/pieces/pawn_white.svg",
Color.WHITE
);
public static RobotFamily PAWN_BLACK = new SvgBasedRobotFamily(
"PAWN_BLACK",
"/pieces/pawn_black.svg",
"/pieces/pawn_black.svg",
Color.BLACK
);
public static RobotFamily ROOK_WHITE = new SvgBasedRobotFamily(
"ROOK_WHITE",
"/pieces/rook_white.svg",
"/pieces/rook_white.svg",
Color.WHITE
);
public static RobotFamily ROOK_BLACK = new SvgBasedRobotFamily(
"ROOK_BLACK",
"/pieces/rook_black.svg",
"/pieces/rook_black.svg",
Color.BLACK
);
public static RobotFamily KNIGHT_WHITE = new SvgBasedRobotFamily(
"KNIGHT_WHITE",
"/pieces/knight_white.svg",
"/pieces/knight_white.svg",
Color.WHITE
);
public static RobotFamily KNIGHT_BLACK = new SvgBasedRobotFamily(
"KNIGHT_BLACK",
"/pieces/knight_black.svg",
"/pieces/knight_black.svg",
Color.BLACK
);
public static RobotFamily BISHOP_WHITE = new SvgBasedRobotFamily(
"BISHOP_WHITE",
"/pieces/bishop_white.svg",
"/pieces/bishop_white.svg",
Color.WHITE
);
public static RobotFamily BISHOP_BLACK = new SvgBasedRobotFamily(
"BISHOP_BLACK",
"/pieces/bishop_black.svg",
"/pieces/bishop_black.svg",
Color.BLACK
);
public static RobotFamily QUEEN_WHITE = new SvgBasedRobotFamily(
"QUEEN_WHITE",
"/pieces/queen_white.svg",
"/pieces/queen_white.svg",
Color.WHITE
);
public static RobotFamily QUEEN_BLACK = new SvgBasedRobotFamily(
"QUEEN_BLACK",
"/pieces/queen_black.svg",
"/pieces/queen_black.svg",
Color.BLACK
);
public static RobotFamily KING_WHITE = new SvgBasedRobotFamily(
"KING_WHITE",
"/pieces/king_white.svg",
"/pieces/king_white.svg",
Color.WHITE
);
public static RobotFamily KING_BLACK = new SvgBasedRobotFamily(
"KING_BLACK",
"/pieces/king_black.svg",
"/pieces/king_black.svg",
Color.BLACK
);
}

View file

@ -1,45 +0,0 @@
package h04.chesspieces;
import fopbot.Robot;
import h04.movement.MoveStrategy;
import h04.template.ChessUtils;
import java.awt.Point;
public class King extends Robot implements ChessPiece {
private final Team team;
public King(final int x, final int y, final Team team) {
super(x, y, team == Team.WHITE ? Families.KING_WHITE : Families.KING_BLACK);
this.team = team;
}
@Override
public Team getTeam() {
return team;
}
@Override
public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) {
strategy.move(this, dx, dy);
}
@Override
public Point[] getPossibleMoveFields() {
return ChessUtils.getAllowedMoves(
this,
new Point[]{
new Point(1, 0),
new Point(-1, 0),
new Point(0, 1),
new Point(0, -1),
new Point(1, 1),
new Point(-1, 1),
new Point(1, -1),
new Point(-1, -1)
},
1
);
}
}

View file

@ -1,44 +0,0 @@
package h04.chesspieces;
import fopbot.Robot;
import h04.movement.MoveStrategy;
import h04.template.ChessUtils;
import java.awt.Point;
public class Knight extends Robot implements ChessPiece {
private final Team team;
public Knight(final int x, final int y, final Team team) {
super(x, y, team == Team.WHITE ? Families.KNIGHT_WHITE : Families.KNIGHT_BLACK);
this.team = team;
}
@Override
public Team getTeam() {
return team;
}
@Override
public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) {
strategy.move(this, dx, dy);
}
@Override
public Point[] getPossibleMoveFields() {
final Point[] possibleMoves = new Point[8];
int index = 0;
for (final Point delta : new Point[]{new Point(1, 2), new Point(2, 1)}) {
for (int i = 0; i < 4; i++) {
final Point move = new Point(getX() + delta.x, getY() + delta.y);
if (ChessUtils.isValidCoordinate(move) && ChessUtils.getTeamAt(move) != getTeam()) {
possibleMoves[index++] = move;
}
//noinspection SuspiciousNameCombination
delta.setLocation(-delta.y, delta.x);
}
}
return possibleMoves;
}
}

View file

@ -1,54 +0,0 @@
package h04.chesspieces;
import fopbot.Robot;
import h04.movement.MoveStrategy;
import java.awt.Point;
import static h04.template.ChessUtils.getTeamAt;
import static h04.template.ChessUtils.isValidCoordinate;
public class Pawn extends Robot implements ChessPiece {
private final Team team;
boolean firstMove = true;
public Pawn(final int x, final int y, final Team team) {
super(x, y, team == Team.WHITE ? Families.PAWN_WHITE : Families.PAWN_BLACK);
this.team = team;
}
@Override
public Team getTeam() {
return team;
}
@Override
public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) {
strategy.move(this, dx, dy);
firstMove = false;
}
@Override
public Point[] getPossibleMoveFields() {
final Point[] possibleMoves = new Point[4];
int index = 0;
final int direction = team == Team.WHITE ? 1 : -1;
final Point front1 = new Point(getX(), getY() + direction);
if (isValidCoordinate(front1) && getTeamAt(front1) == null) {
possibleMoves[index++] = front1;
final Point front2 = new Point(getX(), getY() + 2 * direction);
if (firstMove && isValidCoordinate(front2) && getTeamAt(front2) == null) {
possibleMoves[index++] = front2;
}
}
//attack
for (final int i : new int[]{-1, 1}) {
final Point p = new Point(getX() + i, getY() + direction);
if (isValidCoordinate(p) && getTeamAt(p) == getTeam().getOpponent()) {
possibleMoves[index++] = p;
}
}
return possibleMoves;
}
}

View file

@ -1,33 +0,0 @@
package h04.chesspieces;
import fopbot.Robot;
import h04.movement.DiagonalMover;
import h04.movement.MoveStrategy;
import h04.movement.OrthogonalMover;
import h04.template.ChessUtils;
import java.awt.Point;
public class Queen extends Robot implements OrthogonalMover, DiagonalMover {
private final Team team;
public Queen(final int x, final int y, final Team team) {
super(x, y, team == Team.WHITE ? Families.QUEEN_WHITE : Families.QUEEN_BLACK);
this.team = team;
}
@Override
public Team getTeam() {
return team;
}
@Override
public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) {
strategy.move(this, dx, dy);
}
@Override
public Point[] getPossibleMoveFields() {
return ChessUtils.mergePoints(getOrthogonalMoves(), getDiagonalMoves());
}
}

View file

@ -1,32 +0,0 @@
package h04.chesspieces;
import fopbot.Robot;
import h04.movement.MoveStrategy;
import h04.movement.OrthogonalMover;
import h04.template.ChessUtils;
import java.awt.Point;
public class Rook extends Robot implements OrthogonalMover {
private final Team team;
public Rook(final int x, final int y, final Team team){
super(x, y, team == Team.WHITE ? Families.ROOK_WHITE : Families.ROOK_BLACK);
this.team = team;
}
@Override
public Team getTeam() {
return team;
}
@Override
public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) {
strategy.move(this, dx, dy);
}
@Override
public Point[] getPossibleMoveFields() {
return getOrthogonalMoves();
}
}

View file

@ -1,25 +0,0 @@
package h04.chesspieces;
import java.awt.Color;
public enum Team {
WHITE(Color.WHITE),
BLACK(Color.BLACK);
private final Color color;
Team(final Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
public boolean isOpponent(final Team other) {
return this != other;
}
public Team getOpponent() {
return this == WHITE ? BLACK : WHITE;
}
}

View file

@ -1,21 +0,0 @@
package h04.movement;
import h04.chesspieces.ChessPiece;
import h04.template.ChessUtils;
import java.awt.Point;
public interface DiagonalMover extends ChessPiece {
default Point[] getDiagonalMoves() {
return ChessUtils.getAllowedMoves(
this,
new Point[]{
new Point(1, 1),
new Point(-1, 1),
new Point(1, -1),
new Point(-1, -1)
},
7
);
}
}

View file

@ -1,8 +0,0 @@
package h04.movement;
import fopbot.Robot;
public interface MoveStrategy {
void move(Robot r, int dx, int dy);
}

View file

@ -1,21 +0,0 @@
package h04.movement;
import h04.chesspieces.ChessPiece;
import h04.template.ChessUtils;
import java.awt.Point;
public interface OrthogonalMover extends ChessPiece {
default Point[] getOrthogonalMoves() {
return ChessUtils.getAllowedMoves(
this,
new Point[]{
new Point(1, 0),
new Point(-1, 0),
new Point(0, 1),
new Point(0, -1)
},
7
);
}
}

View file

@ -1,10 +0,0 @@
package h04.movement;
import fopbot.Robot;
public class TeleportingMoveStrategy implements MoveStrategy {
@Override
public void move(final Robot r, final int dx, final int dy) {
r.setField(r.getX() + dx, r.getY() + dy);
}
}

View file

@ -1,40 +0,0 @@
package h04.movement;
import fopbot.Direction;
import fopbot.Robot;
public class WalkingMoveStrategy implements MoveStrategy {
@Override
public void move(final Robot r, int dx, int dy) {
while (dx != 0) {
if (dx > 0) {
turnToDirection(r, Direction.RIGHT);
r.move();
dx--;
} else {
turnToDirection(r, Direction.LEFT);
r.move();
dx++;
}
}
while (dy != 0) {
if (dy > 0) {
turnToDirection(r, Direction.UP);
r.move();
dy--;
} else {
turnToDirection(r, Direction.DOWN);
r.move();
dy++;
}
}
turnToDirection(r, Direction.UP);
}
private void turnToDirection(final Robot r, final Direction d) {
while (r.getDirection() != d) {
r.turnLeft();
}
}
}

View file

@ -1,117 +0,0 @@
package h04.template;
import fopbot.World;
import h04.chesspieces.ChessPiece;
import h04.chesspieces.King;
import h04.chesspieces.Team;
import org.jetbrains.annotations.Nullable;
import java.awt.Color;
import java.awt.Point;
import java.util.Optional;
import java.util.function.Predicate;
public class ChessUtils {
public static @Nullable ChessPiece getPieceAt(final int x, final int y) {
return World.getGlobalWorld().getField(x, y).getEntities()
.stream()
.filter(ChessPiece.class::isInstance)
.map(ChessPiece.class::cast)
.filter(Predicate.not(ChessPiece::isTurnedOff))
.findFirst()
.orElse(null);
}
public static @Nullable ChessPiece getPieceAt(final Point p) {
return getPieceAt(p.x, p.y);
}
public static King[] getKings() {
return World.getGlobalWorld().getAllFieldEntities()
.stream()
.filter(King.class::isInstance)
.map(King.class::cast)
.toArray(King[]::new);
}
/**
* Returns the team at the given position, or {@code null} if there is no team.
*
* @param x the x-coordinate
* @param y the y-coordinate
* @return the team at the given position, or {@code null} if there is no team
*/
public static @Nullable Team getTeamAt(final int x, final int y) {
return Optional.ofNullable(getPieceAt(x, y))
.map(ChessPiece::getTeam)
.orElse(null);
}
public static @Nullable Team getTeamAt(final Point p) {
return getTeamAt(p.x, p.y);
}
public static Point[] getAllowedMoves(final ChessPiece piece, final Point[] directions, final int maxDistance) {
final Point[] moves = new Point[directions.length * maxDistance];
int index = 0;
for (final var p : directions) {
for (int i = 1; i <= maxDistance; i++) {
final var pos = new Point(piece.getX() + i * p.x, piece.getY() + i * p.y);
if (!isValidCoordinate(pos))
break;
final var team = getTeamAt(pos);
if (team == piece.getTeam())
break;
moves[index++] = pos;
if (team == piece.getTeam().getOpponent())
break;
}
}
return moves;
}
public static boolean isValidCoordinate(final int x, final int y) {
return x >= 0 && x < 8 && y >= 0 && y < 8;
}
public static boolean isValidCoordinate(final Point p) {
return isValidCoordinate(p.x, p.y);
}
public static Point[] mergePoints(final Point[] a, final Point[] b) {
final Point[] result = new Point[a.length + b.length];
var index = 0;
for (final var p : a) {
if (p == null)
break;
result[index++] = p;
}
for (final var p : b) {
if (p == null)
break;
result[index++] = p;
}
return result;
}
public static void setFieldColor(final Point field, final @Nullable Color c) {
World.getGlobalWorld().getField(field.x, field.y).setFieldColor(c);
}
public static void colorMoveFields(final Point... fields) {
for (final Point field : fields) {
if (field == null)
continue;
setFieldColor(field, getPieceAt(field) != null ? Color.RED : Color.GREEN);
}
}
public static void resetFieldColor() {
for (int y = 0; y < World.getHeight(); y++) {
for (int x = 0; x < World.getWidth(); x++) {
setFieldColor(new Point(x, y), null);
}
}
}
}

View file

@ -1,179 +0,0 @@
package h04.template;
import fopbot.ColorProfile;
import fopbot.Robot;
import fopbot.World;
import h04.GameController;
import h04.template.InputHandler;
import h04.chesspieces.Bishop;
import h04.chesspieces.ChessPiece;
import h04.chesspieces.King;
import h04.chesspieces.Knight;
import h04.chesspieces.Pawn;
import h04.chesspieces.Queen;
import h04.chesspieces.Rook;
import h04.chesspieces.Team;
import h04.movement.MoveStrategy;
import h04.movement.TeleportingMoveStrategy;
import h04.movement.WalkingMoveStrategy;
import org.jetbrains.annotations.Nullable;
import org.tudalgo.algoutils.student.io.PropertyUtils;
import java.awt.Color;
import java.util.Arrays;
import java.util.Objects;
/**
* A {@link GameControllerTemplate} controls the game loop and the {@link Robot}s and checks the win condition.
*/
public abstract class GameControllerTemplate {
/**
* The {@link InputHandler} that handles the input of the user.
*/
private final InputHandler inputHandler = new InputHandler((GameController) this);
/**
* The {@link Robot}s that are controlled by the {@link GameControllerTemplate}.
*/
protected Team nextToMove = Team.WHITE;
protected boolean gameOver = false;
protected @Nullable ChessPiece selectedPiece;
protected MoveStrategy moveStrategy = PropertyUtils.getBooleanProperty(
"h04.properties",
"USE_TELEPORT_MOVE_STRATEGY"
) ? new TeleportingMoveStrategy() : new WalkingMoveStrategy();
/**
* Starts the game loop.
*/
public void startGame() {
System.out.println("Starting game...");
while (!gameOver) {
final var point = inputHandler.getNextInput(nextToMove);
if (ChessUtils.getTeamAt(point) == nextToMove) {
// select piece
selectedPiece = ChessUtils.getPieceAt(point);
//highlight possible moves
final var possibleMoves = Objects.requireNonNull(selectedPiece).getPossibleMoveFields();
ChessUtils.resetFieldColor();
ChessUtils.colorMoveFields(possibleMoves);
continue;
}
if (selectedPiece != null) {
// check if piece can move to point
final var possibleMoves = selectedPiece.getPossibleMoveFields();
if (Arrays.stream(possibleMoves)
.filter(Objects::nonNull)
.noneMatch(point::equals)
) {
System.out.println("Invalid move");
// deselect piece
selectedPiece = null;
ChessUtils.resetFieldColor();
continue;
}
// valid move selected, move piece
final var oldPiece = ChessUtils.getPieceAt(point);
selectedPiece.moveStrategy(
point.x - selectedPiece.getX(),
point.y - selectedPiece.getY(),
moveStrategy
);
if (oldPiece != null) {
oldPiece.turnOff();
}
if (selectedPiece instanceof Pawn && (selectedPiece.getY() == 0 || selectedPiece.getY() == World.getHeight() - 1)) {
selectedPiece.turnOff();
new Queen(selectedPiece.getX(), selectedPiece.getY(), selectedPiece.getTeam());
}
ChessUtils.resetFieldColor();
if (checkWinCondition()) stopGame(nextToMove);
nextToMove = nextToMove.getOpponent();
selectedPiece = null;
}
}
}
public abstract boolean checkWinCondition();
/**
* Stops the game loop.
*/
public void stopGame(final Team winner) {
gameOver = true;
inputHandler.setStatusText(winner.name() + " wins!");
}
/**
* Sets up the game.
*/
protected void setup() {
setupWorld();
setupTheme();
setupPieces();
//this.inputHandler.install();
}
public void setupTheme() {
//noinspection UnstableApiUsage
World.getGlobalWorld().setColorProfile(
ColorProfile.DEFAULT.toBuilder()
.fieldColorLight(Color.decode("#e0ba97"))
.fieldColorDark(Color.decode("#8d4d2a"))
.customFieldColorPattern(
(cp, p) -> (p.x + p.y) % 2 == 0 ? cp.fieldColorLight() : cp.fieldColorDark()
)
.backgroundColorDark(Color.decode("#8d4d2a"))
.backgroundColorLight(Color.decode("#8d4d2a"))
.innerBorderColorLight(new Color(0, 0, 0, 0))
.innerBorderColorDark(new Color(0, 0, 0, 0))
.fieldBorderThickness(0)
.outerBorderColorDark(Color.BLACK)
.outerBorderColorLight(Color.BLACK)
.build()
);
}
/**
* Initializes the {@link World} and adds the {@link Robot}s to it.
*/
public void setupWorld() {
World.setSize(8, 8);
World.setDelay(0);
World.setVisible(true);
World.getGlobalWorld().setDrawTurnedOffRobots(false);
inputHandler.install();
}
public void setupPieces() {
for (final int y : new int[]{0, 1, World.getHeight() - 2, World.getHeight() - 1}) {
for (int x = 0; x < World.getWidth(); x++) {
if (y == 1 || y == World.getHeight() - 2)
new Pawn(x, y, y == 1 ? Team.WHITE : Team.BLACK);
else if (x == 0 || x == World.getWidth() - 1) {
new Rook(x, y, y == 0 ? Team.WHITE : Team.BLACK);
} else if (x == 1 || x == World.getWidth() - 2) {
new Knight(x, y, y == 0 ? Team.WHITE : Team.BLACK);
} else if (x == 2 || x == World.getWidth() - 3) {
new Bishop(x, y, y == 0 ? Team.WHITE : Team.BLACK);
} else if (x == 3) {
new Queen(x, y, y == 0 ? Team.WHITE : Team.BLACK);
} else if (x == World.getWidth() - 4) {
new King(x, y, y == 0 ? Team.WHITE : Team.BLACK);
}
}
}
}
}

View file

@ -1,68 +0,0 @@
package h04.template;
import fopbot.World;
import h04.GameController;
import h04.chesspieces.Team;
import java.awt.Color;
import java.awt.Point;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import javax.swing.JLabel;
import java.beans.PropertyChangeEvent;
public class InputHandler {
/**
* The input queue.
*/
private final BlockingDeque<Point> inputQueue = new LinkedBlockingDeque<>();
public final GameController controller;
private final JLabel statusLabel = new JLabel("");
public InputHandler(final GameController controller) {
this.controller = controller;
}
@SuppressWarnings("UnstableApiUsage")
public void install() {
final var guiPanel = World.getGlobalWorld().getGuiPanel();
World.getGlobalWorld().getInputHandler().addFieldClickListener(e -> addInput(e.getField().getX(), e.getField().getY()));
statusLabel.setFont(statusLabel.getFont().deriveFont(20.0f));
guiPanel.add(statusLabel, JLabel.CENTER);
guiPanel.addDarkModeChangeListener(this::onDarkModeChange);
// trigger dark mode change to set the correct color
guiPanel.setDarkMode(World.getGlobalWorld().getGuiPanel().isDarkMode());
}
public void onDarkModeChange(final PropertyChangeEvent e) {
final var darkMode = (boolean) e.getNewValue();
statusLabel.setForeground(darkMode ? Color.white : Color.black);
}
private void addInput(final int x, final int y) {
inputQueue.add(new Point(x,y));
System.out.println("Added input: "+x+","+y);
}
public Point getNextInput(final Team currentPlayer) {
statusLabel.setText(currentPlayer.name()+" to move.");
try {
return inputQueue.take();
} catch (final InterruptedException e) {
throw new RuntimeException(e);
}
}
public JLabel getStatusLabel() {
return statusLabel;
}
public void setStatusText(final String s) {
statusLabel.setText(s);
}
}

View file

@ -1,2 +0,0 @@
# Whether to use the TeleportMoveStrategy or not. If not, the WalkingMoveStrategy will be used.
USE_TELEPORT_MOVE_STRATEGY=false

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="24.200001mm"
height="25.799999mm"
viewBox="0 0 24.200001 25.799998"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="Bishop.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="2.9255612"
inkscape:cx="14.698035"
inkscape:cy="43.923197"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<path
d="m 10.443893,15.8801 c -1.1613884,0 -1.7420694,0.182173 -1.742043,0.546523 -3.17e-5,0.318796 0.5123392,0.512366 1.537097,0.580681 h 1.878673 c 2.277136,0 3.415771,-0.193564 3.415771,-0.580681 C 15.533359,16.062265 14.952683,15.8801 13.791348,15.8801 H 10.44384 m 0,-2.117778 c -1.0019768,0 -1.5599037,0.113863 -1.6737275,0.341577 -0.045572,0.04555 -0.068347,0.113861 -0.068315,0.204949 -3.17e-5,0.250489 0.2390749,0.398515 0.7173119,0.44405 0.5920316,0.06831 1.4915356,0.102473 2.6984846,0.102473 1.20695,0 2.117751,-0.03416 2.732617,-0.102473 0.4554,-0.04554 0.683127,-0.193561 0.683154,-0.44405 -3.2e-5,-0.364358 -0.580708,-0.546524 -1.742044,-0.546524 h -3.347507 m 6.353438,1.468782 0.683155,2.630143 c -2.7e-5,0.797005 -0.808435,1.263836 -2.425198,1.400466 1.184117,0.455428 2.28854,0.683154 3.313377,0.683154 0.136607,0 0.808382,-0.03416 2.015305,-0.102476 1.001924,0 1.821709,0.523743 2.459355,1.571255 0.09106,0.182171 0.204923,0.387112 0.341577,0.614839 l -1.229677,1.878674 c -0.364384,0.455427 -0.751496,0.751469 -1.161362,0.8881 -0.09112,-0.478208 -0.819812,-0.774224 -2.186094,-0.8881 l -0.819785,-0.06831 c -2.800879,-0.227716 -4.691062,-0.831162 -5.670285,-1.810359 -0.888127,0.933636 -2.2430573,1.468782 -4.0647929,1.605413 -0.4098925,0.04555 -0.9450391,0.11386 -1.6054121,0.204948 -1.662351,0.136629 -2.630144,0.375735 -2.903273,0.717312 -0.04554,0.06831 -0.07971,0.148016 -0.102476,0.239102 C 2.849608,24.544778 2.291681,23.975482 1.7679389,23.087381 1.5629899,22.723024 1.3238879,22.370069 1.0506269,22.028492 1.6654649,20.889911 2.325839,20.206757 3.031774,19.97903 3.282271,19.88794 3.555516,19.842399 3.851559,19.842399 l 2.015304,0.102476 c 1.047486,0 2.1519361,-0.227721 3.3133775,-0.683154 C 7.5634512,19.125093 6.755043,18.658259 6.755043,17.861255 c 0,-0.06831 0.182174,-0.648996 0.5465236,-1.742043 0.1138555,-0.364358 0.1707885,-0.614839 0.1707885,-0.75147 C 6.083266,13.682638 5.388735,12.191155 5.388735,10.893109 5.388735,9.3901699 6.128827,8.0239674 7.608986,6.7941841 8.929733,5.6783538 9.8861488,5.0862957 10.478128,5.0179803 9.9771126,4.4031415 9.7266316,3.7655222 9.726658,3.1051486 c -2.64e-5,-1.070266 0.53512,-1.7306396 1.605411,-1.9811471 0.25046,-0.068289 0.51234,-0.1024414 0.785628,-0.1024705 1.138555,2.91e-5 1.878647,0.4212696 2.220251,1.2638353 l 0.170788,0.7173119 v 0.1024731 c -2.6e-5,0.6376194 -0.250518,1.2752123 -0.751469,1.9128316 0.432646,0.1138582 1.081616,0.4668309 1.946989,1.058889 2.094971,1.4573779 3.142456,3.0628166 3.142456,4.8162101 -2.6e-5,1.320774 -0.68318,2.766748 -2.049462,4.338109 m -4.064794,-3.176588 v -1.571255 h 1.19552 V 9.1853556 h -1.19552 V 7.7165741 H 11.502779 V 9.1853556 H 10.30726 v 1.2979924 h 1.195519 v 1.571255 h 1.229677 M 12.117617,2.4221823 c -0.455453,0 -0.740119,0.204941 -0.853942,0.6148388 l -0.03415,0.2049409 c -2.9e-5,0.4326732 0.227687,0.7059348 0.683154,0.819785 0.06829,0.022773 0.136602,0.034155 0.204949,0.034155 0.569251,0 0.853916,-0.2846388 0.853942,-0.8539427 -2.9e-5,-0.5465233 -0.284691,-0.819785 -0.853942,-0.819785"
id="path4"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="24.066mm"
height="25.671mm"
viewBox="0 0 24.066 25.670999"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="WhiteBishop.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="16.549473"
inkscape:cx="64.08059"
inkscape:cy="78.461713"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-63.764586,-42.333335)">
<path
d="m 75.772721,56.969419 c -1.594061,0 -2.83501,-0.06832 -3.723216,-0.204946 0.159371,0.318797 0.239075,0.592058 0.239101,0.819785 -2.6e-5,0.341577 -0.06834,0.626216 -0.204941,0.853943 0.660347,-0.204946 1.890025,-0.307419 3.689085,-0.307419 1.799061,0 3.028686,0.102475 3.689086,0.307419 -0.136658,-0.227719 -0.20497,-0.512366 -0.204944,-0.853943 -2.6e-5,-0.273261 0.06829,-0.546523 0.204944,-0.819785 -1.070293,0.136628 -2.29997,0.204946 -3.689086,0.204946 m 0,-12.365037 c -0.478234,0 -0.808434,0.216326 -0.990573,0.648997 -0.04557,0.113858 -0.06834,0.227721 -0.06832,0.341577 -2.6e-5,0.500988 0.25046,0.831162 0.75147,0.990573 0.09106,0.02278 0.193535,0.03416 0.307419,0.03416 0.523717,0 0.865294,-0.23911 1.024732,-0.717312 0.02273,-0.09109 0.03413,-0.193564 0.03416,-0.30742 -3.4e-5,-0.455427 -0.227748,-0.762846 -0.683154,-0.922258 -0.136657,-0.04554 -0.261906,-0.06831 -0.375735,-0.06831 m 0,14.516894 c -0.865346,0 -1.981173,0.0797 -3.347508,0.239104 -0.387112,0.04555 -0.614839,0.261877 -0.683154,0.648996 0,0.273262 0.626189,0.444051 1.878674,0.512366 -0.113888,-0.02278 -0.06834,-0.03416 0.136633,-0.03416 h 2.015305 c 2.664354,0 3.996531,-0.159401 3.996531,-0.478208 -3.2e-5,-0.523743 -0.6604,-0.808408 -1.981147,-0.853943 h -0.990574 c -0.296068,0 -0.546549,-0.01138 -0.751469,-0.03416 h -0.273258 m -0.03416,-3.142457 c 2.550424,0 4.110302,-0.239101 4.679685,-0.717311 0.387086,-0.296043 0.671724,-1.08167 0.853943,-2.356882 -0.113887,-1.138582 -0.853969,-2.231628 -2.220251,-3.279246 -1.275239,-1.001951 -2.391066,-1.559878 -3.347508,-1.673728 -0.888127,0.113861 -1.969797,0.671777 -3.24485,1.673728 -1.343528,1.047512 -2.072217,2.140558 -2.186094,3.279246 0.159406,1.184142 0.409893,1.935612 0.75147,2.254408 0.09109,0.09109 0.193561,0.170789 0.307419,0.239102 0.569304,0.387138 2.038059,0.580681 4.406371,0.580681 m -0.580681,-1.673728 v -1.502939 h -1.161362 v -1.332151 h 1.161362 V 50.00122 h 1.229677 v 1.468781 h 1.161363 v 1.332151 h -1.161363 v 1.502939 h -1.229677 m 0.546523,6.968067 c -0.20497,0 -0.808434,0.398515 -1.810358,1.195519 -0.705961,0.478208 -1.844516,0.762847 -3.415771,0.853943 -1.138581,0 -2.049462,0.05693 -2.732617,0.170789 -0.728689,0.159401 -1.093046,0.466831 -1.093046,0.922258 0.06831,0.455427 0.307419,0.683154 0.717312,0.683154 l 1.810358,-0.273262 c 1.184116,0 2.425197,-0.159401 3.723217,-0.478208 1.480132,-0.387111 2.436548,-1.00195 2.869141,-1.844516 0.614813,1.206924 2.208821,1.935612 4.782079,2.186094 l 0.888101,0.136633 h 0.8881 l 1.844516,0.273262 c 0.409867,0 0.64897,-0.227719 0.717312,-0.683155 -2.6e-5,-0.455427 -0.364384,-0.762846 -1.093046,-0.922258 L 80.144993,63.22015 C 78.983604,63.12906 77.867777,62.673626 76.797484,61.853841 76.31925,61.466703 75.954892,61.27316 75.704438,61.27316 m 0.06832,2.9718 c -0.888127,0.888101 -2.231655,1.434624 -4.030663,1.63957 -0.728689,0.06831 -2.003927,0.227717 -3.82561,0.478208 -0.478208,0.09109 -0.75147,0.30742 -0.819785,0.648997 -0.432673,-0.113858 -1.070266,-0.819785 -1.912832,-2.117778 -0.204946,-0.318797 -0.352954,-0.535146 -0.44405,-0.648997 0.75147,-1.434623 1.685105,-2.151935 2.800879,-2.151935 l 2.015305,0.102473 c 0.933635,0 2.026682,-0.216334 3.279246,-0.648997 C 71.218458,61.341558 70.41005,60.85197 70.41005,60.07772 l 0.683155,-2.595986 v -0.06832 c -1.366309,-1.502939 -2.049463,-2.914914 -2.049463,-4.235449 0,-1.50294 0.740093,-2.869142 2.220251,-4.098925 1.297967,-1.093047 2.254382,-1.673728 2.869142,-1.742044 -0.501015,-0.614838 -0.751496,-1.252431 -0.75147,-1.912831 -2.9e-5,-1.047512 0.523716,-1.707886 1.571255,-1.981147 0.25046,-0.06829 0.523716,-0.102447 0.819785,-0.102476 1.115801,2.9e-5 1.84449,0.42127 2.186093,1.263835 l 0.170789,0.717312 v 0.102468 c -2.7e-5,0.705935 -0.239136,1.343528 -0.717312,1.912832 0.614812,0.06832 1.582605,0.660373 2.903537,1.7762 1.457352,1.206897 2.186067,2.561828 2.186094,4.064794 -3e-5,1.275212 -0.683181,2.687108 -2.049463,4.23545 -2.6e-5,0.318823 0.113832,0.77425 0.341577,1.366308 0.22769,0.728689 0.341551,1.161362 0.341577,1.297993 -2.6e-5,0.77425 -0.808434,1.263835 -2.425197,1.468782 1.229651,0.432673 2.322698,0.648996 3.279246,0.648996 l 2.015304,-0.102473 c 1.115801,0 2.049437,0.717312 2.80088,2.151936 l -1.161362,1.7762 c -0.387139,0.500989 -0.785654,0.831162 -1.19552,0.990574 -0.09112,-0.455427 -0.751496,-0.740093 -1.981147,-0.853943 0.159371,0 -0.182203,-0.03416 -1.024732,-0.102473 -2.846387,-0.273262 -4.73657,-0.876723 -5.670285,-1.810358"
id="path10"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="22.9mm"
height="24.5mm"
viewBox="0 0 22.9 24.5"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="King.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="4.1373683"
inkscape:cx="-19.698512"
inkscape:cy="69.005218"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<path
d="m 12.33603,14.91848 c 0,0.4099 -0.284639,0.61484 -0.853943,0.61484 -0.637619,0 -0.956416,-0.20494 -0.956416,-0.61484 0,-1.89005 -0.6262164,-3.42714 -1.8786744,-4.61116 C 7.5311692,9.3053702 6.4495262,8.8043902 5.4021462,8.8043902 c -1.548474,0 -2.516293,0.61483 -2.903273,1.8445098 l -0.13663,0.92226 v 0.0683 c 0,0.91085 0.671777,2.17471 2.015304,3.79147 0.364358,0.4099 0.671777,0.72869 0.922258,0.95642 0.364358,0.29602 0.967793,0.44405 1.810359,0.44405 0.8881,0 2.3227244,-0.17079 4.3039778,-0.51237 2.003928,0.34158 3.449904,0.51237 4.338104,0.51237 0.86532,0 1.46879,-0.14802 1.81036,-0.44405 0.95642,-0.84257 1.75342,-1.8673 2.39104,-3.07419 0.36436,-0.68316 0.54653,-1.24106 0.54653,-1.67373 0,-1.43462 -0.649,-2.3340998 -1.94699,-2.6984898 -0.34158,-0.0911 -0.70594,-0.13663 -1.09305,-0.13663 -1.04749,0 -2.11778,0.51237 -3.210719,1.5370998 -1.275212,1.13858 -1.912832,2.66435 -1.912832,4.57702 m 7.412301,-3.27924 c 0,0.91085 -0.62621,1.98115 -1.87867,3.21072 l -0.8881,0.75147 -0.34158,0.20494 c -0.43267,0.0683 -0.8881,0.10247 -1.36631,0.10247 -1.411842,0 -2.117776,-0.28464 -2.117776,-0.85394 0.04554,-1.75342 0.569304,-3.1197 1.571256,-4.09893 0.86532,-0.86534 1.75342,-1.2979898 2.66435,-1.2979898 1.16136,0 1.90146,0.4212698 2.22025,1.2638398 l 0.13664,0.71731 m -3.24485,8.67595 c 0,-0.59206 -1.67373,-0.8881 -5.021266,-0.8881 -0.910881,0 -1.7192624,0.0342 -2.4251974,0.10247 l -0.819785,0.0683 c -1.2296774,0.1594 -1.8445164,0.38711 -1.8445164,0.68315 0,0.34158 0.307419,0.51237 0.922258,0.51237 l 4.1330568,-0.34158 4.09893,0.34158 c 0.63759,0 0.95641,-0.1594 0.95641,-0.47821 m 1.91283,0.81978 c -0.0455,1.54848 -2.36826,2.32273 -6.968064,2.32273 -4.5542738,0 -6.8656738,-0.77425 -6.9339358,-2.32273 -0.02277,-1.4574 -0.239104,-2.75537 -0.648997,-3.89387 -0.250489,-0.61484 -0.728689,-1.40046 -1.434623,-2.35688 -0.888101,-1.2069 -1.332151,-2.27719 -1.332151,-3.21072 0,-1.4574 0.626216,-2.5846098 1.878674,-3.3816398 0.705935,-0.45543 1.491562,-0.68315 2.356882,-0.68315 1.184142,0 2.311347,0.43267 3.3816394,1.29799 0,-1.04751 0.102473,-1.76482 0.30742,-2.1519405 0.159401,-0.43267 0.683154,-0.95641 1.5712544,-1.57125 v -0.78563 l -1.4004664,-0.85394 v -1.22968 h 1.2638354 l 0.409893,-1.26383 h 1.161362 l 0.44405,1.26383 h 1.229678 v 1.22968 l -1.366309,0.85394 v 0.78563 c 0.86532,0.63762 1.400466,1.18414 1.605413,1.63957 l 0.239104,0.9905705 c 0.02278,0.27326 0.04555,0.63762 0.06831,1.09305 1.070271,-0.86532 2.174721,-1.29799 3.313381,-1.29799 1.52569,0 2.70986,0.58068 3.5523,1.74204 0.4782,0.6831498 0.71731,1.4573998 0.71731,2.3227198 0,0.93364 -0.44405,2.01531 -1.33215,3.24485 l -0.78563,1.09305 c -0.84254,1.27521 -1.27521,2.98318 -1.29799,5.12366 M 3.1484232,11.63895 c 0,-0.95641 0.478208,-1.57125 1.434624,-1.8445098 0.273261,-0.0911 0.5579,-0.13664 0.853942,-0.13664 0.956416,0 1.867297,0.4326698 2.7326174,1.2979898 0.979197,1.00196 1.491562,2.36826 1.537097,4.09893 0.02278,0.50099 -0.500989,0.78563 -1.5712554,0.85394 h -0.512365 c -0.455427,0 -0.922258,-0.0342 -1.400466,-0.10247 -0.75147,-0.36436 -1.502939,-1.08167 -2.254409,-2.15194 -0.546523,-0.797 -0.819785,-1.46878 -0.819785,-2.0153"
id="path1"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="22.698999mm"
height="24.476mm"
viewBox="0 0 22.699 24.475999"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="WhiteKing.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="2.9255612"
inkscape:cx="-65.799342"
inkscape:cy="55.544899"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-72.23125,-105.56879)">
<path
d="m 83.564504,129.03939 c -4.531519,0 -6.831542,-0.76285 -6.899804,-2.28857 -0.113861,-2.09499 -0.466831,-3.67771 -1.058889,-4.74795 -0.250489,-0.43267 -0.603462,-0.95641 -1.058889,-1.57125 -0.77425,-1.02473 -1.206897,-1.89005 -1.297993,-2.59599 -0.02277,-0.18217 -0.03416,-0.37573 -0.03416,-0.58068 0,-1.43462 0.603461,-2.56182 1.810358,-3.38164 0.296043,-0.18217 0.603462,-0.3302 0.922258,-0.44405 1.206897,-0.43267 2.402417,-0.36435 3.586427,0.20495 0.432674,0.20494 0.86532,0.47821 1.297993,0.81979 l 0.03416,0.0342 c 0,-0.47821 0.02277,-0.99058 0.06831,-1.5371 0,-0.15941 0.0797,-0.37573 0.239101,-0.649 0.364358,-0.59205 0.797005,-1.05888 1.297993,-1.40046 0.09109,-0.0455 0.182174,-0.10248 0.273262,-0.17079 v -0.81978 l -1.400466,-0.81979 V 107.8616 H 82.608 l 0.44405,-1.29799 h 1.024732 l 0.44405,1.29799 h 1.263835 v 1.22968 l -1.400466,0.81979 v 0.81978 c 1.184143,0.75147 1.787578,1.50294 1.810358,2.25441 0.04554,0.45543 0.06832,0.95641 0.06832,1.50294 l 0.03416,-0.0342 c 1.434624,-1.2069 2.937669,-1.59401 4.508765,-1.16136 0.409892,0.11385 0.797004,0.28463 1.161362,0.51236 1.275212,0.77422 1.924209,1.92421 1.946989,3.4499 0,0.91088 -0.455427,1.99253 -1.366308,3.24485 -0.75147,1.04752 -1.218301,1.81036 -1.400466,2.28857 -0.387112,1.02473 -0.614839,2.34548 -0.683154,3.9624 -0.04554,1.52572 -2.345505,2.28857 -6.899804,2.28857 m 0,-11.51123 0.990573,-1.57126 c 0.159404,-0.34157 0.284639,-0.66037 0.375735,-0.95641 0.04555,-0.1594 0.06832,-0.48959 0.06832,-0.99057 0,-1.34353 -0.466831,-2.01531 -1.400466,-2.01531 -0.97917,0 -1.468782,0.67178 -1.468782,2.01531 0,0.50098 0.02278,0.83116 0.06832,0.99057 0.182173,0.61484 0.569304,1.34353 1.161362,2.18609 0.136633,0.15941 0.204949,0.27326 0.204949,0.34158 m 9.120187,-0.0683 c 0,-1.02473 -0.341577,-1.81035 -1.024731,-2.35688 -0.569278,-0.47821 -1.241055,-0.71731 -2.015305,-0.71731 -0.97917,0 -2.038085,0.50096 -3.176588,1.50294 -1.343527,1.16136 -2.1064,2.73262 -2.288566,4.71382 0,0.1594 0.42127,0.34157 1.263835,0.54652 0.979197,0.18218 2.641521,0.27326 4.987131,0.27326 l 1.537097,-2.04946 c 0.478208,-0.72869 0.717312,-1.36631 0.717312,-1.91283 m -9.120187,4.61115 c -0.569304,0.2505 -2.299944,0.46684 -5.191919,0.649 -0.432673,0.0228 -0.785627,0.0455 -1.058889,0.0683 0.227722,0.86532 0.375735,1.82173 0.44405,2.86914 1.571255,-0.50099 3.506788,-0.75147 5.806811,-0.75147 2.345478,0 4.281223,0.25049 5.80681,0.75147 0.06831,-1.13858 0.216331,-2.095 0.44405,-2.86914 l -5.055393,-0.4099 c -0.432674,-0.0683 -0.831163,-0.17078 -1.19552,-0.30742 m -9.120188,-4.61115 c 0,0.70593 0.557901,1.7762 1.673728,3.21072 0.273262,0.34157 0.466831,0.59208 0.580681,0.75146 h 0.614839 c 2.345505,0 4.053416,-0.1594 5.123656,-0.4782 0.341577,-0.0911 0.512366,-0.20494 0.512366,-0.34158 -0.182177,-1.98115 -0.945039,-3.5523 -2.288567,-4.71382 -1.115827,-1.00195 -2.174716,-1.50294 -3.176587,-1.50294 -0.318797,0 -0.660374,0.0683 -1.024732,0.20495 -0.910881,0.22772 -1.525719,0.83116 -1.844516,1.81036 l -0.170788,0.92226 v 0.13663 m 9.120187,10.3497 c 2.140532,0 3.620823,-0.13663 4.440502,-0.40989 0.204946,-0.0683 0.30742,-0.14802 0.30742,-0.23911 0,-0.59206 -1.571255,-0.8881 -4.713817,-0.8881 -1.206897,0 -2.379636,0.0797 -3.518165,0.23911 -0.842565,0.13662 -1.263835,0.35295 -1.263835,0.64899 0,0.34158 1.343528,0.5579 4.030663,0.649 h 0.717311"
id="path7"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="22.5mm"
height="22.200001mm"
viewBox="0 0 22.5 22.200001"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="Knight.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="8.2747365"
inkscape:cx="51.663276"
inkscape:cy="32.569013"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<path
d="m 5.6964116,9.0092082 c 0.5692775,0 1.1727392,-0.3302 1.8103585,-0.990573 0.3415771,-0.341577 0.5123656,-0.63762 0.5123656,-0.888101 0,-0.2960419 -0.2732616,-0.4440499 -0.8197849,-0.4440499 -0.637593,0 -1.1727392,0.284639 -1.6054123,0.8539429 -0.2277242,0.273262 -0.3415771,0.5579 -0.3415771,0.853943 0,0.409892 0.1480132,0.614838 0.4440502,0.614838 M 5.1157306,1.5286443 c 0.045545,0 0.1594008,-0.01139 0.341577,-0.03416 1.0247313,0 2.1177779,0.341578 3.2792458,1.024732 l 0.2049489,0.136628 c 0.6603736,-1.070266 1.1613617,-1.605412 1.5029387,-1.605412 0.728689,0.409892 1.206924,0.853942 1.434624,1.33215 0.113861,0.227722 0.284639,0.705935 0.512366,1.434624 0.182173,-0.04555 0.364357,-0.06831 0.546523,-0.06831 1.912832,0 3.734594,1.172739 5.465233,3.5181649 2.072243,2.709862 3.108325,6.3989478 3.108325,11.0669908 0,1.047512 -0.04554,1.992524 -0.136628,2.835011 H 6.9603844 c 0.045548,-1.52572 0.6034616,-2.9718 1.6737277,-4.338109 0.1138608,-0.182173 0.2732616,-0.387112 0.4782079,-0.614838 0.8425656,-1.070266 1.354931,-1.890051 1.537097,-2.459355 0.09108,-0.296016 0.159401,-0.603462 0.204946,-0.922258 -1.5029391,0.592058 -2.6301434,1.468781 -3.3816395,2.630143 -0.341577,0.569278 -0.7173118,1.161362 -1.1272043,1.776201 -0.1138608,0.182176 -0.2846388,0.273262 -0.5123656,0.273262 -0.569304,0 -0.8539427,-0.352955 -0.8539427,-1.058889 -0.2277243,0.296042 -0.489585,0.44405 -0.7856273,0.44405 L 3.5104294,16.728481 C 2.531233,16.477987 1.8367018,16.045327 1.4268089,15.430488 1.2901809,15.225545 1.1421709,14.95228 0.9827589,14.610703 1.1421649,13.631507 1.9277979,11.684412 3.3396409,8.7697622 4.3643721,6.6747643 5.0019915,5.1716933 5.2524725,4.2609973 c 0.022781,-0.204946 0.034155,-0.500962 0.034155,-0.8881 0,-0.318797 -0.05693,-0.933635 -0.1707886,-1.844516 M 3.0663765,13.51771 c -0.5465234,0 -0.9108811,0.239101 -1.0930467,0.717311 -0.045543,0.113859 -0.068315,0.227717 -0.068315,0.341578 0,0.09108 0.034155,0.204946 0.1024731,0.341577 0.5920581,0 0.9564159,-0.250489 1.0930467,-0.75147 0.022781,-0.06832 0.03416,-0.148021 0.03416,-0.239104 0,-0.04554 -0.022781,-0.182173 -0.068315,-0.409892 m 16.7714084,5.260181 v -1.263835 c 0,-3.71184 -0.945039,-6.751902 -2.835011,-9.1201878 -1.63957,-2.0494619 -3.131079,-3.0741939 -4.474633,-3.0741939 l -0.409892,-0.06831 c -0.04554,0.02277 -0.0797,0.04554 -0.102476,0.06831 -0.296016,0 -0.44405,0.125244 -0.44405,0.375735 0,0.09109 0.06832,0.204949 0.204943,0.341577 1.229678,0.113856 2.573205,0.990574 4.030663,2.6301439 1.844516,2.1405318 2.766748,5.2374268 2.766748,9.2908428 v 0.204949 c 0,1.001951 0.216328,1.50294 0.648996,1.50294 0.364358,0 0.569304,-0.296043 0.614839,-0.888101"
id="path5"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="22.392mm"
height="22.187mm"
viewBox="0 0 22.392001 22.187"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="WhiteKnight.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="5.8511223"
inkscape:cx="53.23765"
inkscape:cy="73.062906"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-66.145827,-72.495833)">
<path
d="m 69.600584,85.616668 c 0.318796,0 0.478208,0.216331 0.478208,0.648997 0,0.569304 -0.284639,0.853942 -0.853943,0.853942 -0.227714,0 -0.341577,-0.182173 -0.341577,-0.546523 0,-0.637619 0.239101,-0.956416 0.717312,-0.956416 m 2.459355,-4.167187 c -0.318797,0 -0.478208,-0.193556 -0.478208,-0.580681 0,-0.614839 0.364357,-1.115801 1.093046,-1.50294 0.318797,-0.1594 0.614839,-0.239101 0.888101,-0.239101 0.478208,0 0.740092,0.159401 0.785627,0.478208 0,0.523743 -0.409892,1.024731 -1.229677,1.502939 -0.409893,0.227724 -0.762847,0.341577 -1.058889,0.341577 M 72.3332,75.027781 c 0.09109,0.318797 0.136628,0.535147 0.136628,0.648997 0,0.06832 -0.03415,0.250489 -0.102473,0.546523 0.364358,0 0.865347,-0.182173 1.50294,-0.546523 -0.614839,-0.318797 -1.127205,-0.535146 -1.537097,-0.648997 m -4.064794,11.750146 c 0.136633,0.546523 0.500988,0.945039 1.093047,1.19552 0.227719,0.09109 0.44405,0.136628 0.648996,0.136628 h 0.06832 c 0.04554,0 0.296042,-0.136628 0.75147,-0.409893 0.136628,-0.09109 0.250489,-0.136628 0.341577,-0.136628 h 0.136628 c 0.113858,0 0.170794,0.06831 0.170794,0.204941 l -0.204949,0.648997 c 0,0.204946 0.159401,0.307419 0.478208,0.307419 0.04554,0 0.3302,-0.398515 0.853943,-1.19552 1.00195,-1.548474 2.425197,-2.721239 4.269581,-3.518164 0.182171,-1.229678 0.637619,-2.311347 1.366308,-3.24485 0.182176,-0.250492 0.364358,-0.375735 0.546523,-0.375735 0.204949,0 0.30742,0.148016 0.30742,0.44405 0,0.06832 -0.204947,0.717312 -0.614839,1.94699 -0.159404,0.523742 -0.239107,0.910881 -0.239107,1.161362 0,0.06831 0.02278,0.216331 0.06832,0.44405 0,1.616789 -0.683154,3.313377 -2.049462,5.089525 -0.910881,1.229677 -1.411844,2.208874 -1.50294,2.937668 h 11.272044 c 0.09109,-1.047511 0.136634,-1.821735 0.136634,-2.322724 0,-4.691062 -1.468782,-8.437033 -4.406371,-11.237912 -0.888101,-0.819785 -1.605413,-1.229678 -2.151936,-1.229678 h -2.049462 c -0.182177,-0.09109 -0.364358,-0.546523 -0.546524,-1.366308 -0.136628,-0.660373 -0.307419,-1.070266 -0.512365,-1.229677 -0.273262,0.819785 -1.115828,1.457404 -2.527671,1.912831 -0.751469,0.227717 -1.275212,0.455428 -1.571254,0.683154 -0.250489,0.797005 -0.990574,2.413821 -2.220251,4.850342 -1.206897,2.413794 -1.844516,3.848365 -1.912832,4.303977 m 19.128317,6.899804 H 73.084463 c 0.09109,-1.571254 0.683155,-3.074194 1.776201,-4.508764 0.842566,-1.138582 1.343528,-1.833139 1.502939,-2.083621 0.318797,-0.500988 0.512366,-1.104423 0.580681,-1.810358 -1.480158,0.637593 -2.630143,1.548474 -3.449902,2.732617 l -0.478207,0.785627 c -0.341578,0.546523 -0.557901,0.853943 -0.648997,0.922258 -0.136628,0.113858 -0.284639,0.170789 -0.44405,0.170789 -0.705908,0 -1.184143,-0.239104 -1.434624,-0.717312 -0.04555,-0.06832 -0.06832,-0.148016 -0.06832,-0.239104 -0.227719,0.113858 -0.455427,0.170788 -0.683154,0.170788 -1.093047,0 -1.958367,-0.683154 -2.595986,-2.049462 0.182174,-1.001951 1.138582,-3.313377 2.869142,-6.933936 0.182176,-0.341577 0.318823,-0.614838 0.409892,-0.819785 0.683154,-1.525719 1.024731,-2.675731 1.024731,-3.449902 0,-0.113855 -0.06831,-0.751469 -0.204948,-1.912831 h 0.273261 c 1.229678,0 2.402417,0.387112 3.518165,1.161362 0.614839,-1.070266 1.127204,-1.605412 1.537097,-1.605412 0.728689,0.387111 1.229677,0.933635 1.502939,1.63957 l 0.375735,1.127204 c 0.227713,-0.04555 0.421269,-0.06832 0.580681,-0.06832 1.821735,0 3.620823,1.161363 5.39697,3.484034 2.072243,2.709862 3.108325,6.421702 3.108325,11.135518 0,1.070266 -0.04554,2.026682 -0.136628,2.869142"
id="path11"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="16.68mm"
height="22.1mm"
viewBox="0 0 16.679999 22.100002"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="Pawn.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="2"
inkscape:cx="-66.25"
inkscape:cy="97.25"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<path
d="m 1.0591685,21.100011 c -0.022754,-0.273262 -0.034152,-0.808408 -0.034152,-1.605412 0,-2.869142 0.8881004,-4.998509 2.664354,-6.387571 0.5237427,-0.432673 1.1613356,-0.831162 1.9128316,-1.19552 C 4.7141013,11.638246 4.1106397,10.966469 3.7918432,9.8962032 3.7007551,9.5546259 3.655215,9.2016719 3.655215,8.8373139 c 0,-1.525719 0.7856273,-2.607363 2.3568821,-3.24485 -0.409919,-0.683154 -0.614865,-1.33215 -0.614839,-1.946989 -2.9e-5,-1.024731 0.500962,-1.787578 1.502939,-2.288566 0.455401,-0.227719 0.944986,-0.3415769 1.468782,-0.3415769 1.138555,0 1.9811199,0.4440499 2.5276699,1.3321499 0.25046,0.387112 0.375708,0.819785 0.375735,1.297993 -2.7e-5,0.660374 -0.193588,1.30937 -0.580681,1.946989 0.842539,0.341577 1.445974,0.797005 1.810358,1.366309 0.364332,0.614838 0.546497,1.241054 0.546524,1.878674 -3.7e-5,1.1841161 -0.409919,2.0836201 -1.229678,2.6984851 -0.204975,0.182176 -0.432699,0.307419 -0.683154,0.375735 2.094971,1.070266 3.449902,2.470732 4.064794,4.201318 0.31877,0.956416 0.478181,2.083621 0.478208,3.38164 -2.7e-5,0.797004 -0.0114,1.332151 -0.03415,1.605412 H 1.0591817"
id="path6"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="16.653999mm"
height="22.084999mm"
viewBox="0 0 16.653999 22.084999"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="WhitePawn.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="4"
inkscape:cx="-9.375"
inkscape:cy="68.375"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-91.545814,-119.85625)">
<path
d="m 105.96968,139.57435 c -3e-5,-2.39104 -0.64902,-4.17857 -1.94699,-5.36284 -0.4327,-0.40989 -0.96782,-0.797 -1.60541,-1.16136 -0.88813,-0.52375 -1.33218,-1.00195 -1.33215,-1.43463 -3e-5,-0.22772 0.22769,-0.4782 0.68315,-0.75147 0.70591,-0.38711 1.12718,-0.84256 1.26384,-1.3663 0.0455,-0.20494 0.0683,-0.45543 0.0683,-0.75147 -3e-5,-1.04752 -0.53517,-1.8673 -1.60541,-2.45936 l -0.61484,-0.44405 c -0.11389,-0.11385 -0.17082,-0.2391 -0.17079,-0.37573 -3e-5,-0.38712 0.1366,-0.77425 0.40989,-1.16137 0.18215,-0.25048 0.27324,-0.54652 0.27326,-0.8881 -2e-5,-0.59205 -0.31882,-1.02473 -0.95641,-1.29799 -0.20498,-0.0683 -0.40992,-0.10247 -0.614845,-0.10247 -0.637646,0 -1.093073,0.28464 -1.366308,0.85394 -0.09111,0.18218 -0.13666,0.36436 -0.136634,0.54652 -2.6e-5,0.20495 0.147995,0.59206 0.44405,1.16137 0.182148,0.31879 0.261848,0.61483 0.23911,0.8881 -3.7e-5,0.27326 -0.261911,0.54652 -0.785628,0.81978 -1.047538,0.61484 -1.571281,1.43463 -1.571254,2.45936 -3.5e-5,0.8881 0.444024,1.59403 1.33215,2.11777 0.432647,0.29602 0.64897,0.54653 0.648997,0.75147 -2.9e-5,0.43268 -0.444077,0.91088 -1.332151,1.43463 -1.63957,1.00195 -2.687108,2.22025 -3.142456,3.65495 -0.250489,0.79701 -0.375735,1.75342 -0.375735,2.86914 H 105.9698 m -13.389771,1.36631 c -0.02278,-0.27326 -0.03416,-0.797 -0.03416,-1.57125 0,-2.80088 0.819785,-4.89585 2.459355,-6.28492 0.546524,-0.45542 1.241029,-0.89947 2.083621,-1.33215 -0.86532,-0.27326 -1.446001,-0.93366 -1.742044,-1.98114 -0.113855,-0.34158 -0.170788,-0.69453 -0.170788,-1.05889 0,-1.5257 0.77425,-2.61877 2.322724,-3.27925 -0.364384,-0.6604 -0.54655,-1.30937 -0.546523,-1.94699 -2.9e-5,-1.04751 0.512339,-1.82173 1.537097,-2.32272 0.432646,-0.20495 0.899451,-0.30742 1.400466,-0.30742 1.161343,0 2.015283,0.44405 2.561833,1.33215 0.25046,0.38711 0.37571,0.81979 0.37573,1.29799 -2e-5,0.61484 -0.20497,1.26384 -0.61484,1.94699 1.57123,0.63762 2.35686,1.73064 2.35689,3.27925 -3e-5,1.20692 -0.44408,2.11778 -1.33215,2.73261 -0.1822,0.13664 -0.38714,0.23911 -0.61484,0.30742 2.04943,1.04752 3.38164,2.37967 3.99653,3.99654 0.38708,1.00195 0.58065,2.20887 0.58068,3.62082 -3e-5,0.75147 -0.0114,1.27521 -0.0342,1.57125 H 92.580034"
id="path12"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.8 KiB

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="19.200001mm"
height="22mm"
viewBox="0 0 19.200001 22"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="Rook.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="5.6568543"
inkscape:cx="21.92031"
inkscape:cy="49.055533"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<path
d="m 1.7350659,20.999302 -0.649,-0.649 v -2.4252 L 4.535966,14.509332 V 7.7119213 l -2.6643501,-2.63014 v -3.04006 l 0.9564101,-0.95642 h 2.4252 l 0.61484,0.58068 v 0.85394 h 1.29799 v -0.85394 l 0.58068,-0.58068 h 3.791482 l 0.58068,0.58068 v 0.85394 h 1.298 v -0.85394 l 0.58068,-0.58068 h 2.45935 l 0.95642,0.95642 v 3.04006 l -2.66436,2.63014 v 6.7974107 l 3.44991,3.41577 v 2.4252 l -0.68316,0.649 H 1.7349259 m 4.0306701,-7.27552 v 1.16137 h 7.753882 v -1.16137 H 5.765596 m 0,-6.1483807 v 1.16136 h 7.753882 v -1.16136 H 5.765596"
id="path3"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="19.146999mm"
height="22.049999mm"
viewBox="0 0 19.146999 22.049999"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="WhiteRook.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="5.8511223"
inkscape:cx="55.459446"
inkscape:cy="56.313982"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-86.518752,-131.49792)">
<path
d="m 92.197395,139.29413 v 6.04599 H 99.9854 v -6.04599 h -7.788005 m -4.030662,13.25324 -0.648997,-0.64899 v -2.35688 l 3.484033,-3.51817 v -6.83154 l -3.005931,-2.63014 v -3.10833 l 0.990574,-0.95641 h 3.074193 l 0.580682,0.58068 v 0.8881 h 0.990573 v -0.8881 l 0.580681,-0.58068 h 3.757348 l 0.580681,0.58068 v 0.8881 h 0.956416 v -0.8881 l 0.614834,-0.58068 h 3.0742 l 0.99058,0.95641 v 3.10833 l -3.00593,2.63014 v 6.83154 l 3.48403,3.51817 v 2.35688 l -0.649,0.64899 H 88.166627 m 0.546523,-2.69848 v 1.33215 h 14.75608 v -1.33215 H 88.71315 m 3.347508,-3.38164 -2.254408,2.18609 h 12.5701 l -2.25442,-2.18609 h -8.061325 m 2.732617,-12.53596 v 0.8881 l -0.512366,0.47821 h -2.220251 l -0.512365,-0.47821 v -0.95641 h -1.912832 l -0.44405,0.4782 v 1.91284 l 2.322724,1.87867 h 9.154318 l 2.32273,-1.87867 v -1.91284 l -0.44405,-0.4782 h -1.91283 v 0.95641 l -0.51237,0.47821 h -2.220254 l -0.512365,-0.47821 v -0.8881 h -2.595986"
id="path9"
style="stroke-width:0.264583" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

1
solution/H04/src/test Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H04/src/test

View file

@ -1,16 +0,0 @@
package h04;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* An example JUnit test class.
*/
public class ExampleJUnitTest {
@Test
public void testAddition() {
assertEquals(2, 1 + 1);
}
}

1
solution/H05/src/main Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H05/src/main

View file

@ -1,57 +0,0 @@
package h05;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class Airspace {
private static Airspace INSTANCE = null;
public static Airspace get(){
if(INSTANCE == null){
INSTANCE = new Airspace();
}
return INSTANCE;
}
private final Set<Flying> flyingInAirspace = new HashSet<>();
private Airspace(){
}
Set<Flying> getFlyingInAirspace() {
return Collections.unmodifiableSet(flyingInAirspace);
}
void register(Flying flying){
flyingInAirspace.add(flying);
}
void deregister(Flying flying){
flyingInAirspace.remove(flying);
}
void scanAirspace(){
System.out.println("Scanning...");
if (flyingInAirspace.isEmpty()){
System.out.println("Airspace is empty");
return;
}
for (Flying flying : flyingInAirspace){
System.out.print(flying.getIdentifier() + " is flying in airspace");
if(flying instanceof PassengerPlane passengerPlane){
System.out.print(" (" + passengerPlane.getPassengerCount() + " PAX)");
}
System.out.println();
}
}
}

View file

@ -1,34 +0,0 @@
package h05;
public class CargoPlane extends Plane implements CarriesCargo{
/*
Stacks are a type of data structure that follows the Last In First Out (LIFO) principle.
Explanation will be found in Task description.
*/
private final CargoStack containers = new CargoStack();
public CargoPlane(String aircraftRegistration, int baseWeight, FuelType fuelType, double maxFuelLevel) {
super(aircraftRegistration, baseWeight, fuelType, maxFuelLevel);
}
@Override
public void loadContainer(int cargoWeight) {
containers.push(cargoWeight);
}
@Override
public boolean hasFreightLoaded() {
return !containers.empty();
}
@Override
public int unloadNextContainer() {
return containers.pop();
}
@Override
protected double mass() {
return baseWeight + containers.getSum();
}
}

View file

@ -1,27 +0,0 @@
package h05;
import java.util.Stack;
public class CargoStack {
private final Stack<Integer> stack = new Stack<>();
private int sum = 0;
public boolean empty(){
return stack.empty();
}
public void push(int value){
sum += value;
stack.push(value);
}
public int pop(){
int removedValue = stack.pop();
sum -= removedValue;
return removedValue;
}
public int getSum(){
return sum;
}
}

View file

@ -1,8 +0,0 @@
package h05;
public interface CarriesCargo {
void loadContainer(int cargoWeight);
boolean hasFreightLoaded();
int unloadNextContainer();
}

View file

@ -1,7 +0,0 @@
package h05;
public interface CarriesPassengers {
void board(int peopleCount);
int getPassengerCount();
void disembark();
}

View file

@ -1,32 +0,0 @@
package h05;
public class CombinedPlane extends PassengerPlane implements CarriesCargo{
private final CargoStack containers = new CargoStack();
public CombinedPlane(String aircraftRegistration, int baseWeight, FuelType fuelType, double maxFuelLevel, int crew) {
super(aircraftRegistration, baseWeight, fuelType, maxFuelLevel, crew);
}
@Override
public void loadContainer(int cargoWeight) {
containers.push(cargoWeight);
}
@Override
public boolean hasFreightLoaded() {
return !containers.empty();
}
@Override
public int unloadNextContainer() {
return containers.pop();
}
@Override
protected double mass() {
return super.mass() + containers.getSum();
}
}

View file

@ -1,5 +0,0 @@
package h05;
public interface Flying {
String getIdentifier();
}

View file

@ -1,14 +0,0 @@
package h05;
public enum FuelType {
JetA(1.0), JetB(1.2), AvGas(0.99), Biokerosin (1.02);
private final double consumptionMultiplicator;
FuelType(double consumptionMultiplicator){
this.consumptionMultiplicator = consumptionMultiplicator;
}
public double getConsumptionMultiplicator() {
return consumptionMultiplicator;
}
}

View file

@ -1,69 +0,0 @@
package h05;
/**
* Main entry point in executing the program.
*/
public class Main {
/**
* Main entry point in executing the program.
*
* @param args program arguments, currently ignored
*/
public static void main(String[] args) {
Airspace airspace = Airspace.get();
airspace.scanAirspace();
/*
Die konkreten Zahlen sind noch nicht final und können sich ändern.
*/
Runway runway01 = new Runway(2000);
Runway runway02 = new Runway(4000);
WeatherBalloon weatherBalloon = new WeatherBalloon(99);
weatherBalloon.start();
Tank jetATank = new Tank(FuelType.JetA);
Tank jetBTank = new Tank(FuelType.JetB);
TankerPlane tankerPlane = new TankerPlane("D-ABCD", 10000, FuelType.JetA, 1000);
tankerPlane.loadFuel(FuelType.AvGas, 100000);
tankerPlane.loadFuel(FuelType.Biokerosin, 100000);
PassengerPlane passengerPlane = new PassengerPlane("GAG-67", 10000, FuelType.JetA, 1700, 5);
jetATank.refuelPlane(passengerPlane);
passengerPlane.board(100);
passengerPlane.takeOff();
airspace.scanAirspace();
CargoPlane cargoPlane = new CargoPlane("D-AFFF", 8000, FuelType.JetB, 1500);
cargoPlane.loadContainer(1000);
jetBTank.refuelPlane(cargoPlane);
passengerPlane.disembark();
airspace.scanAirspace();
cargoPlane.takeOff();
cargoPlane.fly(1000);
airspace.scanAirspace();
CombinedPlane combinedPlane = new CombinedPlane("D-ABBB", 9000, FuelType.AvGas, 10700, 5);
tankerPlane.refuelPlane(combinedPlane);
combinedPlane.board(30);
combinedPlane.loadContainer(400);
combinedPlane.takeOff();
combinedPlane.fly(3000);
airspace.scanAirspace();
runway01.land(combinedPlane);
runway02.land(cargoPlane);
airspace.scanAirspace();
weatherBalloon.pop();
airspace.scanAirspace();
}
}

View file

@ -1,36 +0,0 @@
package h05;
public class PassengerPlane extends Plane implements CarriesPassengers {
protected static final char AVERAGE_PEOPLE_WEIGHT = 100;
protected static final char AVERAGE_LUGGAGE_WEIGHT = 15;
private int passengerCount = 0;
private final int crewCount;
public PassengerPlane(String aircraftRegistration, int baseWeight, FuelType fuelType, double fuelCapacity, int crewCount) {
super(aircraftRegistration, baseWeight, fuelType, fuelCapacity);
this.crewCount = crewCount;
}
@Override
public void board(int passengerCount) {
this.passengerCount += passengerCount;
}
@Override
public void disembark() {
this.passengerCount = 0;
}
@Override
public int getPassengerCount() {
return passengerCount;
}
@Override
protected double mass() {
return baseWeight + (passengerCount + crewCount) * AVERAGE_PEOPLE_WEIGHT + passengerCount * AVERAGE_LUGGAGE_WEIGHT;
}
}

View file

@ -1,77 +0,0 @@
package h05;
public abstract class Plane implements Flying {
private static final double CONSUMPTION_PER_KM_KG = 1.1494e-4;
private final String aircraftRegistration;
protected final int baseWeight;
private double currentFuelLevel;
private final FuelType fuelType;
private final double fuelCapacity;
public Plane(String aircraftRegistration, int baseWeight, FuelType fuelType, double fuelCapacity){
this.aircraftRegistration = aircraftRegistration;
this.baseWeight = baseWeight;
this.fuelType = fuelType;
this.currentFuelLevel = 0;
this.fuelCapacity = fuelCapacity;
}
protected abstract double mass();
protected double getFuelConsumptionPerKilometer(){
return CONSUMPTION_PER_KM_KG * mass() * fuelType.getConsumptionMultiplicator();
}
public void takeOff(){
Airspace.get().register(this);
}
public void land(){
Airspace.get().deregister(this);
}
public void fly(double distance){
double neededFuel = distance * getFuelConsumptionPerKilometer();
// if the plane does not have enough fuel to fly the distance, it will not fly
if(neededFuel > currentFuelLevel){
System.out.println("Plane " + aircraftRegistration + " does not have enough fuel to fly " + distance + " km.");
return;
}
currentFuelLevel -= neededFuel;
System.out.println("Plane " + aircraftRegistration + " flew " + distance + " km and has " + currentFuelLevel + " liters of fuel left.");
}
public FuelType getFuelType() {
return fuelType;
}
public double getFuelCapacity() {
return fuelCapacity;
}
public double getCurrentFuelLevel() {
return currentFuelLevel;
}
public void refuel(double amount){
currentFuelLevel += amount;
if(currentFuelLevel > fuelCapacity){
currentFuelLevel = fuelCapacity;
System.out.println("The Tank of Plane " + aircraftRegistration + " has overflowed!");
}
}
@Override
public String getIdentifier(){
return aircraftRegistration;
}
}

View file

@ -1,5 +0,0 @@
package h05;
public interface Refuelling {
void refuelPlane(Plane plane);
}

View file

@ -1,41 +0,0 @@
package h05;
public class Runway {
private final int runwayLength;
/*
TODO: Man könnte sich noch überlegen, wie Flugzeugtypen, die hier landen können, festgesetzt werden
*/
public Runway(int runwayLength){
this.runwayLength = runwayLength;
}
public int getRunwayLength(){
return runwayLength;
}
/*
TODO: hier müsste man sich noch eine bessere Formel für die Landung überlegen
*/
public static double calculateLandingDistance(double mass){
return mass/40;
}
public boolean canLand(Plane plane){
return calculateLandingDistance(plane.mass()) <= runwayLength;
}
/*
TODO: Man könnte auch stattdessen die land() methode in plane erweitern und diese hier weglassen
*/
public void land(Plane plane){
if(canLand(plane)){
plane.land();
System.out.println("Plane " + plane.getIdentifier() + " has landed successfully.");
} else {
System.out.println("Plane " + plane.getIdentifier() + " could not land. The runway is too short.");
}
}
}

View file

@ -1,21 +0,0 @@
package h05;
public class Tank implements Refuelling{
private final FuelType fuelType;
public Tank(FuelType fuelType){
this.fuelType = fuelType;
}
@Override
public void refuelPlane(Plane plane) {
if(plane.getFuelType() != fuelType){
System.out.println("Incompatible fuel types, not refuelling");
return;
}
double missingFuel = plane.getFuelCapacity() - plane.getCurrentFuelLevel();
plane.refuel(missingFuel);
}
}

View file

@ -1,35 +0,0 @@
package h05;
public class TankerPlane extends Plane implements Refuelling{
private final double[] availableAmount = new double[FuelType.values().length];
public TankerPlane(String aircraftRegistration, int baseWeight, FuelType fuelType, double maxFuelLevel) {
super(aircraftRegistration, baseWeight, fuelType, maxFuelLevel);
}
public void loadFuel(FuelType fuelType, double amount){
availableAmount[fuelType.ordinal()] += amount;
}
@Override
protected double mass() {
double totalAmount = 0;
for (int i = 0; i < FuelType.values().length; i++){
totalAmount += availableAmount[i];
}
return baseWeight + totalAmount;
}
@Override
public void refuelPlane(Plane plane) {
double missingFuel = plane.getFuelCapacity() - plane.getCurrentFuelLevel();
double actualAmount = Math.min(availableAmount[plane.getFuelType().ordinal()], missingFuel);
availableAmount[plane.getFuelType().ordinal()] -= actualAmount;
plane.refuel(actualAmount);
}
}

View file

@ -1,23 +0,0 @@
package h05;
public class WeatherBalloon implements Flying{
private final int balloonNumber;
public WeatherBalloon(int balloonNumber){
this.balloonNumber = balloonNumber;
}
public void start(){
Airspace.get().register(this);
}
public void pop(){
Airspace.get().deregister(this);
}
@Override
public String getIdentifier() {
return "WeatherBalloon " + balloonNumber;
}
}

1
solution/H05/src/test Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H05/src/test

View file

@ -1,16 +0,0 @@
package h05;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* An example JUnit test class.
*/
public class ExampleJUnitTest {
@Test
public void testAddition() {
assertEquals(2, 1 + 1);
}
}

1
solution/H06/src/main Symbolic link
View file

@ -0,0 +1 @@
/home/osh/Desktop/FOP-2425-Marathon/H06/src/main

View file

@ -1,28 +0,0 @@
package h06;
import h06.problems.*;
import h06.ui.DrawInstruction;
import h06.ui.FractalVisualizer;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
/**
* Main entry point in executing the program.
*/
public class Main {
/**
* Main entry point in executing the program.
*
* @param args program arguments, currently ignored
*/
@StudentImplementationRequired
public static void main(String[] args) {
DrawInstruction[] dragonCurveInstructions = Fractals.dragonCurve(14);
DrawInstruction[] kochSnowflakeInstructions = Fractals.kochSnowflake(5);
FractalVisualizer fracVis = new FractalVisualizer(dragonCurveInstructions, 90);
fracVis.setVisible(true);
FractalVisualizer fracVis2 = new FractalVisualizer(kochSnowflakeInstructions, 60);
fracVis2.setVisible(true);
}
}

Some files were not shown because too many files have changed in this diff Show more