From 50e1c934ee0643a079e588f249187e54d4b1d122 Mon Sep 17 00:00:00 2001 From: Volker Leck Date: Tue, 18 Dec 2012 12:32:33 +0100 Subject: [PATCH] migrate from internal trunk --- .gitignore | 14 ++ README.md | 0 build.gradle | 67 +++++++ gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++++++++++++++++++ gradlew.bat | 90 ++++++++++ .../de/devisnik/sliding/FrameFactory.java | 18 ++ .../de/devisnik/sliding/FrameScrambler.java | 81 +++++++++ .../sliding/FromHomeShiftingEvent.java | 9 + src/main/java/de/devisnik/sliding/IFrame.java | 20 +++ .../de/devisnik/sliding/IFrameListener.java | 6 + src/main/java/de/devisnik/sliding/IHole.java | 9 + src/main/java/de/devisnik/sliding/IMove.java | 13 ++ src/main/java/de/devisnik/sliding/IPiece.java | 19 ++ .../java/de/devisnik/sliding/IRandom.java | 5 + .../java/de/devisnik/sliding/IRobotFrame.java | 9 + .../de/devisnik/sliding/IShifterListener.java | 10 ++ .../java/de/devisnik/sliding/MoveFactory.java | 49 ++++++ src/main/java/de/devisnik/sliding/Point.java | 137 +++++++++++++++ .../de/devisnik/sliding/ShiftingEvent.java | 30 ++++ .../de/devisnik/sliding/SlideModel.gwt.xml | 3 + .../devisnik/sliding/ToHomeShiftingEvent.java | 9 + .../AccelerateDecelerateInterpolator.java | 10 ++ .../devisnik/sliding/animation/Animation.java | 25 +++ .../sliding/animation/AnimationRunner.java | 35 ++++ .../sliding/animation/IInterpolator.java | 11 ++ .../devisnik/sliding/animation/IMovement.java | 13 ++ .../sliding/animation/IShiftable.java | 9 + .../sliding/animation/LinearInterpolator.java | 9 + .../sliding/animation/MetaShiftable.java | 31 ++++ .../sliding/animation/ShiftAnimation.java | 13 ++ .../sliding/animation/Translation.java | 40 +++++ .../java/de/devisnik/sliding/impl/Frame.java | 144 +++++++++++++++ .../java/de/devisnik/sliding/impl/Hole.java | 15 ++ .../java/de/devisnik/sliding/impl/Move.java | 27 +++ .../java/de/devisnik/sliding/impl/Piece.java | 46 +++++ .../devisnik/sliding/impl/PieceIterator.java | 37 ++++ .../de/devisnik/sliding/impl/RobotFrame.java | 67 +++++++ .../de/devisnik/sliding/impl/Scrambler.java | 86 +++++++++ .../de/devisnik/sliding/FrameFactoryTest.java | 37 ++++ .../devisnik/sliding/FrameScramblerTest.java | 33 ++++ .../sliding/animation/TestShiftable.java | 41 +++++ .../de/devisnik/sliding/impl/FrameTest.java | 111 ++++++++++++ .../sliding/impl/MoveFactoryTest.java | 34 ++++ .../de/devisnik/sliding/impl/PieceTest.java | 45 +++++ 45 files changed, 1687 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 src/main/java/de/devisnik/sliding/FrameFactory.java create mode 100644 src/main/java/de/devisnik/sliding/FrameScrambler.java create mode 100644 src/main/java/de/devisnik/sliding/FromHomeShiftingEvent.java create mode 100644 src/main/java/de/devisnik/sliding/IFrame.java create mode 100644 src/main/java/de/devisnik/sliding/IFrameListener.java create mode 100644 src/main/java/de/devisnik/sliding/IHole.java create mode 100644 src/main/java/de/devisnik/sliding/IMove.java create mode 100644 src/main/java/de/devisnik/sliding/IPiece.java create mode 100644 src/main/java/de/devisnik/sliding/IRandom.java create mode 100644 src/main/java/de/devisnik/sliding/IRobotFrame.java create mode 100644 src/main/java/de/devisnik/sliding/IShifterListener.java create mode 100644 src/main/java/de/devisnik/sliding/MoveFactory.java create mode 100644 src/main/java/de/devisnik/sliding/Point.java create mode 100644 src/main/java/de/devisnik/sliding/ShiftingEvent.java create mode 100644 src/main/java/de/devisnik/sliding/SlideModel.gwt.xml create mode 100644 src/main/java/de/devisnik/sliding/ToHomeShiftingEvent.java create mode 100644 src/main/java/de/devisnik/sliding/animation/AccelerateDecelerateInterpolator.java create mode 100644 src/main/java/de/devisnik/sliding/animation/Animation.java create mode 100644 src/main/java/de/devisnik/sliding/animation/AnimationRunner.java create mode 100644 src/main/java/de/devisnik/sliding/animation/IInterpolator.java create mode 100644 src/main/java/de/devisnik/sliding/animation/IMovement.java create mode 100644 src/main/java/de/devisnik/sliding/animation/IShiftable.java create mode 100644 src/main/java/de/devisnik/sliding/animation/LinearInterpolator.java create mode 100644 src/main/java/de/devisnik/sliding/animation/MetaShiftable.java create mode 100644 src/main/java/de/devisnik/sliding/animation/ShiftAnimation.java create mode 100644 src/main/java/de/devisnik/sliding/animation/Translation.java create mode 100644 src/main/java/de/devisnik/sliding/impl/Frame.java create mode 100644 src/main/java/de/devisnik/sliding/impl/Hole.java create mode 100644 src/main/java/de/devisnik/sliding/impl/Move.java create mode 100644 src/main/java/de/devisnik/sliding/impl/Piece.java create mode 100644 src/main/java/de/devisnik/sliding/impl/PieceIterator.java create mode 100644 src/main/java/de/devisnik/sliding/impl/RobotFrame.java create mode 100644 src/main/java/de/devisnik/sliding/impl/Scrambler.java create mode 100644 src/test/java/de/devisnik/sliding/FrameFactoryTest.java create mode 100644 src/test/java/de/devisnik/sliding/FrameScramblerTest.java create mode 100644 src/test/java/de/devisnik/sliding/animation/TestShiftable.java create mode 100644 src/test/java/de/devisnik/sliding/impl/FrameTest.java create mode 100644 src/test/java/de/devisnik/sliding/impl/MoveFactoryTest.java create mode 100644 src/test/java/de/devisnik/sliding/impl/PieceTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2959f99 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.class +.DS_Store +.project +.classpath +.settings +.gradle + +bin +build + +# Package Files # +*.jar +*.war +*.ear diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..6c0e620 --- /dev/null +++ b/build.gradle @@ -0,0 +1,67 @@ +apply plugin: 'java' +apply plugin: 'maven' +apply plugin: 'eclipse' + +group = "de.devisnik" +archivesBaseName = "de.devisnik.sliding" +versionName = '1.0.1' +version = new Version(baseVersion: versionName) + +sourceCompatibility = 1.6 + +repositories { mavenCentral() } + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.+' +} + +jar { + manifest { + attributes 'Implementation-Title': archivesBaseName, 'Implementation-Version': version + } +} + +task wrapper(type: Wrapper) { + gradleVersion = '1.3' +} + +task sources_jar(type: Jar, dependsOn:classes) { + description = 'Assembles a jar archive containing the sources.' + group = 'build' + classifier = 'sources' + from sourceSets.main.allSource +} + +task link_jars(dependsOn:[jar, sources_jar]) { + description = 'Creates a properties file conforming Android project standards to link source-jar to code-jar' + ext.jarFile = new File("${jar.archivePath}") + ext.jarProperties = new File("${jar.archivePath}.properties") + ext.sourceJarFile = new File("${sources_jar.archivePath}") + inputs.file files(jarFile, sourceJarFile) + outputs.file jarProperties + doLast { + file(jarProperties).write "src=${sources_jar.archiveName}\n" + } +} + +install { + outputs.file files(jar.archivePath, sources_jar.archivePath, link_jars.jarProperties) +} +artifacts { + archives sources_jar + archives(link_jars.jarProperties) { + type = 'jar.properties' // ensure correct file extension + } +} + +assemble.dependsOn.add('link_jars') +install.dependsOn.add('build') + +class Version { + String baseVersion + String date = new Date().format("yyyyMMddHHmm") + + String toString() { + "$baseVersion.$date" + } +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..814c98e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 17 19:01:04 CET 2012 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-1.3-bin.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +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" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@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 + +@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= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +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 init + +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 + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +: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 %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="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! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/de/devisnik/sliding/FrameFactory.java b/src/main/java/de/devisnik/sliding/FrameFactory.java new file mode 100644 index 0000000..b8a617c --- /dev/null +++ b/src/main/java/de/devisnik/sliding/FrameFactory.java @@ -0,0 +1,18 @@ +package de.devisnik.sliding; + +import de.devisnik.sliding.impl.RobotFrame; +import de.devisnik.sliding.impl.Frame; + +public class FrameFactory { + + private FrameFactory() { + } + + public static IFrame create(int dimX, int dimY) { + return new Frame(dimX, dimY); + } + + public static IRobotFrame createRobot(int dimX, int dimY, IRandom random) { + return new RobotFrame(dimX, dimY, random); + } +} diff --git a/src/main/java/de/devisnik/sliding/FrameScrambler.java b/src/main/java/de/devisnik/sliding/FrameScrambler.java new file mode 100644 index 0000000..a05c3f7 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/FrameScrambler.java @@ -0,0 +1,81 @@ +package de.devisnik.sliding; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class FrameScrambler { + + private final static IMove[] MOVES = new IMove[] { MoveFactory.LEFT, + MoveFactory.RIGHT, MoveFactory.DOWN, MoveFactory.UP }; + + private final IFrame itsFrame; + + private final IRandom itsRandom; + + public FrameScrambler(IFrame frame, IRandom random) { + this.itsFrame = frame; + this.itsRandom = random; + } + + public IMove[] scramble(int numberOfMoves) { + return scrambleGame(numberOfMoves); + } + + public IMove[] scramble() { + Point size = itsFrame.getSize(); + int pieces = size.x * size.y; + return scramble(pieces * 10); + } + + private IMove[] scrambleGame(int numberOfMoves) { + final IMove[] moves = new IMove[numberOfMoves]; + IMove lastInverse = null; + for (int index = 0; index < moves.length; index++) { + IMove randomMove = moveRandomAvoiding(lastInverse); + lastInverse = MoveFactory.getInverse(randomMove); + moves[index] = randomMove; + } + return moves; + } + + private IMove moveRandomAvoiding(IMove avoid) { + List validMoves = determinePossibleMoves(); + validMoves.remove(avoid); + return executeRandomMoveFrom(validMoves); + } + + private IMove executeRandomMoveFrom(List moves) { + IMove move = moves.get(itsRandom.nextInt(moves.size())); + if (!itsFrame.execute(move)) + throw new IllegalStateException("move not executable!"); + return move; + } + + public List determinePossibleMoves() { + ArrayList moves = new ArrayList(); + moves.addAll(Arrays.asList(MOVES)); + Point holePosition = itsFrame.getHole().getPosition(); + if (holePosition.x == 0) + moves.remove(MoveFactory.LEFT); + Point frameDimension = itsFrame.getSize(); + if (holePosition.x == frameDimension.x - 1) + moves.remove(MoveFactory.RIGHT); + if (holePosition.y == 0) + moves.remove(MoveFactory.UP); + if (holePosition.y == frameDimension.y - 1) + moves.remove(MoveFactory.DOWN); + return moves; + } + + public static void main(String[] args) { + new FrameScrambler(FrameFactory.create(4, 4), new IRandom() { + Random random = new Random(); + + public int nextInt(int border) { + return random.nextInt(border); + } + }).scramble(); + } +} diff --git a/src/main/java/de/devisnik/sliding/FromHomeShiftingEvent.java b/src/main/java/de/devisnik/sliding/FromHomeShiftingEvent.java new file mode 100644 index 0000000..589268d --- /dev/null +++ b/src/main/java/de/devisnik/sliding/FromHomeShiftingEvent.java @@ -0,0 +1,9 @@ +package de.devisnik.sliding; + +public class FromHomeShiftingEvent extends ShiftingEvent { + + public FromHomeShiftingEvent(IPiece piece) { + super(piece, piece.getHomePosition(), piece.getPosition()); + } + +} diff --git a/src/main/java/de/devisnik/sliding/IFrame.java b/src/main/java/de/devisnik/sliding/IFrame.java new file mode 100644 index 0000000..a556e9a --- /dev/null +++ b/src/main/java/de/devisnik/sliding/IFrame.java @@ -0,0 +1,20 @@ +package de.devisnik.sliding; + +/** + * A rectangular frame filled with sliding pieces, containing one hole. + * This models a 15-puzzle-like sliding game. + */ +public interface IFrame extends Iterable { + + Point getSize(); + + IPiece getPieceAt(int posX, int posY); + + IHole getHole(); + + boolean execute(IMove move); + + void addListener(IFrameListener listener); + + void removeListener(IFrameListener listener); +} diff --git a/src/main/java/de/devisnik/sliding/IFrameListener.java b/src/main/java/de/devisnik/sliding/IFrameListener.java new file mode 100644 index 0000000..5aac6b5 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/IFrameListener.java @@ -0,0 +1,6 @@ +package de.devisnik.sliding; + +public interface IFrameListener { + void handleSwap(IPiece left, IPiece right); + void handleShifting(ShiftingEvent[] event); +} diff --git a/src/main/java/de/devisnik/sliding/IHole.java b/src/main/java/de/devisnik/sliding/IHole.java new file mode 100644 index 0000000..cd6b06a --- /dev/null +++ b/src/main/java/de/devisnik/sliding/IHole.java @@ -0,0 +1,9 @@ +/* + * Created on 07.11.2006 by leck + * + */ +package de.devisnik.sliding; + +public interface IHole extends IPiece { + +} diff --git a/src/main/java/de/devisnik/sliding/IMove.java b/src/main/java/de/devisnik/sliding/IMove.java new file mode 100644 index 0000000..83f3d75 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/IMove.java @@ -0,0 +1,13 @@ +/* + * Created on 07.11.2006 by leck + * + */ +package de.devisnik.sliding; + +public interface IMove { + + int getX(); + + int getY(); + +} \ No newline at end of file diff --git a/src/main/java/de/devisnik/sliding/IPiece.java b/src/main/java/de/devisnik/sliding/IPiece.java new file mode 100644 index 0000000..f5a50ce --- /dev/null +++ b/src/main/java/de/devisnik/sliding/IPiece.java @@ -0,0 +1,19 @@ +/* + * Created on 21.07.2006 by leck + * + */ +package de.devisnik.sliding; + +/** + * A movable piece of the sliding puzzle. + * + */ +public interface IPiece { + String getLabel(); + + Point getPosition(); + + Point getHomePosition(); + + boolean isAtHome(); +} diff --git a/src/main/java/de/devisnik/sliding/IRandom.java b/src/main/java/de/devisnik/sliding/IRandom.java new file mode 100644 index 0000000..4200d4a --- /dev/null +++ b/src/main/java/de/devisnik/sliding/IRandom.java @@ -0,0 +1,5 @@ +package de.devisnik.sliding; + +public interface IRandom { + int nextInt(int border); +} diff --git a/src/main/java/de/devisnik/sliding/IRobotFrame.java b/src/main/java/de/devisnik/sliding/IRobotFrame.java new file mode 100644 index 0000000..eb19998 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/IRobotFrame.java @@ -0,0 +1,9 @@ +package de.devisnik.sliding; + +public interface IRobotFrame extends IFrame { + + boolean scramble(); + boolean replayNext(); + void resolve(); + boolean isResolved(); +} diff --git a/src/main/java/de/devisnik/sliding/IShifterListener.java b/src/main/java/de/devisnik/sliding/IShifterListener.java new file mode 100644 index 0000000..d086918 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/IShifterListener.java @@ -0,0 +1,10 @@ +/* + * Created on 09.11.2006 by leck + * + */ +package de.devisnik.sliding; + + +public interface IShifterListener { + void doneShifting(); +} diff --git a/src/main/java/de/devisnik/sliding/MoveFactory.java b/src/main/java/de/devisnik/sliding/MoveFactory.java new file mode 100644 index 0000000..e1162fe --- /dev/null +++ b/src/main/java/de/devisnik/sliding/MoveFactory.java @@ -0,0 +1,49 @@ +/* + * Created on 07.11.2006 by leck + * + */ +package de.devisnik.sliding; + +import java.util.Arrays; + +import de.devisnik.sliding.impl.Move; + +public final class MoveFactory { + + public final static IMove LEFT = new Move(-1,0); + public final static IMove RIGHT = new Move(1,0); + public final static IMove DOWN = new Move(0, 1); + public final static IMove UP = new Move(0, -1); + + private MoveFactory() { + } + + public static IMove[] getMovesTo(int x, int y) { + if (x != 0 && y != 0) + return new IMove[0]; + if (x != 0) + return createValueArray(Math.abs(x), x > 0 ? RIGHT : LEFT); + if (y != 0) + return createValueArray(Math.abs(y), y > 0 ? DOWN : UP); + throw new IllegalArgumentException(); + } + + private static IMove[] createValueArray(int length, IMove value) { + IMove[] moves = new IMove[length]; + Arrays.fill(moves, value); + return moves; + } + + public static IMove getInverse(IMove move) { + if (move == LEFT) + return RIGHT; + if (move == RIGHT) + return LEFT; + if (move == DOWN) + return UP; + if (move == UP) + return DOWN; + throw new IllegalArgumentException(); + } + +} diff --git a/src/main/java/de/devisnik/sliding/Point.java b/src/main/java/de/devisnik/sliding/Point.java new file mode 100644 index 0000000..ed94c55 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/Point.java @@ -0,0 +1,137 @@ +package de.devisnik.sliding; + +public class Point { + + public static Point diff(Point left, Point right) { + return new Point(left.x - right.x, left.y - right.y); + } + + public static Point divide(int width, int height, Point size) { + return new Point(width / size.x, height / size.y); + } + + public static Point divide(Point left, Point right) { + return new Point(left.x / right.x, left.y / right.y); + } + + public static Point divide(Point left, int number) { + return new Point(left.x / number, left.y / number); + } + + public static Point sum(Point point, int x, int y) { + return new Point(point.x + x, point.y + y); + } + + public static Point times(Point point, float factor) { + return new Point(Math.round(factor * point.x), Math.round(factor * point.y)); + } + + public static Point times(Point point, int factor) { + return new Point(factor * point.x, factor * point.y); + } + + public static Point times(Point left, Point right) { + return new Point(left.x * right.x, left.y * right.y); + } + + public int x; + public int y; + + public Point() { + this(0, 0); + } + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + public Point add(Point point) { + x += point.x; + y += point.y; + return this; + } + + public Point set(Point point) { + this.x = point.x; + this.y = point.y; + return this; + } + + public int min() { + return Math.min(x, y); + } + + public int max() { + return Math.max(x, y); + } + + public float ratio() { + return ((float) x) / y; + } + + public Point flip() { + int mem = x; + x = y; + y = mem; + return this; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Point other = (Point) obj; + if (x != other.x) + return false; + if (y != other.y) + return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + x; + result = prime * result + y; + return result; + } + + @Override + public String toString() { + return "(" + x + "," + y + ")"; + } + + public Point divideBy(Point point) { + x /= point.x; + y /= point.y; + return this; + } + + public Point multiplyBy(Point point) { + x *= point.x; + y *= point.y; + return this; + } + + public Point minus(Point point) { + x -= point.x; + y -= point.y; + return this; + } + + public Point divideBy(int number) { + x /= number; + y /= number; + return this; + } + + public Point copy() { + return new Point(x, y); + } +} diff --git a/src/main/java/de/devisnik/sliding/ShiftingEvent.java b/src/main/java/de/devisnik/sliding/ShiftingEvent.java new file mode 100644 index 0000000..a1ac3a4 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/ShiftingEvent.java @@ -0,0 +1,30 @@ +/* + * Created on 23.07.2006 by leck + * + */ +package de.devisnik.sliding; + +public class ShiftingEvent { + + private final IPiece itsPiece; + private final Point itsOldPosition; + private final Point itsNewPosition; + + public ShiftingEvent(IPiece piece, Point oldPosition, Point newPosition) { + itsPiece = piece; + itsOldPosition = oldPosition; + itsNewPosition = newPosition; + } + + public IPiece getPiece() { + return itsPiece; + } + + public Point getOldPosition() { + return itsOldPosition; + } + + public Point getNewPosition() { + return itsNewPosition; + } +} diff --git a/src/main/java/de/devisnik/sliding/SlideModel.gwt.xml b/src/main/java/de/devisnik/sliding/SlideModel.gwt.xml new file mode 100644 index 0000000..e372bf6 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/SlideModel.gwt.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/main/java/de/devisnik/sliding/ToHomeShiftingEvent.java b/src/main/java/de/devisnik/sliding/ToHomeShiftingEvent.java new file mode 100644 index 0000000..24fac56 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/ToHomeShiftingEvent.java @@ -0,0 +1,9 @@ +package de.devisnik.sliding; + +public class ToHomeShiftingEvent extends ShiftingEvent { + + public ToHomeShiftingEvent(IPiece piece) { + super(piece, piece.getPosition(), piece.getHomePosition()); + } + +} diff --git a/src/main/java/de/devisnik/sliding/animation/AccelerateDecelerateInterpolator.java b/src/main/java/de/devisnik/sliding/animation/AccelerateDecelerateInterpolator.java new file mode 100644 index 0000000..772e7bb --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/AccelerateDecelerateInterpolator.java @@ -0,0 +1,10 @@ +package de.devisnik.sliding.animation; + +public class AccelerateDecelerateInterpolator implements IInterpolator { + public AccelerateDecelerateInterpolator() { + } + + public float getInterpolation(float input) { + return (float) (Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; + } +} diff --git a/src/main/java/de/devisnik/sliding/animation/Animation.java b/src/main/java/de/devisnik/sliding/animation/Animation.java new file mode 100644 index 0000000..2eaf4e7 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/Animation.java @@ -0,0 +1,25 @@ +package de.devisnik.sliding.animation; + + +public class Animation { + + private final IShiftable itsShiftable; + private final IMovement itsMovement; + + public Animation(IShiftable shiftable, IMovement transition) { + itsShiftable = shiftable; + itsMovement = transition; + } + + public boolean hasNext() { + return itsMovement.hasNext(); + } + + public void stepNext() { + itsShiftable.shift(itsMovement.next()); + } + + public int currentStep() { + return itsMovement.goneStepsNumber(); + } +} diff --git a/src/main/java/de/devisnik/sliding/animation/AnimationRunner.java b/src/main/java/de/devisnik/sliding/animation/AnimationRunner.java new file mode 100644 index 0000000..285faa5 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/AnimationRunner.java @@ -0,0 +1,35 @@ +package de.devisnik.sliding.animation; + +public abstract class AnimationRunner { + + protected final Animation itsAnimation; + + public AnimationRunner(Animation animation) { + itsAnimation = animation; + } + + public void start() { + onStartShifting(); + schedule(new Runnable() { + + public void run() { + itsAnimation.stepNext(); + if (itsAnimation.hasNext()) + schedule(this); + else + onDoneShifting(); + } + }); + } + + protected void onDoneShifting() { + // does nothing + } + + protected void onStartShifting() { + // does nothing + } + + protected abstract void schedule(Runnable runnable); + +} diff --git a/src/main/java/de/devisnik/sliding/animation/IInterpolator.java b/src/main/java/de/devisnik/sliding/animation/IInterpolator.java new file mode 100644 index 0000000..07da825 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/IInterpolator.java @@ -0,0 +1,11 @@ +package de.devisnik.sliding.animation; + +public interface IInterpolator { + + /** + * @param timepoint + * current time of animation, usually in [0.0, 1.0] + * @return interpolation factor, to be applied to current point in animation + */ + float getInterpolation(float timepoint); +} diff --git a/src/main/java/de/devisnik/sliding/animation/IMovement.java b/src/main/java/de/devisnik/sliding/animation/IMovement.java new file mode 100644 index 0000000..04475c7 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/IMovement.java @@ -0,0 +1,13 @@ +package de.devisnik.sliding.animation; + +import de.devisnik.sliding.Point; + +public interface IMovement { + + int goneStepsNumber(); + + boolean hasNext(); + + Point next(); + +} \ No newline at end of file diff --git a/src/main/java/de/devisnik/sliding/animation/IShiftable.java b/src/main/java/de/devisnik/sliding/animation/IShiftable.java new file mode 100644 index 0000000..8edbf2e --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/IShiftable.java @@ -0,0 +1,9 @@ +package de.devisnik.sliding.animation; + +import de.devisnik.sliding.Point; + +public interface IShiftable { + + Point getSize(); + void shift(Point delta); +} diff --git a/src/main/java/de/devisnik/sliding/animation/LinearInterpolator.java b/src/main/java/de/devisnik/sliding/animation/LinearInterpolator.java new file mode 100644 index 0000000..af47a4f --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/LinearInterpolator.java @@ -0,0 +1,9 @@ +package de.devisnik.sliding.animation; + +public final class LinearInterpolator implements IInterpolator { + + public float getInterpolation(float timepoint) { + return timepoint; + } + +} diff --git a/src/main/java/de/devisnik/sliding/animation/MetaShiftable.java b/src/main/java/de/devisnik/sliding/animation/MetaShiftable.java new file mode 100644 index 0000000..accfcbc --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/MetaShiftable.java @@ -0,0 +1,31 @@ +package de.devisnik.sliding.animation; +import java.util.ArrayList; + +import de.devisnik.sliding.Point; + +public class MetaShiftable implements IShiftable { + + private final Point itsSize; + private final ArrayList itsShifters = new ArrayList(); + private final int itsSteps; + + public MetaShiftable(int steps) { + itsSteps = steps; + itsSize = new Point(steps, steps); + } + + public void addShifterFor(IShiftable shiftable, Point shift) { + ShiftAnimation shifter = new ShiftAnimation(shiftable, shift, itsSteps); + itsShifters.add(shifter); + } + + public Point getSize() { + return itsSize; + } + + public void shift(Point delta) { + for (Animation shifter : itsShifters) + shifter.stepNext(); + } + +} \ No newline at end of file diff --git a/src/main/java/de/devisnik/sliding/animation/ShiftAnimation.java b/src/main/java/de/devisnik/sliding/animation/ShiftAnimation.java new file mode 100644 index 0000000..a2d5019 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/ShiftAnimation.java @@ -0,0 +1,13 @@ +package de.devisnik.sliding.animation; + +import de.devisnik.sliding.Point; + +public class ShiftAnimation extends Animation { + + public ShiftAnimation(IShiftable shiftable, Point piecePositionDelta, + int steps) { + super(shiftable, new Translation(Point.times(shiftable.getSize(), + piecePositionDelta), steps, new AccelerateDecelerateInterpolator())); + } + +} diff --git a/src/main/java/de/devisnik/sliding/animation/Translation.java b/src/main/java/de/devisnik/sliding/animation/Translation.java new file mode 100644 index 0000000..629fba4 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/animation/Translation.java @@ -0,0 +1,40 @@ +package de.devisnik.sliding.animation; + +import de.devisnik.sliding.Point; + +public class Translation implements IMovement { + + private int itsSteps; + private Point itsTarget; + private Point itsCurrentPoint = new Point(0, 0); + private int itsCurrentIndex = 0; + private final IInterpolator itsInterpolator; + + public Translation(int width, int height, int steps, IInterpolator interpolator) { + this(new Point(width, height), steps, interpolator); + } + + public Translation(Point target, int steps, IInterpolator interpolator) { + itsSteps = steps; + itsTarget = target; + itsInterpolator = interpolator; + } + + public int goneStepsNumber() { + return itsCurrentIndex; + } + + public boolean hasNext() { + return itsCurrentIndex < itsSteps; + } + + public Point next() { + itsCurrentIndex++; + float interpolatedTime = itsInterpolator.getInterpolation(((float)itsCurrentIndex)/itsSteps); + Point target = Point.times(itsTarget, interpolatedTime); +// Point target = Point.times(itsTarget, itsCurrentIndex).divideBy(itsSteps); + Point step = Point.diff(target, itsCurrentPoint); + itsCurrentPoint = target; + return step; + } +} diff --git a/src/main/java/de/devisnik/sliding/impl/Frame.java b/src/main/java/de/devisnik/sliding/impl/Frame.java new file mode 100644 index 0000000..6e0878b --- /dev/null +++ b/src/main/java/de/devisnik/sliding/impl/Frame.java @@ -0,0 +1,144 @@ +/* + * Created on 21.07.2006 by leck + * + */ +package de.devisnik.sliding.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import de.devisnik.sliding.IFrame; +import de.devisnik.sliding.IFrameListener; +import de.devisnik.sliding.IHole; +import de.devisnik.sliding.IMove; +import de.devisnik.sliding.IPiece; +import de.devisnik.sliding.MoveFactory; +import de.devisnik.sliding.Point; +import de.devisnik.sliding.ShiftingEvent; + +public class Frame implements IFrame { + + public static void main(String[] args) { + Frame shiftingGame = new Frame(5, 5); + System.out.println(shiftingGame.toString()); + shiftingGame.moveHole(MoveFactory.UP); + System.out.println(shiftingGame.toString()); + shiftingGame.moveHole(MoveFactory.UP); + System.out.println(shiftingGame.toString()); + shiftingGame.moveHole(MoveFactory.LEFT); + System.out.println(shiftingGame.toString()); + shiftingGame.moveHole(MoveFactory.LEFT); + System.out.println(shiftingGame.toString()); + shiftingGame.moveHole(MoveFactory.UP); + System.out.println(shiftingGame.toString()); + shiftingGame.moveHole(MoveFactory.LEFT); + System.out.println(shiftingGame.toString()); + shiftingGame.moveHole(MoveFactory.DOWN); + System.out.println(shiftingGame.toString()); + } + + private int itsDimX; + private int itsDimY; + private Hole itsHole; + private Piece[][] itsPieces; + + private List itsShiftingGameListeners = new ArrayList(); + + public Frame(int x, int y) { + itsDimX = x; + itsDimY = y; + createPieces(x, y); + } + + public void addListener(IFrameListener listener) { + if (listener == null) + return; + itsShiftingGameListeners.add(listener); + } + + private Piece createPieceAt(int x, int y) { + return new Piece(x, y, "" + (y * itsDimX + x + 1)); + } + + private void createPieces(int dimX, int dimY) { + itsPieces = new Piece[dimX][dimY]; + for (int y = 0; y < dimY; y++) + for (int x = 0; x < dimX; x++) + itsPieces[x][y] = createPieceAt(x, y); + itsHole = new Hole(dimX - 1, dimY - 1, " "); + itsPieces[dimX - 1][dimY - 1] = itsHole; + } + + private void exchange(Point first, Point second) { + Piece buffer = itsPieces[first.x][first.y]; + putPieceAt(itsPieces[second.x][second.y], first.x, first.y); + putPieceAt(buffer, second.x, second.y); + } + + public boolean execute(IMove move) { + ShiftingEvent[] event = moveHole(move); +// fireShiftingEvent(event[1]); + fireSwap(event[0].getPiece(), event[1].getPiece()); + return true; + } + + protected final void fireSwap(IPiece left, IPiece right) { + for (IFrameListener listener : itsShiftingGameListeners) + listener.handleSwap(left, right); + } + + protected final void fireShiftingEvents(final ShiftingEvent[] events) { + for (IFrameListener listener : itsShiftingGameListeners) + listener.handleShifting(events); + } + + public IHole getHole() { + return itsHole; + } + + public IPiece getPieceAt(int posX, int posY) { + return itsPieces[posX][posY]; + } + + public Point getSize() { + return new Point(itsDimX, itsDimY); + } + + protected final ShiftingEvent[] moveHole(IMove move) { + Point holePosition = getHole().getPosition().copy(); + Point target = Point.sum(holePosition, move.getX(), move.getY()); + IPiece piece = getPieceAt(target.x, target.y); + exchange(holePosition, target); + Point oldPosition = holePosition; + return new ShiftingEvent[] { new ShiftingEvent(piece, target, oldPosition), + new ShiftingEvent(itsHole, oldPosition, target) }; + } + + protected final void putPieceAt(Piece piece, int x, int y) { + itsPieces[x][y] = piece; + piece.setPosition(x, y); + } + + public void removeListener(IFrameListener listener) { + itsShiftingGameListeners.remove(listener); + } + + @Override + public String toString() { + StringBuffer stringBuffer = new StringBuffer(); + for (int y = 0; y < itsDimY; y++) { + for (int x = 0; x < itsDimX; x++) { + String label = itsPieces[x][y].getLabel(); + stringBuffer.append(label); + stringBuffer.append(" "); + } + stringBuffer.append("\n"); + } + return stringBuffer.toString(); + } + + public Iterator iterator() { + return new PieceIterator(itsPieces); + } +} diff --git a/src/main/java/de/devisnik/sliding/impl/Hole.java b/src/main/java/de/devisnik/sliding/impl/Hole.java new file mode 100644 index 0000000..5837ca0 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/impl/Hole.java @@ -0,0 +1,15 @@ +/* + * Created on 21.07.2006 by leck + * + */ +package de.devisnik.sliding.impl; + +import de.devisnik.sliding.IHole; + +public class Hole extends Piece implements IHole { + + public Hole(int posX, int posY, String label) { + super(posX, posY, label); + } + +} diff --git a/src/main/java/de/devisnik/sliding/impl/Move.java b/src/main/java/de/devisnik/sliding/impl/Move.java new file mode 100644 index 0000000..0760b3d --- /dev/null +++ b/src/main/java/de/devisnik/sliding/impl/Move.java @@ -0,0 +1,27 @@ +/* + * Created on 26.10.2006 by leck + * + */ +package de.devisnik.sliding.impl; + +import de.devisnik.sliding.IMove; + +public class Move implements IMove { + + private final int x; + private final int y; + + public Move(int moveX, int moveY) { + x = moveX; + y = moveY; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + +} diff --git a/src/main/java/de/devisnik/sliding/impl/Piece.java b/src/main/java/de/devisnik/sliding/impl/Piece.java new file mode 100644 index 0000000..54746f9 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/impl/Piece.java @@ -0,0 +1,46 @@ +package de.devisnik.sliding.impl; + +import de.devisnik.sliding.IPiece; +import de.devisnik.sliding.Point; + +public class Piece implements IPiece { + + private String itsLabel; + public int itsPosY; + public int itsPosX; + private Point itsHomePosition; + private boolean itsIsHome; + + public Piece(int posX, int posY, String label) { + itsLabel = label; + itsHomePosition = new Point(posX, posY); + setPosition(posX, posY); + } + + public String getLabel() { + return itsLabel; + } + + public Point getPosition() { + return new Point(itsPosX, itsPosY); + } + + void setPosition(int posX, int posY) { + itsPosX = posX; + itsPosY = posY; + itsIsHome = itsPosX == itsHomePosition.x && itsPosY == itsHomePosition.y; + } + + @Override + public int hashCode() { + return itsHomePosition.hashCode(); + } + + public Point getHomePosition() { + return itsHomePosition; + } + + public boolean isAtHome() { + return itsIsHome; + } +} diff --git a/src/main/java/de/devisnik/sliding/impl/PieceIterator.java b/src/main/java/de/devisnik/sliding/impl/PieceIterator.java new file mode 100644 index 0000000..fd50cc2 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/impl/PieceIterator.java @@ -0,0 +1,37 @@ +package de.devisnik.sliding.impl; + +import java.util.ArrayList; +import java.util.Iterator; + +import de.devisnik.sliding.IPiece; + +class PieceIterator implements Iterator { + + private int itsCurrent; + private final ArrayList itsPieceList; + + public PieceIterator(final IPiece[][] pieces) { + itsPieceList = new ArrayList(pieces.length*pieces[0].length); + for (IPiece[] row : pieces) { + for (IPiece piece : row) { + itsPieceList.add(piece); + } + } + itsCurrent = 0; + } + + public boolean hasNext() { + return itsCurrent < itsPieceList.size(); + } + + public IPiece next() { + IPiece value = itsPieceList.get(itsCurrent); + itsCurrent++; + return value; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/de/devisnik/sliding/impl/RobotFrame.java b/src/main/java/de/devisnik/sliding/impl/RobotFrame.java new file mode 100644 index 0000000..5937f52 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/impl/RobotFrame.java @@ -0,0 +1,67 @@ +package de.devisnik.sliding.impl; + +import java.util.ArrayList; + +import de.devisnik.sliding.FromHomeShiftingEvent; +import de.devisnik.sliding.IMove; +import de.devisnik.sliding.IPiece; +import de.devisnik.sliding.IRandom; +import de.devisnik.sliding.IRobotFrame; +import de.devisnik.sliding.MoveFactory; +import de.devisnik.sliding.Point; +import de.devisnik.sliding.ShiftingEvent; +import de.devisnik.sliding.ToHomeShiftingEvent; + +public class RobotFrame extends Frame implements IRobotFrame { + + private Scrambler itsScrambler; + private IMove[] itsMoves = new IMove[0]; + private int itsNextMoveIndex = -1; + + public RobotFrame(int x, int y, IRandom random) { + super(x, y); + itsScrambler = new Scrambler(this, random); + } + + public final boolean isResolved() { + return itsNextMoveIndex == -1; + } + + public boolean replayNext() { + if (isResolved()) + return false; + execute(MoveFactory.getInverse(itsMoves[itsNextMoveIndex])); + itsNextMoveIndex--; + return true; + } + + public boolean scramble() { + if (!isResolved()) + return false; + itsMoves = itsScrambler.scramble(); + itsNextMoveIndex = itsMoves.length - 1; + ArrayList events = new ArrayList(); + for (IPiece piece : this) + events.add(new FromHomeShiftingEvent(piece)); + fireShiftingEvents(events.toArray(new ShiftingEvent[0])); + return true; + } + + public void resolve() { + if (isResolved()) + return; + ArrayList events = new ArrayList(); + for (IPiece piece : this) { + events.add(new ToHomeShiftingEvent(piece)); + putAtHome(piece); + } + itsNextMoveIndex = -1; + fireShiftingEvents(events.toArray(new ShiftingEvent[0])); + } + + private void putAtHome(IPiece piece) { + Point homePosition = piece.getHomePosition(); + putPieceAt((Piece) piece, homePosition.x, homePosition.y); + } + +} diff --git a/src/main/java/de/devisnik/sliding/impl/Scrambler.java b/src/main/java/de/devisnik/sliding/impl/Scrambler.java new file mode 100644 index 0000000..673c610 --- /dev/null +++ b/src/main/java/de/devisnik/sliding/impl/Scrambler.java @@ -0,0 +1,86 @@ +package de.devisnik.sliding.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import de.devisnik.sliding.FrameFactory; +import de.devisnik.sliding.IMove; +import de.devisnik.sliding.IRandom; +import de.devisnik.sliding.MoveFactory; +import de.devisnik.sliding.Point; + +public class Scrambler { + + private final static IMove[] MOVES = new IMove[] { MoveFactory.LEFT, + MoveFactory.RIGHT, MoveFactory.DOWN, MoveFactory.UP }; + + private final Frame itsFrame; + + private final IRandom itsRandom; + + public Scrambler(Frame frame, IRandom random) { + this.itsFrame = frame; + this.itsRandom = random; + } + + public IMove[] scramble(int numberOfMoves) { + return scrambleGame(numberOfMoves); + } + + public IMove[] scramble() { + Point size = itsFrame.getSize(); + int pieces = size.x * size.y; + return scramble(pieces * 10); + } + + private IMove[] scrambleGame(int numberOfMoves) { + final IMove[] moves = new IMove[numberOfMoves]; + IMove lastInverse = null; + for (int index = 0; index < moves.length; index++) { + IMove randomMove = moveRandomAvoiding(lastInverse); + lastInverse = MoveFactory.getInverse(randomMove); + moves[index] = randomMove; + } + return moves; + } + + private IMove moveRandomAvoiding(IMove avoid) { + List validMoves = determinePossibleMoves(); + validMoves.remove(avoid); + return executeRandomMoveFrom(validMoves); + } + + private IMove executeRandomMoveFrom(List moves) { + IMove move = moves.get(itsRandom.nextInt(moves.size())); + itsFrame.moveHole(move); + return move; + } + + public List determinePossibleMoves() { + ArrayList moves = new ArrayList(); + moves.addAll(Arrays.asList(MOVES)); + Point holePosition = itsFrame.getHole().getPosition(); + if (holePosition.x == 0) + moves.remove(MoveFactory.LEFT); + Point frameDimension = itsFrame.getSize(); + if (holePosition.x == frameDimension.x - 1) + moves.remove(MoveFactory.RIGHT); + if (holePosition.y == 0) + moves.remove(MoveFactory.UP); + if (holePosition.y == frameDimension.y - 1) + moves.remove(MoveFactory.DOWN); + return moves; + } + + public static void main(String[] args) { + new Scrambler((Frame) FrameFactory.create(4, 4), new IRandom() { + Random random = new Random(); + + public int nextInt(int border) { + return random.nextInt(border); + } + }).scramble(); + } +} diff --git a/src/test/java/de/devisnik/sliding/FrameFactoryTest.java b/src/test/java/de/devisnik/sliding/FrameFactoryTest.java new file mode 100644 index 0000000..d4b7f81 --- /dev/null +++ b/src/test/java/de/devisnik/sliding/FrameFactoryTest.java @@ -0,0 +1,37 @@ +package de.devisnik.sliding; + +import static org.junit.Assert.*; + +import java.util.Random; + +import org.junit.Test; + +import de.devisnik.sliding.FrameFactory; +import de.devisnik.sliding.IFrame; +import de.devisnik.sliding.IRandom; +import de.devisnik.sliding.Point; + +public class FrameFactoryTest { + + @Test + public void testCreate() { + IFrame frame = FrameFactory.create(3, 4); + assertEquals(new Point(3,4),frame.getSize()); + assertEquals(frame.getHole(), frame.getPieceAt(2, 3)); + } + + @Test + public void testCreateRobot() { + IFrame frame = FrameFactory.createRobot(3, 4, new IRandom() { + + private Random random = new Random(); + + @Override + public int nextInt(int border) { + return random.nextInt(border); + } + }); + assertEquals(new Point(3,4),frame.getSize()); + } + +} diff --git a/src/test/java/de/devisnik/sliding/FrameScramblerTest.java b/src/test/java/de/devisnik/sliding/FrameScramblerTest.java new file mode 100644 index 0000000..1375966 --- /dev/null +++ b/src/test/java/de/devisnik/sliding/FrameScramblerTest.java @@ -0,0 +1,33 @@ +package de.devisnik.sliding; + +import static org.junit.Assert.assertEquals; + +import java.util.Iterator; +import java.util.Random; + +import org.junit.Test; + +public class FrameScramblerTest { + + @Test + public void testScrambleInt() { + IFrame frame = FrameFactory.create(4, 3); + FrameScrambler frameScrambler = new FrameScrambler(frame, new IRandom() { + + Random mRandom = new Random(); + @Override + public int nextInt(int border) { + return mRandom.nextInt(border); + } + }); + IMove[] moves = frameScrambler.scramble(20); + for (int i = moves.length-1; i >= 0; i--) { + frame.execute(MoveFactory.getInverse(moves[i])); + } + for (Iterator iterator = frame.iterator(); iterator.hasNext();) { + IPiece piece = (IPiece) iterator.next(); + assertEquals(true, piece.isAtHome()); + } + } + +} diff --git a/src/test/java/de/devisnik/sliding/animation/TestShiftable.java b/src/test/java/de/devisnik/sliding/animation/TestShiftable.java new file mode 100644 index 0000000..bbf54b7 --- /dev/null +++ b/src/test/java/de/devisnik/sliding/animation/TestShiftable.java @@ -0,0 +1,41 @@ +/* + * Created on 10.11.2006 by leck + * + */ +package de.devisnik.sliding.animation; + +import de.devisnik.sliding.Point; +import de.devisnik.sliding.animation.IShiftable; + +class TestShiftable implements IShiftable { + + + private final Point itsPosition; + + public TestShiftable(int startX, int startY) { + itsPosition = new Point(startX, startY); + } + + public Point getPosition() { + return itsPosition; + } + + public boolean isDisposed() { + return false; + } + + public void setPosition(int x, int y) { + itsPosition.x = x; + itsPosition.y = y; + } + + public Point getSize() { + return new Point(10,10); + } + + @Override + public void shift(Point delta) { + // TODO Auto-generated method stub + + } +} \ No newline at end of file diff --git a/src/test/java/de/devisnik/sliding/impl/FrameTest.java b/src/test/java/de/devisnik/sliding/impl/FrameTest.java new file mode 100644 index 0000000..7e8e103 --- /dev/null +++ b/src/test/java/de/devisnik/sliding/impl/FrameTest.java @@ -0,0 +1,111 @@ +package de.devisnik.sliding.impl; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import de.devisnik.sliding.IFrameListener; +import de.devisnik.sliding.IPiece; +import de.devisnik.sliding.MoveFactory; +import de.devisnik.sliding.Point; +import de.devisnik.sliding.ShiftingEvent; + +public class FrameTest { + + private Frame mFrame; + + @Before + public void createFrame() { + mFrame = new Frame(3, 3); + } + + @Test + public void testNotifyListener() { + final boolean[] swapped = new boolean[1]; + mFrame.addListener(new IFrameListener() { + @Override + public void handleSwap(IPiece left, IPiece right) { + swapped[0] = true; + } + + @Override + public void handleShifting(ShiftingEvent[] event) { + } + }); + mFrame.execute(MoveFactory.UP); + assertEquals(true, swapped[0]); + } + + @Test + public void testAddRemoveListener() { + final int[] count = new int[1]; + IFrameListener listener = new IFrameListener() { + + @Override + public void handleSwap(IPiece left, IPiece right) { + count[0]++; + } + + @Override + public void handleShifting(ShiftingEvent[] event) { + } + }; + mFrame.addListener(listener); + mFrame.execute(MoveFactory.UP); + mFrame.removeListener(listener); + mFrame.execute(MoveFactory.DOWN); + assertEquals(1, count[0]); + } + + @Test + public void testAddNullListener() { + mFrame.addListener(null); + mFrame.execute(MoveFactory.UP); + } + + @Test + public void testMovingHole() { + mFrame.execute(MoveFactory.LEFT); + assertEquals(mFrame.getHole(), mFrame.getPieceAt(1, 2)); + assertEquals(mFrame.getPieceAt(2, 2).getHomePosition(), new Point(1, 2)); + + mFrame.execute(MoveFactory.UP); + assertEquals(mFrame.getHole(), mFrame.getPieceAt(1, 1)); + assertEquals(mFrame.getPieceAt(1, 2).getHomePosition(), new Point(1, 1)); + + mFrame.execute(MoveFactory.RIGHT); + assertEquals(mFrame.getHole(), mFrame.getPieceAt(2, 1)); + assertEquals(mFrame.getPieceAt(1, 1).getHomePosition(), new Point(2, 1)); + + mFrame.execute(MoveFactory.DOWN); + assertEquals(mFrame.getHole(), mFrame.getPieceAt(2, 2)); + assertEquals(mFrame.getPieceAt(2, 1).getHomePosition(), new Point(1, 2)); + + } + + @Test + public void testGetHole() { + assertEquals(mFrame.getHole(), mFrame.getPieceAt(2, 2)); + } + + @Test + public void testGetPieceAt() { + for (IPiece piece : mFrame) + assertEquals(piece.getPosition(), piece.getHomePosition()); + } + + @Test + public void testGetSize() { + assertEquals(new Point(3, 3), mFrame.getSize()); + } + + @Test + public void shouldIterateOverAllPieces() { + int count = 0; + for (@SuppressWarnings("unused") IPiece piece : mFrame) + count++; + Point size = mFrame.getSize(); + assertEquals(size.x * size.y, count); + } +} diff --git a/src/test/java/de/devisnik/sliding/impl/MoveFactoryTest.java b/src/test/java/de/devisnik/sliding/impl/MoveFactoryTest.java new file mode 100644 index 0000000..8eb476e --- /dev/null +++ b/src/test/java/de/devisnik/sliding/impl/MoveFactoryTest.java @@ -0,0 +1,34 @@ +package de.devisnik.sliding.impl; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +import de.devisnik.sliding.IMove; +import de.devisnik.sliding.MoveFactory; + +public class MoveFactoryTest { + + @Test + public void shouldKnowInverseMoves() { + assertEquals(MoveFactory.DOWN, MoveFactory.getInverse(MoveFactory.UP)); + assertEquals(MoveFactory.LEFT, + MoveFactory.getInverse(MoveFactory.RIGHT)); + assertEquals(MoveFactory.RIGHT, + MoveFactory.getInverse(MoveFactory.LEFT)); + assertEquals(MoveFactory.UP, MoveFactory.getInverse(MoveFactory.DOWN)); + } + + @Test + public void shouldConstructMultiMovesInOneDirection() { + IMove[] threeHorizonalMoves = MoveFactory.getMovesTo(3, 0); + assertEquals(3, threeHorizonalMoves.length); + for (int i = 0; i < threeHorizonalMoves.length; i++) { + assertEquals(MoveFactory.RIGHT, threeHorizonalMoves[i]); + } + IMove[] twoVerticalMoves = MoveFactory.getMovesTo(0, 2); + assertEquals(2, twoVerticalMoves.length); + for (int i = 0; i < twoVerticalMoves.length; i++) { + assertEquals(MoveFactory.DOWN, twoVerticalMoves[i]); + } + } +} diff --git a/src/test/java/de/devisnik/sliding/impl/PieceTest.java b/src/test/java/de/devisnik/sliding/impl/PieceTest.java new file mode 100644 index 0000000..cc108b1 --- /dev/null +++ b/src/test/java/de/devisnik/sliding/impl/PieceTest.java @@ -0,0 +1,45 @@ +package de.devisnik.sliding.impl; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import de.devisnik.sliding.Point; + +public class PieceTest { + + private static final String LABEL = "X"; + private Piece mPiece; + @Before + public void createTestPiece() { + mPiece = new Piece(1, 2, LABEL); + } + + @Test + public void shouldReturnPositionGivenInConstructor() { + assertEquals(new Point(1,2), mPiece.getPosition()); + } + + @Test + public void shouldReturnLabelGivenInConstructor() { + assertEquals(LABEL, mPiece.getLabel()); + } + + @Test + public void shouldBeInitiallyAtHome() { + assertEquals(true, mPiece.isAtHome()); + } + + @Test + public void shouldNotBeHomeAfterChangingPosition() { + mPiece.setPosition(0, 0); + assertEquals(false, mPiece.isAtHome()); + } + + @Test + public void shouldReturnNewPositionAfterSetting() { + mPiece.setPosition(0, 0); + assertEquals(new Point(0,0), mPiece.getPosition()); + } +}