Squashed 'solution/H04/' content from commit 2ed3e56

git-subtree-dir: solution/H04
git-subtree-split: 2ed3e5642f6d0a6d1d02ae17ffc33f3a1076f8bb
This commit is contained in:
Oshgnacknak 2025-01-11 16:41:09 +01:00
commit 638df0b63d
75 changed files with 3278 additions and 0 deletions

12
.editorconfig Normal file
View file

@ -0,0 +1,12 @@
# Editor configuration, see https://editorconfig.org
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
[{*.yml,*.json}]
indent_size = 2

88
.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

4
README.md Normal file
View file

@ -0,0 +1,4 @@
# Musterlösung zu Hausübung 04
Beachten Sie die Hinweise zum Herunterladen, Importieren, Bearbeitern, Exportieren und Hochladen in unserem
[Studierenden-Guide](https://wiki.tudalgo.org/)

45
build.gradle.kts Normal file
View file

@ -0,0 +1,45 @@
plugins {
alias(libs.plugins.algomate)
alias(libs.plugins.style)
}
version = file("version").readLines().first()
exercise {
assignmentId.set("h04")
}
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 = "ab12cdef"
firstName = "sol_first"
lastName = "sol_last"
// Optionally require own tests for mainBuildSubmission task. Default is false
requireTests = false
}
dependencies {
implementation(libs.fopbot)
}
jagr {
graders {
val graderPublic by getting {
configureDependencies {
implementation(libs.algoutils.tutor)
}
}
val graderPrivate by creating {
parent(graderPublic)
graderName.set("FOP-2425-H04-Private")
rubricProviderName.set("h04.H04_RubricProvider")
}
}
}

11
gradle/libs.versions.toml Normal file
View file

@ -0,0 +1,11 @@
[versions]
algoutils = "0.9.1-SNAPSHOT"
[plugins]
algomate = { id = "org.tudalgo.algomate", version = "0.7.1" }
style = { id = "org.sourcegrade.style", version = "3.0.0" }
[libraries]
algoutils-student = { module = "org.tudalgo:algoutils-student", version.ref = "algoutils" }
algoutils-tutor = { module = "org.tudalgo:algoutils-tutor", version.ref = "algoutils" }
fopbot = { module = "org.tudalgo:fopbot", version = "0.8.1" }

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

245
gradlew vendored Executable file
View file

@ -0,0 +1,245 @@
#!/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##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && 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
which java >/dev/null 2>&1 || 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
# 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=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=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, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
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
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.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
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
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 = "H04-Root"

View file

@ -0,0 +1,113 @@
package h04;
import fopbot.Robot;
import fopbot.World;
import h04.chesspieces.King;
import h04.chesspieces.Team;
import h04.template.ChessUtils;
import h04.template.GameControllerTemplate;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.Invocation;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.transform.util.MethodSubstitution;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.util.stream.Stream;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertCallEquals;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.call;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
@TestForSubmission
public class GameControllerTest {
private final MethodHeader gameControllerConstructor = MethodHeader.of(GameController.class);
private final MethodHeader gameController_checkWinCondition = MethodHeader.of(GameController.class, "checkWinCondition");
private final MethodHeader chessUtils_getKings = MethodHeader.of(ChessUtils.class, "getKings");
@BeforeEach
public void setupEnvironment() {
World.setSize(2, 1);
World.setDelay(0);
}
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testCheckWinConditionCallsChessUtils() {
SubmissionExecutionHandler.Substitution.enable(gameControllerConstructor, new MethodSubstitution() {
@Override
public ConstructorInvocation getConstructorInvocation() {
return new ConstructorInvocation(Type.getInternalName(GameControllerTemplate.class), "()V");
}
@Override
public Object execute(Invocation invocation) {
return null;
}
});
SubmissionExecutionHandler.Logging.enable(chessUtils_getKings);
SubmissionExecutionHandler.Delegation.disable(gameController_checkWinCondition);
King whiteKing = new King(0, 0, Team.WHITE);
King blackKing = new King(1, 0, Team.BLACK);
Context context = contextBuilder()
.add("white king", whiteKing)
.add("black king", blackKing)
.build();
call(() -> new GameController().checkWinCondition(), context, result -> "An exception occurred while invoking method checkWinCondition");
assertTrue(!SubmissionExecutionHandler.Logging.getInvocations(chessUtils_getKings).isEmpty(),
context,
result -> "ChessUtils.getKings() was not called at least once");
}
@ParameterizedTest
@ValueSource(ints = {0, 1, 2, 3})
public void testCheckWinCondition(int n) {
SubmissionExecutionHandler.Substitution.enable(gameControllerConstructor, new MethodSubstitution() {
@Override
public ConstructorInvocation getConstructorInvocation() {
return new ConstructorInvocation(Type.getInternalName(GameControllerTemplate.class), "()V");
}
@Override
public Object execute(Invocation invocation) {
return null;
}
});
SubmissionExecutionHandler.Delegation.disable(gameController_checkWinCondition);
boolean turnOffWhiteKing = (n & 1) != 0;
boolean turnOffBlackKing = (n & 2) != 0;
King whiteKing = new King(0, 0, Team.WHITE);
King blackKing = new King(1, 0, Team.BLACK);
if (turnOffWhiteKing) {
whiteKing.turnOff();
}
if (turnOffBlackKing) {
blackKing.turnOff();
}
Context context = contextBuilder()
.add("white king", whiteKing)
.add("black king", blackKing)
.add("turned off king(s)", Stream.of(whiteKing, blackKing).filter(Robot::isTurnedOff).toList())
.build();
assertCallEquals(turnOffWhiteKing || turnOffBlackKing,
() -> new GameController().checkWinCondition(),
context,
result -> "Method checkWinCondition returned an incorrect value");
}
}

View file

@ -0,0 +1,196 @@
package h04;
import h04.chesspieces.BishopTest;
import h04.chesspieces.ChessPieceTest;
import h04.chesspieces.KingTest;
import h04.chesspieces.QueenTest;
import h04.chesspieces.RookTest;
import h04.movement.DiagonalMoverTest;
import h04.movement.MoveStrategyTest;
import h04.movement.OrthogonalMoverTest;
import h04.movement.TeleportingMoveStrategyTest;
import h04.movement.WalkingMoveStrategyTest;
import org.sourcegrade.jagr.api.rubric.*;
import org.sourcegrade.jagr.api.testing.RubricConfiguration;
import org.tudalgo.algoutils.transform.SolutionMergingClassTransformer;
import static org.tudalgo.algoutils.tutor.general.jagr.RubricUtils.criterion;
@SuppressWarnings("unused")
public class H04_RubricProvider implements RubricProvider {
private static final Criterion H4_1 = Criterion.builder()
.shortDescription("H4.1 | Das Ende kommt zuerst")
.addChildCriteria(
criterion("Die Könige werden mittels ChessUtils.getKings abgerufen.",
JUnitTestRef.ofMethod(() -> GameControllerTest.class.getDeclaredMethod("testCheckWinConditionCallsChessUtils"))),
criterion("Die Methode checkWinCondition() gibt true zurück, wenn ein König geschlagen wurde, ansonsten false.",
JUnitTestRef.ofMethod(() -> GameControllerTest.class.getDeclaredMethod("testCheckWinCondition", int.class)))
)
.build();
private static final Criterion H4_2_1 = Criterion.builder()
.shortDescription("H4.2.1 | MoveStrategy Interface")
.addChildCriteria(
criterion("Das MoveStrategy-Interface ist korrekt implementiert.",
JUnitTestRef.ofMethod(() -> MoveStrategyTest.class.getDeclaredMethod("testDeclaration")))
)
.build();
private static final Criterion H4_2_2 = Criterion.builder()
.shortDescription("H4.2.2 | TeleportingMoveStrategy")
.addChildCriteria(
criterion("Die TeleportingMoveStrategy-Klasse ist korrekt deklariert.",
JUnitTestRef.ofMethod(() -> TeleportingMoveStrategyTest.class.getDeclaredMethod("testClassHeader"))),
criterion("Methode move(Robot, int, int) ist korrekt implementiert.",
JUnitTestRef.ofMethod(() -> TeleportingMoveStrategyTest.class.getDeclaredMethod("testMove", int.class)))
)
.build();
private static final Criterion H4_2_3 = Criterion.builder()
.shortDescription("H4.2.3 | WalkingMoveStrategy")
.addChildCriteria(
criterion("Die WalkingMoveStrategy-Klasse implementiert das MoveStrategy-Interface korrekt.",
JUnitTestRef.ofMethod(() -> WalkingMoveStrategyTest.class.getDeclaredMethod("testClassHeader"))),
criterion("Der Roboter bewegt sich korrekt.",
JUnitTestRef.ofMethod(() -> WalkingMoveStrategyTest.class.getDeclaredMethod("testMove", int.class))),
criterion("Der Roboter schaut nach der Bewegung in die richtige Richtung.",
JUnitTestRef.ofMethod(() -> WalkingMoveStrategyTest.class.getDeclaredMethod("testMoveFacesUp", int.class)))
)
.build();
private static final Criterion H4_2 = Criterion.builder()
.shortDescription("H4.2 | MoveStrategy")
.addChildCriteria(H4_2_1, H4_2_2, H4_2_3)
.build();
private static final Criterion H4_3 = Criterion.builder()
.shortDescription("H4.3 | ChessPiece Interface")
.addChildCriteria(
criterion("Methode moveStrategy(int, int, MoveStrategy) ist korrekt deklariert.",
JUnitTestRef.ofMethod(() -> ChessPieceTest.class.getDeclaredMethod("testMoveStrategyDeclaration"))),
criterion("Methode getPossibleMoveFields() ist korrekt deklariert.",
JUnitTestRef.ofMethod(() -> ChessPieceTest.class.getDeclaredMethod("testGetPossibleMoveFieldDeclaration")))
)
.build();
private static final Criterion H4_4_1 = Criterion.builder()
.shortDescription("H4.4.1 | King MoveStrategy")
.addChildCriteria(
criterion("Die Methode moveStrategy ist korrekt implementiert.", 2,
JUnitTestRef.ofMethod(() -> KingTest.class.getDeclaredMethod("testMoveStrategy")))
)
.build();
private static final Criterion H4_4_2 = Criterion.builder()
.shortDescription("H4.4.2 | King getPossibleMoveFields")
.addChildCriteria(
criterion("Die Methode getPossibleMoveFields ist korrekt deklariert.",
JUnitTestRef.ofMethod(() -> KingTest.class.getDeclaredMethod("testGetPossibleMoveFieldsHeader"))),
criterion("Die Methode gibt nicht mehr als die korrekte Anzahl an Feldern zurück.",
JUnitTestRef.ofMethod(() -> KingTest.class.getDeclaredMethod("testGetPossibleMoveFieldsCorrectAmount"))),
criterion("Die Methode gibt keine Felder zurück, auf denen sich ein eigener König befindet.",
JUnitTestRef.ofMethod(() -> KingTest.class.getDeclaredMethod("testGetPossibleMoveFieldsExcludesSelf"))),
criterion("Die Methode gibt keine Felder zurück, die außerhalb des Spielfelds liegen.",
JUnitTestRef.ofMethod(() -> KingTest.class.getDeclaredMethod("testGetPossibleMoveFieldsInWorld"))),
criterion("Die Methode gibt die korrekten Felder zurück, auf die der König ziehen kann.",
JUnitTestRef.ofMethod(() -> KingTest.class.getDeclaredMethod("testGetPossibleMoveFieldsCorrect")))
)
.build();
private static final Criterion H4_4 = Criterion.builder()
.shortDescription("H4.4 | Schachfiguren-Bewegung I")
.addChildCriteria(H4_4_1, H4_4_2)
.build();
private static final Criterion H4_5_1 = Criterion.builder()
.shortDescription("H4.5.1 | OrthogonalMover and DiagonalMover")
.addChildCriteria(
criterion("Die Methode getOrthogonalMoves wird korrekt hinzugefügt.",
JUnitTestRef.ofMethod(() -> OrthogonalMoverTest.class.getDeclaredMethod("testMethodHeader"))),
criterion("Die Methode getOrthogonalMoves gibt die korrekten Felder zurück.",
JUnitTestRef.ofMethod(() -> OrthogonalMoverTest.class.getDeclaredMethod("testGetOrthogonalMoves"))),
criterion("Die Methode getDiagonalMoves wird korrekt hinzugefügt.",
JUnitTestRef.ofMethod(() -> DiagonalMoverTest.class.getDeclaredMethod("testMethodHeader"))),
criterion("Die Methode getDiagonalMoves gibt die korrekten Felder zurück.",
JUnitTestRef.ofMethod(() -> DiagonalMoverTest.class.getDeclaredMethod("testGetDiagonalMoves"))),
criterion("OrthogonalMover und DiagonalMover erweitern beide das Interface ChessPiece.",
JUnitTestRef.ofMethod(() -> OrthogonalMoverTest.class.getDeclaredMethod("testClassHeader")),
JUnitTestRef.ofMethod(() -> DiagonalMoverTest.class.getDeclaredMethod("testClassHeader")))
)
.build();
private static final Criterion H4_5_2 = Criterion.builder()
.shortDescription("H4.5.2 | Rook and Bishop")
.addChildCriteria(
criterion("Die Rook-Klasse implementiert das OrthogonalMover-Interface korrekt.",
JUnitTestRef.ofMethod(() -> RookTest.class.getDeclaredMethod("testClassHeader"))),
criterion("Die Methoden moveStrategy und getPossibleMoveFields der Klasse Rook sind korrekt implementiert.",
JUnitTestRef.ofMethod(() -> RookTest.class.getDeclaredMethod("testMoveStrategy")),
JUnitTestRef.ofMethod(() -> RookTest.class.getDeclaredMethod("testGetPossibleMoveFields"))),
criterion("Die Bishop-Klasse implementiert das DiagonalMover-Interface korrekt.",
JUnitTestRef.ofMethod(() -> BishopTest.class.getDeclaredMethod("testClassHeader"))),
criterion("Die Methoden moveStrategy und getPossibleMoveFields der Klasse Bishop sind korrekt implementiert.",
JUnitTestRef.ofMethod(() -> BishopTest.class.getDeclaredMethod("testMoveStrategy")),
JUnitTestRef.ofMethod(() -> BishopTest.class.getDeclaredMethod("testGetPossibleMoveFields"))),
criterion("Beide Klassen sind vollständig korrekt implementiert.",
JUnitTestRef.ofMethod(() -> RookTest.class.getDeclaredMethod("testClassHeader")),
JUnitTestRef.ofMethod(() -> RookTest.class.getDeclaredMethod("testMoveStrategy")),
JUnitTestRef.ofMethod(() -> RookTest.class.getDeclaredMethod("testGetPossibleMoveFields")),
JUnitTestRef.ofMethod(() -> BishopTest.class.getDeclaredMethod("testClassHeader")),
JUnitTestRef.ofMethod(() -> BishopTest.class.getDeclaredMethod("testMoveStrategy")),
JUnitTestRef.ofMethod(() -> BishopTest.class.getDeclaredMethod("testGetPossibleMoveFields")))
)
.build();
private static final Criterion H4_5 = Criterion.builder()
.shortDescription("H4.5 | Schachfiguren-Bewegung II")
.addChildCriteria(H4_5_1, H4_5_2)
.build();
private static final Criterion H4_6 = Criterion.builder()
.shortDescription("H4.6 | Queen")
.addChildCriteria(
criterion("Die Queen-Klasse implementiert das OrthogonalMover- und DiagonalMover-Interface korrekt.",
JUnitTestRef.ofMethod(() -> QueenTest.class.getDeclaredMethod("testClassHeader"))),
criterion("Die Methode getPossibleMoveFields gibt die korrekten Felder zurück.", 2,
JUnitTestRef.ofMethod(() -> QueenTest.class.getDeclaredMethod("testGetPossibleMoveFields_Correct"))),
criterion("Die Rückgaben der Methoden getOrthogonalMoves und getDiagonalMoves werden korrekt kombiniert.", 2,
JUnitTestRef.ofMethod(() -> QueenTest.class.getDeclaredMethod("testGetPossibleMoveFields_Combine")))
)
.build();
@Override
public Rubric getRubric() {
return Rubric.builder()
.title("H04 | Schach")
.addChildCriteria(H4_1, H4_2, H4_3, H4_4, H4_5, H4_6)
.build();
}
@Override
public void configure(RubricConfiguration configuration) {
configuration.addTransformer(() -> new SolutionMergingClassTransformer.Builder("h04")
.addSolutionClass("h04.chesspieces.Bishop")
.addSolutionClass("h04.chesspieces.ChessPiece")
.addSolutionClass("h04.chesspieces.Families")
.addSolutionClass("h04.chesspieces.King")
.addSolutionClass("h04.chesspieces.Knight")
.addSolutionClass("h04.chesspieces.Pawn")
.addSolutionClass("h04.chesspieces.Queen")
.addSolutionClass("h04.chesspieces.Rook")
.addSolutionClass("h04.chesspieces.Team")
.addSolutionClass("h04.movement.DiagonalMover", "h04.DiagonalMover")
.addSolutionClass("h04.movement.MoveStrategy", "h04.MoveStrategy")
.addSolutionClass("h04.movement.OrthogonalMover", "h04.OrthogonalMover")
.addSolutionClass("h04.movement.TeleportingMoveStrategy", "h04.TeleportingMoveStrategy")
.addSolutionClass("h04.movement.WalkingMoveStrategy", "h04.WalkingMoveStrategy")
.addSolutionClass("h04.template.ChessUtils")
.addSolutionClass("h04.template.GameControllerTemplate")
.addSolutionClass("h04.template.InputHandler")
.addSolutionClass("h04.GameController")
.addSolutionClass("h04.Main")
.setSimilarity(0.90)
.build());
}
}

View file

@ -0,0 +1,103 @@
package h04.chesspieces;
import fopbot.Robot;
import fopbot.World;
import h04.movement.DiagonalMover;
import h04.movement.MoveStrategy;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.ClassHeader;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.awt.Point;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertEquals;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertSame;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.call;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.callObject;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
@TestForSubmission
public class BishopTest {
private final MethodHeader bishop_moveStrategy = MethodHeader.of(Bishop.class,
"moveStrategy", int.class, int.class, MoveStrategy.class);
private final MethodHeader bishop_getPossibleMoveFields = MethodHeader.of(Bishop.class,
"getPossibleMoveFields");
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testClassHeader() {
ClassHeader originalClassHeader = SubmissionExecutionHandler.getOriginalClassHeader(Bishop.class);
assertTrue(Arrays.stream(originalClassHeader.interfaces()).anyMatch(s -> s.equals(Type.getInternalName(DiagonalMover.class))),
emptyContext(),
result -> "Class h04.chesspieces.Bishop does not implement interface h04.movement.DiagonalMover");
}
@Test
public void testMoveStrategy() {
SubmissionExecutionHandler.Delegation.disable(bishop_moveStrategy);
World.setSize(3, 3);
World.setDelay(0);
AtomicReference<Robot> robotRef = new AtomicReference<>();
AtomicInteger dxInt = new AtomicInteger(-1);
AtomicInteger dyInt = new AtomicInteger(-1);
MoveStrategy moveStrategy = (r, dx, dy) -> {
robotRef.set(r);
dxInt.set(dx);
dyInt.set(dy);
};
int dx = 1;
int dy = 1;
Context context = contextBuilder()
.add("dx", dx)
.add("dy", dy)
.add("strategy", moveStrategy)
.build();
Bishop bishopInstance = new Bishop(0, 0, Team.WHITE);
call(() -> bishopInstance.moveStrategy(dx, dy, moveStrategy), context, result ->
"An exception occurred while invoking moveStrategy(int, int, MoveStrategy)");
assertSame(bishopInstance, robotRef.get(), context, result ->
"Method move of MoveStrategy was called with incorrect first parameter");
assertEquals(dx, dxInt.get(), context, result ->
"Method move of MoveStrategy was called with incorrect second parameter");
assertEquals(dy, dyInt.get(), context, result ->
"Method move of MoveStrategy was called with incorrect third parameter");
}
@Test
public void testGetPossibleMoveFields() {
SubmissionExecutionHandler.Delegation.disable(bishop_getPossibleMoveFields);
Point[] points = new Point[0];
SubmissionExecutionHandler.Substitution.enable(MethodHeader.of(DiagonalMover.class, "getDiagonalMoves"),
invocation -> points);
int worldSize = 8;
World.setSize(worldSize, worldSize);
World.setDelay(0);
Context context = contextBuilder()
.add("world size", worldSize)
.add("x", 0)
.add("y", 0)
.build();
Point[] returnValue = callObject(() -> new Bishop(0, 0, Team.WHITE).getPossibleMoveFields(), context, result ->
"An exception occurred while invoking getPossibleMoveFields()");
assertSame(points, returnValue, context, result -> "Method did not return the result of getPossibleMoveFields()");
}
}

View file

@ -0,0 +1,37 @@
package h04.chesspieces;
import h04.movement.MoveStrategy;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import java.awt.Point;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.fail;
@TestForSubmission
public class ChessPieceTest {
@Test
public void testMoveStrategyDeclaration() {
MethodHeader moveStrategyMethodHeader = SubmissionExecutionHandler.getOriginalMethodHeaders(ChessPiece.class)
.stream()
.filter(methodHeader -> methodHeader.name().equals("moveStrategy") &&
methodHeader.descriptor().equals(Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.getType(MoveStrategy.class))))
.findAny()
.orElseGet(() -> fail(emptyContext(), result -> "ChessPiece does not declare method 'moveStrategy(int, int, MoveStrategy)'"));
}
@Test
public void testGetPossibleMoveFieldDeclaration() {
MethodHeader getPossibleMoveFieldsMethodHeader = SubmissionExecutionHandler.getOriginalMethodHeaders(ChessPiece.class)
.stream()
.filter(methodHeader -> methodHeader.name().equals("getPossibleMoveFields") &&
methodHeader.descriptor().equals(Type.getMethodDescriptor(Type.getType(Point[].class))))
.findAny()
.orElseGet(() -> fail(emptyContext(), result -> "ChessPiece does not declare method 'getPossibleMoveFields()'"));
}
}

View file

@ -0,0 +1,167 @@
package h04.chesspieces;
import fopbot.Robot;
import fopbot.World;
import h04.movement.MoveStrategy;
import kotlin.Triple;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.awt.Point;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertEquals;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertFalse;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertNotNull;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertSame;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.call;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.callObject;
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;
@TestForSubmission
public class KingTest {
private final MethodHeader king_moveStrategy = MethodHeader.of(King.class,
"moveStrategy", int.class, int.class, MoveStrategy.class);
private final MethodHeader king_getPossibleMoveFieldsMethod = MethodHeader.of(King.class,
"getPossibleMoveFields");
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testMoveStrategy() {
SubmissionExecutionHandler.Delegation.disable(king_moveStrategy);
World.setSize(3, 3);
World.setDelay(0);
AtomicReference<Robot> robotRef = new AtomicReference<>();
AtomicInteger dxInt = new AtomicInteger(-1);
AtomicInteger dyInt = new AtomicInteger(-1);
MoveStrategy moveStrategy = (r, dx, dy) -> {
robotRef.set(r);
dxInt.set(dx);
dyInt.set(dy);
};
int dx = 1;
int dy = 1;
Context context = contextBuilder()
.add("dx", dx)
.add("dy", dy)
.add("strategy", moveStrategy)
.build();
King kingInstance = new King(0, 0, Team.WHITE);
call(() -> kingInstance.moveStrategy(dx, dy, moveStrategy), context, result ->
"An exception occurred while invoking moveStrategy(int, int, MoveStrategy)");
assertSame(kingInstance, robotRef.get(), context, result ->
"Method move of MoveStrategy was called with incorrect first parameter");
assertEquals(dx, dxInt.get(), context, result ->
"Method move of MoveStrategy was called with incorrect second parameter");
assertEquals(dy, dyInt.get(), context, result ->
"Method move of MoveStrategy was called with incorrect third parameter");
}
@Test
public void testGetPossibleMoveFieldsHeader() {
MethodHeader getPossibleMoveFieldsMethodHeader = SubmissionExecutionHandler.getOriginalMethodHeaders(King.class)
.stream()
.filter(methodHeader -> methodHeader.name().equals("getPossibleMoveFields") &&
methodHeader.descriptor().equals(Type.getMethodDescriptor(Type.getType(Point[].class))))
.findAny()
.orElseGet(() -> fail(emptyContext(), result -> "King does not declare method 'getPossibleMoveFields()'"));
}
@Test
public void testGetPossibleMoveFieldsCorrectAmount() {
Triple<Context, King, Point[]> invocationResult = invokeGetPossibleMoveFields(5, 2, 2);
Context context = invocationResult.getFirst();
Point[] returnValue = invocationResult.getThird();
assertNotNull(returnValue, context, result -> "Method returned null");
assertTrue(returnValue.length <= 8, context, result -> "Method returned more than eight possible options");
}
@Test
public void testGetPossibleMoveFieldsExcludesSelf() {
int x = 2;
int y = 2;
Triple<Context, King, Point[]> invocationResult = invokeGetPossibleMoveFields(5, x, y);
Context context = invocationResult.getFirst();
Point[] returnValue = invocationResult.getThird();
Point kingPosition = new Point(x, y);
assertNotNull(returnValue, context, result -> "Method returned null");
assertFalse(Arrays.asList(returnValue).contains(kingPosition), context, result ->
"Method returned a point with the king's current position");
}
@Test
public void testGetPossibleMoveFieldsInWorld() {
int worldSize = 5;
Triple<Context, King, Point[]> invocationResult = invokeGetPossibleMoveFields(worldSize, 0, 0);
Context context = invocationResult.getFirst();
Point[] returnValue = invocationResult.getThird();
assertNotNull(returnValue, context, result -> "Method returned null");
List<Point> pointsOutsideWorld = Arrays.stream(returnValue)
.filter(Objects::nonNull) // TODO: not sure if method is allowed to return null elements
.filter(point -> point.x < 0 || point.x >= worldSize || point.y < 0 || point.y >= worldSize)
.toList();
assertEquals(Collections.emptyList(), pointsOutsideWorld, context, result ->
"Method returned points that were outside the world");
}
@Test
public void testGetPossibleMoveFieldsCorrect() {
int x = 2;
int y = 2;
Triple<Context, King, Point[]> invocationResult = invokeGetPossibleMoveFields(5, x, y);
Context context = invocationResult.getFirst();
Point[] returnValue = invocationResult.getThird();
assertNotNull(returnValue, context, result -> "Method returned null");
assertEquals(8, returnValue.length, context, result -> "Method did not return eight possible options");
List<Point> points = Arrays.asList(returnValue);
int[] deltas = new int[] {-1, 0, 1};
for (int dx : deltas) {
for (int dy : deltas) {
if (dx == 0 && dy == 0) {
continue;
}
assertTrue(points.contains(new Point(x + dx, y + dy)), context, result ->
"Method did not return a valid point: (%d|%d)".formatted(x + dx, y + dy));
}
}
}
private Triple<Context, King, Point[]> invokeGetPossibleMoveFields(int worldSize, int x, int y) {
SubmissionExecutionHandler.Delegation.disable(king_getPossibleMoveFieldsMethod);
World.setSize(worldSize, worldSize);
World.setDelay(0);
King kingInstance = new King(x, y, Team.WHITE);
Context context = contextBuilder()
.add("world size", worldSize)
.add("x-coordinate", x)
.add("y-coordinate", y)
.build();
Point[] returnValue = callObject(kingInstance::getPossibleMoveFields, context, result ->
"An exception occurred while invoking getPossibleMoveFields()");
return new Triple<>(context, kingInstance, returnValue);
}
}

View file

@ -0,0 +1,126 @@
package h04.chesspieces;
import fopbot.World;
import h04.movement.DiagonalMover;
import h04.movement.MoveStrategy;
import h04.movement.OrthogonalMover;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.ClassHeader;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.awt.Point;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
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.assertNotNull;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.callObject;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
@TestForSubmission
public class QueenTest {
private final MethodHeader queen_moveStrategy = MethodHeader.of(Queen.class,
"moveStrategy", int.class, int.class, MoveStrategy.class);
private final MethodHeader queen_getPossibleMoveFields = MethodHeader.of(Queen.class, "getPossibleMoveFields");
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testClassHeader() {
ClassHeader originalClassHeader = SubmissionExecutionHandler.getOriginalClassHeader(Queen.class);
assertTrue(Arrays.stream(originalClassHeader.interfaces()).anyMatch(s -> s.equals(Type.getInternalName(OrthogonalMover.class))),
emptyContext(),
result -> "Class h04.chesspieces.Queen does not implement interface h04.movement.OrthogonalMover");
assertTrue(Arrays.stream(originalClassHeader.interfaces()).anyMatch(s -> s.equals(Type.getInternalName(DiagonalMover.class))),
emptyContext(),
result -> "Class h04.chesspieces.Queen does not implement interface h04.movement.DiagonalMover");
}
@Test
public void testGetPossibleMoveFields_Correct() {
SubmissionExecutionHandler.Delegation.disable(queen_getPossibleMoveFields);
int worldSize = 8;
for (int x : new int[] {0, worldSize - 1}) {
for (int y : new int[] {0, worldSize - 1}) {
World.setSize(worldSize, worldSize);
World.setDelay(0);
Queen queenInstance = new Queen(x, y, Team.WHITE);
Context context = contextBuilder()
.add("world size", worldSize)
.add("x-coordinate", x)
.add("y-coordinate", y)
.build();
Point[] returnValue = callObject(queenInstance::getPossibleMoveFields, context, result ->
"An exception occurred while invoking getPossibleMoveFields()");
assertNotNull(returnValue, context, result -> "getPossibleMoveFields() returned null");
List<Point> points = Arrays.stream(returnValue).filter(Objects::nonNull).collect(Collectors.toList());
Point[] vectors = new Point[] {
new Point(0, 1),
new Point(1, 1),
new Point(1, 0),
new Point(1, -1),
new Point(0, -1),
new Point(-1, -1),
new Point(-1, 0),
new Point(-1, 1),
};
for (Point vector : vectors) {
for (int n = 1; n < worldSize; n++) {
if (vector.x * n + x < 0 || vector.x * n + x >= worldSize || vector.y * n + y < 0 || vector.y * n + y >= worldSize) {
break;
}
Point expectedPoint = new Point(vector.x * n + x, vector.y * n + y);
assertTrue(points.contains(expectedPoint), context, result ->
"Point %s was not found in returned array".formatted(expectedPoint));
points.remove(expectedPoint);
}
}
assertEquals(Collections.emptyList(), points, context, result -> "Returned array contained more points than are valid");
}
}
}
@Test
public void testGetPossibleMoveFields_Combine() {
SubmissionExecutionHandler.Delegation.disable(queen_getPossibleMoveFields);
int worldSize = 8;
World.setSize(worldSize, worldSize);
World.setDelay(0);
Queen queenInstance = new Queen(1, 1, Team.WHITE);
Context context = contextBuilder()
.add("world size", worldSize)
.add("x-coordinate", queenInstance.getX())
.add("y-coordinate", queenInstance.getY())
.build();
Point[] returnValue = callObject(queenInstance::getPossibleMoveFields, context, result ->
"An exception occurred while invoking getPossibleMoveFields()");
assertNotNull(returnValue, context, result -> "getPossibleMoveFields() returned null");
Set<Point> expectedPoints = Stream.of(queenInstance.getDiagonalMoves(), queenInstance.getOrthogonalMoves())
.flatMap(Stream::of)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Set<Point> actualPoints = Arrays.stream(returnValue).filter(Objects::nonNull).collect(Collectors.toSet());
assertEquals(expectedPoints, actualPoints, context, result ->
"Method did not merge results of getOrthogonalMoves() and getDiagonalMoves()");
}
}

View file

@ -0,0 +1,103 @@
package h04.chesspieces;
import fopbot.Robot;
import fopbot.World;
import h04.movement.MoveStrategy;
import h04.movement.OrthogonalMover;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.ClassHeader;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.awt.Point;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertEquals;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertSame;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.call;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.callObject;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
@TestForSubmission
public class RookTest {
private final MethodHeader rook_moveStrategy = MethodHeader.of(Rook.class,
"moveStrategy", int.class, int.class, MoveStrategy.class);
private final MethodHeader rook_getPossibleMoveFields = MethodHeader.of(Rook.class,
"getPossibleMoveFields");
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testClassHeader() {
ClassHeader originalClassHeader = SubmissionExecutionHandler.getOriginalClassHeader(Rook.class);
assertTrue(Arrays.stream(originalClassHeader.interfaces()).anyMatch(s -> s.equals(Type.getInternalName(OrthogonalMover.class))),
emptyContext(),
result -> "Class h04.chesspieces.Rook does not implement interface h04.movement.OrthogonalMover");
}
@Test
public void testMoveStrategy() {
SubmissionExecutionHandler.Delegation.disable(rook_moveStrategy);
World.setSize(3, 3);
World.setDelay(0);
AtomicReference<Robot> robotRef = new AtomicReference<>();
AtomicInteger dxInt = new AtomicInteger(-1);
AtomicInteger dyInt = new AtomicInteger(-1);
MoveStrategy moveStrategy = (r, dx, dy) -> {
robotRef.set(r);
dxInt.set(dx);
dyInt.set(dy);
};
int dx = 1;
int dy = 1;
Context context = contextBuilder()
.add("dx", dx)
.add("dy", dy)
.add("strategy", moveStrategy)
.build();
Rook rookInstance = new Rook(0, 0, Team.WHITE);
call(() -> rookInstance.moveStrategy(dx, dy, moveStrategy), context, result ->
"An exception occurred while invoking moveStrategy(int, int, MoveStrategy)");
assertSame(rookInstance, robotRef.get(), context, result ->
"Method move of MoveStrategy was called with incorrect first parameter");
assertEquals(dx, dxInt.get(), context, result ->
"Method move of MoveStrategy was called with incorrect second parameter");
assertEquals(dy, dyInt.get(), context, result ->
"Method move of MoveStrategy was called with incorrect third parameter");
}
@Test
public void testGetPossibleMoveFields() {
SubmissionExecutionHandler.Delegation.disable(rook_getPossibleMoveFields);
Point[] points = new Point[0];
SubmissionExecutionHandler.Substitution.enable(MethodHeader.of(OrthogonalMover.class, "getOrthogonalMoves"),
invocation -> points);
int worldSize = 8;
World.setSize(worldSize, worldSize);
World.setDelay(0);
Context context = contextBuilder()
.add("world size", worldSize)
.add("x", 0)
.add("y", 0)
.build();
Point[] returnValue = callObject(() -> new Rook(0, 0, Team.WHITE).getPossibleMoveFields(), context, result ->
"An exception occurred while invoking getPossibleMoveFields()");
assertSame(points, returnValue, context, result -> "Method did not return the result of getOrthogonalMoves()");
}
}

View file

@ -0,0 +1,133 @@
package h04.movement;
import fopbot.World;
import h04.chesspieces.ChessPiece;
import h04.chesspieces.Team;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.ClassHeader;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.awt.Point;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertEquals;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertFalse;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertNotNull;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.callObject;
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;
@TestForSubmission
public class DiagonalMoverTest {
private final MethodHeader diagonalMover_getDiagonalMoves = MethodHeader.of(DiagonalMover.class, "getDiagonalMoves");
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testClassHeader() {
ClassHeader originalClassHeader = SubmissionExecutionHandler.getOriginalClassHeader(DiagonalMover.class);
assertTrue(Arrays.stream(originalClassHeader.interfaces()).anyMatch(s -> s.equals(Type.getInternalName(ChessPiece.class))),
emptyContext(),
result -> "Interface h04.movement.DiagonalMover does not extend interface h04.movement.ChessPiece");
}
@Test
public void testMethodHeader() {
MethodHeader getDiagonalMovesMethodHeader = SubmissionExecutionHandler.getOriginalMethodHeaders(DiagonalMover.class)
.stream()
.filter(methodHeader -> methodHeader.name().equals("getDiagonalMoves") &&
methodHeader.descriptor().equals(Type.getMethodDescriptor(Type.getType(Point[].class))))
.findAny()
.orElseGet(() -> fail(emptyContext(), result -> "DiagonalMover does not declare method 'getDiagonalMoves()'"));
assertTrue(Modifier.isPublic(getDiagonalMovesMethodHeader.access()), emptyContext(), result ->
"Method getDiagonalMoves() is not declared public");
assertFalse(Modifier.isAbstract(getDiagonalMovesMethodHeader.access()), emptyContext(), result ->
"Method getDiagonalMoves() is not declared default");
}
@Test
public void testGetDiagonalMoves() {
SubmissionExecutionHandler.Delegation.disable(diagonalMover_getDiagonalMoves);
int worldSize = 8;
World.setSize(worldSize, worldSize);
World.setDelay(0);
for (int x : new int[] {0, worldSize - 1}) {
for (int y : new int[] {0, worldSize - 1}) {
DiagonalMover diagonalMoverInstance = new DiagonalMover() {
@Override
public Team getTeam() {
return Team.WHITE;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
@Override
public boolean isTurnedOff() {
return false;
}
@Override
public void turnOff() {
}
@Override
public void moveStrategy(int dx, int dy, MoveStrategy strategy) {
}
@Override
public Point[] getPossibleMoveFields() {
return new Point[0];
}
};
Context context = contextBuilder()
.add("ChessPiece x-coordinate", x)
.add("ChessPiece y-coordinate", y)
.build();
Point[] returnValue = callObject(diagonalMoverInstance::getDiagonalMoves, context, result ->
"An exception occurred while invoking getDiagonalMoves()");
assertNotNull(returnValue, context, result -> "getDiagonalMoves() returned null");
List<Point> points = Arrays.stream(returnValue).filter(Objects::nonNull).collect(Collectors.toList());
for (Point vector : new Point[] {new Point(1, 1), new Point(1, -1), new Point(-1, 1), new Point(-1, -1)}) {
for (int n = 1; n < worldSize; n++) {
if (vector.x * n + x < 0 || vector.x * n + x >= worldSize || vector.y * n + y < 0 || vector.y * n + y >= worldSize) {
break;
}
Point expectedPoint = new Point(vector.x * n + x, vector.y * n + y);
assertTrue(points.contains(expectedPoint), context, result ->
"Point %s was not found in returned array".formatted(expectedPoint));
points.remove(expectedPoint);
}
}
assertEquals(Collections.emptyList(), points, context, result -> "Returned array contained more points than are valid");
}
}
}
}

View file

@ -0,0 +1,33 @@
package h04.movement;
import fopbot.Robot;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.ClassHeader;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import java.lang.reflect.Modifier;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.fail;
@TestForSubmission
public class MoveStrategyTest {
@Test
public void testDeclaration() {
ClassHeader originalClassHeader = SubmissionExecutionHandler.getOriginalClassHeader(MoveStrategy.class);
assertTrue(Modifier.isInterface(originalClassHeader.access()), emptyContext(), result ->
"Class h04.movement.MoveStrategy is not an interface");
MethodHeader moveMethodHeader = SubmissionExecutionHandler.getOriginalMethodHeaders(MoveStrategy.class)
.stream()
.filter(methodHeader -> methodHeader.name().equals("move") &&
methodHeader.descriptor().equals(Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Robot.class), Type.INT_TYPE, Type.INT_TYPE)))
.findAny()
.orElseGet(() -> fail(emptyContext(), result -> "MoveStrategy does not declare method 'move(Robot, int, int)'"));
}
}

View file

@ -0,0 +1,133 @@
package h04.movement;
import fopbot.World;
import h04.chesspieces.ChessPiece;
import h04.chesspieces.Team;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.ClassHeader;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.awt.Point;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertEquals;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertFalse;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertNotNull;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.assertTrue;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.callObject;
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;
@TestForSubmission
public class OrthogonalMoverTest {
private final MethodHeader orthogonalMover_getOrthogonalMoves = MethodHeader.of(OrthogonalMover.class, "getOrthogonalMoves");
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testClassHeader() {
ClassHeader originalClassHeader = SubmissionExecutionHandler.getOriginalClassHeader(OrthogonalMover.class);
assertTrue(Arrays.stream(originalClassHeader.interfaces()).anyMatch(s -> s.equals(Type.getInternalName(ChessPiece.class))),
emptyContext(),
result -> "Interface h04.movement.OrthogonalMover does not extend interface h04.movement.ChessPiece");
}
@Test
public void testMethodHeader() {
MethodHeader getOrthogonalMovesMethodHeader = SubmissionExecutionHandler.getOriginalMethodHeaders(OrthogonalMover.class)
.stream()
.filter(methodHeader -> methodHeader.name().equals("getOrthogonalMoves") &&
methodHeader.descriptor().equals(Type.getMethodDescriptor(Type.getType(Point[].class))))
.findAny()
.orElseGet(() -> fail(emptyContext(), result -> "OrthogonalMover does not declare method 'getOrthogonalMoves()'"));
assertTrue(Modifier.isPublic(getOrthogonalMovesMethodHeader.access()), emptyContext(), result ->
"Method getOrthogonalMoves() is not declared public");
assertFalse(Modifier.isAbstract(getOrthogonalMovesMethodHeader.access()), emptyContext(), result ->
"Method getOrthogonalMoves() is not declared default");
}
@Test
public void testGetOrthogonalMoves() {
SubmissionExecutionHandler.Delegation.disable(orthogonalMover_getOrthogonalMoves);
int worldSize = 8;
World.setSize(worldSize, worldSize);
World.setDelay(0);
for (int x : new int[] {0, worldSize - 1}) {
for (int y : new int[] {0, worldSize - 1}) {
OrthogonalMover orthogonalMoverInstance = new OrthogonalMover() {
@Override
public Team getTeam() {
return Team.WHITE;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
@Override
public boolean isTurnedOff() {
return false;
}
@Override
public void turnOff() {
}
@Override
public void moveStrategy(int dx, int dy, MoveStrategy strategy) {
}
@Override
public Point[] getPossibleMoveFields() {
return new Point[0];
}
};
Context context = contextBuilder()
.add("ChessPiece x-coordinate", x)
.add("ChessPiece y-coordinate", y)
.build();
Point[] returnValue = callObject(orthogonalMoverInstance::getOrthogonalMoves, context, result ->
"An exception occurred while invoking getOrthogonalMoves()");
assertNotNull(returnValue, context, result -> "getOrthogonalMoves() returned null");
List<Point> points = Arrays.stream(returnValue).filter(Objects::nonNull).collect(Collectors.toList());
for (Point vector : new Point[] {new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1)}) {
for (int n = 1; n < worldSize; n++) {
if (vector.x * n + x < 0 || vector.x * n + x >= worldSize || vector.y * n + y < 0 || vector.y * n + y >= worldSize) {
break;
}
Point expectedPoint = new Point(vector.x * n + x, vector.y * n + y);
assertTrue(points.contains(expectedPoint), context, result ->
"Point %s was not found in the returned array".formatted(expectedPoint));
points.remove(expectedPoint);
}
}
assertEquals(Collections.emptyList(), points, context, result -> "Returned array contained more points than are valid");
}
}
}
}

View file

@ -0,0 +1,76 @@
package h04.movement;
import fopbot.Robot;
import fopbot.World;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.ClassHeader;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.util.Arrays;
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.call;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
@TestForSubmission
public class TeleportingMoveStrategyTest {
private final MethodHeader teleportingMoveStrategy_move = MethodHeader.of(TeleportingMoveStrategy.class,
"move", Robot.class, int.class, int.class);
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testClassHeader() {
ClassHeader originalClassHeader = SubmissionExecutionHandler.getOriginalClassHeader(TeleportingMoveStrategy.class);
assertTrue(Arrays.stream(originalClassHeader.interfaces()).anyMatch(s -> s.equals(Type.getInternalName(MoveStrategy.class))),
emptyContext(),
result -> "Class h04.movement.TeleportingMoveStrategy does not implement interface h04.movement.MoveStrategy");
}
@ParameterizedTest
@ValueSource(ints = {0, 1, 2, 4, 5, 6, 8, 9, 10})
public void testMove(int n) { // encoding: 4 bits, lower 2: x-coordinate, upper 2: y-coordinate
SubmissionExecutionHandler.Delegation.disable(teleportingMoveStrategy_move);
Robot robot = setupEnvironment();
int expectedX = n & 0b11;
int expectedY = n >> 2;
int dx = expectedX - 1;
int dy = expectedY - 1;
Context context = contextBuilder()
.add("robot", robot)
.add("dx", dx)
.add("dy", dy)
.build();
TeleportingMoveStrategy teleportingMoveStrategyInstance = new TeleportingMoveStrategy();
call(() -> teleportingMoveStrategyInstance.move(robot, dx, dy), context, result ->
"An exception occurred while invoking method move");
assertEquals(expectedX, robot.getX(), context, result -> "Robot was not teleported to correct x-coordinate");
assertEquals(expectedY, robot.getY(), context, result -> "Robot was not teleported to correct y-coordinate");
}
private Robot setupEnvironment() {
World.setSize(3, 3);
World.setDelay(0);
return new Robot(1, 1) {
@Override
public void move() {
// do nothing
}
};
}
}

View file

@ -0,0 +1,105 @@
package h04.movement;
import fopbot.Direction;
import fopbot.Robot;
import fopbot.World;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.objectweb.asm.Type;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.transform.SubmissionExecutionHandler;
import org.tudalgo.algoutils.transform.util.headers.ClassHeader;
import org.tudalgo.algoutils.transform.util.headers.MethodHeader;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import java.util.Arrays;
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.call;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.contextBuilder;
import static org.tudalgo.algoutils.tutor.general.assertions.Assertions2.emptyContext;
@TestForSubmission
public class WalkingMoveStrategyTest {
private final MethodHeader walkingMoveStrategy_move = MethodHeader.of(WalkingMoveStrategy.class,
"move", Robot.class, int.class, int.class);
@AfterEach
public void tearDown() {
SubmissionExecutionHandler.resetAll();
}
@Test
public void testClassHeader() {
ClassHeader originalClassHeader = SubmissionExecutionHandler.getOriginalClassHeader(WalkingMoveStrategy.class);
assertTrue(Arrays.stream(originalClassHeader.interfaces()).anyMatch(s -> s.equals(Type.getInternalName(MoveStrategy.class))),
emptyContext(),
result -> "Class h04.movement.WalkingMoveStrategy does not implement interface h04.movement.MoveStrategy");
}
@ParameterizedTest
@ValueSource(ints = {0, 1, 2, 4, 5, 6, 8, 9, 10})
public void testMove(int n) { // encoding: 4 bits, lower 2: x-coordinate, upper 2: y-coordinate
SubmissionExecutionHandler.Delegation.disable(walkingMoveStrategy_move);
Robot robot = setupEnvironment();
int expectedX = n & 0b11;
int expectedY = n >> 2;
Context context = invokeMove(robot, n);
assertEquals(expectedX, robot.getX(), context, result -> "Robot did not walk to correct x-coordinate");
assertEquals(expectedY, robot.getY(), context, result -> "Robot did not walk to correct y-coordinate");
}
@ParameterizedTest
@ValueSource(ints = {0, 1, 2, 4, 5, 6, 8, 9, 10})
public void testMoveFacesUp(int n) { // encoding: 4 bits, lower 2: x-coordinate, upper 2: y-coordinate
SubmissionExecutionHandler.Delegation.disable(walkingMoveStrategy_move);
Robot robot = setupEnvironment();
Context context = invokeMove(robot, n);
assertEquals(Direction.UP, robot.getDirection(), context, result -> "Robot does not face upwards after calling move");
}
private Robot setupEnvironment() {
World.setSize(3, 3);
World.setDelay(0);
return new Robot(1, 1) {
@Override
public void setField(int x, int y) {
// do nothing
}
@Override
public void setX(int x) {
// do nothing
}
@Override
public void setY(int y) {
// do nothing
}
};
}
private Context invokeMove(Robot robot, int n) {
int expectedX = n & 0b11;
int expectedY = n >> 2;
int dx = expectedX - 1;
int dy = expectedY - 1;
Context context = contextBuilder()
.add("robot", robot)
.add("dx", dx)
.add("dy", dy)
.build();
WalkingMoveStrategy walkingMoveStrategyInstance = new WalkingMoveStrategy();
call(() -> walkingMoveStrategyInstance.move(robot, dx, dy), context, result ->
"An exception occurred while invoking method move");
return context;
}
}

Binary file not shown.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

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

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

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

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

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

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

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

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

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

After

Width:  |  Height:  |  Size: 4.7 KiB

View file

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

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

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

After

Width:  |  Height:  |  Size: 3.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.8 KiB

View file

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

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

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

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

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

1
version Normal file
View file

@ -0,0 +1 @@
0.1.0-SNAPSHOT