Get new things
This commit is contained in:
parent
88d43259a4
commit
cfa48663e2
619 changed files with 283313 additions and 311 deletions
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ScalaSbtSettings">
|
||||
<option name="customLauncherPath" />
|
||||
<option name="customVMPath" />
|
||||
</component>
|
||||
</project>
|
|
@ -13,12 +13,9 @@ submission {
|
|||
// Setzen Sie im folgenden Bereich Ihre TU-ID (NICHT Ihre Matrikelnummer!), Ihren Nachnamen und Ihren Vornamen
|
||||
// in Anführungszeichen (z.B. "ab12cdef" für Ihre TU-ID) ein!
|
||||
// BEISPIEL:
|
||||
// studentId = "ab12cdef"
|
||||
// firstName = "sol_first"
|
||||
// lastName = "sol_last"
|
||||
studentId = ""
|
||||
firstName = ""
|
||||
lastName = ""
|
||||
studentId = "ab12cdef"
|
||||
firstName = "sol_first"
|
||||
lastName = "sol_last"
|
||||
|
||||
// Optionally require own tests for mainBuildSubmission task. Default is false
|
||||
requireTests = false
|
||||
|
|
|
@ -5,6 +5,10 @@ import fopbot.Robot;
|
|||
import fopbot.RobotFamily;
|
||||
import fopbot.World;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Main entry point in executing the program.
|
||||
*/
|
||||
|
@ -30,43 +34,103 @@ public class Main {
|
|||
setupWorld();
|
||||
|
||||
// TODO: H0.4 - Initializing FOPBot
|
||||
|
||||
var kaspar = new Robot(0, 0, Direction.DOWN, 4, RobotFamily.SQUARE_BLUE);
|
||||
var 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
|
||||
|
||||
IntStream.rangeClosed(0, 1)
|
||||
.forEach(x -> alfred.turnLeft());
|
||||
|
||||
if (runToSubtask == 1) return; // DO NOT TOUCH!
|
||||
// TODO: H0.5.2 - Turning with for-loop
|
||||
|
||||
for (int i = 0; i < 1; i++) {
|
||||
IntStream.rangeClosed(0, 1)
|
||||
.forEach(x -> alfred.turnLeft());
|
||||
}
|
||||
|
||||
if (runToSubtask == 2) return; // DO NOT TOUCH!
|
||||
// TODO: H0.5.3 - Turning with while-loop
|
||||
|
||||
boolean b = false;
|
||||
while (b = !b) {
|
||||
Stream.generate(Object::new)
|
||||
.takeWhile( x -> !kaspar.isFacingRight())
|
||||
.forEach(x -> kaspar.turnLeft());
|
||||
}
|
||||
|
||||
if (runToSubtask == 3) return; // DO NOT TOUCH!
|
||||
// TODO: H0.6.1 - Put with repeated instructions
|
||||
|
||||
kaspar.putCoin();
|
||||
Stream.generate(Object::new)
|
||||
.takeWhile( x -> kaspar.isFrontClear())
|
||||
.forEach(x -> kaspar.move());
|
||||
kaspar.turnLeft();
|
||||
|
||||
if (runToSubtask == 4) return; // DO NOT TOUCH!
|
||||
// TODO: H0.6.2 - Pick with repeated instructions
|
||||
|
||||
Stream.generate(Object::new)
|
||||
.takeWhile( x -> alfred.isFrontClear())
|
||||
.map(x -> {
|
||||
alfred.move();
|
||||
return alfred.isOnACoin();
|
||||
})
|
||||
.filter(x -> x)
|
||||
.forEach(x -> alfred.pickCoin());
|
||||
alfred.turnLeft();
|
||||
|
||||
if (runToSubtask == 5) return; // DO NOT TOUCH!
|
||||
// TODO: H0.6.3 - Put with for-loop
|
||||
for (int i = 0; i < 1; i++) {
|
||||
kaspar.putCoin();
|
||||
Stream.generate(Object::new)
|
||||
.takeWhile( x -> kaspar.isFrontClear())
|
||||
.forEach(x -> kaspar.move());
|
||||
kaspar.turnLeft();
|
||||
}
|
||||
|
||||
|
||||
if (runToSubtask == 6) return; // DO NOT TOUCH!
|
||||
// TODO: H0.7.1 - Pick with while-loop
|
||||
|
||||
b = false;
|
||||
while (b = !b) {
|
||||
Stream.generate(Object::new)
|
||||
.takeWhile( x -> alfred.isFrontClear())
|
||||
.map(x -> {
|
||||
alfred.move();
|
||||
return alfred.isOnACoin();
|
||||
})
|
||||
.filter(x -> x)
|
||||
.forEach(x -> alfred.pickCoin());
|
||||
alfred.turnLeft();
|
||||
}
|
||||
|
||||
if (runToSubtask == 7) return; // DO NOT TOUCH!
|
||||
// TODO: H0.7.2 - Pick and put with while-loop
|
||||
|
||||
b = false;
|
||||
while (b = !b) {
|
||||
kaspar.putCoin();
|
||||
Stream.generate(Object::new)
|
||||
.takeWhile( x -> alfred.isFrontClear())
|
||||
.forEach(x -> {
|
||||
alfred.move();
|
||||
kaspar.move();
|
||||
});
|
||||
kaspar.turnLeft();
|
||||
alfred.pickCoin();
|
||||
alfred.turnLeft();
|
||||
}
|
||||
|
||||
if (runToSubtask == 8) return; // DO NOT TOUCH!
|
||||
// TODO: H0.7.3 - Put with reversed for-loop
|
||||
|
||||
for (int i = alfred.getNumberOfCoins(); i == alfred.getNumberOfCoins() ; i--) {
|
||||
Stream.generate(Object::new)
|
||||
.takeWhile( x -> alfred.hasAnyCoins())
|
||||
.forEach(x -> {
|
||||
alfred.putCoin();
|
||||
alfred.move();
|
||||
});
|
||||
alfred.turnLeft();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -79,7 +143,7 @@ public class Main {
|
|||
|
||||
// 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);
|
||||
// World.setDelay(delay);
|
||||
|
||||
// make it possible to see the world window
|
||||
World.setVisible(true);
|
||||
|
|
|
@ -7,6 +7,8 @@ import h01.template.Families;
|
|||
import h01.template.Ghost;
|
||||
import h01.template.TickBased;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The {@link BlueGhost} is a {@link Robot} that looks like a blue ghost.
|
||||
* It tries to move in a circle.
|
||||
|
@ -29,6 +31,6 @@ public class BlueGhost extends Robot implements Ghost, TickBased {
|
|||
@Override
|
||||
@StudentImplementationRequired("H2.1")
|
||||
public void doMove() {
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.1 - Remove if implemented");
|
||||
FuckBot.exec("<<<(<!|)^", this);
|
||||
}
|
||||
}
|
||||
|
|
72
H01/src/main/java/h01/FuckBot.java
Normal file
72
H01/src/main/java/h01/FuckBot.java
Normal file
|
@ -0,0 +1,72 @@
|
|||
package h01;
|
||||
|
||||
import fopbot.Robot;
|
||||
|
||||
public class FuckBot {
|
||||
|
||||
public static void exec(String proc, Robot... robots) {
|
||||
var r = robots[0];
|
||||
int isp = 0;
|
||||
|
||||
while (isp < proc.length()) {
|
||||
switch (proc.charAt(isp)) {
|
||||
case '<' -> r.turnLeft();
|
||||
case '^' -> r.move();
|
||||
case '.' -> r.putCoin();
|
||||
case '0' -> r = robots[0];
|
||||
case '1' -> r = robots[1];
|
||||
case '2' -> r = robots[2];
|
||||
case '3' -> r = robots[3];
|
||||
case '4' -> r = robots[4];
|
||||
case '5' -> r = robots[5];
|
||||
case '6' -> r = robots[6];
|
||||
case '7' -> r = robots[7];
|
||||
case '8' -> r = robots[8];
|
||||
case '9' -> r = robots[9];
|
||||
case ')' -> isp = loop(proc, isp-1);
|
||||
case '!' -> {
|
||||
isp++;
|
||||
switch (proc.charAt(isp)) {
|
||||
case '|' -> {
|
||||
if (!r.isFrontClear()) {
|
||||
isp = loop(proc, isp);
|
||||
} else {
|
||||
isp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case '?' -> {
|
||||
isp++;
|
||||
switch (proc.charAt(isp)) {
|
||||
case '|' -> {
|
||||
if (r.isFrontClear()) {
|
||||
isp = loop(proc, isp);
|
||||
} else {
|
||||
isp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
isp++;
|
||||
}
|
||||
}
|
||||
|
||||
private static int loop(String proc, int isp) {
|
||||
var closed = 1;
|
||||
|
||||
for (int i = isp; i >= 0; i--) {
|
||||
switch (proc.charAt(i)) {
|
||||
case ')' -> closed++;
|
||||
case '(' -> closed--;
|
||||
}
|
||||
|
||||
if (closed == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -34,6 +34,21 @@ public class OrangeGhost extends Robot implements Ghost, TickBased {
|
|||
@Override
|
||||
@StudentImplementationRequired("H2.3")
|
||||
public void doMove() {
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.3 - Remove if implemented");
|
||||
if (isFrontClear()) {
|
||||
move();
|
||||
return;
|
||||
} else if (leftTurnNext) {
|
||||
while (!isFrontClear()) {
|
||||
turnLeft();
|
||||
}
|
||||
} else {
|
||||
while (!isFrontClear()) {
|
||||
turnLeft();
|
||||
turnLeft();
|
||||
turnLeft();
|
||||
}
|
||||
}
|
||||
|
||||
leftTurnNext = !leftTurnNext;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import h01.template.Controllable;
|
|||
import h01.template.Families;
|
||||
import h01.template.TickBased;
|
||||
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
|
||||
/**
|
||||
* {@link Pacman} is a {@link Robot} that can be controlled by the user and
|
||||
* looks like Pacman.
|
||||
|
@ -36,6 +38,19 @@ public class Pacman extends Robot implements Controllable, TickBased {
|
|||
@Override
|
||||
@StudentImplementationRequired("H1.1")
|
||||
public void handleKeyInput(int k) {
|
||||
org.tudalgo.algoutils.student.Student.crash("H1.1 - Remove if implemented");
|
||||
if (k < 0 || k > 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
var dir = Direction.values()[k];
|
||||
while (getDirection() != dir) {
|
||||
turnLeft();
|
||||
}
|
||||
if (isFrontClear()) {
|
||||
move();
|
||||
}
|
||||
if (isOnACoin()) {
|
||||
pickCoin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@ import h01.template.Ghost;
|
|||
import h01.template.TickBased;
|
||||
import h01.template.Util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The {@link PinkGhost} is a {@link Robot} that looks like a pink ghost.
|
||||
* It tries to move in a random direction.
|
||||
|
@ -31,6 +35,19 @@ public class PinkGhost extends Robot implements Ghost, TickBased {
|
|||
@Override
|
||||
@StudentImplementationRequired("H2.2")
|
||||
public void doMove() {
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.2 - Remove if implemented");
|
||||
var dirs = IntStream.range(0, 4)
|
||||
.mapToObj(x -> {
|
||||
turnLeft();
|
||||
return isFrontClear();
|
||||
})
|
||||
.filter(x -> x)
|
||||
.map(x -> getDirection())
|
||||
.toList();
|
||||
var i = Util.getRandomInteger(1, dirs.size());
|
||||
var dir = dirs.get(i-1);
|
||||
while (dir != getDirection()) {
|
||||
turnLeft();
|
||||
}
|
||||
move();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,13 @@ public class RedGhost extends Robot implements Ghost, TickBased {
|
|||
@Override
|
||||
@StudentImplementationRequired("H2.4")
|
||||
public void doMove() {
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.4 - Remove if implemented");
|
||||
var dir = Util.furthestDirection(chased, this);
|
||||
while (getDirection() != dir) {
|
||||
turnLeft();
|
||||
}
|
||||
while (!isFrontClear()) {
|
||||
turnLeft();
|
||||
}
|
||||
move();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ 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);
|
||||
public final InputHandler inputHandler = new InputHandler(this);
|
||||
/**
|
||||
* The width of the game board.
|
||||
*/
|
||||
|
@ -70,7 +70,17 @@ public class FourWins {
|
|||
@StudentImplementationRequired("H2.2.1")
|
||||
public static boolean validateInput(final int column, final RobotFamily[][] stones) {
|
||||
// TODO: H2.2.1
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.2.1 - Remove if implemented");
|
||||
if (column < 0 || column >= World.getWidth()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int y = 0; y < World.getHeight(); y++) {
|
||||
if (stones[y][column] == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -86,7 +96,14 @@ public class FourWins {
|
|||
@StudentImplementationRequired("H2.2.2")
|
||||
public static int getDestinationRow(final int column, final RobotFamily[][] stones) {
|
||||
// TODO: H2.2.2
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.2.2 - Remove if implemented");
|
||||
|
||||
for (int y = 0; y < World.getHeight(); y++) {
|
||||
if (stones[y][column] == null) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,7 +122,14 @@ public class FourWins {
|
|||
@StudentImplementationRequired("H2.2.2")
|
||||
public static void dropStone(final int column, final RobotFamily[][] stones, final RobotFamily currentPlayer) {
|
||||
// TODO: H2.2.2
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.2.2 - Remove if implemented");
|
||||
var robot = new Robot(column, World.getHeight()-1, Direction.DOWN, 0, currentPlayer);
|
||||
var row = getDestinationRow(column, stones);
|
||||
while (robot.getY() != row) {
|
||||
robot.move();
|
||||
}
|
||||
robot.turnLeft();
|
||||
robot.turnLeft();
|
||||
stones[robot.getY()][robot.getX()] = robot.getRobotFamily();
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,7 +145,7 @@ public class FourWins {
|
|||
@StudentImplementationRequired("H2.2.3")
|
||||
public static boolean testWinConditions(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
|
||||
// TODO: H2.2.3
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.2.3 - Remove if implemented");
|
||||
return testWinDiagonal(stones, currentPlayer) || testWinVertical(stones, currentPlayer) || testWinHorizontal(stones, currentPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,7 +159,20 @@ public class FourWins {
|
|||
@StudentImplementationRequired("H2.2.3")
|
||||
public static boolean testWinHorizontal(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
|
||||
// TODO: H2.2.3
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.2.3 - Remove if implemented");
|
||||
for (int y = 0; y < World.getHeight(); y++) {
|
||||
int count = 0;
|
||||
for (int x = 0; x < World.getWidth(); x++) {
|
||||
if (stones[y][x] == currentPlayer) {
|
||||
count++;
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
if (count == 4) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,7 +186,20 @@ public class FourWins {
|
|||
@StudentImplementationRequired("H2.2.3")
|
||||
public static boolean testWinVertical(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
|
||||
// TODO: H2.2.3
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.2.3 - Remove if implemented");
|
||||
for (int x = 0; x < World.getWidth(); x++) {
|
||||
int count = 0;
|
||||
for (int y = 0; y < World.getHeight(); y++) {
|
||||
if (stones[y][x] == currentPlayer) {
|
||||
count++;
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
if (count == 4) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,7 +258,10 @@ public class FourWins {
|
|||
@StudentImplementationRequired("H2.2.4")
|
||||
public static RobotFamily nextPlayer(final RobotFamily currentPlayer) {
|
||||
// TODO: H2.2.4
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.2.4 - Remove if implemented");
|
||||
return currentPlayer == RobotFamily.SQUARE_BLUE
|
||||
? RobotFamily.SQUARE_RED
|
||||
: RobotFamily.SQUARE_BLUE;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,7 +272,7 @@ public class FourWins {
|
|||
inputHandler.displayDrawStatus();
|
||||
|
||||
// TODO: H2.2.4
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.2.4 - Remove if implemented");
|
||||
System.out.println("No valid columns found. Hence, game ends with a draw.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -232,7 +285,7 @@ public class FourWins {
|
|||
inputHandler.displayWinnerStatus(winner);
|
||||
|
||||
// TODO: H2.2.4
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.2.4 - Remove if implemented");
|
||||
System.out.printf("Player %s wins the game!\n", winner);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,7 +297,11 @@ public class FourWins {
|
|||
@StudentImplementationRequired("H2.2.4")
|
||||
public static void colorFieldBackground(final RobotFamily winner) {
|
||||
// TODO: H2.2.4
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.2.4 - Remove if implemented");
|
||||
for (int y = 0; y < World.getHeight(); y++) {
|
||||
for (int x = 0; x < World.getWidth(); x++) {
|
||||
setFieldColor(x, y, winner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -266,7 +323,7 @@ public class FourWins {
|
|||
while (!finished) {
|
||||
// TODO: H2.2.4
|
||||
// set next player
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.2.4 - Remove if implemented");
|
||||
currentPlayer = nextPlayer(currentPlayer);
|
||||
|
||||
// wait for click in column (DO NOT TOUCH)
|
||||
finished = draw = isGameBoardFull(stones);
|
||||
|
@ -278,7 +335,8 @@ public class FourWins {
|
|||
// TODO: H2.2.4
|
||||
// let stone drop
|
||||
// test win conditions
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.2.4 - Remove if implemented");
|
||||
dropStone(column, stones, currentPlayer);
|
||||
finished = testWinConditions(stones, currentPlayer);
|
||||
}
|
||||
|
||||
// displaying either draw or winner (DO NOT TOUCH)
|
||||
|
@ -341,5 +399,4 @@ public class FourWins {
|
|||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import fopbot.RobotFamily;
|
|||
import fopbot.World;
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
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;
|
||||
|
@ -41,7 +43,10 @@ public class Main {
|
|||
@StudentImplementationRequired("H2.3")
|
||||
public static void sanityChecksH211() {
|
||||
// TODO: H2.3
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.3 - Remove if implemented");
|
||||
var arr = new int[0];
|
||||
arr = OneDimensionalArrayStuff.push(arr, 4);
|
||||
arr = OneDimensionalArrayStuff.push(arr, 2);
|
||||
testEquals(true, Arrays.equals(arr, new int[]{4,2}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +68,11 @@ public class Main {
|
|||
};
|
||||
|
||||
// TODO: H2.3
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.3 - Remove if implemented");
|
||||
var x = TwoDimensionalArrayStuff.meanOccurrencesPerLine(simpleTest, "a");
|
||||
testEquals(1.0f, x);
|
||||
|
||||
var y = TwoDimensionalArrayStuff.meanOccurrencesPerLine(complexTest, "a");
|
||||
testEquals(2.0f, y);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,7 +102,6 @@ public class Main {
|
|||
};
|
||||
|
||||
// TODO: H2.4
|
||||
org.tudalgo.algoutils.student.Student.crash("H2.4 - Remove if implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,8 +24,12 @@ public class OneDimensionalArrayStuff {
|
|||
@SuppressWarnings("ManualArrayCopy")
|
||||
@StudentImplementationRequired("H2.1.1")
|
||||
public static int[] push(final int[] array, final int value) {
|
||||
// TODO: H2.1.1
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.1.1 - Remove if implemented");
|
||||
var newarr = new int[array.length+1];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
newarr[i] = array[i];
|
||||
}
|
||||
newarr[array.length] = value;
|
||||
return newarr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,8 +41,9 @@ public class OneDimensionalArrayStuff {
|
|||
*/
|
||||
@StudentImplementationRequired("H2.1.1")
|
||||
public static int[] calculateNextFibonacci(final int[] array) {
|
||||
// TODO: H2.1.1
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.1.1 - Remove if implemented");
|
||||
var a = array[array.length-2];
|
||||
var b = array[array.length-1];
|
||||
return push(array, a+b);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,8 +53,15 @@ public class OneDimensionalArrayStuff {
|
|||
* @return the n-th Fibonacci number
|
||||
*/
|
||||
@StudentImplementationRequired("H2.1.1")
|
||||
public static int fibonacci(final int n) {
|
||||
// TODO: H2.1.1
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.1.1 - Remove if implemented");
|
||||
public static int fibonacci(int n) {
|
||||
var arr = new int[] {0, 1};
|
||||
if (n < 2) {
|
||||
return arr[n];
|
||||
}
|
||||
n -= 2;
|
||||
while (n --> 0) {
|
||||
arr = calculateNextFibonacci(arr);
|
||||
}
|
||||
return arr[arr.length-1];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,11 @@ package h02;
|
|||
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
import java.util.regex.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* This class serves as a container for the methods that are to be implemented by the students for exercise H2.1.2.
|
||||
|
@ -27,7 +31,17 @@ public class TwoDimensionalArrayStuff {
|
|||
@StudentImplementationRequired("H2.1.2")
|
||||
public static int[] occurrences(final String[][] input, final String query) {
|
||||
// TODO: H2.1.2
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.1.2 - Remove if implemented");
|
||||
return Stream.of(input)
|
||||
.map(line -> String.join("\0", line))
|
||||
.mapToInt(line -> {
|
||||
var m = Pattern.compile(query).matcher(line);
|
||||
var i = 0;
|
||||
while (m.find()) {
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
})
|
||||
.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,7 +53,7 @@ public class TwoDimensionalArrayStuff {
|
|||
@StudentImplementationRequired("H2.1.2")
|
||||
public static float mean(final int[] input) {
|
||||
// TODO: H2.1.2
|
||||
return org.tudalgo.algoutils.student.Student.crash("H2.1.2 - Remove if implemented");
|
||||
return (float) (IntStream.of(input).sum()) / input.length;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
package h03;
|
||||
|
||||
import fopbot.World;
|
||||
import h03.robots.DoublePowerRobot;
|
||||
import h03.robots.HackingRobot;
|
||||
import h03.robots.MovementType;
|
||||
import h03.robots.VersatileRobot;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Main entry point in executing the program.
|
||||
|
@ -15,5 +23,33 @@ public class Main {
|
|||
// Create a 5x5 world and make it visible
|
||||
World.setSize(5, 5);
|
||||
World.setVisible(true);
|
||||
|
||||
var haxxor = new HackingRobot(3, 2, true);
|
||||
var olaf = new HackingRobot(1, 4, false);
|
||||
|
||||
var versi = new VersatileRobot(4, 3, true, false);
|
||||
while (versi.getType() != MovementType.DIAGONAL) {
|
||||
versi = new VersatileRobot(4, 3, true, false);
|
||||
}
|
||||
|
||||
var doubleTrouble1 = new DoublePowerRobot(2, 1, true);
|
||||
var doubleTrouble2 = new DoublePowerRobot(2, 1, false);
|
||||
var doubleTrouble3 = new DoublePowerRobot(2, 3, true);
|
||||
|
||||
var set = Stream.of(doubleTrouble1, doubleTrouble2, doubleTrouble3)
|
||||
.flatMap(x -> Stream.of(x.getType(), x.getNextType()))
|
||||
.collect(Collectors.toSet());
|
||||
while (set.size() < 3) {
|
||||
doubleTrouble1 = new DoublePowerRobot(2, 1, true);
|
||||
doubleTrouble2 = new DoublePowerRobot(2, 1, false);
|
||||
doubleTrouble3 = new DoublePowerRobot(2, 3, true);
|
||||
|
||||
set = Stream.of(doubleTrouble1, doubleTrouble2, doubleTrouble3)
|
||||
.flatMap(x -> Stream.of(x.getType(), x.getNextType()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
var challenge = new RobotsChallenge(0, 4, doubleTrouble1, doubleTrouble2, doubleTrouble3);
|
||||
System.out.println(Arrays.deepToString(challenge.findWinners()));
|
||||
}
|
||||
}
|
||||
|
|
65
H03/src/main/java/h03/RobotsChallenge.java
Normal file
65
H03/src/main/java/h03/RobotsChallenge.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package h03;
|
||||
|
||||
import h03.robots.DoublePowerRobot;
|
||||
import h03.robots.MovementType;
|
||||
|
||||
import javax.swing.text.html.parser.TagElement;
|
||||
import java.awt.*;
|
||||
|
||||
public class RobotsChallenge {
|
||||
|
||||
private final int winThreshold = 2;
|
||||
|
||||
private final int begin;
|
||||
|
||||
private final int goal;
|
||||
|
||||
private final DoublePowerRobot[] robots;
|
||||
|
||||
public RobotsChallenge(int begin, int goal, DoublePowerRobot... robots) {
|
||||
this.goal = goal;
|
||||
this.robots = robots;
|
||||
this.begin = begin / 2;
|
||||
}
|
||||
|
||||
public int calculateStepsDiagonal() {
|
||||
return Math.abs(begin - goal);
|
||||
}
|
||||
|
||||
public int calculateStepsOverstep() {
|
||||
var diff = Math.abs(begin - goal);
|
||||
if (diff % 2 == 0) {
|
||||
return diff;
|
||||
}
|
||||
return diff+1;
|
||||
}
|
||||
|
||||
public int calculateStepsTeleport() {
|
||||
var diff = Math.abs(begin - goal);
|
||||
if (diff % 2 == 0) {
|
||||
return diff / 2;
|
||||
}
|
||||
return (diff / 2) + 2;
|
||||
}
|
||||
|
||||
public int calculateSteps(MovementType type) {
|
||||
return switch (type) {
|
||||
case DIAGONAL -> calculateStepsDiagonal();
|
||||
case OVERSTEP -> calculateStepsOverstep();
|
||||
case TELEPORT -> calculateStepsTeleport();
|
||||
};
|
||||
}
|
||||
|
||||
public DoublePowerRobot[] findWinners() {
|
||||
var arr = new DoublePowerRobot[robots.length];
|
||||
int index = 0;
|
||||
|
||||
for (var r : robots) {
|
||||
if (Math.min(calculateSteps(r.getType()), calculateSteps(r.getNextType())) <= winThreshold) {
|
||||
arr[index++] = r;
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
}
|
27
H03/src/main/java/h03/robots/DoublePowerRobot.java
Normal file
27
H03/src/main/java/h03/robots/DoublePowerRobot.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package h03.robots;
|
||||
|
||||
public class DoublePowerRobot extends HackingRobot {
|
||||
|
||||
private MovementType[] doublePowerTypes = new MovementType[2];
|
||||
|
||||
public DoublePowerRobot(int x, int y, boolean order) {
|
||||
super(x, y, order);
|
||||
doublePowerTypes[0] = getType();
|
||||
doublePowerTypes[1] = getNextType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shuffle() {
|
||||
super.shuffle();
|
||||
doublePowerTypes[0] = getType();
|
||||
doublePowerTypes[1] = getNextType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shuffle(int itNr) {
|
||||
var changed = super.shuffle(itNr);
|
||||
doublePowerTypes[0] = getType();
|
||||
doublePowerTypes[1] = getNextType();
|
||||
return changed;
|
||||
}
|
||||
}
|
62
H03/src/main/java/h03/robots/HackingRobot.java
Normal file
62
H03/src/main/java/h03/robots/HackingRobot.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
package h03.robots;
|
||||
|
||||
import fopbot.Robot;
|
||||
import fopbot.RobotTrace;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
public class HackingRobot extends Robot {
|
||||
|
||||
private MovementType type;
|
||||
|
||||
private MovementType[] robotTypes = new MovementType[] {
|
||||
MovementType.TELEPORT, MovementType.OVERSTEP, MovementType.DIAGONAL
|
||||
};
|
||||
|
||||
|
||||
public HackingRobot(int x, int y, boolean order) {
|
||||
super(x, y);
|
||||
|
||||
if (order) { // right shift
|
||||
var t = robotTypes[2];
|
||||
robotTypes[2] = robotTypes[1];
|
||||
robotTypes[1] = robotTypes[0];
|
||||
robotTypes[0] = t;
|
||||
} else { // left shift
|
||||
var t = robotTypes[0];
|
||||
robotTypes[0] = robotTypes[1];
|
||||
robotTypes[1] = robotTypes[2];
|
||||
robotTypes[2] = t;
|
||||
}
|
||||
|
||||
type = robotTypes[0];
|
||||
}
|
||||
|
||||
public MovementType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public MovementType getNextType() {
|
||||
var i = Arrays.asList(robotTypes).indexOf(type);
|
||||
i = (i + 1) % 3;
|
||||
return robotTypes[i];
|
||||
}
|
||||
|
||||
public int getRandom(int limit) {
|
||||
return new Random().nextInt(limit);
|
||||
}
|
||||
|
||||
public boolean shuffle(int itNr) {
|
||||
var old = type;
|
||||
for (int i = 0; i < itNr; i++) {
|
||||
int index = getRandom(3);
|
||||
type = robotTypes[index];
|
||||
}
|
||||
return type != old;
|
||||
}
|
||||
|
||||
public void shuffle() {
|
||||
while (!shuffle(1));
|
||||
}
|
||||
}
|
5
H03/src/main/java/h03/robots/MovementType.java
Normal file
5
H03/src/main/java/h03/robots/MovementType.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package h03.robots;
|
||||
|
||||
public enum MovementType {
|
||||
DIAGONAL, OVERSTEP, TELEPORT
|
||||
}
|
36
H03/src/main/java/h03/robots/VersatileRobot.java
Normal file
36
H03/src/main/java/h03/robots/VersatileRobot.java
Normal file
|
@ -0,0 +1,36 @@
|
|||
package h03.robots;
|
||||
|
||||
public class VersatileRobot extends HackingRobot {
|
||||
|
||||
public VersatileRobot(int x, int y, boolean order, boolean exchange) {
|
||||
super(x, y, order);
|
||||
|
||||
if (exchange) {
|
||||
setField(y, x);
|
||||
}
|
||||
|
||||
if (getType() == MovementType.DIAGONAL) {
|
||||
setY(getX());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shuffle(int itNr) {
|
||||
var changed = super.shuffle(itNr);
|
||||
|
||||
if (getType() == MovementType.DIAGONAL) {
|
||||
setY(getX());
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shuffle() {
|
||||
super.shuffle();
|
||||
|
||||
if (getType() == MovementType.DIAGONAL) {
|
||||
setY(getX());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
package h04;
|
||||
|
||||
import fopbot.Robot;
|
||||
import h04.template.ChessUtils;
|
||||
import h04.template.GameControllerTemplate;
|
||||
import h04.chesspieces.King;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class GameController extends GameControllerTemplate {
|
||||
public GameController() {
|
||||
super();
|
||||
|
@ -13,6 +16,7 @@ public class GameController extends GameControllerTemplate {
|
|||
@Override
|
||||
public boolean checkWinCondition() {
|
||||
//TODO H4.1
|
||||
return false;
|
||||
var kings = ChessUtils.getKings();
|
||||
return Stream.of(kings).anyMatch(Robot::isTurnedOff);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
package h04.chesspieces;
|
||||
|
||||
import fopbot.Robot;
|
||||
import h04.movement.DiagonalMover;
|
||||
import h04.movement.MoveStrategy;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.MoveStrategy;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
|
||||
public class Bishop extends Robot {
|
||||
public class Bishop extends Robot implements DiagonalMover {
|
||||
|
||||
private final Team team;
|
||||
|
||||
|
@ -21,4 +23,13 @@ public class Bishop extends Robot {
|
|||
public Team getTeam() { return team;}
|
||||
|
||||
//TODO H4.5
|
||||
@Override
|
||||
public void moveStrategy(int dx, int dy, MoveStrategy strategy) {
|
||||
strategy.move(this, dx, dy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point[] getPossibleMoveFields() {
|
||||
return getDiagonalMoves();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package h04.chesspieces;
|
|||
//Wichtig für Implementation
|
||||
//import h04.movement.MoveStrategy;
|
||||
|
||||
import h04.movement.MoveStrategy;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
public interface ChessPiece {
|
||||
|
@ -17,4 +19,7 @@ public interface ChessPiece {
|
|||
void turnOff();
|
||||
|
||||
//TODO H4.3
|
||||
void moveStrategy(int dx, int dy, MoveStrategy strategy);
|
||||
|
||||
Point[] getPossibleMoveFields();
|
||||
}
|
||||
|
|
|
@ -3,9 +3,12 @@ package h04.chesspieces;
|
|||
import fopbot.Robot;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.MoveStrategy;
|
||||
import fopbot.World;
|
||||
import h04.movement.MoveStrategy;
|
||||
import h04.template.ChessUtils;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class King extends Robot implements ChessPiece {
|
||||
|
||||
|
@ -22,4 +25,79 @@ public class King extends Robot implements ChessPiece {
|
|||
}
|
||||
|
||||
//TODO H4.4
|
||||
@Override
|
||||
public void moveStrategy(int dx, int dy, MoveStrategy strategy) {
|
||||
strategy.move(this, dx, dy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point[] getPossibleMoveFields() {
|
||||
var list = new ArrayList<Point>();
|
||||
|
||||
if (getX() > 0) {
|
||||
if (getY() > 0) {
|
||||
var target = new Point(getX()-1, getY()-1);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
}
|
||||
|
||||
var target = new Point(getX()-1, getY());
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
|
||||
if (getY() < World.getHeight()-1) {
|
||||
target = new Point(getX()-1, getY()+1);
|
||||
r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getY() > 0) {
|
||||
var target = new Point(getX(), getY()-1);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
}
|
||||
|
||||
if (getY() < World.getHeight()-1) {
|
||||
var target = new Point(getX(), getY()+1);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
}
|
||||
|
||||
if (getX() < World.getWidth()-1) {
|
||||
if (getY() > 0) {
|
||||
var target = new Point(getX()+1, getY()-1);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
}
|
||||
|
||||
var target = new Point(getX()+1, getY());
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
|
||||
if (getY() < World.getHeight()-1) {
|
||||
target = new Point(getX()+1, getY()+1);
|
||||
r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list.toArray(Point[]::new);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package h04.chesspieces;
|
|||
import fopbot.Robot;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.MoveStrategy;
|
||||
import h04.movement.MoveStrategy;
|
||||
import h04.template.ChessUtils;
|
||||
|
||||
import java.awt.Point;
|
||||
|
@ -21,14 +22,12 @@ public class Knight extends Robot implements ChessPiece {
|
|||
return team;
|
||||
}
|
||||
|
||||
//Wichtig für Implementation
|
||||
/*
|
||||
@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;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package h04.chesspieces;
|
||||
|
||||
import fopbot.Robot;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.MoveStrategy;
|
||||
import h04.movement.MoveStrategy;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
|
@ -24,15 +23,13 @@ public class Pawn extends Robot implements ChessPiece {
|
|||
return team;
|
||||
}
|
||||
|
||||
//Wichtig für Implementation
|
||||
/*
|
||||
@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;
|
||||
|
|
|
@ -3,11 +3,15 @@ package h04.chesspieces;
|
|||
import fopbot.Robot;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.MoveStrategy;
|
||||
import h04.movement.DiagonalMover;
|
||||
import h04.movement.MoveStrategy;
|
||||
import h04.movement.OrthogonalMover;
|
||||
import h04.template.ChessUtils;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Queen extends Robot {
|
||||
public class Queen extends Robot implements OrthogonalMover, DiagonalMover {
|
||||
private final Team team;
|
||||
|
||||
public Queen(final int x, final int y, final Team team) {
|
||||
|
@ -22,4 +26,15 @@ public class Queen extends Robot {
|
|||
}
|
||||
|
||||
//TODO H4.6
|
||||
@Override
|
||||
public void moveStrategy(int dx, int dy, MoveStrategy strategy) {
|
||||
strategy.move(this, dx, dy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point[] getPossibleMoveFields() {
|
||||
return Stream.of(getOrthogonalMoves(), getDiagonalMoves())
|
||||
.flatMap(Stream::of)
|
||||
.toArray(Point[]::new);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ package h04.chesspieces;
|
|||
import fopbot.Robot;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.MoveStrategy;
|
||||
import h04.movement.MoveStrategy;
|
||||
import h04.movement.OrthogonalMover;
|
||||
import h04.template.ChessUtils;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
public class Rook extends Robot {
|
||||
public class Rook extends Robot implements OrthogonalMover {
|
||||
private final Team team;
|
||||
|
||||
public Rook(final int x, final int y, final Team team){
|
||||
|
@ -22,4 +24,13 @@ public class Rook extends Robot {
|
|||
}
|
||||
|
||||
//TODO H4.5
|
||||
@Override
|
||||
public void moveStrategy(int dx, int dy, MoveStrategy strategy) {
|
||||
strategy.move(this, dx, dy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point[] getPossibleMoveFields() {
|
||||
return getOrthogonalMoves();
|
||||
}
|
||||
}
|
||||
|
|
53
H04/src/main/java/h04/movement/DiagonalMover.java
Normal file
53
H04/src/main/java/h04/movement/DiagonalMover.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
package h04.movement;
|
||||
|
||||
import fopbot.World;
|
||||
import h04.chesspieces.ChessPiece;
|
||||
import h04.template.ChessUtils;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface DiagonalMover extends ChessPiece {
|
||||
|
||||
default Point[] getDiagonalMoves() {
|
||||
var list = new ArrayList<Point>();
|
||||
|
||||
for (int i = 1; getX()-i >= 0 && getY()-i >= 0; i++) {
|
||||
var target = new Point(getX()-i, getY()-i);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
if (r != null) break;
|
||||
}
|
||||
|
||||
for (int i = 1; getX()+i < World.getWidth() && getY()-i >= 0; i++) {
|
||||
var target = new Point(getX()+i, getY()-i);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
if (r != null) break;
|
||||
}
|
||||
|
||||
for (int i = 1; getX()-i >= 0 && getY()+i < World.getHeight(); i++) {
|
||||
var target = new Point(getX()-i, getY()+i);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
if (r != null) break;
|
||||
}
|
||||
|
||||
for (int i = 1; getX()+i < World.getWidth() && getY()+i < World.getHeight(); i++) {
|
||||
var target = new Point(getX()+i, getY()+i);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
if (r != null) break;
|
||||
}
|
||||
|
||||
return list.toArray(Point[]::new);
|
||||
}
|
||||
}
|
8
H04/src/main/java/h04/movement/MoveStrategy.java
Normal file
8
H04/src/main/java/h04/movement/MoveStrategy.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package h04.movement;
|
||||
|
||||
import fopbot.Robot;
|
||||
|
||||
public interface MoveStrategy {
|
||||
|
||||
void move(Robot robot, int dx, int dy);
|
||||
}
|
53
H04/src/main/java/h04/movement/OrthogonalMover.java
Normal file
53
H04/src/main/java/h04/movement/OrthogonalMover.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
package h04.movement;
|
||||
|
||||
import fopbot.World;
|
||||
import h04.chesspieces.ChessPiece;
|
||||
import h04.template.ChessUtils;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface OrthogonalMover extends ChessPiece {
|
||||
|
||||
default Point[] getOrthogonalMoves() {
|
||||
var list = new ArrayList<Point>();
|
||||
|
||||
for (int i = getX()-1; i >= 0; i--) {
|
||||
var target = new Point(i, getY());
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
if (r != null) break;
|
||||
}
|
||||
|
||||
for (int i = getX()+1; i < World.getWidth(); i++) {
|
||||
var target = new Point(i, getY());
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
if (r != null) break;
|
||||
}
|
||||
|
||||
for (int i = getY()-1; i >= 0; i--) {
|
||||
var target = new Point(getX(), i);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
if (r != null) break;
|
||||
}
|
||||
|
||||
for (int i = getY()+1; i < World.getHeight(); i++) {
|
||||
var target = new Point(getX(), i);
|
||||
var r = ChessUtils.getPieceAt(target);
|
||||
if (r == null || r.getTeam() != getTeam()) {
|
||||
list.add(target);
|
||||
}
|
||||
if (r != null) break;
|
||||
}
|
||||
|
||||
return list.toArray(Point[]::new);
|
||||
}
|
||||
}
|
11
H04/src/main/java/h04/movement/TeleportingMoveStrategy.java
Normal file
11
H04/src/main/java/h04/movement/TeleportingMoveStrategy.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package h04.movement;
|
||||
|
||||
import fopbot.Robot;
|
||||
|
||||
public class TeleportingMoveStrategy implements MoveStrategy {
|
||||
|
||||
@Override
|
||||
public void move(Robot robot, int dx, int dy) {
|
||||
robot.setField(robot.getX()+dx, robot.getY()+dy);
|
||||
}
|
||||
}
|
40
H04/src/main/java/h04/movement/WalkingMoveStrategy.java
Normal file
40
H04/src/main/java/h04/movement/WalkingMoveStrategy.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package h04.movement;
|
||||
|
||||
import fopbot.Direction;
|
||||
import fopbot.Robot;
|
||||
|
||||
public class WalkingMoveStrategy implements MoveStrategy {
|
||||
|
||||
@Override
|
||||
public void move(Robot robot, int dx, int dy) {
|
||||
if (dx < 0) {
|
||||
turnFacing(robot, Direction.LEFT);
|
||||
}
|
||||
if (dx > 0) {
|
||||
turnFacing(robot, Direction.RIGHT);
|
||||
}
|
||||
dx = Math.abs(dx);
|
||||
while (dx --> 0) {
|
||||
robot.move();
|
||||
}
|
||||
|
||||
if (dy < 0) {
|
||||
turnFacing(robot, Direction.DOWN);
|
||||
}
|
||||
if (dy > 0) {
|
||||
turnFacing(robot, Direction.UP);
|
||||
}
|
||||
dy = Math.abs(dy);
|
||||
while (dy --> 0) {
|
||||
robot.move();
|
||||
}
|
||||
|
||||
turnFacing(robot, Direction.UP);
|
||||
}
|
||||
|
||||
private void turnFacing(Robot robot, Direction dir) {
|
||||
while (robot.getDirection() != dir) {
|
||||
robot.turnLeft();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,12 +13,9 @@ import h04.chesspieces.Pawn;
|
|||
import h04.chesspieces.Queen;
|
||||
import h04.chesspieces.Rook;
|
||||
import h04.chesspieces.Team;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.MoveStrategy;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.TeleportingMoveStrategy;
|
||||
//Wichtig für Implementation
|
||||
//import h04.movement.WalkingMoveStrategy;
|
||||
import h04.movement.MoveStrategy;
|
||||
import h04.movement.TeleportingMoveStrategy;
|
||||
import h04.movement.WalkingMoveStrategy;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tudalgo.algoutils.student.io.PropertyUtils;
|
||||
|
||||
|
@ -45,13 +42,10 @@ public abstract class GameControllerTemplate {
|
|||
|
||||
protected @Nullable ChessPiece selectedPiece;
|
||||
|
||||
//Wichtig für Implementation
|
||||
/*
|
||||
protected MoveStrategy moveStrategy = PropertyUtils.getBooleanProperty(
|
||||
"h04.properties",
|
||||
"USE_TELEPORT_MOVE_STRATEGY"
|
||||
) ? new TeleportingMoveStrategy() : new WalkingMoveStrategy();
|
||||
*/
|
||||
|
||||
/**
|
||||
* Starts the game loop.
|
||||
|
@ -62,8 +56,6 @@ public abstract class GameControllerTemplate {
|
|||
while (!gameOver) {
|
||||
final var point = inputHandler.getNextInput(nextToMove);
|
||||
|
||||
//Wichtig für Implementation
|
||||
/*
|
||||
if (ChessUtils.getTeamAt(point) == nextToMove) {
|
||||
// select piece
|
||||
selectedPiece = ChessUtils.getPieceAt(point);
|
||||
|
@ -107,7 +99,6 @@ public abstract class GameControllerTemplate {
|
|||
nextToMove = nextToMove.getOpponent();
|
||||
selectedPiece = null;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public class Airspace {
|
|||
}
|
||||
|
||||
// TODO: H5.1.1 - Uncomment the following lines
|
||||
/* private final Set<Flying> flyingInAirspace = new HashSet<>();
|
||||
private final Set<Flying> flyingInAirspace = new HashSet<>();
|
||||
|
||||
private Airspace(){
|
||||
|
||||
|
@ -28,9 +28,27 @@ public class Airspace {
|
|||
|
||||
void deregister(Flying flying){
|
||||
flyingInAirspace.remove(flying);
|
||||
} */
|
||||
}
|
||||
|
||||
void scanAirspace() {
|
||||
// TODO: H5.5
|
||||
System.out.println("Scanning...");
|
||||
|
||||
if (flyingInAirspace.isEmpty()) {
|
||||
System.out.println("Airspace is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
for (var f : flyingInAirspace) {
|
||||
if (f instanceof CarriesPassengers cp) {
|
||||
System.out.printf("%s is flying in airspace (%d PAX).\n", f.getIdentifier(), cp.getPassengerCount());
|
||||
} else {
|
||||
System.out.printf("%s is flying in airspace.\n", f.getIdentifier());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Flying> getFlyingInAirspace() {
|
||||
return flyingInAirspace;
|
||||
}
|
||||
}
|
||||
|
|
30
H05/src/main/java/h05/CargoPlane.java
Normal file
30
H05/src/main/java/h05/CargoPlane.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package h05;
|
||||
|
||||
public class CargoPlane extends Plane implements CarriesCargo {
|
||||
|
||||
private final CargoStack containers = new CargoStack();
|
||||
|
||||
public CargoPlane(String aircraftRegistration, int baseWeight, FuelType fuelType, double fuelCapacity) {
|
||||
super(aircraftRegistration, baseWeight, fuelType, fuelCapacity);
|
||||
}
|
||||
|
||||
@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 getBaseWeight() + containers.getSum();
|
||||
}
|
||||
}
|
10
H05/src/main/java/h05/CarriesCargo.java
Normal file
10
H05/src/main/java/h05/CarriesCargo.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package h05;
|
||||
|
||||
public interface CarriesCargo {
|
||||
|
||||
void loadContainer(int cargoWeight);
|
||||
|
||||
boolean hasFreightLoaded();
|
||||
|
||||
int unloadNextContainer();
|
||||
}
|
10
H05/src/main/java/h05/CarriesPassengers.java
Normal file
10
H05/src/main/java/h05/CarriesPassengers.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package h05;
|
||||
|
||||
public interface CarriesPassengers {
|
||||
|
||||
void board(int passengers);
|
||||
|
||||
void disembark();
|
||||
|
||||
int getPassengerCount();
|
||||
}
|
53
H05/src/main/java/h05/CombinedPlane.java
Normal file
53
H05/src/main/java/h05/CombinedPlane.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
package h05;
|
||||
|
||||
public class CombinedPlane extends Plane implements CarriesCargo, CarriesPassengers{
|
||||
|
||||
protected static final char AVERAGE_PEOPLE_WEIGHT = 100;
|
||||
protected static final char AVERAGE_LUGGAGE_WEIGHT = 15;
|
||||
|
||||
private final int crewCount;
|
||||
|
||||
private int passengerCount = 0;
|
||||
|
||||
public CombinedPlane(String aircraftRegistration, int baseWeight, FuelType fuelType, double fuelCapacity, int crewCount) {
|
||||
super(aircraftRegistration, baseWeight, fuelType, fuelCapacity);
|
||||
this.crewCount = crewCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double mass() {
|
||||
return containers.getSum() + getBaseWeight() + passengerCount * AVERAGE_LUGGAGE_WEIGHT + passengerCount * AVERAGE_PEOPLE_WEIGHT + crewCount * AVERAGE_PEOPLE_WEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void board(int passengers) {
|
||||
passengerCount += passengers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disembark() {
|
||||
passengerCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPassengerCount() {
|
||||
return passengerCount;
|
||||
}
|
||||
|
||||
private final CargoStack containers = new CargoStack();
|
||||
|
||||
@Override
|
||||
public void loadContainer(int cargoWeight) {
|
||||
containers.push(cargoWeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFreightLoaded() {
|
||||
return !containers.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int unloadNextContainer() {
|
||||
return containers.pop();
|
||||
}
|
||||
}
|
6
H05/src/main/java/h05/Flying.java
Normal file
6
H05/src/main/java/h05/Flying.java
Normal file
|
@ -0,0 +1,6 @@
|
|||
package h05;
|
||||
|
||||
public interface Flying {
|
||||
|
||||
String getIdentifier();
|
||||
}
|
18
H05/src/main/java/h05/FuelType.java
Normal file
18
H05/src/main/java/h05/FuelType.java
Normal file
|
@ -0,0 +1,18 @@
|
|||
package h05;
|
||||
|
||||
public enum FuelType {
|
||||
AvGas(0.99),
|
||||
Biokerosin(1.02),
|
||||
JetA(1.0),
|
||||
JetB(1.2);
|
||||
|
||||
private final double consumptionMultiplicator;
|
||||
|
||||
FuelType(double consumptionMultiplicator) {
|
||||
this.consumptionMultiplicator = consumptionMultiplicator;
|
||||
}
|
||||
|
||||
public double getConsumptionMultiplicator() {
|
||||
return consumptionMultiplicator;
|
||||
}
|
||||
}
|
|
@ -11,5 +11,50 @@ public class Main {
|
|||
*/
|
||||
public static void main(String[] args) {
|
||||
// TODO: H5.6
|
||||
Airspace.get().scanAirspace();
|
||||
|
||||
var longRunway = new Runway(4000);
|
||||
|
||||
var shortRunway = new Runway(2000);
|
||||
|
||||
var balloon = new WeatherBalloon(99);
|
||||
balloon.start();
|
||||
|
||||
var tankA = new Tank(FuelType.JetA);
|
||||
|
||||
var tankB = new Tank(FuelType.JetB);
|
||||
|
||||
var tankerPlane = new TankerPlane("D-ABCD", 10000, FuelType.JetA, 1000);
|
||||
tankerPlane.loadFuel(FuelType.AvGas, 100000);
|
||||
tankerPlane.takeOff();
|
||||
|
||||
var passangerPlane = new PassengerPlane("GAG-67", 10000, FuelType.JetA, 1700, 5);
|
||||
tankA.refuelPlane(passangerPlane);
|
||||
passangerPlane.board(100);
|
||||
passangerPlane.takeOff();
|
||||
|
||||
Airspace.get().scanAirspace();
|
||||
|
||||
var cargoPlane = new CargoPlane("D-AFFF", 8000, FuelType.JetB, 1500);
|
||||
cargoPlane.loadContainer(1000);
|
||||
tankB.refuelPlane(cargoPlane);
|
||||
|
||||
var 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.get().scanAirspace();
|
||||
|
||||
shortRunway.land(combinedPlane);
|
||||
longRunway.land(cargoPlane);
|
||||
|
||||
Airspace.get().scanAirspace();
|
||||
|
||||
balloon.pop();
|
||||
|
||||
Airspace.get().scanAirspace();
|
||||
}
|
||||
}
|
||||
|
|
36
H05/src/main/java/h05/PassengerPlane.java
Normal file
36
H05/src/main/java/h05/PassengerPlane.java
Normal file
|
@ -0,0 +1,36 @@
|
|||
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 final int crewCount;
|
||||
|
||||
private int passengerCount = 0;
|
||||
|
||||
public PassengerPlane(String aircraftRegistration, int baseWeight, FuelType fuelType, double fuelCapacity, int crewCount) {
|
||||
super(aircraftRegistration, baseWeight, fuelType, fuelCapacity);
|
||||
this.crewCount = crewCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double mass() {
|
||||
return getBaseWeight() + passengerCount * AVERAGE_LUGGAGE_WEIGHT + passengerCount * AVERAGE_PEOPLE_WEIGHT + crewCount * AVERAGE_PEOPLE_WEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void board(int passengers) {
|
||||
passengerCount += passengers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disembark() {
|
||||
passengerCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPassengerCount() {
|
||||
return passengerCount;
|
||||
}
|
||||
}
|
80
H05/src/main/java/h05/Plane.java
Normal file
80
H05/src/main/java/h05/Plane.java
Normal file
|
@ -0,0 +1,80 @@
|
|||
package h05;
|
||||
|
||||
public abstract class Plane implements Flying {
|
||||
|
||||
private static final double CONSUMPTION_PER_KM_KG = 1.1494e-4;
|
||||
|
||||
private final String aircraftRegistration;
|
||||
|
||||
private final int baseWeight;
|
||||
|
||||
private final FuelType fuelType;
|
||||
|
||||
private final double fuelCapacity;
|
||||
|
||||
private double currentFuelLevel;
|
||||
|
||||
public Plane(String aircraftRegistration, int baseWeight, FuelType fuelType, double fuelCapacity) {
|
||||
this.aircraftRegistration = aircraftRegistration;
|
||||
this.baseWeight = baseWeight;
|
||||
this.fuelType = fuelType;
|
||||
this.fuelCapacity = fuelCapacity;
|
||||
this.currentFuelLevel = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return aircraftRegistration;
|
||||
}
|
||||
|
||||
public double getCurrentFuelLevel() {
|
||||
return currentFuelLevel;
|
||||
}
|
||||
|
||||
public double getFuelCapacity() {
|
||||
return fuelCapacity;
|
||||
}
|
||||
|
||||
public FuelType getFuelType() {
|
||||
return fuelType;
|
||||
}
|
||||
|
||||
public int getBaseWeight() {
|
||||
return baseWeight;
|
||||
}
|
||||
|
||||
public void refuel(double amount) {
|
||||
if (currentFuelLevel + amount > fuelCapacity) {
|
||||
System.out.printf("The Tank of Plane %s has overflowed!\n", aircraftRegistration);
|
||||
return;
|
||||
}
|
||||
|
||||
currentFuelLevel += amount;
|
||||
}
|
||||
|
||||
protected abstract double mass();
|
||||
|
||||
protected double getFuelConsumptionPerKilometer() {
|
||||
return CONSUMPTION_PER_KM_KG * fuelType.getConsumptionMultiplicator() * mass();
|
||||
}
|
||||
|
||||
public void fly(double distance) {
|
||||
var fuelNeeded = getFuelConsumptionPerKilometer() * distance;
|
||||
|
||||
if (currentFuelLevel < fuelNeeded) {
|
||||
System.out.printf("Plane %s does not have enough fuel to fly %f km.", aircraftRegistration, distance / 100000);
|
||||
return;
|
||||
}
|
||||
|
||||
currentFuelLevel -= fuelNeeded;
|
||||
System.out.printf("Plane %s flew %s km and has %s liters of fuel left.", aircraftRegistration, distance, currentFuelLevel);
|
||||
}
|
||||
|
||||
public void takeOff() {
|
||||
Airspace.get().register(this);
|
||||
}
|
||||
|
||||
public void land() {
|
||||
Airspace.get().deregister(this);
|
||||
}
|
||||
}
|
6
H05/src/main/java/h05/Refuelling.java
Normal file
6
H05/src/main/java/h05/Refuelling.java
Normal file
|
@ -0,0 +1,6 @@
|
|||
package h05;
|
||||
|
||||
public interface Refuelling {
|
||||
|
||||
void refuelPlane(Plane plane);
|
||||
}
|
31
H05/src/main/java/h05/Runway.java
Normal file
31
H05/src/main/java/h05/Runway.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
package h05;
|
||||
|
||||
public class Runway {
|
||||
|
||||
private final int runwayLength;
|
||||
|
||||
public Runway(int runwayLength) {
|
||||
this.runwayLength = runwayLength;
|
||||
}
|
||||
|
||||
public int getRunwayLength() {
|
||||
return runwayLength;
|
||||
}
|
||||
|
||||
public static double calculateLandingDistance(double mass) {
|
||||
return mass / 40;
|
||||
}
|
||||
|
||||
public boolean canLand(Plane plane) {
|
||||
return runwayLength >= calculateLandingDistance(plane.mass());
|
||||
}
|
||||
|
||||
public void land(Plane plane) {
|
||||
if (canLand(plane)) {
|
||||
plane.land();
|
||||
System.out.printf("Plane %s has landed successfully.\n", plane.getIdentifier());
|
||||
} else {
|
||||
System.out.printf("Plane %s could not land. The runway is too short.\n", plane.getIdentifier());
|
||||
}
|
||||
}
|
||||
}
|
22
H05/src/main/java/h05/Tank.java
Normal file
22
H05/src/main/java/h05/Tank.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
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("Hat nicht geklappt >:(");
|
||||
return;
|
||||
}
|
||||
|
||||
plane.refuel(plane.getFuelCapacity() - plane.getCurrentFuelLevel());
|
||||
}
|
||||
|
||||
|
||||
}
|
35
H05/src/main/java/h05/TankerPlane.java
Normal file
35
H05/src/main/java/h05/TankerPlane.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
package h05;
|
||||
|
||||
import java.util.stream.DoubleStream;
|
||||
|
||||
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 fuelCapacity) {
|
||||
super(aircraftRegistration, baseWeight, fuelType, fuelCapacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double mass() {
|
||||
return getBaseWeight() + DoubleStream.of(availableAmount).sum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refuelPlane(Plane plane) {
|
||||
var diff = plane.getFuelCapacity() - plane.getCurrentFuelLevel();
|
||||
var avail = availableAmount[plane.getFuelType().ordinal()];
|
||||
|
||||
if (diff > avail) {
|
||||
System.out.println("auawuduiwahduihdauwihdw");
|
||||
return;
|
||||
}
|
||||
|
||||
plane.refuel(diff);
|
||||
availableAmount[plane.getFuelType().ordinal()] -= diff;
|
||||
}
|
||||
|
||||
public void loadFuel(FuelType type, double amount) {
|
||||
availableAmount[type.ordinal()] = amount;
|
||||
}
|
||||
}
|
25
H05/src/main/java/h05/WeatherBalloon.java
Normal file
25
H05/src/main/java/h05/WeatherBalloon.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package h05;
|
||||
|
||||
import kotlin.Pair;
|
||||
|
||||
public class WeatherBalloon implements Flying {
|
||||
|
||||
private final int balloonNumber;
|
||||
|
||||
public WeatherBalloon(int balloonNumber) {
|
||||
this.balloonNumber = balloonNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "WeatherBalloon " + balloonNumber;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
Airspace.get().register(this);
|
||||
}
|
||||
|
||||
public void pop() {
|
||||
Airspace.get().deregister(this);
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package h07;
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
import h07.peano.NaturalNumber;
|
||||
import h07.peano.Successor;
|
||||
import h07.peano.Zero;
|
||||
|
||||
import static org.tudalgo.algoutils.student.Student.crash;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
testHeader("Multiplication Table");
|
||||
numberExpressionMultiplicationTableTests();
|
||||
|
||||
testHeader("Peano Number Expressions");
|
||||
peanoNumberExpressionTests();
|
||||
|
||||
testHeader("Filter, Fold, Map");
|
||||
filterFoldMapTests();
|
||||
}
|
||||
|
||||
@DoNotTouch
|
||||
private static void testHeader(String testName) {
|
||||
System.out.println("-----------------------------------");
|
||||
System.out.println("Running test: " + testName);
|
||||
System.out.println("-----------------------------------");
|
||||
}
|
||||
|
||||
@DoNotTouch
|
||||
private static void numberExpressionMultiplicationTableTests() {
|
||||
// TODO: H2.2 - uncomment to test
|
||||
// int lowerBound = 1;
|
||||
// int upperBound = 10;
|
||||
// NumberExpression[] multiplicationTable = NumberExpressionFactory.multiplicationTable(lowerBound, upperBound);
|
||||
//
|
||||
// for (int i = lowerBound; i <= upperBound; i++) {
|
||||
// for (int j = lowerBound; j <= upperBound; j++) {
|
||||
// System.out.printf("| %4s ", multiplicationTable[(i - lowerBound) * (upperBound - lowerBound + 1) + (j - lowerBound)].evaluate());
|
||||
// }
|
||||
// System.out.println("|");
|
||||
// }
|
||||
}
|
||||
|
||||
private static final NaturalNumber THREE = new Successor(new Successor(new Successor(new Zero())));
|
||||
private static final NaturalNumber SEVEN = new Successor(new Successor(new Successor(new Successor(new Successor(new Successor(new Successor(new Zero())))))));
|
||||
|
||||
@StudentImplementationRequired
|
||||
private static void peanoNumberExpressionTests() {
|
||||
crash(); // TODO: H3.3 - remove if implemented
|
||||
}
|
||||
|
||||
@StudentImplementationRequired
|
||||
private static void filterFoldMapTests() {
|
||||
crash(); // TODO: H4.6 - remove if implemented
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package h07;
|
||||
|
||||
import java.util.function.IntPredicate;
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
import static org.tudalgo.algoutils.student.Student.crash;
|
||||
|
||||
/**
|
||||
* A factory class for creating number expressions.
|
||||
*/
|
||||
public class NumberExpressionFactory {
|
||||
/**
|
||||
* Calculates the product of all possible pairs of numbers in the given array.
|
||||
*
|
||||
* @param numbers the array of number expressions to calculate the multiplication table
|
||||
* @return An array of number expressions representing the result of the
|
||||
* multiplication table of the given numbers.
|
||||
*/
|
||||
// @StudentImplementationRequired
|
||||
// public static NumberExpression[] multiplicationTable(NumberExpression[] numbers) {
|
||||
// return crash(); // TODO: H2.1 - remove if implemented
|
||||
// }
|
||||
|
||||
|
||||
// TODO: H2.2 - uncomment for testing
|
||||
/**
|
||||
* Calculates the product of all possible pairs of numbers in the given range.
|
||||
*
|
||||
* @param lowerBound the lower bound of the multiplication table, inclusive
|
||||
* @param upperBound the upper bound of the multiplication table, inclusive
|
||||
* @return An array of number expressions representing the result of the
|
||||
* multiplication table of the numbers from lowerBound to upperBound.
|
||||
*/
|
||||
// @DoNotTouch
|
||||
// public static NumberExpression[] multiplicationTable(int lowerBound, int upperBound) {
|
||||
// int numberOfNumbers = upperBound - lowerBound + 1;
|
||||
// NumberExpression[] baseNumbers = new NumberExpression[numberOfNumbers];
|
||||
//
|
||||
// for (int i = lowerBound; i <= upperBound; i++) {
|
||||
// // Copy to local variable to make it effectively final, so it can be used in
|
||||
// // lambda
|
||||
// int finalI = i;
|
||||
// baseNumbers[i - lowerBound] = () -> finalI;
|
||||
// }
|
||||
//
|
||||
// return multiplicationTable(baseNumbers);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Filters the given array of number expressions based on the given predicate.
|
||||
* The returned array should contain only the number expressions that satisfy
|
||||
* the predicate in the same order as they appear in the input array.
|
||||
* This means there should be no null values in the returned array.
|
||||
*
|
||||
* @param numbers the array of number expressions to filter
|
||||
* @param predicate the predicate to filter the number expressions
|
||||
* @return An array of number expressions that satisfy the predicate.
|
||||
*/
|
||||
// @StudentImplementationRequired
|
||||
// public static NumberExpression[] filter(NumberExpression[] numbers, IntPredicate predicate) {
|
||||
// return crash(); // TODO: H4.4 - remove if implemented
|
||||
// }
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package h07.peano;
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
|
||||
|
||||
/**
|
||||
* Represents a natural number.
|
||||
*/
|
||||
@DoNotTouch
|
||||
public abstract class NaturalNumber {
|
||||
/**
|
||||
* Returns the string representation of the natural number.
|
||||
*
|
||||
* @return the string representation of the natural number
|
||||
*/
|
||||
@Override
|
||||
public abstract String toString();
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package h07.peano;
|
||||
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
import static org.tudalgo.algoutils.student.Student.crash;
|
||||
|
||||
/**
|
||||
* Represents a factory for Peano number expressions.
|
||||
*/
|
||||
public class PeanoNumberExpressionFactory {
|
||||
/**
|
||||
* Converts an array of number expressions to an array of Peano number expressions.
|
||||
*
|
||||
* @param numberExpressions the number expressions to convert
|
||||
* @return the converted Peano number expressions
|
||||
*/
|
||||
// @StudentImplementationRequired
|
||||
// public static PeanoNumberExpression[] fromNumberExpressions(NumberExpression[] numberExpressions) {
|
||||
// return crash(); // TODO: H4.3 - remove if implemented
|
||||
// }
|
||||
|
||||
/**
|
||||
* Folds an array of Peano number expressions into a single Peano number expression.
|
||||
*
|
||||
* @param peanoNumberExpressions the Peano number expressions to fold
|
||||
* @param initial the initial Peano number expression
|
||||
* @param operation the operation to apply
|
||||
* @return the folded Peano number expression
|
||||
*/
|
||||
// @StudentImplementationRequired
|
||||
// public static PeanoNumberExpression fold(PeanoNumberExpression[] peanoNumberExpressions, PeanoNumberExpression initial, PeanoArithmeticExpression operation) {
|
||||
// return crash(); // TODO: H4.5 - remove if implemented
|
||||
// }
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package h07.peano;
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
|
||||
|
||||
/**
|
||||
* Represents a successor of a natural number in Peano arithmetic.
|
||||
*/
|
||||
@DoNotTouch
|
||||
public class Successor extends NaturalNumber {
|
||||
public final NaturalNumber predecessor;
|
||||
|
||||
public Successor(NaturalNumber predecessor) {
|
||||
this.predecessor = predecessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "S(" + predecessor.toString() + ")";
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package h07.peano;
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
|
||||
|
||||
/**
|
||||
* Represents the number zero in Peano arithmetic.
|
||||
*/
|
||||
@DoNotTouch
|
||||
public class Zero extends NaturalNumber {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Z";
|
||||
}
|
||||
}
|
0
H07/.gitignore → H08/.gitignore
vendored
0
H07/.gitignore → H08/.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
# Vorlage zu Hausübung 07
|
||||
# Vorlage zu Hausübung 08
|
||||
|
||||
Beachten Sie die Hinweise zum Herunterladen, Importieren, Bearbeitern, Exportieren und Hochladen in unserem
|
||||
[Studierenden-Guide](https://wiki.tudalgo.org/)
|
|
@ -5,7 +5,7 @@ plugins {
|
|||
}
|
||||
|
||||
exercise {
|
||||
assignmentId.set("h07")
|
||||
assignmentId.set("h08")
|
||||
}
|
||||
|
||||
submission {
|
||||
|
@ -31,3 +31,7 @@ tasks {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
applicationDefaultJvmArgs += "-ea"
|
||||
}
|
0
H07/gradlew → H08/gradlew
vendored
0
H07/gradlew → H08/gradlew
vendored
0
H07/gradlew.bat → H08/gradlew.bat
vendored
0
H07/gradlew.bat → H08/gradlew.bat
vendored
|
@ -8,4 +8,4 @@ dependencyResolutionManagement {
|
|||
}
|
||||
}
|
||||
|
||||
rootProject.name = "H07-Student"
|
||||
rootProject.name = "H08-Student"
|
114
H08/src/main/java/h08/Airport.java
Normal file
114
H08/src/main/java/h08/Airport.java
Normal file
|
@ -0,0 +1,114 @@
|
|||
package h08;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represents an airport. An airport manages departing and arriving flights, allowing for their addition, removal, and retrieval based on the airport code.
|
||||
*/
|
||||
public class Airport {
|
||||
|
||||
/**
|
||||
* The code of the airport.
|
||||
*/
|
||||
private String airportCode;
|
||||
|
||||
/**
|
||||
* The departing flights of the airport.
|
||||
*/
|
||||
private Flight[] departingFlights;
|
||||
|
||||
/**
|
||||
* The arriving flights to the airport.
|
||||
*/
|
||||
private Flight[] arrivingFlights;
|
||||
|
||||
/**
|
||||
* The number of departing flights of the airport.
|
||||
*/
|
||||
private int departingSize;
|
||||
|
||||
/**
|
||||
* The number of arriving flights to the airport.
|
||||
*/
|
||||
private int arrivingSize;
|
||||
|
||||
/**
|
||||
* Constructs a new airport with the specified airport code and initial capacity.
|
||||
*
|
||||
* @param airportCode the code of the airport
|
||||
* @param initialCapacity the initial capacity of the airport
|
||||
*/
|
||||
public Airport(String airportCode, int initialCapacity) {
|
||||
this.airportCode = airportCode;
|
||||
this.departingFlights = new Flight[initialCapacity];
|
||||
this.arrivingFlights = new Flight[initialCapacity];
|
||||
this.departingSize = 0;
|
||||
this.arrivingSize = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a flight.
|
||||
*
|
||||
* @param flight the flight to add
|
||||
* @param isDeparting if true, adds to departing flights, otherwise to arriving flights
|
||||
* @throws IllegalArgumentException if the flight's airport code doesn't match the airport's code
|
||||
*/
|
||||
public void addFlight(Flight flight, boolean isDeparting) {
|
||||
//TODO H8.4.1
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.4.1 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a flight by flight number.
|
||||
*
|
||||
* @param flightNumber the flight number
|
||||
* @param isDeparting if true, removes from departing flights, otherwise from arriving flights
|
||||
* @throws FlightNotFoundException if the flight is not found
|
||||
*/
|
||||
public void removeFlight(String flightNumber, boolean isDeparting) {
|
||||
//TODO H8.4.2
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.4.2 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flight by flight number.
|
||||
*
|
||||
* @param flightNumber the flight number
|
||||
* @param isDeparting if true, searches in departing flights, otherwise in arriving flights
|
||||
* @return the flight with the specified flight number
|
||||
* @throws FlightNotFoundException if the flight is not found
|
||||
*/
|
||||
public Flight getFlight(String flightNumber, boolean isDeparting) {
|
||||
//TODO H8.4.3
|
||||
return org.tudalgo.algoutils.student.Student.crash("H8.4.3 - Remove if implemented");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the departing flights of the airport.
|
||||
*
|
||||
* @return the departing flights of the airport
|
||||
*/
|
||||
public Flight[] getAllDepartingFlights() {
|
||||
return Arrays.copyOf(departingFlights, departingSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arriving flights to the airport.
|
||||
*
|
||||
* @return the arriving flights to the airport
|
||||
*/
|
||||
public Flight[] getAllArrivingFlights() {
|
||||
return Arrays.copyOf(arrivingFlights, arrivingSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the airport code.
|
||||
*
|
||||
* @return the airport code
|
||||
*/
|
||||
public String getAirportCode() {
|
||||
return airportCode;
|
||||
}
|
||||
}
|
97
H08/src/main/java/h08/Booking.java
Normal file
97
H08/src/main/java/h08/Booking.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package h08;
|
||||
|
||||
/**
|
||||
* Represents a flight booking. A booking allows the reservation of a flight as long as managing its identification and its relevant information.
|
||||
*/
|
||||
public class Booking {
|
||||
|
||||
/**
|
||||
* The booking ID of a booking.
|
||||
*/
|
||||
private String bookingId;
|
||||
|
||||
/**
|
||||
* The flight number of a booking.
|
||||
*/
|
||||
private String flightNumber;
|
||||
|
||||
/**
|
||||
* The passenger ID of a booking.
|
||||
*/
|
||||
private String passengerId;
|
||||
|
||||
/**
|
||||
* The cancellations status of a booking.
|
||||
*/
|
||||
private boolean isCancelled;
|
||||
|
||||
/**
|
||||
* Constructs a new booking with the specified booking ID, flight number and passenger ID.
|
||||
*
|
||||
* @param bookingId the booking ID of the booking
|
||||
* @param flightNumber the flight number of the booking
|
||||
* @param passengerId the passenger ID of the booking
|
||||
*/
|
||||
public Booking(String bookingId, String flightNumber, String passengerId) {
|
||||
this.bookingId = bookingId;
|
||||
this.flightNumber = flightNumber;
|
||||
this.passengerId = passengerId;
|
||||
this.isCancelled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the booking ID of the booking.
|
||||
*
|
||||
* @return the booking ID of the booking
|
||||
*/
|
||||
public String getBookingId() {
|
||||
return bookingId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flight number of the booking.
|
||||
*
|
||||
* @return the flight number of the booking
|
||||
*/
|
||||
public String getFlightNumber() {
|
||||
return flightNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the passenger ID of the booking.
|
||||
*
|
||||
* @return the passenger ID of the booking
|
||||
*/
|
||||
public String getPassengerId() {
|
||||
return passengerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cancellation status of the booking.
|
||||
*
|
||||
* @return the cancellation status of the booking
|
||||
*/
|
||||
public boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the booking.
|
||||
*
|
||||
* @throws BookingAlreadyCancelledException if the booking is already cancelled
|
||||
*/
|
||||
public void cancelBooking() {
|
||||
//TODO H8.4.4
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.4.4 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the booking details.
|
||||
*
|
||||
* @return the booking details
|
||||
*/
|
||||
public String viewBooking() {
|
||||
return String.format("Booking ID: %s, Flight Number: %s, Passenger ID: %s, Is Cancelled: %b",
|
||||
bookingId, flightNumber, passengerId, isCancelled);
|
||||
}
|
||||
}
|
93
H08/src/main/java/h08/BookingManagement.java
Normal file
93
H08/src/main/java/h08/BookingManagement.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
package h08;
|
||||
|
||||
/**
|
||||
* Represents a booking management. A booking management oversees booking operations, ensuring validity and handling duplicates.
|
||||
*/
|
||||
public class BookingManagement {
|
||||
|
||||
/**
|
||||
* The bookings to be managed.
|
||||
*/
|
||||
private Booking[] bookings;
|
||||
|
||||
/**
|
||||
* The current number of bookings.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* The flight management for the bookings.
|
||||
*/
|
||||
private FlightManagement flightManagement;
|
||||
|
||||
/**
|
||||
* Constructs a new booking management with the specified initial capacity and flight management.
|
||||
*
|
||||
* @param initialCapacity the initial number of bookings that can be managed
|
||||
* @param flightManagement the flight management for the bookings
|
||||
*/
|
||||
public BookingManagement(int initialCapacity, FlightManagement flightManagement) {
|
||||
this.bookings = new Booking[initialCapacity];
|
||||
this.size = 0;
|
||||
this.flightManagement = flightManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a booking.
|
||||
*
|
||||
* @param bookingId the booking ID of the booking
|
||||
* @param flightNumber the flight number of the booking
|
||||
* @param passengerId the passenger ID of the booking
|
||||
*/
|
||||
public void createBooking(String bookingId, String flightNumber, String passengerId) {
|
||||
//TODO H8.5.5
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.5.5 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the booking details and checks for duplicates.
|
||||
*
|
||||
* @param bookingId the booking ID of the booking
|
||||
* @param flightNumber the flight number of the booking
|
||||
* @param passengerId the passenger ID of the booking
|
||||
* @throws InvalidBookingException if the booking details are invalid
|
||||
* @throws DuplicateBookingException if the booking ID is already in use
|
||||
*/
|
||||
private void validateAndCheckBooking(String bookingId, String flightNumber, String passengerId){
|
||||
//TODO H8.5.2
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.5.2 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a booking by booking ID.
|
||||
*
|
||||
* @param bookingId the booking ID of the booking
|
||||
* @return the booking with the specified booking ID
|
||||
* @throws BookingNotFoundException if the booking ist not found
|
||||
*/
|
||||
private Booking searchBooking(String bookingId){
|
||||
//TODO H8.5.3
|
||||
return org.tudalgo.algoutils.student.Student.crash("H8.5.3 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a booking by booking ID.
|
||||
*
|
||||
* @param bookingId the booking ID of the booking
|
||||
* @return the booking with the specified booking ID
|
||||
*/
|
||||
public Booking getBooking(String bookingId) {
|
||||
//TODO H8.5.3
|
||||
return org.tudalgo.algoutils.student.Student.crash("H8.5.3 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a booking by booking ID.
|
||||
*
|
||||
* @param bookingId the booking ID of the booking
|
||||
*/
|
||||
public void cancelBooking(String bookingId) {
|
||||
//TODO H8.5.4
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.5.4 - Remove if implemented");
|
||||
}
|
||||
}
|
146
H08/src/main/java/h08/Flight.java
Normal file
146
H08/src/main/java/h08/Flight.java
Normal file
|
@ -0,0 +1,146 @@
|
|||
package h08;
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Represents a flight. A flight offers information such as the flight details and seat management.
|
||||
*/
|
||||
public class Flight {
|
||||
|
||||
/**
|
||||
* The flight number of the flight.
|
||||
*/
|
||||
private String flightNumber;
|
||||
|
||||
/**
|
||||
* The departure airport of the flight.
|
||||
*/
|
||||
private String departure;
|
||||
|
||||
/**
|
||||
* The destination airport of the flight.
|
||||
*/
|
||||
private String destination;
|
||||
|
||||
/**
|
||||
* The departure time of the flight.
|
||||
*/
|
||||
private LocalDateTime departureTime;
|
||||
|
||||
/**
|
||||
* The initial number of seats of the flight.
|
||||
*/
|
||||
private final int initialSeats;
|
||||
|
||||
/**
|
||||
* The number of available seats.
|
||||
*/
|
||||
private int availableSeats;
|
||||
|
||||
/**
|
||||
* Constructs a new flight with the specified flight number, departure airport, destination airport, departure time and initial number of seats.
|
||||
*
|
||||
* @param flightNumber the flight number of the flight
|
||||
* @param departure the departure airport of the flight
|
||||
* @param destination the destination airport of the flight
|
||||
* @param departureTime the departure time of the flight
|
||||
* @param initialSeats the initial number of seats of the flight
|
||||
*/
|
||||
public Flight(String flightNumber, String departure, String destination, LocalDateTime departureTime, int initialSeats) {
|
||||
//TODO H8.2.1
|
||||
this.flightNumber = flightNumber;
|
||||
this.departure = departure;
|
||||
this.destination = destination;
|
||||
this.departureTime = departureTime;
|
||||
this.initialSeats = initialSeats;
|
||||
this.availableSeats = initialSeats;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the flight number.
|
||||
*
|
||||
* @param flightNumber the flight number of the flight
|
||||
*/
|
||||
@StudentImplementationRequired("H8.2.1")
|
||||
public void validateFlightNumber(String flightNumber) {
|
||||
//TODO H8.2.1
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.2.1 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flight number of the flight.
|
||||
*
|
||||
* @return the flight number of the flight
|
||||
*/
|
||||
public String getFlightNumber() {
|
||||
return flightNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the departure airport of the flight.
|
||||
*
|
||||
* @return the departure airport of the flight
|
||||
*/
|
||||
public String getDeparture() {
|
||||
return departure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the destination airport of the flight.
|
||||
*
|
||||
* @return the destination airport of the flight
|
||||
*/
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the departure time of the flight.
|
||||
*
|
||||
* @return the departure time of the flight
|
||||
*/
|
||||
public String getDepartureTime() {
|
||||
return departureTime.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of available seats of the flight.
|
||||
*
|
||||
* @return the number of available seats of the flight
|
||||
*/
|
||||
public int getAvailableSeats() {
|
||||
return availableSeats;
|
||||
}
|
||||
|
||||
@StudentImplementationRequired("H8.2.2")
|
||||
public void bookSeat() {
|
||||
//TODO H8.2.2
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.2.2 - Remove if implemented");
|
||||
}
|
||||
|
||||
public void cancelSeat() {
|
||||
if (availableSeats < initialSeats) {
|
||||
availableSeats++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the flight.
|
||||
*
|
||||
* @return a string representation of the flight
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Flight{" +
|
||||
"flightNumber='" + flightNumber + '\'' +
|
||||
", departure='" + departure + '\'' +
|
||||
", destination='" + destination + '\'' +
|
||||
", departureTime=" + departureTime +
|
||||
", initialSeats=" + initialSeats +
|
||||
", availableSeats=" + availableSeats +
|
||||
'}';
|
||||
}
|
||||
}
|
106
H08/src/main/java/h08/FlightManagement.java
Normal file
106
H08/src/main/java/h08/FlightManagement.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
package h08;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represents a flight management. A flight management oversees the management of flights and airports.
|
||||
*/
|
||||
public class FlightManagement {
|
||||
|
||||
/**
|
||||
* The airports whose flights are managed.
|
||||
*/
|
||||
private Airport[] airports;
|
||||
|
||||
/**
|
||||
* The current number of airports whose flights are managed.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Constructs a new flight management with the specified initial capacity.
|
||||
*
|
||||
* @param initialCapacity the initial capacity
|
||||
*/
|
||||
public FlightManagement(int initialCapacity) {
|
||||
this.airports = new Airport[initialCapacity];
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an airport to the flight management.
|
||||
*
|
||||
* @param airport the airport to be added
|
||||
*/
|
||||
public void addAirport(Airport airport) {
|
||||
if (size >= airports.length) {
|
||||
airports = Arrays.copyOf(airports, airports.length * 2);
|
||||
}
|
||||
airports[size++] = airport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the addition or removal of a flight for a specific airport.
|
||||
*
|
||||
* @param airportCode the airport code where the flight should be managed
|
||||
* @param flight the flight to be added or removed
|
||||
* @param isAddOperation if true, the flight will be added; if false, the flight will be removed
|
||||
*/
|
||||
public void manageFlight(String airportCode, Flight flight, boolean isAddOperation) {
|
||||
//TODO H8.5.2
|
||||
org.tudalgo.algoutils.student.Student.crash("H8.5.2 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flight from a specific airport.
|
||||
*
|
||||
* @param airportCode the airport code from which the flight should be returned
|
||||
* @param flightNumber the flight number of the flight
|
||||
* @return a flight from a specific airport
|
||||
*/
|
||||
public Flight getFlight(String airportCode, String flightNumber){
|
||||
//TODO H8.5.1
|
||||
return org.tudalgo.algoutils.student.Student.crash("H8.5.1 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flight with a specified flight number.
|
||||
*
|
||||
* @param flightNumber the flight number of the flight
|
||||
* @return a flight with a specified flight number
|
||||
*/
|
||||
public Flight getFlight(String flightNumber){
|
||||
for (int i = 0; i < size; i++) {
|
||||
Flight flight = searchFlight(airports[i], flightNumber);
|
||||
if (flight != null) {
|
||||
return flight;
|
||||
}
|
||||
}
|
||||
System.out.println("Error retrieving flight: Flight not found: " + flightNumber);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for an airport by airport code.
|
||||
*
|
||||
* @param airportCode the airport code
|
||||
* @return an airport by airport code
|
||||
* @throws Exception if the airport ist not found
|
||||
*/
|
||||
private Airport searchAirport(String airportCode) {
|
||||
//TODO H8.5.1
|
||||
return org.tudalgo.algoutils.student.Student.crash("H8.5.1 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a flight in departing or arriving flights.
|
||||
*
|
||||
* @param airport the airport in which the flight should be searched
|
||||
* @param flightNumber the flight number of the flight
|
||||
* @return a flight in departing or arriving flights
|
||||
*/
|
||||
private Flight searchFlight(Airport airport, String flightNumber) {
|
||||
//TODO H8.5.1
|
||||
return org.tudalgo.algoutils.student.Student.crash("H8.5.1 - Remove if implemented");
|
||||
}
|
||||
}
|
15
H08/src/main/java/h08/Main.java
Normal file
15
H08/src/main/java/h08/Main.java
Normal file
|
@ -0,0 +1,15 @@
|
|||
package h08;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
System.out.println("Hello World!");
|
||||
}
|
||||
}
|
111
H08/src/main/java/h08/Passenger.java
Normal file
111
H08/src/main/java/h08/Passenger.java
Normal file
|
@ -0,0 +1,111 @@
|
|||
package h08;
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Represents a passenger. A Passenger represents an individual with personal details and a unique identifier.
|
||||
*/
|
||||
public class Passenger {
|
||||
|
||||
/**
|
||||
* The ID of the passenger.
|
||||
*/
|
||||
private String passengerID;
|
||||
|
||||
/**
|
||||
* The first name of the passenger.
|
||||
*/
|
||||
private String firstName;
|
||||
|
||||
/**
|
||||
* The last name of the passenger.
|
||||
*/
|
||||
private String lastName;
|
||||
|
||||
/**
|
||||
* The date of birth of the passenger.
|
||||
*/
|
||||
private LocalDate dateOfBirth;
|
||||
|
||||
/**
|
||||
* Constructs a new passenger with the specified first name, last name and date of birth.
|
||||
*
|
||||
* @param firstName the first name of the passenger
|
||||
* @param lastName the last name of the passenger
|
||||
* @param dateOfBirth the date of birth of the passenger
|
||||
*/
|
||||
public Passenger(String firstName, String lastName, LocalDate dateOfBirth) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.dateOfBirth = dateOfBirth;
|
||||
this.passengerID = generatePassengerID(firstName, lastName, dateOfBirth);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generated ID of the passenger.
|
||||
*
|
||||
* @param firstName the first name of the passenger
|
||||
* @param lastName the last name of the passenger
|
||||
* @param dateOfBirth the date of birth of the passenger
|
||||
* @return the generated ID of the passenger
|
||||
*/
|
||||
@StudentImplementationRequired("H8.1")
|
||||
private String generatePassengerID(String firstName, String lastName, LocalDate dateOfBirth) {
|
||||
//TODO H8.1
|
||||
return org.tudalgo.algoutils.student.Student.crash("H8.1 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the passenger.
|
||||
*
|
||||
* @return the ID of the passenger
|
||||
*/
|
||||
public String getPassengerID() {
|
||||
return passengerID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first name of the passenger.
|
||||
*
|
||||
* @return the first name of the passenger
|
||||
*/
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last name of the passenger.
|
||||
*
|
||||
* @return the last name of the passenger
|
||||
*/
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date of birth of the passenger.
|
||||
*
|
||||
* @return the date of birth of the passenger
|
||||
*/
|
||||
public LocalDate getDateOfBirth() {
|
||||
return dateOfBirth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the passenger.
|
||||
*
|
||||
* @return a string representation of the passenger
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Passenger{" +
|
||||
"passengerID='" + passengerID + '\'' +
|
||||
", firstName='" + firstName + '\'' +
|
||||
", lastName='" + lastName + '\'' +
|
||||
", dateOfBirth=" + dateOfBirth +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package h07;
|
||||
package h08;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
88
H09/.gitignore
vendored
Normal file
88
H09/.gitignore
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
### Intellij ###
|
||||
.idea/
|
||||
*.iws
|
||||
/out/
|
||||
*.iml
|
||||
.idea_modules/
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
### VS-Code ###
|
||||
.vscode/
|
||||
.VSCodeCounter/
|
||||
|
||||
### Eclipse ###
|
||||
.metadata
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.recommenders
|
||||
.externalToolBuilders/
|
||||
*.launch
|
||||
.factorypath
|
||||
.recommenders/
|
||||
.apt_generated/
|
||||
.project
|
||||
.classpath
|
||||
|
||||
### Linux ###
|
||||
*~
|
||||
.fuse_hidden*
|
||||
.directory
|
||||
.Trash-*
|
||||
.nfs*
|
||||
|
||||
### macOS ###
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
Icon
|
||||
._*
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
||||
|
||||
### Windows ###
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
*.stackdump
|
||||
[Dd]esktop.ini
|
||||
$RECYCLE.BIN/
|
||||
*.lnk
|
||||
|
||||
### Gradle ###
|
||||
.gradle
|
||||
/build/
|
||||
out/
|
||||
gradle-app.setting
|
||||
!gradle-wrapper.jar
|
||||
.gradletasknamecache
|
||||
|
||||
*.hprof
|
||||
screenshots
|
||||
|
||||
jagr.conf
|
|
@ -1,4 +1,4 @@
|
|||
# Musterlösung zu Hausübung 07
|
||||
# Vorlage zu Hausübung 09
|
||||
|
||||
Beachten Sie die Hinweise zum Herunterladen, Importieren, Bearbeitern, Exportieren und Hochladen in unserem
|
||||
[Studierenden-Guide](https://wiki.tudalgo.org/)
|
33
H09/build.gradle.kts
Normal file
33
H09/build.gradle.kts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import org.sourcegrade.jagr.gradle.task.grader.GraderRunTask
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.algomate)
|
||||
}
|
||||
|
||||
exercise {
|
||||
assignmentId.set("h09")
|
||||
}
|
||||
|
||||
submission {
|
||||
// ACHTUNG!
|
||||
// Setzen Sie im folgenden Bereich Ihre TU-ID (NICHT Ihre Matrikelnummer!), Ihren Nachnamen und Ihren Vornamen
|
||||
// in Anführungszeichen (z.B. "ab12cdef" für Ihre TU-ID) ein!
|
||||
// BEISPIEL:
|
||||
// studentId = "ab12cdef"
|
||||
// firstName = "sol_first"
|
||||
// lastName = "sol_last"
|
||||
studentId = ""
|
||||
firstName = ""
|
||||
lastName = ""
|
||||
|
||||
// Optionally require own tests for mainBuildSubmission task. Default is false
|
||||
requireTests = false
|
||||
}
|
||||
|
||||
jagr {
|
||||
graders {
|
||||
val graderPublic by getting {
|
||||
rubricProviderName.set("h09.H09_RubricProviderPublic")
|
||||
}
|
||||
}
|
||||
}
|
2
H09/gradle/libs.versions.toml
Normal file
2
H09/gradle/libs.versions.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[plugins]
|
||||
algomate = { id = "org.tudalgo.algomate", version = "0.7.1" }
|
BIN
H09/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
H09/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
H09/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
H09/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
249
H09/gradlew
vendored
Executable file
249
H09/gradlew
vendored
Executable file
|
@ -0,0 +1,249 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
H09/gradlew.bat
vendored
Normal file
92
H09/gradlew.bat
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
11
H09/settings.gradle.kts
Normal file
11
H09/settings.gradle.kts
Normal file
|
@ -0,0 +1,11 @@
|
|||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
// mavenLocal()
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots")
|
||||
maven("https://jitpack.io")
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "H09-Student"
|
149
H09/src/graderPublic/java/h09/EnclosureTestPublic.java
Normal file
149
H09/src/graderPublic/java/h09/EnclosureTestPublic.java
Normal file
|
@ -0,0 +1,149 @@
|
|||
package h09;
|
||||
|
||||
import h09.abilities.Swims;
|
||||
import h09.animals.Animal;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
|
||||
import org.tudalgo.algoutils.tutor.general.assertions.Context;
|
||||
import org.tudalgo.algoutils.tutor.general.reflections.BasicTypeLink;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static h09.H09_TestUtils.assertDefinedParameters;
|
||||
import static h09.H09_TestUtils.assertParameters;
|
||||
import static h09.H09_TestUtils.assertReturnParameter;
|
||||
import static h09.H09_TestUtils.assertType;
|
||||
import static h09.H09_TestUtils.getDefinedTypes;
|
||||
import static h09.H09_TestUtils.match;
|
||||
import static h09.H09_TestUtils.matchNested;
|
||||
import static h09.H09_TestUtils.matchUpperBounds;
|
||||
import static h09.H09_TestUtils.matchWildcard;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertEquals;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertNotNull;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.fail;
|
||||
import static org.tudalgo.algoutils.tutor.general.match.BasicStringMatchers.identical;
|
||||
|
||||
@TestForSubmission
|
||||
public class EnclosureTestPublic {
|
||||
|
||||
BasicTypeLink enclosureLink;
|
||||
Method getStack;
|
||||
Method forEach;
|
||||
Method filterObj;
|
||||
Method filterFunc;
|
||||
Method eatAndSink;
|
||||
Field swimsAtLowElevation;
|
||||
Field feedAndSleep;
|
||||
|
||||
@BeforeEach
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setUp() {
|
||||
enclosureLink = BasicTypeLink.of(Enclosure.class);
|
||||
|
||||
getStack = enclosureLink.getMethod(identical("getStack")).reflection();
|
||||
forEach = enclosureLink.getMethod(identical("forEach")).reflection();
|
||||
filterObj = enclosureLink.getMethod(identical("filterObj")).reflection();
|
||||
filterFunc = enclosureLink.getMethod(identical("filterFunc")).reflection();
|
||||
eatAndSink = enclosureLink.getMethod(identical("EAT_AND_SINK")).reflection();
|
||||
|
||||
swimsAtLowElevation = enclosureLink.getField(identical("SWIMS_AT_LOW_ELEVATION")).reflection();
|
||||
feedAndSleep = enclosureLink.getField(identical("FEED_AND_SLEEP")).reflection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassParameter() {
|
||||
assertDefinedParameters(Enclosure.class, Set.of(matchUpperBounds("A", Animal.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStack_ReturnType() {
|
||||
Predicate<Type> typeMatcher = getDefinedTypes(Enclosure.class, ".*").stream()
|
||||
.map(H09_TestUtils::match)
|
||||
.reduce(Predicate::or)
|
||||
.orElse(new H09_TestUtils.GenericPredicate(i -> false, "Expected type is not defined"));
|
||||
|
||||
assertReturnParameter(getStack, matchNested(StackOfObjects.class, typeMatcher));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach_Parameter() {
|
||||
Predicate<Type> typeMatcher = getDefinedTypes(Enclosure.class, ".*").stream()
|
||||
.map(type -> matchWildcard(false, type))
|
||||
.reduce(Predicate::or)
|
||||
.orElse(new H09_TestUtils.GenericPredicate(i -> false, "Expected type is not defined"));
|
||||
|
||||
assertParameters(forEach, List.of(matchNested(Consumer.class, typeMatcher)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSWIMS_AT_LOW_ELEVATION_Type() {
|
||||
assertType(swimsAtLowElevation, matchNested(Predicate.class, match(Swims.class)));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({"5,false", "-3,false", "-5,true", "-5,true"})
|
||||
public void testSWIMS_AT_LOW_ELEVATION_Implementation(float elevation, boolean predicateResult) {
|
||||
assertNotNull(Enclosure.SWIMS_AT_LOW_ELEVATION, emptyContext(), r -> "SWIMS_AT_LOW_ELEVATION is not implemented");
|
||||
|
||||
try {
|
||||
Swims mock = mock(Swims.class);
|
||||
when(mock.getElevation()).thenReturn(elevation);
|
||||
|
||||
Context context = contextBuilder().add("elevation", elevation).build();
|
||||
|
||||
assertEquals(
|
||||
predicateResult,
|
||||
Enclosure.SWIMS_AT_LOW_ELEVATION.test(mock),
|
||||
context,
|
||||
r -> "SWIMS_AT_LOW_ELEVATION is not implemented correctly"
|
||||
);
|
||||
|
||||
} catch (ClassCastException exception) {
|
||||
fail(
|
||||
emptyContext(),
|
||||
r -> "SWIMS_AT_LOW_ELEVATION does not accept correct type of objects. Message of thrown Exception: %s".formatted(
|
||||
exception.getMessage())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFEED_AND_SLEEP_Type() {
|
||||
assertType(feedAndSleep, matchNested(Consumer.class, match(Animal.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFEED_AND_SLEEP_Implementation() {
|
||||
assertNotNull(Enclosure.FEED_AND_SLEEP, emptyContext(), r -> "FEED_AND_SLEEP is not implemented");
|
||||
|
||||
try {
|
||||
Animal mock = mock(Animal.class);
|
||||
|
||||
Enclosure.FEED_AND_SLEEP.accept(mock);
|
||||
|
||||
verify(mock, atLeastOnce()).eat();
|
||||
verify(mock, atLeastOnce()).sleep();
|
||||
|
||||
} catch (ClassCastException exception) {
|
||||
fail(
|
||||
emptyContext(),
|
||||
r -> "FEED_AND_SLEEP does not accept correct type of objects. Message of thrown Exception: %s".formatted(exception.getMessage())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
152
H09/src/graderPublic/java/h09/H09_RubricProviderPublic.java
Normal file
152
H09/src/graderPublic/java/h09/H09_RubricProviderPublic.java
Normal file
|
@ -0,0 +1,152 @@
|
|||
package h09;
|
||||
|
||||
import org.sourcegrade.jagr.api.rubric.Criterion;
|
||||
import org.sourcegrade.jagr.api.rubric.JUnitTestRef;
|
||||
import org.sourcegrade.jagr.api.rubric.Rubric;
|
||||
import org.sourcegrade.jagr.api.rubric.RubricProvider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.tudalgo.algoutils.tutor.general.jagr.RubricUtils.criterion;
|
||||
import static org.tudalgo.algoutils.tutor.general.jagr.RubricUtils.graderPrivateOnly;
|
||||
|
||||
public class H09_RubricProviderPublic implements RubricProvider {
|
||||
|
||||
public static final Rubric RUBRIC = Rubric.builder()
|
||||
.title("H09")
|
||||
.addChildCriteria(
|
||||
Criterion.builder()
|
||||
.shortDescription("H9.1 | StackOfObjects")
|
||||
.addChildCriteria(
|
||||
criterion(
|
||||
"Der generische Typparameter O wird korrekt deklariert und das Attribut objs wird korrekt initialisiert.",
|
||||
JUnitTestRef.and(
|
||||
JUnitTestRef.ofMethod(() -> StackOfObjectsTestPublic.class.getMethod("testClassParameter")),
|
||||
JUnitTestRef.ofMethod(() -> StackOfObjectsTestPublic.class.getMethod("testObjsType"))
|
||||
)
|
||||
),
|
||||
criterion(
|
||||
"push wird korrekt mit generischem Typparameter angepasst.",
|
||||
JUnitTestRef.ofMethod(() -> StackOfObjectsTestPublic.class.getMethod("testPushParameter"))
|
||||
),
|
||||
criterion(
|
||||
"remove wird korrekt mit generischem Typparameter angepasst.",
|
||||
JUnitTestRef.ofMethod(() -> StackOfObjectsTestPublic.class.getMethod("testRemoveParameter"))
|
||||
),
|
||||
criterion(
|
||||
"get und pop werden korrekt mit generischem Typparameter angepasst.",
|
||||
JUnitTestRef.and(
|
||||
JUnitTestRef.ofMethod(() -> StackOfObjectsTestPublic.class.getMethod("testGetParameter")),
|
||||
JUnitTestRef.ofMethod(() -> StackOfObjectsTestPublic.class.getMethod("testPopParameter"))
|
||||
)
|
||||
),
|
||||
criterion(
|
||||
"of wird korrekt mit generischem Typparameter angepasst.",
|
||||
JUnitTestRef.ofMethod(() -> StackOfObjectsTestPublic.class.getMethod("testOfParameter"))
|
||||
, 2
|
||||
)
|
||||
)
|
||||
.build(),
|
||||
Criterion.builder()
|
||||
.shortDescription("H9.2 | Generische Typen beschränken")
|
||||
.addChildCriteria(
|
||||
criterion(
|
||||
"Der generische Typparameter von Enclosure wird korrekt deklariert und beschränkt.",
|
||||
JUnitTestRef.ofMethod(() -> EnclosureTestPublic.class.getMethod("testClassParameter"))
|
||||
),
|
||||
criterion(
|
||||
"Enclosure::getStack von Enclosure wird korrekt mit generischem Typparameter angepasst.",
|
||||
JUnitTestRef.ofMethod(() -> EnclosureTestPublic.class.getMethod("testGetStack_ReturnType"))
|
||||
),
|
||||
privateCriterion(
|
||||
"Waterenclosure besitzt einen korrekt beschränkten Typparameter und implementiert Enclosure korrekt.",
|
||||
0,
|
||||
1
|
||||
),
|
||||
privateCriterion("Waterenclosure::getStack funktioniert korrekt.", 0, 1),
|
||||
criterion(
|
||||
"Waterenclosure::feed funktioniert korrekt.",
|
||||
JUnitTestRef.ofMethod(() -> WaterEnclosureTestPublic.class.getMethod("testFeed"))
|
||||
, 2
|
||||
),
|
||||
criterion(
|
||||
"Waterenclosure::getMeanElevation funktioniert korrekt.",
|
||||
JUnitTestRef.ofMethod(() -> WaterEnclosureTestPublic.class.getMethod(
|
||||
"testGetMeanElevation",
|
||||
List.class,
|
||||
double.class
|
||||
))
|
||||
)
|
||||
)
|
||||
.build(),
|
||||
Criterion.builder()
|
||||
.shortDescription("H9.3 | Bearbeitung von Enclosures mit funktionalen Interfaces")
|
||||
.addChildCriteria(
|
||||
criterion(
|
||||
"forEach hat korrekt beschränkte Typparameter.",
|
||||
JUnitTestRef.ofMethod(() -> EnclosureTestPublic.class.getMethod("testForEach_Parameter")),
|
||||
3
|
||||
),
|
||||
privateCriterion("filterObj hat korrekt beschränkte Typparameter.", 0, 3),
|
||||
privateCriterion("filterFunc hat korrekt beschränkte Typparameter.", 0, 4),
|
||||
privateCriterion("filterFunc gibt korrekt ein neues Enclosure mit gefilterten Tieren zurück.", 0, 2)
|
||||
)
|
||||
.build(),
|
||||
Criterion.builder()
|
||||
.shortDescription("H9.4 | Predicates and Consumer mit Lambda")
|
||||
.addChildCriteria(
|
||||
criterion(
|
||||
"SWIMS_AT_LOW_ELEVATION funktioniert korrekt und wurde korrekt beschränkt.",
|
||||
JUnitTestRef.and(
|
||||
JUnitTestRef.ofMethod(() -> EnclosureTestPublic.class.getMethod("testSWIMS_AT_LOW_ELEVATION_Type")),
|
||||
JUnitTestRef.ofMethod(() -> EnclosureTestPublic.class.getMethod(
|
||||
"testSWIMS_AT_LOW_ELEVATION_Implementation",
|
||||
float.class,
|
||||
boolean.class
|
||||
))
|
||||
)
|
||||
),
|
||||
criterion(
|
||||
"FEED_AND_SLEEP funktioniert korrekt und wurde korrekt beschränkt.",
|
||||
JUnitTestRef.and(
|
||||
JUnitTestRef.ofMethod(() -> EnclosureTestPublic.class.getMethod("testFEED_AND_SLEEP_Type")),
|
||||
JUnitTestRef.ofMethod(() -> EnclosureTestPublic.class.getMethod("testFEED_AND_SLEEP_Implementation"))
|
||||
)
|
||||
),
|
||||
privateCriterion("EAT_AND_SINK() gibt einen korrekten Consumer zurück, welcher korrekt beschränkt ist.", 0, 2)
|
||||
)
|
||||
.build(),
|
||||
Criterion.builder()
|
||||
.shortDescription("H9.5 | Enclosure::forEach")
|
||||
.addChildCriteria(
|
||||
privateCriterion(
|
||||
"Drei Lion Objekte werden erstellt sowie gefüttert. Die Methode forEach wird grundlegend getestet.",
|
||||
0,
|
||||
1
|
||||
),
|
||||
privateCriterion("Zwei Penguin Objekte werden korrekt erstellt, bewegt und gefüttert.", 0, 1),
|
||||
privateCriterion("Einfache Fehlfunktionen der Methode filterFunc werden erkannt.", 0, 1)
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public Rubric getRubric() {
|
||||
return RUBRIC;
|
||||
}
|
||||
|
||||
public static Criterion privateCriterion(String message, int min, int max) {
|
||||
return Criterion.builder()
|
||||
.shortDescription(message)
|
||||
.grader(graderPrivateOnly(max))
|
||||
.minPoints(min)
|
||||
.maxPoints(max)
|
||||
.build();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void configure(final RubricConfiguration configuration) {
|
||||
// configuration.addTransformer(new AccessTransformer());
|
||||
// }
|
||||
}
|
689
H09/src/graderPublic/java/h09/H09_TestUtils.java
Normal file
689
H09/src/graderPublic/java/h09/H09_TestUtils.java
Normal file
|
@ -0,0 +1,689 @@
|
|||
package h09;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.tudalgo.algoutils.tutor.general.assertions.Context;
|
||||
import org.tudalgo.algoutils.tutor.general.reflections.BasicMethodLink;
|
||||
import org.tudalgo.algoutils.tutor.general.reflections.BasicTypeLink;
|
||||
import spoon.reflect.declaration.CtField;
|
||||
import spoon.reflect.declaration.CtMethod;
|
||||
import spoon.reflect.declaration.CtParameter;
|
||||
import spoon.reflect.declaration.CtType;
|
||||
import spoon.reflect.declaration.CtTypeParameter;
|
||||
import spoon.reflect.reference.CtTypeReference;
|
||||
import spoon.reflect.visitor.filter.TypeFilter;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertEquals;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
|
||||
|
||||
public class H09_TestUtils {
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it has the given name and no bounds.
|
||||
*
|
||||
* @param name the name of the Type that should be matched. Also accepts a regex for the name.
|
||||
* @return a Predicate that matches a Type with the given name.
|
||||
*/
|
||||
public static Predicate<Type> matchNoBounds(String name) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
Pair<List<Type>, List<Type>> bounds = getBounds(type);
|
||||
if (!type.getTypeName().matches(name)) {
|
||||
return false;
|
||||
}
|
||||
if (bounds.getLeft() != null) {
|
||||
return false;
|
||||
}
|
||||
return bounds.getRight().size() == 1 && bounds.getRight().get(0) == Object.class;
|
||||
},
|
||||
String.format("Name: %s; Bounds: No Bounds", name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it has the given name and bounds.
|
||||
*
|
||||
* @param name the name of the Type that should be matched. Also accepts a regex for the name.
|
||||
* @param expectedBounds the lower Bounds that a type should have to be matched by this Predicate.
|
||||
* @return a Predicate that matches a Type with the given name and bounds.
|
||||
*/
|
||||
public static Predicate<Type> matchLowerBounds(String name, Type... expectedBounds) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
Pair<List<Type>, List<Type>> bounds = getBounds(type);
|
||||
if (!type.getTypeName().matches(name)) {
|
||||
return false;
|
||||
}
|
||||
return bounds.getLeft().size() == expectedBounds.length
|
||||
&& new HashSet<>(bounds.getLeft()).containsAll(List.of(expectedBounds));
|
||||
},
|
||||
String.format(
|
||||
"Name: %s; Bounds: %s",
|
||||
name,
|
||||
Arrays.stream(expectedBounds).map(Type::getTypeName).collect(Collectors.joining(", "))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it has the given name and bounds.
|
||||
*
|
||||
* @param name the name of the Type that should be matched. Also accepts a regex for the name.
|
||||
* @param expectedBounds the upper Bounds that a type should have to be matched by this Predicate.
|
||||
* @return a Predicate that matches a Type with the given name and bounds.
|
||||
*/
|
||||
public static Predicate<Type> matchLowerBounds(String name, Predicate<Type>... expectedBounds) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
Pair<List<Type>, List<Type>> bounds = getBounds(type);
|
||||
if (!type.getTypeName().matches(name)) {
|
||||
return false;
|
||||
}
|
||||
return bounds.getLeft().size() == expectedBounds.length
|
||||
&& bounds.getLeft()
|
||||
.stream()
|
||||
.allMatch(actual -> Stream.of(expectedBounds).anyMatch(expected -> expected.test(actual)))
|
||||
&& Stream.of(expectedBounds).allMatch(expected -> bounds.getLeft().stream().anyMatch(expected));
|
||||
},
|
||||
String.format(
|
||||
"Name: %s; Bounds: %s",
|
||||
name,
|
||||
Arrays.stream(expectedBounds).map(Object::toString).collect(Collectors.joining(", "))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it has the given name and bounds.
|
||||
*
|
||||
* @param name the name of the Type that should be matched. Also accepts a regex for the name.
|
||||
* @param expectedBounds the upper Bounds that a type should have to be matched by this Predicate.
|
||||
* @return a Predicate that matches a Type with the given name and bounds.
|
||||
*/
|
||||
public static Predicate<Type> matchUpperBounds(String name, Type... expectedBounds) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
Pair<List<Type>, List<Type>> bounds = getBounds(type);
|
||||
if (!type.getTypeName().matches(name)) {
|
||||
return false;
|
||||
}
|
||||
return bounds.getRight().size() == expectedBounds.length
|
||||
&& new HashSet<>(bounds.getRight()).containsAll(List.of(expectedBounds));
|
||||
},
|
||||
String.format(
|
||||
"Name: %s; Bounds: %s",
|
||||
name,
|
||||
Arrays.stream(expectedBounds).map(Type::getTypeName).collect(Collectors.joining(", "))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it has the given name and bounds.
|
||||
*
|
||||
* @param name the name of the Type that should be matched. Also accepts a regex for the name.
|
||||
* @param expectedBounds the upper Bounds that a type should have to be matched by this Predicate.
|
||||
* @return a Predicate that matches a Type with the given name and bounds.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static Predicate<Type> matchUpperBounds(String name, Predicate<Type>... expectedBounds) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
Pair<List<Type>, List<Type>> bounds = getBounds(type);
|
||||
if (!type.getTypeName().matches(name)) {
|
||||
return false;
|
||||
}
|
||||
return bounds.getRight().size() == expectedBounds.length
|
||||
&& bounds.getRight()
|
||||
.stream()
|
||||
.allMatch(actual -> Stream.of(expectedBounds).anyMatch(expected -> expected.test(actual)))
|
||||
&& Stream.of(expectedBounds).allMatch(expected -> bounds.getRight().stream().anyMatch(expected));
|
||||
},
|
||||
String.format(
|
||||
"Name: %s; Bounds: %s",
|
||||
name,
|
||||
Arrays.stream(expectedBounds).map(Object::toString).collect(Collectors.joining(", "))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it is a wildcard type and has the given bounds.
|
||||
*
|
||||
* @param isUpperBound indicates if the given Bounds should be the upper or lower bounds of the type
|
||||
* @param expectedBounds the expected Bounds that a type should have to be matched by this Predicate.
|
||||
* @return a Predicate that matches a wildcard type with the given bounds.
|
||||
*/
|
||||
public static Predicate<Type> matchWildcard(boolean isUpperBound, Type... expectedBounds) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
Pair<List<Type>, List<Type>> bounds = getBounds(type);
|
||||
if (!(type instanceof WildcardType wildcardType)) {
|
||||
return false;
|
||||
}
|
||||
if (isUpperBound) {
|
||||
return bounds.getRight().size() == expectedBounds.length &&
|
||||
new HashSet<>(bounds.getRight()).containsAll(List.of(expectedBounds));
|
||||
}
|
||||
return bounds.getLeft().size() == expectedBounds.length &&
|
||||
new HashSet<>(bounds.getLeft()).containsAll(List.of(expectedBounds));
|
||||
},
|
||||
String.format(
|
||||
"Wildcard: ? %s %s",
|
||||
isUpperBound ? "extends" : "super",
|
||||
Arrays.stream(expectedBounds).map(Type::getTypeName).collect(Collectors.joining(" & "))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it is a wildcard type and has the given bounds.
|
||||
*
|
||||
* @param isUpperBound indicates if the given Bounds should be the upper or lower bounds of the type
|
||||
* @param expectedBounds the expected Bounds that a type should have to be matched by this Predicate.
|
||||
* @return a Predicate that matches a wildcard type with the given bounds.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static Predicate<Type> matchWildcard(boolean isUpperBound, Predicate<Type>... expectedBounds) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
Pair<List<Type>, List<Type>> bounds = getBounds(type);
|
||||
if (!(type instanceof WildcardType wildcardType)) {
|
||||
return false;
|
||||
}
|
||||
if (isUpperBound) {
|
||||
return bounds.getRight().size() == expectedBounds.length
|
||||
&& bounds.getRight()
|
||||
.stream()
|
||||
.allMatch(actual -> Stream.of(expectedBounds).anyMatch(expected -> expected.test(actual)))
|
||||
&& Stream.of(expectedBounds).allMatch(expected -> bounds.getRight().stream().anyMatch(expected));
|
||||
}
|
||||
return bounds.getLeft().size() == expectedBounds.length
|
||||
&& bounds.getLeft()
|
||||
.stream()
|
||||
.allMatch(actual -> Stream.of(expectedBounds).anyMatch(expected -> expected.test(actual)))
|
||||
&& Stream.of(expectedBounds).allMatch(expected -> bounds.getLeft().stream().anyMatch(expected));
|
||||
},
|
||||
String.format(
|
||||
"Wildcard: ? %s %s",
|
||||
isUpperBound ? "extends" : "super",
|
||||
Arrays.stream(expectedBounds).map(Object::toString).collect(Collectors.joining(" & "))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it is an exact match with the given Type.
|
||||
*
|
||||
* @param expected the type that is expected.
|
||||
* @return the Predicate matching the expected type.
|
||||
*/
|
||||
public static Predicate<Type> match(Type expected) {
|
||||
return new GenericPredicate(
|
||||
(type) -> type.equals(expected),
|
||||
String.format("Type: %s", expected.getTypeName())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it is a match with an array of the given Type.
|
||||
*
|
||||
* @param expected the type that is expected.
|
||||
* @return the Predicate matching the expected type.
|
||||
*/
|
||||
public static Predicate<Type> matchArray(Type expected) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
if (type instanceof GenericArrayType arrayType) {
|
||||
return arrayType.getGenericComponentType().equals(expected);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
String.format("Type: %s", expected.getTypeName())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it is a match with an array of the given Type.
|
||||
*
|
||||
* @param expected the type that is expected.
|
||||
* @return the Predicate matching the expected type.
|
||||
*/
|
||||
public static Predicate<Type> matchArray(Predicate<Type> expected) {
|
||||
return new GenericPredicate(
|
||||
(type) -> {
|
||||
if (type instanceof GenericArrayType arrayType) {
|
||||
return expected.test(arrayType.getGenericComponentType());
|
||||
}
|
||||
return false;
|
||||
},
|
||||
String.format("Type: %s", expected.toString())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate that matches a Type if it has the expected outer Type and the inner Types all match the
|
||||
* expectedNested types
|
||||
*
|
||||
* @param outerType the Type of the outer type.
|
||||
* @param expectedNested an array of predicates for all inner types that should be matched.
|
||||
* @return a predicate that checks the outer and inner types of a ParameterizedType.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static Predicate<Type> matchNested(Type outerType, Predicate<Type>... expectedNested) {
|
||||
return new Predicate<>() {
|
||||
@Override
|
||||
public boolean test(Type type) {
|
||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
||||
return false;
|
||||
}
|
||||
if (!parameterizedType.getRawType().equals(outerType)) {
|
||||
return false;
|
||||
}
|
||||
Type[] actualType = parameterizedType.getActualTypeArguments();
|
||||
for (int i = 0; i < expectedNested.length; i++) {
|
||||
if (!expectedNested[i].test(actualType[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Type: %s; Inner Type: %s", outerType.getTypeName(), List.of(expectedNested));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches if any of the supplied Types is passed to the predicate
|
||||
*
|
||||
* @param typesToMatch the types to match
|
||||
* @return a Predicate that checks if one of the supplied Types is tested
|
||||
*/
|
||||
public static Predicate<Type> matchAny(Type... typesToMatch) {
|
||||
return Arrays.stream(typesToMatch)
|
||||
.map(H09_TestUtils::match)
|
||||
.reduce(Predicate::or)
|
||||
.orElse(new H09_TestUtils.GenericPredicate(i -> false, "Expected type is not defined"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches if any of the supplied Types is passed to the predicate
|
||||
*
|
||||
* @param typesToMatch the types to match
|
||||
* @return a Predicate that checks if one of the supplied Types is tested
|
||||
*/
|
||||
public static Predicate<Type> matchAny(List<Type> typesToMatch) {
|
||||
return typesToMatch.stream()
|
||||
.map(H09_TestUtils::match)
|
||||
.reduce(Predicate::or)
|
||||
.orElse(new H09_TestUtils.GenericPredicate(i -> false, "Expected type is not defined"));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the upper and lower bounds of the given type.
|
||||
*
|
||||
* <p>The returned Pair contains a list of lower bounds in the left Parameter and a list of upper bounds in the right
|
||||
* Parameter.
|
||||
*
|
||||
* <p>If the given Type does not have any lower bounds the left element of the Pair will be null.
|
||||
*
|
||||
* <p>If the given Type is not generic this method will return null.
|
||||
*
|
||||
* @param type the type to getrieve the Bounds from
|
||||
* @return a Pair containing both the upper and the lower bounds of the given Type
|
||||
*/
|
||||
public static Pair<List<Type>, List<Type>> getBounds(Type type) {
|
||||
if (type instanceof WildcardType wildcardType) {
|
||||
return ImmutablePair.of(Arrays.asList(wildcardType.getLowerBounds()), Arrays.asList(wildcardType.getUpperBounds()));
|
||||
}
|
||||
if (type instanceof ParameterizedType parameterizedType) {
|
||||
return ImmutablePair.of(null, Arrays.asList(parameterizedType.getActualTypeArguments()));
|
||||
}
|
||||
if (type instanceof TypeVariable<?> typeVariable) {
|
||||
return ImmutablePair.of(null, Arrays.asList(typeVariable.getBounds()));
|
||||
}
|
||||
if (type instanceof GenericArrayType) {
|
||||
return ImmutablePair.of(null, List.of(Object[].class));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the inner type of the given Type.
|
||||
*
|
||||
* @param type the type to get the inner type from.
|
||||
* @return the inner type of the given type. Returns empty list if no inner type is present.
|
||||
*/
|
||||
public static List<Type> getInnerTypes(Type type) {
|
||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
||||
return List.of();
|
||||
}
|
||||
return Arrays.asList(parameterizedType.getActualTypeArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the super Types of the given Type if it is a class. Returns upper bounds otherwise.
|
||||
*
|
||||
* @param type the type to get the super types from.
|
||||
* @return the super types or upper bounds of the given type. Returns a list containing only Object if no supertype can be
|
||||
* determined.
|
||||
*/
|
||||
public static List<Type> getGenericSuperTypes(Type type) {
|
||||
if (type instanceof Class<?> clazz) {
|
||||
List<Type> superTypes = new ArrayList<>();
|
||||
if (clazz.getGenericSuperclass() != null) {
|
||||
superTypes.add(clazz.getGenericSuperclass());
|
||||
}
|
||||
if (clazz.getGenericInterfaces().length > 0) {
|
||||
superTypes.addAll(List.of(clazz.getGenericInterfaces()));
|
||||
}
|
||||
return superTypes;
|
||||
}
|
||||
|
||||
Pair<List<Type>, List<Type>> bounds = getBounds(type);
|
||||
if (bounds != null) {
|
||||
return bounds.getRight();
|
||||
}
|
||||
return List.of(Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the return type of the given Method.
|
||||
*
|
||||
* @param method the method to get the return type from.
|
||||
* @return the return type of the given method.
|
||||
*/
|
||||
public static Type getReturnType(Method method) {
|
||||
return method.getGenericReturnType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all parameters of the given method. Returned parameters may not generic.
|
||||
*
|
||||
* @param method the method that the generic types should be retrieved from.
|
||||
* @param regex a regex that is used to filter all generic type names.
|
||||
* @return a List containing all types of the parameters from the method whose type names match the given regex.
|
||||
*/
|
||||
public static List<Type> getTypeParameters(Method method, String regex) {
|
||||
return Arrays.stream(method.getGenericParameterTypes()).filter(t -> t.getTypeName().matches(regex)).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all generic types that are defined by the given method.
|
||||
*
|
||||
* @param method the method that the generic types should be retrieved from.
|
||||
* @param regex a regex that is used to filter all generic type names.
|
||||
* @return a List containing all defined types that match the given regex.
|
||||
*/
|
||||
public static List<Type> getDefinedTypes(Method method, String regex) {
|
||||
return Arrays.stream(method.getTypeParameters()).filter(t -> t.getTypeName().matches(regex)).map(t -> (Type) t).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all generic types that are defined by the given class.
|
||||
*
|
||||
* @param clazz the class that the generic types should be retrieved from.
|
||||
* @param regex a regex that is used to filter all generic type names.
|
||||
* @return a List containing all defined types that match the given regex.
|
||||
*/
|
||||
public static List<Type> getDefinedTypes(Class clazz, String regex) {
|
||||
return Arrays.stream(clazz.getTypeParameters()).filter(t -> t.getTypeName().matches(regex)).map(t -> (Type) t).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given {@link Class} defines a certain set a generic Parameters.
|
||||
*
|
||||
* @param clazz the Class that should be tested.
|
||||
* @param expected a set of predicates that is used to check if all defined generic Types match an expected Type.
|
||||
*/
|
||||
public static void assertDefinedParameters(Class<?> clazz, Set<Predicate<Type>> expected) {
|
||||
|
||||
List<TypeVariable<?>> typeVariable = Arrays.asList(clazz.getTypeParameters());
|
||||
CtType<?> ctClass = (CtType<?>) BasicTypeLink.of(clazz).getCtElement();
|
||||
var actualNames =
|
||||
ctClass.getFormalCtTypeParameters().stream().map(CtType::toStringDebug).map(s -> s.replace("\n", "")).toList();
|
||||
Context context = contextBuilder()
|
||||
.add("expected", expected)
|
||||
.add("actual", actualNames)
|
||||
.build();
|
||||
|
||||
assertTrue(
|
||||
!typeVariable.isEmpty(),
|
||||
emptyContext(),
|
||||
r -> clazz.getSimpleName() + " does not have any generic parameters."
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
expected.size(),
|
||||
typeVariable.size(),
|
||||
context,
|
||||
r -> clazz.getSimpleName() + " does not have the expected number of generic parameters."
|
||||
);
|
||||
typeVariable.forEach(a ->
|
||||
assertTrue(
|
||||
expected.stream().anyMatch(e -> e.test(a)),
|
||||
context,
|
||||
r -> String.format("The type parameter %s of %s do not match any expected types.", a, clazz.getSimpleName())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given {@link Method} defines a specific set of generic types.
|
||||
*
|
||||
* @param method the method that is checked for type definitions.
|
||||
* @param expected a set of predicates that is used to check if all defined generic Types match an expected Type.
|
||||
*/
|
||||
public static void assertDefinedParameters(Method method, Set<Predicate<Type>> expected) {
|
||||
|
||||
List<TypeVariable<?>> typeVariable = Arrays.asList(method.getTypeParameters());
|
||||
CtMethod<?> ctMethod = BasicMethodLink.of(method).getCtElement();
|
||||
var actualNames = ctMethod.getFormalCtTypeParameters()
|
||||
.stream()
|
||||
.map(CtTypeParameter::toStringDebug)
|
||||
.map(s -> s.replace("\n", ""))
|
||||
.toList();
|
||||
Context context = contextBuilder()
|
||||
.add("expected", expected)
|
||||
.add("actual", actualNames)
|
||||
.build();
|
||||
|
||||
assertTrue(!typeVariable.isEmpty(), emptyContext(), r -> method.getName() + " does not have any generic parameters.");
|
||||
|
||||
assertEquals(
|
||||
expected.size(),
|
||||
typeVariable.size(),
|
||||
context,
|
||||
r -> method.getName() + " does not have the expected number of generic parameters."
|
||||
);
|
||||
typeVariable.forEach(a ->
|
||||
assertTrue(
|
||||
expected.stream().anyMatch(e -> e.test(a)),
|
||||
context,
|
||||
r -> String.format("The type parameter %s of %s do not match any expected types.", a, method.getName())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given {@link Method} has a return type that matches the given {@link Predicate}.
|
||||
*
|
||||
* @param method the method that should be tested.
|
||||
* @param expected the {@link Predicate} that shoul be used to check the return type.
|
||||
*/
|
||||
public static void assertReturnParameter(Method method, Predicate<Type> expected) {
|
||||
Type type = method.getGenericReturnType();
|
||||
|
||||
CtMethod<?> ctMethod = BasicMethodLink.of(method).getCtElement();
|
||||
var actualNames = ctMethod.getType().toStringDebug().replace("\n", "");
|
||||
Context context = contextBuilder()
|
||||
.add("actual type", actualNames)
|
||||
.add("expected", expected)
|
||||
.build();
|
||||
|
||||
assertTrue(expected.test(type), context, r -> String.format("%s has a wrong return type.", method.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given {@link Method} has a correct list of parameters each parameter is checked with the given
|
||||
* {@link Predicate} for the index.
|
||||
*
|
||||
* @param method the method that should be checked
|
||||
* @param expected a list containing a {@link Predicate} for each Parameter of the method.
|
||||
*/
|
||||
public static void assertParameters(Method method, List<Predicate<Type>> expected) {
|
||||
Type[] type = method.getGenericParameterTypes();
|
||||
|
||||
assertEquals(
|
||||
expected.size(),
|
||||
type.length,
|
||||
emptyContext(), r -> String.format("The method %s() does not have the correct amount of parameters", method.getName())
|
||||
);
|
||||
|
||||
CtMethod<?> ctMethod = BasicMethodLink.of(method).getCtElement();
|
||||
var actualNames =
|
||||
ctMethod.getParameters()
|
||||
.stream()
|
||||
.map(CtParameter::getType)
|
||||
.map(CtTypeReference::toStringDebug)
|
||||
.map(s -> s.replace("\n", ""))
|
||||
.toList();
|
||||
|
||||
for (int i = 0; i < type.length; i++) {
|
||||
int finalI = i;
|
||||
|
||||
Context context = contextBuilder()
|
||||
.add("actual type", actualNames.get(i))
|
||||
.add("expected", expected.get(i))
|
||||
.build();
|
||||
|
||||
assertTrue(
|
||||
expected.get(i).test(type[i]),
|
||||
context,
|
||||
r -> String.format("%s has a wrong parameter at index %d.", method.getName(), finalI)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given field has a {@link Type} that matches the given {@link Predicate}.
|
||||
*
|
||||
* @param field the field that should be checked.
|
||||
* @param expected the {@link Predicate} that is used to check if the Field has a correct Type.
|
||||
*/
|
||||
public static void assertType(Field field, Predicate<Type> expected) {
|
||||
Type type = field.getGenericType();
|
||||
|
||||
CtField<?> ctField =
|
||||
BasicTypeLink.of(field.getDeclaringClass()).getCtElement().filterChildren(new TypeFilter<>(CtField.class) {
|
||||
@Override
|
||||
public boolean matches(CtField element) {
|
||||
return super.matches(element) && element.getSimpleName().equals(field.getName());
|
||||
}
|
||||
}).first();
|
||||
var actualNames = ctField.getType().toStringDebug();
|
||||
|
||||
Context context = contextBuilder()
|
||||
.add("actual type", actualNames)
|
||||
.add("expected", expected)
|
||||
.build();
|
||||
|
||||
assertTrue(expected.test(type), context, r -> String.format("%s has a wrong type.", field.getName()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given method is generic.
|
||||
*
|
||||
* @param toTest a method reference to the method that should be checked.
|
||||
*/
|
||||
public static void assertGeneric(Method toTest) {
|
||||
|
||||
Predicate<Method> isGeneric = (method) -> !getTypeParameters(method, ".*").isEmpty();
|
||||
isGeneric = isGeneric.or((method) -> getBounds(getReturnType(method)) != null);
|
||||
|
||||
assertTrue(
|
||||
isGeneric.test(toTest),
|
||||
emptyContext(),
|
||||
r -> String.format("The method %s() is not Generic.", toTest.getName())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple Predicate that can store a custom toString() method for better readability.
|
||||
*/
|
||||
public static class GenericPredicate implements Predicate<Type> {
|
||||
|
||||
/**
|
||||
* The description that should be displayed if toString() is called.
|
||||
*/
|
||||
private final String description;
|
||||
/**
|
||||
* The underlying predicate.
|
||||
*/
|
||||
private final Predicate<Type> predicate;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GenericPredicate} from a {@link Predicate} and a short description that describes what the
|
||||
* predicate matches.
|
||||
*
|
||||
* @param predicate the predicate that should be used to match any object.
|
||||
* @param description the description of what the predicate matches.
|
||||
*/
|
||||
GenericPredicate(Predicate<Type> predicate, String description) {
|
||||
this.predicate = predicate;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Type type) {
|
||||
return predicate.test(type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Predicate<Type> and(@NotNull Predicate<? super Type> other) {
|
||||
return new GenericPredicate(predicate.and(other), "(" + this.description + " and " + other + ")");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Predicate<Type> negate() {
|
||||
return new GenericPredicate(predicate.negate(), "(not " + description + ")");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Predicate<Type> or(@NotNull Predicate<? super Type> other) {
|
||||
return new GenericPredicate(predicate.or(other), "(" + this.description + " or " + other + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
}
|
191
H09/src/graderPublic/java/h09/ReflectionUtils.java
Normal file
191
H09/src/graderPublic/java/h09/ReflectionUtils.java
Normal file
|
@ -0,0 +1,191 @@
|
|||
package h09;
|
||||
|
||||
import com.google.common.primitives.Primitives;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ReflectionUtils {
|
||||
|
||||
public static void setFieldValue(Object instance, String fieldName, Object value) {
|
||||
try {
|
||||
Class<?> objectClass = instance.getClass();
|
||||
Field declaredField;
|
||||
try {
|
||||
declaredField = objectClass.getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
declaredField = getSuperClassesIncludingSelf(objectClass).stream()
|
||||
.filter((c) -> List.of(c.getDeclaredFields()).stream()
|
||||
.map(Field::getName)
|
||||
.anyMatch(name -> name.equals(fieldName))
|
||||
)
|
||||
.map((c) -> {
|
||||
try {
|
||||
return c.getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
})
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NoSuchFieldException(e.getMessage()));
|
||||
}
|
||||
|
||||
//best case field in non Final
|
||||
if (!Modifier.isFinal(declaredField.getModifiers())) {
|
||||
try {
|
||||
declaredField.setAccessible(true);
|
||||
declaredField.set(instance, value);
|
||||
return;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
//field has setter
|
||||
Optional<Method> setter = Arrays
|
||||
.stream(objectClass.getDeclaredMethods())
|
||||
.filter(
|
||||
m -> m.getName().equalsIgnoreCase("set" + fieldName)
|
||||
).findFirst();
|
||||
if (setter.isPresent()) {
|
||||
setter.get().invoke(instance, value);
|
||||
return;
|
||||
}
|
||||
|
||||
//rely on Unsafe to set value
|
||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
|
||||
Field theInternalUnsafeField = Unsafe.class.getDeclaredField("theInternalUnsafe");
|
||||
theInternalUnsafeField.setAccessible(true);
|
||||
Object theInternalUnsafe = theInternalUnsafeField.get(null);
|
||||
|
||||
Method offset = Class.forName("jdk.internal.misc.Unsafe").getMethod("objectFieldOffset", Field.class);
|
||||
unsafe.putBoolean(offset, 12, true);
|
||||
|
||||
switch (value) {
|
||||
case Boolean val -> unsafe.putBoolean(instance, (long) offset.invoke(theInternalUnsafe, declaredField), val);
|
||||
case Character val -> unsafe.putChar(instance, (long) offset.invoke(theInternalUnsafe, declaredField), val);
|
||||
case Short val -> unsafe.putShort(instance, (long) offset.invoke(theInternalUnsafe, declaredField), val);
|
||||
case Integer val -> unsafe.putInt(instance, (long) offset.invoke(theInternalUnsafe, declaredField), val);
|
||||
case Long val -> unsafe.putLong(instance, (long) offset.invoke(theInternalUnsafe, declaredField), val);
|
||||
case Double val -> unsafe.putDouble(instance, (long) offset.invoke(theInternalUnsafe, declaredField), val);
|
||||
case Float val -> unsafe.putFloat(instance, (long) offset.invoke(theInternalUnsafe, declaredField), val);
|
||||
default -> unsafe.putObject(instance, (long) offset.invoke(theInternalUnsafe, declaredField), value);
|
||||
}
|
||||
} catch (IllegalAccessException | NoSuchFieldException | ClassNotFoundException | NoSuchMethodException |
|
||||
InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T getFieldValue(Object instance, String fieldName) {
|
||||
Field f;
|
||||
Class<?> fieldType = null;
|
||||
try {
|
||||
f = instance.getClass().getDeclaredField(fieldName);
|
||||
|
||||
try {
|
||||
f.setAccessible(true);
|
||||
return (T) f.get(instance);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
fieldType = f.getType();
|
||||
if (Primitives.isWrapperType(fieldType)) {
|
||||
fieldType = Primitives.unwrap(fieldType);
|
||||
}
|
||||
|
||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
|
||||
Field theInternalUnsafeField = Unsafe.class.getDeclaredField("theInternalUnsafe");
|
||||
theInternalUnsafeField.setAccessible(true);
|
||||
Object theInternalUnsafe = theInternalUnsafeField.get(null);
|
||||
|
||||
Method offset = Class.forName("jdk.internal.misc.Unsafe").getMethod("objectFieldOffset", Field.class);
|
||||
unsafe.putBoolean(offset, 12, true);
|
||||
|
||||
Object fieldValue;
|
||||
if (boolean.class == fieldType) {
|
||||
fieldValue = unsafe.getBoolean(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
} else if (byte.class == fieldType) {
|
||||
fieldValue = unsafe.getByte(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
} else if (short.class == fieldType) {
|
||||
fieldValue = unsafe.getShort(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
} else if (int.class == fieldType) {
|
||||
fieldValue = unsafe.getInt(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
} else if (long.class == fieldType) {
|
||||
fieldValue = unsafe.getLong(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
} else if (float.class == fieldType) {
|
||||
fieldValue = unsafe.getFloat(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
} else if (double.class == fieldType) {
|
||||
fieldValue = unsafe.getDouble(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
} else if (char.class == fieldType) {
|
||||
fieldValue = unsafe.getChar(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
} else {
|
||||
fieldValue = unsafe.getObject(instance, (long) offset.invoke(theInternalUnsafe, f));
|
||||
}
|
||||
return (T) fieldValue;
|
||||
} catch (NoSuchFieldException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
|
||||
IllegalAccessException e) {
|
||||
throw new RuntimeException(
|
||||
"Could not set value for Field %s(%s) in %s. Please do not access this field.".formatted(
|
||||
fieldName,
|
||||
fieldType,
|
||||
instance.getClass()
|
||||
), e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyFields(Object source, Object dest) {
|
||||
for (Field f : source.getClass().getDeclaredFields()) {
|
||||
setFieldValue(dest, f.getName(), getFieldValue(source, f.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean actsLikePrimitive(Class<?> type) {
|
||||
return type.isPrimitive() ||
|
||||
Enum.class.isAssignableFrom(type) ||
|
||||
Primitives.isWrapperType(type) ||
|
||||
type == String.class;
|
||||
}
|
||||
|
||||
public static List<Class<?>> getSuperClassesIncludingSelf(Class<?> clazz) {
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
Deque<Class<?>> classDeque = new ArrayDeque<>();
|
||||
|
||||
classDeque.add(clazz);
|
||||
|
||||
while ((clazz = classDeque.peekFirst()) != null) {
|
||||
classDeque.pop();
|
||||
|
||||
classes.add(clazz);
|
||||
if (clazz.getSuperclass() != null) {
|
||||
classDeque.add(clazz.getSuperclass());
|
||||
}
|
||||
if (clazz.getInterfaces().length > 0) {
|
||||
classDeque.addAll(List.of(clazz.getInterfaces()));
|
||||
}
|
||||
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
public static boolean isObjectMethod(Method methodToCheck) {
|
||||
List<String> objectMethods =
|
||||
List.of("getClass", "hashCode", "equals", "clone", "toString", "notify", "notifyAll", "wait", "finalize");
|
||||
return objectMethods.contains(methodToCheck.getName());
|
||||
}
|
||||
}
|
101
H09/src/graderPublic/java/h09/StackOfObjectsTestPublic.java
Normal file
101
H09/src/graderPublic/java/h09/StackOfObjectsTestPublic.java
Normal file
|
@ -0,0 +1,101 @@
|
|||
package h09;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
|
||||
import org.tudalgo.algoutils.tutor.general.reflections.BasicTypeLink;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static h09.H09_TestUtils.assertDefinedParameters;
|
||||
import static h09.H09_TestUtils.assertParameters;
|
||||
import static h09.H09_TestUtils.assertReturnParameter;
|
||||
import static h09.H09_TestUtils.assertType;
|
||||
import static h09.H09_TestUtils.getTypeParameters;
|
||||
import static h09.H09_TestUtils.match;
|
||||
import static h09.H09_TestUtils.matchArray;
|
||||
import static h09.H09_TestUtils.matchNested;
|
||||
import static h09.H09_TestUtils.matchNoBounds;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertNotNull;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
|
||||
import static org.tudalgo.algoutils.tutor.general.match.BasicStringMatchers.identical;
|
||||
|
||||
@TestForSubmission
|
||||
public class StackOfObjectsTestPublic {
|
||||
|
||||
BasicTypeLink stackLink;
|
||||
Class<?> ctClassStack;
|
||||
Method get;
|
||||
Method pop;
|
||||
Method push;
|
||||
Method remove;
|
||||
Method of;
|
||||
Field objs;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
stackLink = BasicTypeLink.of(StackOfObjects.class);
|
||||
ctClassStack = stackLink.reflection();
|
||||
get = stackLink.getMethod(identical("get")).reflection();
|
||||
pop = stackLink.getMethod(identical("pop")).reflection();
|
||||
push = stackLink.getMethod(identical("push")).reflection();
|
||||
remove = stackLink.getMethod(identical("remove")).reflection();
|
||||
of = stackLink.getMethod(identical("of")).reflection();
|
||||
objs = stackLink.getField(identical("objs")).reflection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassParameter() {
|
||||
assertDefinedParameters(ctClassStack, Set.of(matchNoBounds("O")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjsType() {
|
||||
assertType(objs, matchArray(matchNoBounds("O")));
|
||||
assertNotNull(
|
||||
ReflectionUtils.getFieldValue(new StackOfObjects<>(), "objs"),
|
||||
emptyContext(),
|
||||
r -> "Field objs is not correctly initialized"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushParameter() {
|
||||
assertParameters(push, List.of(matchNoBounds("O")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveParameter() {
|
||||
assertParameters(remove, List.of(matchNoBounds("O")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopParameter() {
|
||||
assertReturnParameter(pop, matchNoBounds("O"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParameter() {
|
||||
assertReturnParameter(get, matchNoBounds("O"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOfParameter() {
|
||||
assertDefinedParameters(of, Set.of(matchNoBounds("O")));
|
||||
|
||||
List<Type> types = getTypeParameters(of, ".*");
|
||||
|
||||
assertReturnParameter(
|
||||
of,
|
||||
matchNested(StackOfObjects.class, match(((GenericArrayType) types.get(0)).getGenericComponentType()))
|
||||
);
|
||||
|
||||
assertParameters(of, List.of(match(types.get(0))));
|
||||
}
|
||||
}
|
140
H09/src/graderPublic/java/h09/WaterEnclosureTestPublic.java
Normal file
140
H09/src/graderPublic/java/h09/WaterEnclosureTestPublic.java
Normal file
|
@ -0,0 +1,140 @@
|
|||
package h09;
|
||||
|
||||
import h09.abilities.Swims;
|
||||
import h09.animals.Penguin;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
|
||||
import org.tudalgo.algoutils.tutor.general.assertions.Context;
|
||||
import org.tudalgo.algoutils.tutor.general.reflections.BasicTypeLink;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
|
||||
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.fail;
|
||||
import static org.tudalgo.algoutils.tutor.general.match.BasicStringMatchers.identical;
|
||||
|
||||
@TestForSubmission
|
||||
public class WaterEnclosureTestPublic {
|
||||
|
||||
BasicTypeLink waterEnclosureLink;
|
||||
Class<?> waterEnclosureClass;
|
||||
Method getStack;
|
||||
Method feed;
|
||||
Method getMeanElevation;
|
||||
Field animals;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
waterEnclosureLink = BasicTypeLink.of(WaterEnclosure.class);
|
||||
waterEnclosureClass = waterEnclosureLink.reflection();
|
||||
getStack = waterEnclosureLink.getMethod(identical("getStack")).reflection();
|
||||
feed = waterEnclosureLink.getMethod(identical("feed")).reflection();
|
||||
getMeanElevation = waterEnclosureLink.getMethod(identical("getMeanElevation")).reflection();
|
||||
animals = waterEnclosureLink.getField(identical("animals")).reflection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeed() {
|
||||
|
||||
WaterEnclosure enclosure = new WaterEnclosure();
|
||||
List<Penguin> animals = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Penguin mock = mock(Penguin.class, CALLS_REAL_METHODS);
|
||||
ReflectionUtils.setFieldValue(mock, "isHungry", false);
|
||||
ReflectionUtils.setFieldValue(mock, "elevation", Swims.MAX_ELEVATION);
|
||||
if (i % 2 == 0) {
|
||||
ReflectionUtils.setFieldValue(mock, "isHungry", true);
|
||||
}
|
||||
if (i % 3 == 0) {
|
||||
ReflectionUtils.setFieldValue(mock, "elevation", Swims.MIN_ELEVATION);
|
||||
}
|
||||
|
||||
enclosure.getStack().push(mock);
|
||||
animals.add(mock);
|
||||
}
|
||||
|
||||
Context context = contextBuilder()
|
||||
.add("Animals", animals)
|
||||
.build();
|
||||
|
||||
enclosure.feed();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (enclosure.getStack().size() <= 0) {
|
||||
fail(context, r -> "WaterEnclosure does not have correct number of Animals after feeding.");
|
||||
}
|
||||
Penguin mock = (Penguin) enclosure.getStack().pop();
|
||||
|
||||
int id = animals.indexOf(mock);
|
||||
|
||||
if (id % 2 == 0) {
|
||||
verify(mock).eat();
|
||||
verify(mock).swimDown();
|
||||
if (i % 3 == 0) {
|
||||
verify(mock).swimUp();
|
||||
} else {
|
||||
verify(mock, never()).swimUp();
|
||||
}
|
||||
} else {
|
||||
verify(mock, never()).eat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provide_testGetMeanElevation")
|
||||
public void testGetMeanElevation(List<Double> elevations, double expected) {
|
||||
|
||||
WaterEnclosure enclosure = new WaterEnclosure<>();
|
||||
|
||||
for (double elevation : elevations) {
|
||||
Penguin mock = mock(Penguin.class);
|
||||
when(mock.getElevation()).thenReturn((float) elevation);
|
||||
|
||||
enclosure.getStack().push(mock);
|
||||
}
|
||||
|
||||
float actual = enclosure.getMeanElevation();
|
||||
|
||||
Context context = contextBuilder()
|
||||
.add("Elevations", elevations)
|
||||
.build();
|
||||
|
||||
double error = 0.00001;
|
||||
|
||||
assertTrue(
|
||||
Math.abs(Math.abs(expected) - Math.abs(actual)) < error,
|
||||
context,
|
||||
r -> "Average Elevation is not calculated correctly."
|
||||
);
|
||||
}
|
||||
|
||||
public static Stream<Arguments> provide_testGetMeanElevation() {
|
||||
return Stream.of(
|
||||
Arguments.of(List.of(0d, 0d, 0d, 0d, 0d, 0d), 0.0),
|
||||
Arguments.of(List.of(0d, -1d, -2d, -3d, -4d, -5d), -2.5),
|
||||
Arguments.of(List.of(-1d, -2d, -3d, -4d, -5d, -6d), -3.5),
|
||||
Arguments.of(List.of(-6d, -5d, -4d, -3d, -2d, -1d), -3.5),
|
||||
Arguments.of(List.of(-3d, -5d, 0d, -3d, -10d, -1d), -3.6666667),
|
||||
Arguments.of(List.of(-3d, -2d, 0d, -3d, -2d, -3d), -2.1666667),
|
||||
Arguments.of(List.of(-2d, -2d, -2d, -2d, -2d, -2d), -2.0),
|
||||
Arguments.of(List.of(-1d, -2d, -2d), -1.6666666)
|
||||
);
|
||||
}
|
||||
}
|
119
H09/src/main/java/h09/Enclosure.java
Normal file
119
H09/src/main/java/h09/Enclosure.java
Normal file
|
@ -0,0 +1,119 @@
|
|||
package h09;
|
||||
|
||||
import h09.animals.Animal;
|
||||
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An object of a class implementing {@link Enclosure} has the ability to contain and manage a stack of {@link Animal}s.
|
||||
*/
|
||||
// TODO: H9.2.1
|
||||
public interface Enclosure<TODO_REPLACE> {
|
||||
/**
|
||||
* @return the stack of animals which is used manage the contained {@link Animal}s
|
||||
*/
|
||||
@StudentImplementationRequired("H9.2.1")
|
||||
// TODO: H9.2.1
|
||||
StackOfObjects getStack();
|
||||
|
||||
/**
|
||||
* Feeds all contained animals.
|
||||
*/
|
||||
@DoNotTouch
|
||||
void feed();
|
||||
|
||||
/**
|
||||
* Counts the number of hungry {@link Animal}s in the enclosure.
|
||||
*
|
||||
* @return number of hungry {@link Animal}s in the enclosure
|
||||
*/
|
||||
@DoNotTouch
|
||||
@SuppressWarnings("RedundantCast")
|
||||
default int countHungry() {
|
||||
int count = 0;
|
||||
for (int i = 0; i < this.getStack().size(); i++)
|
||||
if (((Animal) this.getStack().get(i)).isHungry()) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Applies a {@link Consumer} operation on each {@link Animal} in the enclosure.
|
||||
*
|
||||
* @param func operation to be applied to each {@link Animal} in the enclosure
|
||||
*/
|
||||
@StudentImplementationRequired("H9.3.1") // TODO: H9.3.1
|
||||
default void forEach(Consumer func) {
|
||||
for (int i = 0; i < this.getStack().size(); i++)
|
||||
func.accept(this.getStack().get(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a {@link Predicate} operation on each {@link Animal} in the enclosure and removes every {@link Animal}
|
||||
* which does not satisfy the predicate. That means only {@link Animal}s for which the predicate returns 'true'
|
||||
* remain in the enclosure.
|
||||
*
|
||||
* @param filter operation to test to each {@link Animal} in the enclosure
|
||||
*/
|
||||
@StudentImplementationRequired("H9.3.2") // TODO: H9.3.2
|
||||
default void filterObj(Predicate filter) {
|
||||
for (int i = 0; i < this.getStack().size(); i++) {
|
||||
Object a = this.getStack().get(i);
|
||||
if (!filter.test(a)) {
|
||||
this.getStack().remove(a);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link Enclosure} that contains only the {@link Animal}s of the previous {@link Enclosure} which
|
||||
* satisfied the predicate. That means only {@link Animal}s for which the predicate returns 'true' are included
|
||||
* in the new enclosure.
|
||||
*
|
||||
* @param supp {@link Supplier} which is used to create the new {@link Enclosure} to be returned
|
||||
* @param filter operation to test to each {@link Animal} in the enclosure
|
||||
* @param <E> Type of the new {@link Enclosure} which is returned
|
||||
* @return a new {@link Enclosure} that contains only the {@link Animal}s of the previous {@link Enclosure} which
|
||||
* satisfied the predicate
|
||||
*/
|
||||
@StudentImplementationRequired("H9.3.3")
|
||||
default Enclosure filterFunc(Supplier<Enclosure> supp, Predicate<Object> filter) {
|
||||
// TODO: H9.3.3
|
||||
return org.tudalgo.algoutils.student.Student.crash("H9.3.3 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Predicate} which returns true if an {@link Animal} is old (that means older than 10).
|
||||
*/
|
||||
@DoNotTouch
|
||||
Predicate<Animal> IS_OLD = animal -> animal.getAge() > 10;
|
||||
|
||||
/**
|
||||
* {@link Predicate} which returns true if a swimming {@link Animal} swims at a low elevation.
|
||||
*/
|
||||
@StudentImplementationRequired("H9.4.1") // TODO: H9.4.1
|
||||
Predicate SWIMS_AT_LOW_ELEVATION = null;
|
||||
|
||||
/**
|
||||
* {@link Consumer} which lets the consumed {@link Animal} eat and sleep.
|
||||
*/
|
||||
@StudentImplementationRequired("H9.4.2") // TODO: H9.4.2
|
||||
Consumer FEED_AND_SLEEP = null;
|
||||
|
||||
/**
|
||||
* Returns a {@link Consumer} which lets the consumed swimming {@link Animal} eat and swim down.
|
||||
*
|
||||
* @param <T> Type of the swimming {@link Animal} to eat and swim down
|
||||
* @return a {@link Consumer} which lets the consumed swimming {@link Animal} eat and swim down
|
||||
*/
|
||||
@StudentImplementationRequired("H9.4.3")
|
||||
static Consumer EAT_AND_SINK() {
|
||||
// TODO: H9.4.3
|
||||
return org.tudalgo.algoutils.student.Student.crash("H9.4.3 - Remove if implemented");
|
||||
}
|
||||
}
|
40
H09/src/main/java/h09/GroundEnclosure.java
Normal file
40
H09/src/main/java/h09/GroundEnclosure.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package h09;
|
||||
|
||||
import h09.abilities.Walks;
|
||||
import h09.animals.Animal;
|
||||
|
||||
/**
|
||||
* An object of a class implementing {@link GroundEnclosure} has the ability to contain and manage a stack of
|
||||
* {@link Animal}s which have the ability to {@link Walks}.
|
||||
*/
|
||||
public class GroundEnclosure<A extends Animal & Walks> implements Enclosure<A> {
|
||||
/**
|
||||
* The stack of animals which is used manage the contained Animals.
|
||||
*/
|
||||
final StackOfObjects<A> animals = new StackOfObjects<>();
|
||||
|
||||
@Override
|
||||
public StackOfObjects<A> getStack() {
|
||||
return animals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void feed() {
|
||||
for (int i = 0; i < this.getStack().size(); i++) {
|
||||
A a = (A) this.getStack().get(i);
|
||||
a.eat();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the total number of legs of all {@link Animal}s in the enclosure.
|
||||
*
|
||||
* @return the total number of legs of all {@link Animal}s in the enclosure
|
||||
*/
|
||||
public int countLegs() {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < this.getStack().size(); i++)
|
||||
sum += ((A) this.getStack().get(i)).getNumberOfLegs();
|
||||
return sum;
|
||||
}
|
||||
}
|
15
H09/src/main/java/h09/Main.java
Normal file
15
H09/src/main/java/h09/Main.java
Normal file
|
@ -0,0 +1,15 @@
|
|||
package h09;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
System.out.println("Hello World!");
|
||||
}
|
||||
}
|
90
H09/src/main/java/h09/StackOfObjects.java
Normal file
90
H09/src/main/java/h09/StackOfObjects.java
Normal file
|
@ -0,0 +1,90 @@
|
|||
package h09;
|
||||
|
||||
import org.tudalgo.algoutils.student.annotation.DoNotTouch;
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
/**
|
||||
* An object of class {@link StackOfObjects} represents a data structure of type stack.
|
||||
*/
|
||||
@SuppressWarnings({"ManualArrayCopy"})
|
||||
public class StackOfObjects<TODO_REPLACE> {
|
||||
@StudentImplementationRequired("H9.1.1") // TODO: H9.1.1
|
||||
private Object[] objs = new Object[0];
|
||||
|
||||
/**
|
||||
* Pushes the given object on this stack.
|
||||
*
|
||||
* @param obj the object
|
||||
*/
|
||||
@StudentImplementationRequired("H9.1.2") // TODO: H9.1.2
|
||||
public void push(Object obj) {
|
||||
Object[] newArray = new Object[objs.length + 1];
|
||||
for (int i = 0; i < objs.length; i++) newArray[i] = objs[i];
|
||||
newArray[objs.length] = obj;
|
||||
objs = newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given object from this stack.
|
||||
*
|
||||
* @param obj the object
|
||||
*/
|
||||
@StudentImplementationRequired("H9.1.3") // TODO: H9.1.3
|
||||
public void remove(Object obj) {
|
||||
Object[] newArray = new Object[objs.length - 1];
|
||||
int n = 0;
|
||||
for (Object currObj : objs) {
|
||||
if (currObj == obj) continue;
|
||||
newArray[n++] = currObj;
|
||||
}
|
||||
objs = newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of objects in this stack.
|
||||
*
|
||||
* @return the number of objects
|
||||
*/
|
||||
@DoNotTouch
|
||||
public int size() {
|
||||
return objs.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object at the given index in this stack.
|
||||
*
|
||||
* @param index the index
|
||||
* @return the object
|
||||
*/
|
||||
@StudentImplementationRequired("H9.1.4") // TODO: H9.1.4
|
||||
public Object get(int index) {
|
||||
return objs[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the top object of this stack.
|
||||
*
|
||||
* @return the top object
|
||||
*/
|
||||
@StudentImplementationRequired("H9.1.4") // TODO: H9.1.4
|
||||
public Object pop() {
|
||||
Object o = get(objs.length - 1);
|
||||
remove(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns a stack with the given objects.
|
||||
* The last object is the top object.
|
||||
*
|
||||
* @param objs the objects
|
||||
* @return the stack
|
||||
*/
|
||||
@SafeVarargs
|
||||
@StudentImplementationRequired("H9.1.5") // TODO: H9.1.5
|
||||
public static StackOfObjects of(Object... objs) {
|
||||
StackOfObjects stack = new StackOfObjects();
|
||||
stack.objs = objs;
|
||||
return stack;
|
||||
}
|
||||
}
|
43
H09/src/main/java/h09/WaterEnclosure.java
Normal file
43
H09/src/main/java/h09/WaterEnclosure.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
package h09;
|
||||
|
||||
import h09.abilities.Swims;
|
||||
import h09.animals.Animal;
|
||||
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
|
||||
|
||||
/**
|
||||
* An object of a class implementing {@link WaterEnclosure} has the ability to contain and manage a stack of
|
||||
* {@link Animal}s which have the ability to {@link Swims}.
|
||||
*/
|
||||
// TODO: H9.2.2
|
||||
public class WaterEnclosure<TODO_REPLACE> {
|
||||
/**
|
||||
* The stack of animals which is used manage the contained Animals.
|
||||
*/
|
||||
@StudentImplementationRequired("H9.2.2") // TODO: H9.2.2
|
||||
final StackOfObjects animals = null;
|
||||
|
||||
@StudentImplementationRequired("H9.2.2")
|
||||
// @Override
|
||||
public StackOfObjects getStack() {
|
||||
// TODO: H9.2.2
|
||||
return org.tudalgo.algoutils.student.Student.crash("H9.2.2 - Remove if implemented");
|
||||
}
|
||||
|
||||
@StudentImplementationRequired("H9.2.2")
|
||||
// @Override
|
||||
public void feed() {
|
||||
// TODO: H9.2.2
|
||||
org.tudalgo.algoutils.student.Student.crash("H9.2.2 - Remove if implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the elevations of all {@link Animal}s in the enclosure and returns the mean.
|
||||
*
|
||||
* @return the mean elevation of all {@link Animal}s in the enclosure
|
||||
*/
|
||||
@StudentImplementationRequired("H9.2.2")
|
||||
public float getMeanElevation() {
|
||||
// TODO: H9.2.2
|
||||
return org.tudalgo.algoutils.student.Student.crash("H9.2.2 - Remove if implemented");
|
||||
}
|
||||
}
|
18
H09/src/main/java/h09/abilities/Flies.java
Normal file
18
H09/src/main/java/h09/abilities/Flies.java
Normal file
|
@ -0,0 +1,18 @@
|
|||
package h09.abilities;
|
||||
|
||||
public interface Flies {
|
||||
/**
|
||||
* Lets the animal land.
|
||||
*/
|
||||
void land();
|
||||
|
||||
/**
|
||||
* Lets the animal fly.
|
||||
*/
|
||||
void takeOff();
|
||||
|
||||
/**
|
||||
* @return whether the animal is flying.
|
||||
*/
|
||||
boolean isFlying();
|
||||
}
|
36
H09/src/main/java/h09/abilities/Swims.java
Normal file
36
H09/src/main/java/h09/abilities/Swims.java
Normal file
|
@ -0,0 +1,36 @@
|
|||
package h09.abilities;
|
||||
|
||||
/**
|
||||
* An object of a class implementing {@link Swims} has the ability to swim and live in an {@link h09.WaterEnclosure}
|
||||
*/
|
||||
public interface Swims {
|
||||
/**
|
||||
* @return the elevation of the swimming animal
|
||||
*/
|
||||
float getElevation();
|
||||
|
||||
/**
|
||||
* Lets the animal swim up and increase in elevation.
|
||||
*/
|
||||
void swimUp();
|
||||
|
||||
/**
|
||||
* Lets the animal swim down and decrease in elevation.
|
||||
*/
|
||||
void swimDown();
|
||||
|
||||
/**
|
||||
* The max elevation an animal can swim to.
|
||||
*/
|
||||
float MAX_ELEVATION = 0;
|
||||
|
||||
/**
|
||||
* The min elevation an animal can swim to.
|
||||
*/
|
||||
float MIN_ELEVATION = -10;
|
||||
|
||||
/**
|
||||
* The elevation above which an animal is considered at a high elevation or at the surface.
|
||||
*/
|
||||
float HIGH_ELEVATION = -3;
|
||||
}
|
11
H09/src/main/java/h09/abilities/Walks.java
Normal file
11
H09/src/main/java/h09/abilities/Walks.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package h09.abilities;
|
||||
|
||||
/**
|
||||
* An object of a class implementing {@link Walks} has the ability to walk and live in an {@link h09.GroundEnclosure}
|
||||
*/
|
||||
public interface Walks {
|
||||
/**
|
||||
* @return the number of legs of the animal
|
||||
*/
|
||||
int getNumberOfLegs();
|
||||
}
|
71
H09/src/main/java/h09/animals/Animal.java
Normal file
71
H09/src/main/java/h09/animals/Animal.java
Normal file
|
@ -0,0 +1,71 @@
|
|||
package h09.animals;
|
||||
|
||||
/**
|
||||
* An object of a class {@link Animal} represents an animal.
|
||||
*/
|
||||
public class Animal {
|
||||
/**
|
||||
* Name of the animal.
|
||||
*/
|
||||
protected String name;
|
||||
/**
|
||||
* Age of the animal.
|
||||
*/
|
||||
private int age;
|
||||
|
||||
/**
|
||||
* A 'true' value represents that the animal is hungry.
|
||||
*/
|
||||
private boolean isHungry = true;
|
||||
|
||||
/**
|
||||
* Constructs an Animal with the given name and age.
|
||||
*
|
||||
* @param name the name of the animal
|
||||
* @param age the age of the animal
|
||||
*/
|
||||
public Animal(String name, int age) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the animal
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets the animal eat. This prints a message to the system output noting that the animal has eaten and sets the
|
||||
* animal to not hungry.
|
||||
*/
|
||||
public void eat() {
|
||||
System.out.println(name + " ate...");
|
||||
isHungry = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets the animal sleep. This prints a message to the system output noting that the animal has eaten. It also
|
||||
* increases the age of the animal and sets the animal to hungry.
|
||||
*/
|
||||
public void sleep() {
|
||||
System.out.println(name + " slept...");
|
||||
isHungry = true;
|
||||
age++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the animal is hungry; false otherwise
|
||||
*/
|
||||
public boolean isHungry() {
|
||||
return isHungry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the age of the animal
|
||||
*/
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
}
|
14
H09/src/main/java/h09/animals/ClownFish.java
Normal file
14
H09/src/main/java/h09/animals/ClownFish.java
Normal file
|
@ -0,0 +1,14 @@
|
|||
package h09.animals;
|
||||
|
||||
public class ClownFish extends Fish {
|
||||
public ClownFish(String name, int age) {
|
||||
super(name, age);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a joke about fish playing basketball.
|
||||
*/
|
||||
public void tellJoke() {
|
||||
System.out.println(getName() + " says: Why don't fish play basketball? Because they're afraid of the net!");
|
||||
}
|
||||
}
|
34
H09/src/main/java/h09/animals/Fish.java
Normal file
34
H09/src/main/java/h09/animals/Fish.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
package h09.animals;
|
||||
|
||||
import h09.abilities.Swims;
|
||||
|
||||
/**
|
||||
* An object of a class {@link Fish} represents a fish which can swim.
|
||||
*/
|
||||
public class Fish extends Animal implements Swims {
|
||||
/**
|
||||
* Constructs a Fish with the given name and age.
|
||||
*
|
||||
* @param name the name of the animal
|
||||
* @param age the age of the animal
|
||||
*/
|
||||
public Fish(String name, int age) {
|
||||
super(name, age);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getElevation() {
|
||||
return Swims.MAX_ELEVATION - (Swims.MAX_ELEVATION - Swims.MIN_ELEVATION) / (getName().length() + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swimUp() {
|
||||
name += "Blub";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swimDown() {
|
||||
if (name.length() < 4) return;
|
||||
name = name.substring(0, name.length() - 4);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue