Get new things

This commit is contained in:
Oshgnacknak 2025-03-16 16:45:18 +01:00
parent 88d43259a4
commit cfa48663e2
Signed by: Oshgnacknak
GPG key ID: 8CB7375654585956
619 changed files with 283313 additions and 311 deletions

5
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

7
.idea/misc.xml generated Normal file
View 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>

View file

@ -13,12 +13,9 @@ submission {
// Setzen Sie im folgenden Bereich Ihre TU-ID (NICHT Ihre Matrikelnummer!), Ihren Nachnamen und Ihren Vornamen // 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! // in Anführungszeichen (z.B. "ab12cdef" für Ihre TU-ID) ein!
// BEISPIEL: // BEISPIEL:
// studentId = "ab12cdef" studentId = "ab12cdef"
// firstName = "sol_first" firstName = "sol_first"
// lastName = "sol_last" lastName = "sol_last"
studentId = ""
firstName = ""
lastName = ""
// Optionally require own tests for mainBuildSubmission task. Default is false // Optionally require own tests for mainBuildSubmission task. Default is false
requireTests = false requireTests = false

View file

@ -5,6 +5,10 @@ import fopbot.Robot;
import fopbot.RobotFamily; import fopbot.RobotFamily;
import fopbot.World; 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. * Main entry point in executing the program.
*/ */
@ -30,43 +34,103 @@ public class Main {
setupWorld(); setupWorld();
// TODO: H0.4 - Initializing FOPBot // 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! if (runToSubtask == 0) return; // DO NOT TOUCH!
// TODO: H0.5.1 - Turning with repeated instructions // TODO: H0.5.1 - Turning with repeated instructions
IntStream.rangeClosed(0, 1)
.forEach(x -> alfred.turnLeft());
if (runToSubtask == 1) return; // DO NOT TOUCH! if (runToSubtask == 1) return; // DO NOT TOUCH!
// TODO: H0.5.2 - Turning with for-loop // 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! if (runToSubtask == 2) return; // DO NOT TOUCH!
// TODO: H0.5.3 - Turning with while-loop // 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! if (runToSubtask == 3) return; // DO NOT TOUCH!
// TODO: H0.6.1 - Put with repeated instructions // 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! if (runToSubtask == 4) return; // DO NOT TOUCH!
// TODO: H0.6.2 - Pick with repeated instructions // 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! if (runToSubtask == 5) return; // DO NOT TOUCH!
// TODO: H0.6.3 - Put with for-loop // 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! if (runToSubtask == 6) return; // DO NOT TOUCH!
// TODO: H0.7.1 - Pick with while-loop // 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! if (runToSubtask == 7) return; // DO NOT TOUCH!
// TODO: H0.7.2 - Pick and put with while-loop // 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! if (runToSubtask == 8) return; // DO NOT TOUCH!
// TODO: H0.7.3 - Put with reversed for-loop // 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) // speed of how fast the world gets refreshed (e.g. how fast the robot(s) act)
// the lower the number, the faster the refresh // the lower the number, the faster the refresh
World.setDelay(delay); // World.setDelay(delay);
// make it possible to see the world window // make it possible to see the world window
World.setVisible(true); World.setVisible(true);

View file

@ -7,6 +7,8 @@ import h01.template.Families;
import h01.template.Ghost; import h01.template.Ghost;
import h01.template.TickBased; import h01.template.TickBased;
import java.util.stream.Stream;
/** /**
* The {@link BlueGhost} is a {@link Robot} that looks like a blue ghost. * The {@link BlueGhost} is a {@link Robot} that looks like a blue ghost.
* It tries to move in a circle. * It tries to move in a circle.
@ -29,6 +31,6 @@ public class BlueGhost extends Robot implements Ghost, TickBased {
@Override @Override
@StudentImplementationRequired("H2.1") @StudentImplementationRequired("H2.1")
public void doMove() { public void doMove() {
org.tudalgo.algoutils.student.Student.crash("H2.1 - Remove if implemented"); FuckBot.exec("<<<(<!|)^", this);
} }
} }

View 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;
}
}

View file

@ -34,6 +34,21 @@ public class OrangeGhost extends Robot implements Ghost, TickBased {
@Override @Override
@StudentImplementationRequired("H2.3") @StudentImplementationRequired("H2.3")
public void doMove() { 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;
} }
} }

View file

@ -8,6 +8,8 @@ import h01.template.Controllable;
import h01.template.Families; import h01.template.Families;
import h01.template.TickBased; import h01.template.TickBased;
import javax.xml.xpath.XPathConstants;
/** /**
* {@link Pacman} is a {@link Robot} that can be controlled by the user and * {@link Pacman} is a {@link Robot} that can be controlled by the user and
* looks like Pacman. * looks like Pacman.
@ -36,6 +38,19 @@ public class Pacman extends Robot implements Controllable, TickBased {
@Override @Override
@StudentImplementationRequired("H1.1") @StudentImplementationRequired("H1.1")
public void handleKeyInput(int k) { 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();
}
} }
} }

View file

@ -8,6 +8,10 @@ import h01.template.Ghost;
import h01.template.TickBased; import h01.template.TickBased;
import h01.template.Util; 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. * The {@link PinkGhost} is a {@link Robot} that looks like a pink ghost.
* It tries to move in a random direction. * It tries to move in a random direction.
@ -31,6 +35,19 @@ public class PinkGhost extends Robot implements Ghost, TickBased {
@Override @Override
@StudentImplementationRequired("H2.2") @StudentImplementationRequired("H2.2")
public void doMove() { 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();
} }
} }

View file

@ -34,6 +34,13 @@ public class RedGhost extends Robot implements Ghost, TickBased {
@Override @Override
@StudentImplementationRequired("H2.4") @StudentImplementationRequired("H2.4")
public void doMove() { 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();
} }
} }

View file

@ -14,7 +14,7 @@ import java.util.Optional;
* The {@link FourWins} class represents the main class of the FourWins game. * The {@link FourWins} class represents the main class of the FourWins game.
*/ */
public class FourWins { public class FourWins {
private final InputHandler inputHandler = new InputHandler(this); public final InputHandler inputHandler = new InputHandler(this);
/** /**
* The width of the game board. * The width of the game board.
*/ */
@ -70,7 +70,17 @@ public class FourWins {
@StudentImplementationRequired("H2.2.1") @StudentImplementationRequired("H2.2.1")
public static boolean validateInput(final int column, final RobotFamily[][] stones) { public static boolean validateInput(final int column, final RobotFamily[][] stones) {
// TODO: H2.2.1 // 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") @StudentImplementationRequired("H2.2.2")
public static int getDestinationRow(final int column, final RobotFamily[][] stones) { public static int getDestinationRow(final int column, final RobotFamily[][] stones) {
// TODO: H2.2.2 // 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") @StudentImplementationRequired("H2.2.2")
public static void dropStone(final int column, final RobotFamily[][] stones, final RobotFamily currentPlayer) { public static void dropStone(final int column, final RobotFamily[][] stones, final RobotFamily currentPlayer) {
// TODO: H2.2.2 // 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") @StudentImplementationRequired("H2.2.3")
public static boolean testWinConditions(final RobotFamily[][] stones, final RobotFamily currentPlayer) { public static boolean testWinConditions(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
// TODO: H2.2.3 // 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") @StudentImplementationRequired("H2.2.3")
public static boolean testWinHorizontal(final RobotFamily[][] stones, final RobotFamily currentPlayer) { public static boolean testWinHorizontal(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
// TODO: H2.2.3 // 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") @StudentImplementationRequired("H2.2.3")
public static boolean testWinVertical(final RobotFamily[][] stones, final RobotFamily currentPlayer) { public static boolean testWinVertical(final RobotFamily[][] stones, final RobotFamily currentPlayer) {
// TODO: H2.2.3 // 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") @StudentImplementationRequired("H2.2.4")
public static RobotFamily nextPlayer(final RobotFamily currentPlayer) { public static RobotFamily nextPlayer(final RobotFamily currentPlayer) {
// TODO: H2.2.4 // 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(); inputHandler.displayDrawStatus();
// TODO: H2.2.4 // 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); inputHandler.displayWinnerStatus(winner);
// TODO: H2.2.4 // 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") @StudentImplementationRequired("H2.2.4")
public static void colorFieldBackground(final RobotFamily winner) { public static void colorFieldBackground(final RobotFamily winner) {
// TODO: H2.2.4 // 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) { while (!finished) {
// TODO: H2.2.4 // TODO: H2.2.4
// set next player // 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) // wait for click in column (DO NOT TOUCH)
finished = draw = isGameBoardFull(stones); finished = draw = isGameBoardFull(stones);
@ -278,7 +335,8 @@ public class FourWins {
// TODO: H2.2.4 // TODO: H2.2.4
// let stone drop // let stone drop
// test win conditions // 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) // displaying either draw or winner (DO NOT TOUCH)
@ -341,5 +399,4 @@ public class FourWins {
public boolean isFinished() { public boolean isFinished() {
return finished; return finished;
} }
} }

View file

@ -4,6 +4,8 @@ import fopbot.RobotFamily;
import fopbot.World; import fopbot.World;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired; 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.io.PropertyUtils.getIntProperty;
import static org.tudalgo.algoutils.student.test.StudentTestUtils.printTestResults; import static org.tudalgo.algoutils.student.test.StudentTestUtils.printTestResults;
import static org.tudalgo.algoutils.student.test.StudentTestUtils.testEquals; import static org.tudalgo.algoutils.student.test.StudentTestUtils.testEquals;
@ -41,7 +43,10 @@ public class Main {
@StudentImplementationRequired("H2.3") @StudentImplementationRequired("H2.3")
public static void sanityChecksH211() { public static void sanityChecksH211() {
// TODO: H2.3 // 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 // 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 // TODO: H2.4
org.tudalgo.algoutils.student.Student.crash("H2.4 - Remove if implemented");
} }
} }

View file

@ -24,8 +24,12 @@ public class OneDimensionalArrayStuff {
@SuppressWarnings("ManualArrayCopy") @SuppressWarnings("ManualArrayCopy")
@StudentImplementationRequired("H2.1.1") @StudentImplementationRequired("H2.1.1")
public static int[] push(final int[] array, final int value) { public static int[] push(final int[] array, final int value) {
// TODO: H2.1.1 var newarr = new int[array.length+1];
return org.tudalgo.algoutils.student.Student.crash("H2.1.1 - Remove if implemented"); 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") @StudentImplementationRequired("H2.1.1")
public static int[] calculateNextFibonacci(final int[] array) { public static int[] calculateNextFibonacci(final int[] array) {
// TODO: H2.1.1 var a = array[array.length-2];
return org.tudalgo.algoutils.student.Student.crash("H2.1.1 - Remove if implemented"); var b = array[array.length-1];
return push(array, a+b);
} }
/** /**
@ -48,8 +53,15 @@ public class OneDimensionalArrayStuff {
* @return the n-th Fibonacci number * @return the n-th Fibonacci number
*/ */
@StudentImplementationRequired("H2.1.1") @StudentImplementationRequired("H2.1.1")
public static int fibonacci(final int n) { public static int fibonacci(int n) {
// TODO: H2.1.1 var arr = new int[] {0, 1};
return org.tudalgo.algoutils.student.Student.crash("H2.1.1 - Remove if implemented"); if (n < 2) {
return arr[n];
}
n -= 2;
while (n --> 0) {
arr = calculateNextFibonacci(arr);
}
return arr[arr.length-1];
} }
} }

View file

@ -3,7 +3,11 @@ package h02;
import org.tudalgo.algoutils.student.annotation.DoNotTouch; import org.tudalgo.algoutils.student.annotation.DoNotTouch;
import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired; import org.tudalgo.algoutils.student.annotation.StudentImplementationRequired;
import java.util.regex.*;
import java.util.Arrays; 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. * 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") @StudentImplementationRequired("H2.1.2")
public static int[] occurrences(final String[][] input, final String query) { public static int[] occurrences(final String[][] input, final String query) {
// TODO: H2.1.2 // 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") @StudentImplementationRequired("H2.1.2")
public static float mean(final int[] input) { public static float mean(final int[] input) {
// TODO: H2.1.2 // 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;
} }
/** /**

View file

@ -1,6 +1,14 @@
package h03; package h03;
import fopbot.World; 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. * Main entry point in executing the program.
@ -15,5 +23,33 @@ public class Main {
// Create a 5x5 world and make it visible // Create a 5x5 world and make it visible
World.setSize(5, 5); World.setSize(5, 5);
World.setVisible(true); 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()));
} }
} }

View 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;
}
}

View 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;
}
}

View 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));
}
}

View file

@ -0,0 +1,5 @@
package h03.robots;
public enum MovementType {
DIAGONAL, OVERSTEP, TELEPORT
}

View 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());
}
}
}

View file

@ -1,9 +1,12 @@
package h04; package h04;
import fopbot.Robot;
import h04.template.ChessUtils; import h04.template.ChessUtils;
import h04.template.GameControllerTemplate; import h04.template.GameControllerTemplate;
import h04.chesspieces.King; import h04.chesspieces.King;
import java.util.stream.Stream;
public class GameController extends GameControllerTemplate { public class GameController extends GameControllerTemplate {
public GameController() { public GameController() {
super(); super();
@ -13,6 +16,7 @@ public class GameController extends GameControllerTemplate {
@Override @Override
public boolean checkWinCondition() { public boolean checkWinCondition() {
//TODO H4.1 //TODO H4.1
return false; var kings = ChessUtils.getKings();
return Stream.of(kings).anyMatch(Robot::isTurnedOff);
} }
} }

View file

@ -1,13 +1,15 @@
package h04.chesspieces; package h04.chesspieces;
import fopbot.Robot; import fopbot.Robot;
import h04.movement.DiagonalMover;
import h04.movement.MoveStrategy;
//Wichtig für Implementation //Wichtig für Implementation
//import h04.movement.MoveStrategy; //import h04.movement.MoveStrategy;
import java.awt.Point; import java.awt.Point;
public class Bishop extends Robot { public class Bishop extends Robot implements DiagonalMover {
private final Team team; private final Team team;
@ -21,4 +23,13 @@ public class Bishop extends Robot {
public Team getTeam() { return team;} public Team getTeam() { return team;}
//TODO H4.5 //TODO H4.5
@Override
public void moveStrategy(int dx, int dy, MoveStrategy strategy) {
strategy.move(this, dx, dy);
}
@Override
public Point[] getPossibleMoveFields() {
return getDiagonalMoves();
}
} }

View file

@ -2,6 +2,8 @@ package h04.chesspieces;
//Wichtig für Implementation //Wichtig für Implementation
//import h04.movement.MoveStrategy; //import h04.movement.MoveStrategy;
import h04.movement.MoveStrategy;
import java.awt.Point; import java.awt.Point;
public interface ChessPiece { public interface ChessPiece {
@ -17,4 +19,7 @@ public interface ChessPiece {
void turnOff(); void turnOff();
//TODO H4.3 //TODO H4.3
void moveStrategy(int dx, int dy, MoveStrategy strategy);
Point[] getPossibleMoveFields();
} }

View file

@ -3,9 +3,12 @@ package h04.chesspieces;
import fopbot.Robot; import fopbot.Robot;
//Wichtig für Implementation //Wichtig für Implementation
//import h04.movement.MoveStrategy; //import h04.movement.MoveStrategy;
import fopbot.World;
import h04.movement.MoveStrategy;
import h04.template.ChessUtils; import h04.template.ChessUtils;
import java.awt.Point; import java.awt.Point;
import java.util.ArrayList;
public class King extends Robot implements ChessPiece { public class King extends Robot implements ChessPiece {
@ -22,4 +25,79 @@ public class King extends Robot implements ChessPiece {
} }
//TODO H4.4 //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);
}
} }

View file

@ -3,6 +3,7 @@ package h04.chesspieces;
import fopbot.Robot; import fopbot.Robot;
//Wichtig für Implementation //Wichtig für Implementation
//import h04.movement.MoveStrategy; //import h04.movement.MoveStrategy;
import h04.movement.MoveStrategy;
import h04.template.ChessUtils; import h04.template.ChessUtils;
import java.awt.Point; import java.awt.Point;
@ -21,14 +22,12 @@ public class Knight extends Robot implements ChessPiece {
return team; return team;
} }
//Wichtig für Implementation
/*
@Override @Override
public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) { public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) {
strategy.move(this, dx, dy); strategy.move(this, dx, dy);
} }
@Override @Override
*/
public Point[] getPossibleMoveFields() { public Point[] getPossibleMoveFields() {
final Point[] possibleMoves = new Point[8]; final Point[] possibleMoves = new Point[8];
int index = 0; int index = 0;

View file

@ -1,8 +1,7 @@
package h04.chesspieces; package h04.chesspieces;
import fopbot.Robot; import fopbot.Robot;
//Wichtig für Implementation import h04.movement.MoveStrategy;
//import h04.movement.MoveStrategy;
import java.awt.Point; import java.awt.Point;
@ -24,15 +23,13 @@ public class Pawn extends Robot implements ChessPiece {
return team; return team;
} }
//Wichtig für Implementation
/*
@Override @Override
public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) { public void moveStrategy(final int dx, final int dy, final MoveStrategy strategy) {
strategy.move(this, dx, dy); strategy.move(this, dx, dy);
firstMove = false; firstMove = false;
} }
@Override @Override
*/
public Point[] getPossibleMoveFields() { public Point[] getPossibleMoveFields() {
final Point[] possibleMoves = new Point[4]; final Point[] possibleMoves = new Point[4];
int index = 0; int index = 0;

View file

@ -3,11 +3,15 @@ package h04.chesspieces;
import fopbot.Robot; import fopbot.Robot;
//Wichtig für Implementation //Wichtig für Implementation
//import h04.movement.MoveStrategy; //import h04.movement.MoveStrategy;
import h04.movement.DiagonalMover;
import h04.movement.MoveStrategy;
import h04.movement.OrthogonalMover;
import h04.template.ChessUtils; import h04.template.ChessUtils;
import java.awt.Point; 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; private final Team team;
public Queen(final int x, final int y, 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 //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);
}
} }

View file

@ -3,11 +3,13 @@ package h04.chesspieces;
import fopbot.Robot; import fopbot.Robot;
//Wichtig für Implementation //Wichtig für Implementation
//import h04.movement.MoveStrategy; //import h04.movement.MoveStrategy;
import h04.movement.MoveStrategy;
import h04.movement.OrthogonalMover;
import h04.template.ChessUtils; import h04.template.ChessUtils;
import java.awt.Point; import java.awt.Point;
public class Rook extends Robot { public class Rook extends Robot implements OrthogonalMover {
private final Team team; private final Team team;
public Rook(final int x, final int y, 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 //TODO H4.5
@Override
public void moveStrategy(int dx, int dy, MoveStrategy strategy) {
strategy.move(this, dx, dy);
}
@Override
public Point[] getPossibleMoveFields() {
return getOrthogonalMoves();
}
} }

View 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);
}
}

View file

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

View 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);
}
}

View 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);
}
}

View 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();
}
}
}

View file

@ -13,12 +13,9 @@ import h04.chesspieces.Pawn;
import h04.chesspieces.Queen; import h04.chesspieces.Queen;
import h04.chesspieces.Rook; import h04.chesspieces.Rook;
import h04.chesspieces.Team; import h04.chesspieces.Team;
//Wichtig für Implementation import h04.movement.MoveStrategy;
//import h04.movement.MoveStrategy; import h04.movement.TeleportingMoveStrategy;
//Wichtig für Implementation import h04.movement.WalkingMoveStrategy;
//import h04.movement.TeleportingMoveStrategy;
//Wichtig für Implementation
//import h04.movement.WalkingMoveStrategy;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.tudalgo.algoutils.student.io.PropertyUtils; import org.tudalgo.algoutils.student.io.PropertyUtils;
@ -45,13 +42,10 @@ public abstract class GameControllerTemplate {
protected @Nullable ChessPiece selectedPiece; protected @Nullable ChessPiece selectedPiece;
//Wichtig für Implementation
/*
protected MoveStrategy moveStrategy = PropertyUtils.getBooleanProperty( protected MoveStrategy moveStrategy = PropertyUtils.getBooleanProperty(
"h04.properties", "h04.properties",
"USE_TELEPORT_MOVE_STRATEGY" "USE_TELEPORT_MOVE_STRATEGY"
) ? new TeleportingMoveStrategy() : new WalkingMoveStrategy(); ) ? new TeleportingMoveStrategy() : new WalkingMoveStrategy();
*/
/** /**
* Starts the game loop. * Starts the game loop.
@ -62,8 +56,6 @@ public abstract class GameControllerTemplate {
while (!gameOver) { while (!gameOver) {
final var point = inputHandler.getNextInput(nextToMove); final var point = inputHandler.getNextInput(nextToMove);
//Wichtig für Implementation
/*
if (ChessUtils.getTeamAt(point) == nextToMove) { if (ChessUtils.getTeamAt(point) == nextToMove) {
// select piece // select piece
selectedPiece = ChessUtils.getPieceAt(point); selectedPiece = ChessUtils.getPieceAt(point);
@ -107,7 +99,6 @@ public abstract class GameControllerTemplate {
nextToMove = nextToMove.getOpponent(); nextToMove = nextToMove.getOpponent();
selectedPiece = null; selectedPiece = null;
} }
*/
} }
} }

View file

@ -16,7 +16,7 @@ public class Airspace {
} }
// TODO: H5.1.1 - Uncomment the following lines // TODO: H5.1.1 - Uncomment the following lines
/* private final Set<Flying> flyingInAirspace = new HashSet<>(); private final Set<Flying> flyingInAirspace = new HashSet<>();
private Airspace(){ private Airspace(){
@ -28,9 +28,27 @@ public class Airspace {
void deregister(Flying flying){ void deregister(Flying flying){
flyingInAirspace.remove(flying); flyingInAirspace.remove(flying);
} */ }
void scanAirspace() { void scanAirspace() {
// TODO: H5.5 // 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;
} }
} }

View 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();
}
}

View file

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

View file

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

View 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();
}
}

View file

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

View 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;
}
}

View file

@ -11,5 +11,50 @@ public class Main {
*/ */
public static void main(String[] args) { public static void main(String[] args) {
// TODO: H5.6 // 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();
} }
} }

View 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;
}
}

View 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);
}
}

View file

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

View 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());
}
}
}

View 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());
}
}

View 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;
}
}

View 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);
}
}

View file

@ -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
}
}

View file

@ -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
// }
}

View file

@ -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();
}

View file

@ -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
// }
}

View file

@ -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() + ")";
}
}

View file

@ -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";
}
}

View file

View file

@ -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 Beachten Sie die Hinweise zum Herunterladen, Importieren, Bearbeitern, Exportieren und Hochladen in unserem
[Studierenden-Guide](https://wiki.tudalgo.org/) [Studierenden-Guide](https://wiki.tudalgo.org/)

View file

@ -5,7 +5,7 @@ plugins {
} }
exercise { exercise {
assignmentId.set("h07") assignmentId.set("h08")
} }
submission { submission {
@ -31,3 +31,7 @@ tasks {
} }
} }
} }
application {
applicationDefaultJvmArgs += "-ea"
}

View file

View file

View file

@ -8,4 +8,4 @@ dependencyResolutionManagement {
} }
} }
rootProject.name = "H07-Student" rootProject.name = "H08-Student"

View 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;
}
}

View 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);
}
}

View 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");
}
}

View 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 +
'}';
}
}

View 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");
}
}

View 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!");
}
}

View 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 +
'}';
}
}

View file

@ -1,4 +1,4 @@
package h07; package h08;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

88
H09/.gitignore vendored Normal file
View 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

View file

@ -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 Beachten Sie die Hinweise zum Herunterladen, Importieren, Bearbeitern, Exportieren und Hochladen in unserem
[Studierenden-Guide](https://wiki.tudalgo.org/) [Studierenden-Guide](https://wiki.tudalgo.org/)

33
H09/build.gradle.kts Normal file
View 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")
}
}
}

View 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

Binary file not shown.

View 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
View 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
View 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
View 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"

View 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())
);
}
}
}

View 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());
// }
}

View 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;
}
}
}

View 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());
}
}

View 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))));
}
}

View 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)
);
}
}

View 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");
}
}

View 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;
}
}

View 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!");
}
}

View 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;
}
}

View 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");
}
}

View 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();
}

View 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;
}

View 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();
}

View 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;
}
}

View 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!");
}
}

View 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