diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index ec895971f..856fcd8f0 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -8,30 +8,82 @@ on: pull_request: jobs: - build: + build-ubuntu: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 21 + distribution: temurin - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle run: ./gradlew build -x test + - name: JPackage + run: ./gradlew copyInstaller + - uses: actions/upload-artifact@v4 + with: + name: Ubuntu-Artifact + path: installer + + build-windows: + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 21 + uses: actions/setup-java@v1 + with: + java-version: 21 + distribution: temurin + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew build -x test + - name: JPackage + run: ./gradlew copyInstaller + - uses: actions/upload-artifact@v4 + with: + name: Windows-Artifact + path: installer + + build-macos: + + runs-on: macos-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 21 + uses: actions/setup-java@v1 + with: + java-version: 21 + distribution: temurin + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew build -x test + - name: JPackage + run: ./gradlew copyInstaller + - uses: actions/upload-artifact@v4 + with: + name: Mac Artifact + path: installer checkstyle: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 21 + distribution: temurin - name: gradlew executable run: chmod +x gradlew - name: Run checkstyle diff --git a/.github/workflows/java-autoformat.yml b/.github/workflows/java-autoformat.yml new file mode 100644 index 000000000..116332804 --- /dev/null +++ b/.github/workflows/java-autoformat.yml @@ -0,0 +1,93 @@ +name: Java Code Auto Format +on: pull_request + +jobs: + format_dev: + if: | + github.event.pull_request.head.ref == 'dev' && + github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v1 + with: + ref: ${{ github.head_ref }} + + - name: Set up JDK 21 + uses: actions/setup-java@v1 + with: + java-version: 21 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew build -x test + + - name: Run spotless + run: ./gradlew :spotlessApply + + - name: Check for modified files + id: git-check + run: echo "modified=$(if [[ -n $(git status -s) ]]; then echo "true"; else echo "false"; fi)" >> $GITHUB_OUTPUT + + - name: Create temporary branch and pull request + if: steps.git-check.outputs.modified == 'true' + run: | + git config --global user.name 'Bram van Heuveln' + git config --global user.email 'bram28@users.noreply.github.com' + git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} + branch_name="auto-format-code-$(date +%s)" + git checkout -b $branch_name + ./gradlew :spotlessApply + git add . + git commit -am "Automated Java code formatting changes" + git push --set-upstream origin $branch_name + gh pr create -B dev -H $branch_name --title 'Automated Java code formatting changes' --body 'This pull request contains automated code formatting changes.' --reviewer ${{ github.actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Must approve auto-format pull request + if: steps.git-check.outputs.modified == 'true' + run: | + echo "Please review and approve the appropriate auto-format-code pull request." + exit 1 + + format_pull_request_to_dev: + if: | + github.event.pull_request.base.ref == 'dev' && + github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v1 + with: + ref: ${{ github.head_ref }} + + - name: Set up JDK 21 + uses: actions/setup-java@v1 + with: + java-version: 21 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew build -x test + + - name: Run spotless + run: ./gradlew :spotlessApply + + - name: Check for modified files + id: git-check + run: echo "modified=$(if [[ -n $(git status -s) ]]; then echo "true"; else echo "false"; fi)" >> $GITHUB_OUTPUT + + - name: Push changes + if: steps.git-check.outputs.modified == 'true' + run: | + git config --global user.name 'Bram van Heuveln' + git config --global user.email 'bram28@users.noreply.github.com' + git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} + git add . + git commit -am "Automated Java code formatting changes" + git push diff --git a/.github/workflows/publish-javadoc.yml b/.github/workflows/publish-javadoc.yml index 4e1e64608..8818f74b5 100644 --- a/.github/workflows/publish-javadoc.yml +++ b/.github/workflows/publish-javadoc.yml @@ -18,6 +18,7 @@ jobs: with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} javadoc-branch: javadoc - java-version: 11 + java-version: 21 + distribution: temurin target-folder: docs project: gradle \ No newline at end of file diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index bed9d7ad2..03092ecdf 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -18,10 +18,11 @@ jobs: - name: Check Out Code uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 21 + distribution: temurin - name: Grant execute permission for gradlew run: chmod +x gradlew @@ -40,10 +41,11 @@ jobs: - name: Check Out Code uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 21 + distribution: temurin - name: Grant execute permission for gradlew run: chmod +x gradlew @@ -65,8 +67,8 @@ jobs: - name: Set up JDK and Gradle on Windows uses: actions/setup-java@v2 with: - java-version: 11 - distribution: 'adopt' + java-version: 21 + distribution: temurin - name: Run JUnit Tests on Windows run: | diff --git a/.gitignore b/.gitignore index baee37e51..bafea84a3 100644 --- a/.gitignore +++ b/.gitignore @@ -92,4 +92,5 @@ gradle-app.setting gradle/wrapper/gradle-wrapper.properties # Visual Studio Code configs -.vscode/* \ No newline at end of file +.vscode/* +src/test/java/legup/TestRunner.java diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index f23d52492..38a6942c4 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..ea640e792 --- /dev/null +++ b/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments=--init-script /home/gamma/.cache/jdtls/config/org.eclipse.osgi/55/0/.cp/gradle/init/init.gradle +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=/usr/lib/jvm/java-21-openjdk-amd64 +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/README.md b/README.md index f4f99d75c..f32928efb 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ LEGUP (**L**ogic **E**ngine for **G**rid-**U**sing **P**uzzles) is a better way to learn formal logic. It was created by [Dr. Bram van Heuveln](https://science.rpi.edu/itws/faculty/bram-van-heuveln), whose goal for this project is to provide a better interface for students to learn the basic principles of logical reasoning. -> Note: A web version of LEGUP ([Bram-Hub/LegupWeb](https://github.com/Bram-Hub/LegupWeb)) based on this app version of LEGUP was being developed. It is very much in the early stages of development and will not be ready for general use for quite a while. Development on this web version has halted for a while, as no one has been actively working on the project. Contributions to both versions of LEGUP are greatly appreciated. However, if you are interested in using LEGUP for educational purposes, please use this app version. +> Note: A web version of LEGUP ([Bram-Hub/LegupWeb](https://github.com/Bram-Hub/LegupWeb)) was previously under development, but it has been halted due to no one actively working on the project. Contributions to both versions of LEGUP are greatly appreciated. If you are interested in using LEGUP for educational purposes, please use this app version. ## Table of Contents - [Background](#background) diff --git a/bin/main/edu/rpi/legup/legup/config b/bin/main/edu/rpi/legup/legup/config deleted file mode 100644 index ccd4f5be3..000000000 --- a/bin/main/edu/rpi/legup/legup/config +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - diff --git a/build.gradle b/build.gradle index 062a2cbff..38a94e3f3 100644 --- a/build.gradle +++ b/build.gradle @@ -2,16 +2,50 @@ plugins { id 'java' id 'edu.sc.seis.launch4j' version '2.5.3' id 'kr.motd.sphinx' version '2.10.0' + id 'com.diffplug.spotless' version '6.25.0' } -version '2.0.0' +version '6.0.0' apply plugin: 'java' apply plugin: 'application' + +spotless { + enforceCheck false + + format 'misc', { + // define the files to apply `misc` to + target '*.gradle', '*.md', '.gitignore' + + // define the steps to apply to those files + trimTrailingWhitespace() + indentWithSpaces() // or spaces. Takes an integer argument if you don't like 4 + endWithNewline() + } + + java { + // Use the default importOrder configuration + importOrder() + + // Cleanthat will refactor your code, but it may break your style: apply it before your formatter + cleanthat() + + googleJavaFormat('1.19.2').aosp() + + formatAnnotations() + } +} + apply plugin: 'checkstyle' -mainClassName = 'edu.rpi.legup.Legup' -sourceCompatibility = 11 +application { + mainClass.set('edu.rpi.legup.Legup') +} + +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} dependencies { implementation 'org.jetbrains:annotations:20.1.0' @@ -70,42 +104,37 @@ jar { archiveFileName = 'Legup.jar' } -/* - * CREATES NATIVE WINDOWS EXECUTABLE - * Launches launch4j to create an executable (.exe) file wrapping the jar - * THIS IS NOT THE INSTALLER - * Add "icon = 'path/to/icon.ico'" to set an icon for the executable - */ -createExe() { - mainClassName = 'edu.rpi.legup.Legup' - outputDir = '../native/windows' - outfile = 'bin/Legup.exe' - bundledJrePath = 'jre' - bundledJre64Bit = true - jdkPreference = 'preferJre' - jreMinVersion = '11' - jreRuntimeBits = '64/32' +repositories { + mavenCentral() } -/* - * CREATES NATIVE WINDOWS INSTALLER -- ONLY RUNS ON WINDOWS - * Runs the shipped version of Inno Setup (6.2) to compile the installer - * Modify the setup settings in native/windows/legup_inno_setup.iss - * - * Modifications are likely required to run the setup script on your computer: - * Edit the "CHANGE ME" line in native/windows/legup_inno_setup.iss to reflect - * the path to the Java installation you want to ship inside the executable. - */ -task buildNativeWindows(type: Exec, dependsOn: 'createExe') { - jar - createExe - - workingDir = "${buildDir}/../native/windows" - commandLine 'cmd', '/c', 'make_windows_installer.bat' +tasks.register("jpackage") { + group("jpackage") + doLast { + var operatingSystem = System.getProperty("os.name").toLowerCase() + if (operatingSystem.contains("windows")) { + exec { + commandLine 'cmd', '/c', 'jpackage', '--input', 'build/libs', '--main-jar', 'Legup.jar', '--win-dir-chooser', '--win-shortcut-prompt', '--win-shortcut', '--dest', 'build/installer', '-n', "LEGUP", '--app-version', "${project.version}", '--icon', "src/main/resources/edu/rpi/legup/images/Legup/logo.ico" + } + } else if (operatingSystem.contains("linux")) { + exec { + commandLine 'sh', '-c', "jpackage --input build/libs --main-jar Legup.jar --dest build/installer -n LEGUP --icon src/main/resources/edu/rpi/legup/images/Legup/logo.ico --app-version ${project.version}" + } + } else if (operatingSystem.contains("mac")) { + exec { + commandLine 'bash', '-c', "jpackage --input build/libs --main-jar Legup.jar --dest build/installer -n \"LEGUP\" --icon src/main/resources/edu/rpi/legup/images/Legup/logo.ico --app-version ${project.version}" + } + } else { + println("JPackage task is not set up for " + System.getProperty("os.name")) + } + } } - -repositories { - mavenCentral() +tasks.register('copyInstaller', Sync) { + group("jpackage") + from ("build/installer/") + into("installer") + rename("LEGUP-${project.version}", "LEGUP-installer-${project.version}") } -targetCompatibility = JavaVersion.VERSION_11 + +copyInstaller.dependsOn(jpackage) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index a5dfea0af..6e17e3fc5 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -7,12 +7,6 @@ - - - - - diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 28861d273..d64cd4917 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2d2fd7c74..1af9e0930 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists \ No newline at end of file +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 index cccdd3d51..1aa94a426 --- a/gradlew +++ b/gradlew @@ -1,78 +1,127 @@ -#!/usr/bin/env sh +#!/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 UN*X -## +# +# 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 -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 +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 -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +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 - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +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" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,92 +130,120 @@ 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. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "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 +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# 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 +# 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" ) -# 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"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # 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\"" + 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 - i=$((i+1)) + # 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 - 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 -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f9553162f..93e3f59f1 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@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 @@ -9,19 +25,23 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +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= +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%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_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=%* - :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% +"%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%"=="0" goto mainEnd +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! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +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 diff --git a/native/windows/OLD_inno_setup.iss b/native/windows/OLD_inno_setup.iss deleted file mode 100644 index 528b0b660..000000000 --- a/native/windows/OLD_inno_setup.iss +++ /dev/null @@ -1,53 +0,0 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -#define MyAppName "Legup" -#define MyAppVersion "2.0" -#define MyAppPublisher "Bram, Inc." -#define MyAppURL "https://github.com/jpoegs/legup2.0" -#define MyAppExeName "Legup.jar" - -[Setup] -; NOTE: The value of AppId uniquely identifies this application. -; Do not use the same AppId value in installers for other applications. -; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{C1DFC564-DE07-4A5D-BF85-DDCF514B57BA} -AppName={#MyAppName} -AppVersion={#MyAppVersion} -;AppVerName={#MyAppName} {#MyAppVersion} -AppPublisher={#MyAppPublisher} -AppPublisherURL={#MyAppURL} -AppSupportURL={#MyAppURL} -AppUpdatesURL={#MyAppURL} -DefaultDirName={pf}\{#MyAppName} -DisableProgramGroupPage=yes -OutputBaseFilename=setup -Compression=lzma -SolidCompression=yes -ChangesAssociations=yes - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked -Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 - -[Files] -Source: "D:\GitHub\Legup\build\libs\Legup.jar"; DestDir: "{app}"; Flags: ignoreversion -; NOTE: Don't use "Flags: ignoreversion" on any shared system files - -[Icons] -Name: "{commonprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" -Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon -Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon - -[Run] -Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: shellexec postinstall skipifsilent - -[Registry] - -Root: HKCR; Subkey: ".legup"; ValueData: "{#MyAppName}"; Flags: uninsdeletevalue; ValueType: string; ValueName: "" -Root: HKCR; Subkey: "{#MyAppName}"; ValueData: "{#MyAppName}"; Flags: uninsdeletekey; ValueType: string; ValueName: "" -Root: HKCR; Subkey: "{#MyAppName}\DefaultIcon"; ValueData: "{app}\{#MyAppExeName},0"; ValueType: string; ValueName: "" -Root: HKCR; Subkey: "{#MyAppName}\shell\open\command"; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; ValueType: string; ValueName: "" \ No newline at end of file diff --git a/native/windows/inno-setup/Compil32.exe b/native/windows/inno-setup/Compil32.exe deleted file mode 100644 index 544993108..000000000 Binary files a/native/windows/inno-setup/Compil32.exe and /dev/null differ diff --git a/native/windows/inno-setup/Default.isl b/native/windows/inno-setup/Default.isl deleted file mode 100644 index ce9b70e2e..000000000 --- a/native/windows/inno-setup/Default.isl +++ /dev/null @@ -1,384 +0,0 @@ -; *** Inno Setup version 6.1.0+ English messages *** -; -; To download user-contributed translations of this file, go to: -; https://jrsoftware.org/files/istrans/ -; -; Note: When translating this text, do not add periods (.) to the end of -; messages that didn't have them already, because on those messages Inno -; Setup adds the periods automatically (appending a period would result in -; two periods being displayed). - -[LangOptions] -; The following three entries are very important. Be sure to read and -; understand the '[LangOptions] section' topic in the help file. -LanguageName=English -LanguageID=$0409 -LanguageCodePage=0 -; If the language you are translating to requires special font faces or -; sizes, uncomment any of the following entries and change them accordingly. -;DialogFontName= -;DialogFontSize=8 -;WelcomeFontName=Verdana -;WelcomeFontSize=12 -;TitleFontName=Arial -;TitleFontSize=29 -;CopyrightFontName=Arial -;CopyrightFontSize=8 - -[Messages] - -; *** Application titles -SetupAppTitle=Setup -SetupWindowTitle=Setup - %1 -UninstallAppTitle=Uninstall -UninstallAppFullTitle=%1 Uninstall - -; *** Misc. common -InformationTitle=Information -ConfirmTitle=Confirm -ErrorTitle=Error - -; *** SetupLdr messages -SetupLdrStartupMessage=This will install %1. Do you wish to continue? -LdrCannotCreateTemp=Unable to create a temporary file. Setup aborted -LdrCannotExecTemp=Unable to execute file in the temporary directory. Setup aborted -HelpTextNote= - -; *** Startup error messages -LastErrorMessage=%1.%n%nError %2: %3 -SetupFileMissing=The file %1 is missing from the installation directory. Please correct the problem or obtain a new copy of the program. -SetupFileCorrupt=The setup files are corrupted. Please obtain a new copy of the program. -SetupFileCorruptOrWrongVer=The setup files are corrupted, or are incompatible with this version of Setup. Please correct the problem or obtain a new copy of the program. -InvalidParameter=An invalid parameter was passed on the command line:%n%n%1 -SetupAlreadyRunning=Setup is already running. -WindowsVersionNotSupported=This program does not support the version of Windows your computer is running. -WindowsServicePackRequired=This program requires %1 Service Pack %2 or later. -NotOnThisPlatform=This program will not run on %1. -OnlyOnThisPlatform=This program must be run on %1. -OnlyOnTheseArchitectures=This program can only be installed on versions of Windows designed for the following processor architectures:%n%n%1 -WinVersionTooLowError=This program requires %1 version %2 or later. -WinVersionTooHighError=This program cannot be installed on %1 version %2 or later. -AdminPrivilegesRequired=You must be logged in as an administrator when installing this program. -PowerUserPrivilegesRequired=You must be logged in as an administrator or as a member of the Power Users group when installing this program. -SetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. -UninstallAppRunningError=Uninstall has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. - -; *** Startup questions -PrivilegesRequiredOverrideTitle=Select Setup Install Mode -PrivilegesRequiredOverrideInstruction=Select install mode -PrivilegesRequiredOverrideText1=%1 can be installed for all users (requires administrative privileges), or for you only. -PrivilegesRequiredOverrideText2=%1 can be installed for you only, or for all users (requires administrative privileges). -PrivilegesRequiredOverrideAllUsers=Install for &all users -PrivilegesRequiredOverrideAllUsersRecommended=Install for &all users (recommended) -PrivilegesRequiredOverrideCurrentUser=Install for &me only -PrivilegesRequiredOverrideCurrentUserRecommended=Install for &me only (recommended) - -; *** Misc. errors -ErrorCreatingDir=Setup was unable to create the directory "%1" -ErrorTooManyFilesInDir=Unable to create a file in the directory "%1" because it contains too many files - -; *** Setup common messages -ExitSetupTitle=Exit Setup -ExitSetupMessage=Setup is not complete. If you exit now, the program will not be installed.%n%nYou may run Setup again at another time to complete the installation.%n%nExit Setup? -AboutSetupMenuItem=&About Setup... -AboutSetupTitle=About Setup -AboutSetupMessage=%1 version %2%n%3%n%n%1 home page:%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< &Back -ButtonNext=&Next > -ButtonInstall=&Install -ButtonOK=OK -ButtonCancel=Cancel -ButtonYes=&Yes -ButtonYesToAll=Yes to &All -ButtonNo=&No -ButtonNoToAll=N&o to All -ButtonFinish=&Finish -ButtonBrowse=&Browse... -ButtonWizardBrowse=B&rowse... -ButtonNewFolder=&Make New Folder - -; *** "Select Language" dialog messages -SelectLanguageTitle=Select Setup Language -SelectLanguageLabel=Select the language to use during the installation. - -; *** Common wizard text -ClickNext=Click Next to continue, or Cancel to exit Setup. -BeveledLabel= -BrowseDialogTitle=Browse For Folder -BrowseDialogLabel=Select a folder in the list below, then click OK. -NewFolderName=New Folder - -; *** "Welcome" wizard page -WelcomeLabel1=Welcome to the [name] Setup Wizard -WelcomeLabel2=This will install [name/ver] on your computer.%n%nIt is recommended that you close all other applications before continuing. - -; *** "Password" wizard page -WizardPassword=Password -PasswordLabel1=This installation is password protected. -PasswordLabel3=Please provide the password, then click Next to continue. Passwords are case-sensitive. -PasswordEditLabel=&Password: -IncorrectPassword=The password you entered is not correct. Please try again. - -; *** "License Agreement" wizard page -WizardLicense=License Agreement -LicenseLabel=Please read the following important information before continuing. -LicenseLabel3=Please read the following License Agreement. You must accept the terms of this agreement before continuing with the installation. -LicenseAccepted=I &accept the agreement -LicenseNotAccepted=I &do not accept the agreement - -; *** "Information" wizard pages -WizardInfoBefore=Information -InfoBeforeLabel=Please read the following important information before continuing. -InfoBeforeClickLabel=When you are ready to continue with Setup, click Next. -WizardInfoAfter=Information -InfoAfterLabel=Please read the following important information before continuing. -InfoAfterClickLabel=When you are ready to continue with Setup, click Next. - -; *** "User Information" wizard page -WizardUserInfo=User Information -UserInfoDesc=Please enter your information. -UserInfoName=&User Name: -UserInfoOrg=&Organization: -UserInfoSerial=&Serial Number: -UserInfoNameRequired=You must enter a name. - -; *** "Select Destination Location" wizard page -WizardSelectDir=Select Destination Location -SelectDirDesc=Where should [name] be installed? -SelectDirLabel3=Setup will install [name] into the following folder. -SelectDirBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse. -DiskSpaceGBLabel=At least [gb] GB of free disk space is required. -DiskSpaceMBLabel=At least [mb] MB of free disk space is required. -CannotInstallToNetworkDrive=Setup cannot install to a network drive. -CannotInstallToUNCPath=Setup cannot install to a UNC path. -InvalidPath=You must enter a full path with drive letter; for example:%n%nC:\APP%n%nor a UNC path in the form:%n%n\\server\share -InvalidDrive=The drive or UNC share you selected does not exist or is not accessible. Please select another. -DiskSpaceWarningTitle=Not Enough Disk Space -DiskSpaceWarning=Setup requires at least %1 KB of free space to install, but the selected drive only has %2 KB available.%n%nDo you want to continue anyway? -DirNameTooLong=The folder name or path is too long. -InvalidDirName=The folder name is not valid. -BadDirName32=Folder names cannot include any of the following characters:%n%n%1 -DirExistsTitle=Folder Exists -DirExists=The folder:%n%n%1%n%nalready exists. Would you like to install to that folder anyway? -DirDoesntExistTitle=Folder Does Not Exist -DirDoesntExist=The folder:%n%n%1%n%ndoes not exist. Would you like the folder to be created? - -; *** "Select Components" wizard page -WizardSelectComponents=Select Components -SelectComponentsDesc=Which components should be installed? -SelectComponentsLabel2=Select the components you want to install; clear the components you do not want to install. Click Next when you are ready to continue. -FullInstallation=Full installation -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=Compact installation -CustomInstallation=Custom installation -NoUninstallWarningTitle=Components Exist -NoUninstallWarning=Setup has detected that the following components are already installed on your computer:%n%n%1%n%nDeselecting these components will not uninstall them.%n%nWould you like to continue anyway? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceGBLabel=Current selection requires at least [gb] GB of disk space. -ComponentsDiskSpaceMBLabel=Current selection requires at least [mb] MB of disk space. - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=Select Additional Tasks -SelectTasksDesc=Which additional tasks should be performed? -SelectTasksLabel2=Select the additional tasks you would like Setup to perform while installing [name], then click Next. - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=Select Start Menu Folder -SelectStartMenuFolderDesc=Where should Setup place the program's shortcuts? -SelectStartMenuFolderLabel3=Setup will create the program's shortcuts in the following Start Menu folder. -SelectStartMenuFolderBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse. -MustEnterGroupName=You must enter a folder name. -GroupNameTooLong=The folder name or path is too long. -InvalidGroupName=The folder name is not valid. -BadGroupName=The folder name cannot include any of the following characters:%n%n%1 -NoProgramGroupCheck2=&Don't create a Start Menu folder - -; *** "Ready to Install" wizard page -WizardReady=Ready to Install -ReadyLabel1=Setup is now ready to begin installing [name] on your computer. -ReadyLabel2a=Click Install to continue with the installation, or click Back if you want to review or change any settings. -ReadyLabel2b=Click Install to continue with the installation. -ReadyMemoUserInfo=User information: -ReadyMemoDir=Destination location: -ReadyMemoType=Setup type: -ReadyMemoComponents=Selected components: -ReadyMemoGroup=Start Menu folder: -ReadyMemoTasks=Additional tasks: - -; *** TDownloadWizardPage wizard page and DownloadTemporaryFile -DownloadingLabel=Downloading additional files... -ButtonStopDownload=&Stop download -StopDownload=Are you sure you want to stop the download? -ErrorDownloadAborted=Download aborted -ErrorDownloadFailed=Download failed: %1 %2 -ErrorDownloadSizeFailed=Getting size failed: %1 %2 -ErrorFileHash1=File hash failed: %1 -ErrorFileHash2=Invalid file hash: expected %1, found %2 -ErrorProgress=Invalid progress: %1 of %2 -ErrorFileSize=Invalid file size: expected %1, found %2 - -; *** "Preparing to Install" wizard page -WizardPreparing=Preparing to Install -PreparingDesc=Setup is preparing to install [name] on your computer. -PreviousInstallNotCompleted=The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.%n%nAfter restarting your computer, run Setup again to complete the installation of [name]. -CannotContinue=Setup cannot continue. Please click Cancel to exit. -ApplicationsFound=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. -ApplicationsFound2=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. After the installation has completed, Setup will attempt to restart the applications. -CloseApplications=&Automatically close the applications -DontCloseApplications=&Do not close the applications -ErrorCloseApplications=Setup was unable to automatically close all applications. It is recommended that you close all applications using files that need to be updated by Setup before continuing. -PrepareToInstallNeedsRestart=Setup must restart your computer. After restarting your computer, run Setup again to complete the installation of [name].%n%nWould you like to restart now? - -; *** "Installing" wizard page -WizardInstalling=Installing -InstallingLabel=Please wait while Setup installs [name] on your computer. - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=Completing the [name] Setup Wizard -FinishedLabelNoIcons=Setup has finished installing [name] on your computer. -FinishedLabel=Setup has finished installing [name] on your computer. The application may be launched by selecting the installed shortcuts. -ClickFinish=Click Finish to exit Setup. -FinishedRestartLabel=To complete the installation of [name], Setup must restart your computer. Would you like to restart now? -FinishedRestartMessage=To complete the installation of [name], Setup must restart your computer.%n%nWould you like to restart now? -ShowReadmeCheck=Yes, I would like to view the README file -YesRadio=&Yes, restart the computer now -NoRadio=&No, I will restart the computer later -; used for example as 'Run MyProg.exe' -RunEntryExec=Run %1 -; used for example as 'View Readme.txt' -RunEntryShellExec=View %1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=Setup Needs the Next Disk -SelectDiskLabel2=Please insert Disk %1 and click OK.%n%nIf the files on this disk can be found in a folder other than the one displayed below, enter the correct path or click Browse. -PathLabel=&Path: -FileNotInDir2=The file "%1" could not be located in "%2". Please insert the correct disk or select another folder. -SelectDirectoryLabel=Please specify the location of the next disk. - -; *** Installation phase messages -SetupAborted=Setup was not completed.%n%nPlease correct the problem and run Setup again. -AbortRetryIgnoreSelectAction=Select action -AbortRetryIgnoreRetry=&Try again -AbortRetryIgnoreIgnore=&Ignore the error and continue -AbortRetryIgnoreCancel=Cancel installation - -; *** Installation status messages -StatusClosingApplications=Closing applications... -StatusCreateDirs=Creating directories... -StatusExtractFiles=Extracting files... -StatusCreateIcons=Creating shortcuts... -StatusCreateIniEntries=Creating INI entries... -StatusCreateRegistryEntries=Creating registry entries... -StatusRegisterFiles=Registering files... -StatusSavingUninstall=Saving uninstall information... -StatusRunProgram=Finishing installation... -StatusRestartingApplications=Restarting applications... -StatusRollback=Rolling back changes... - -; *** Misc. errors -ErrorInternal2=Internal error: %1 -ErrorFunctionFailedNoCode=%1 failed -ErrorFunctionFailed=%1 failed; code %2 -ErrorFunctionFailedWithMessage=%1 failed; code %2.%n%3 -ErrorExecutingProgram=Unable to execute file:%n%1 - -; *** Registry errors -ErrorRegOpenKey=Error opening registry key:%n%1\%2 -ErrorRegCreateKey=Error creating registry key:%n%1\%2 -ErrorRegWriteKey=Error writing to registry key:%n%1\%2 - -; *** INI errors -ErrorIniEntry=Error creating INI entry in file "%1". - -; *** File copying errors -FileAbortRetryIgnoreSkipNotRecommended=&Skip this file (not recommended) -FileAbortRetryIgnoreIgnoreNotRecommended=&Ignore the error and continue (not recommended) -SourceIsCorrupted=The source file is corrupted -SourceDoesntExist=The source file "%1" does not exist -ExistingFileReadOnly2=The existing file could not be replaced because it is marked read-only. -ExistingFileReadOnlyRetry=&Remove the read-only attribute and try again -ExistingFileReadOnlyKeepExisting=&Keep the existing file -ErrorReadingExistingDest=An error occurred while trying to read the existing file: -FileExistsSelectAction=Select action -FileExists2=The file already exists. -FileExistsOverwriteExisting=&Overwrite the existing file -FileExistsKeepExisting=&Keep the existing file -FileExistsOverwriteOrKeepAll=&Do this for the next conflicts -ExistingFileNewerSelectAction=Select action -ExistingFileNewer2=The existing file is newer than the one Setup is trying to install. -ExistingFileNewerOverwriteExisting=&Overwrite the existing file -ExistingFileNewerKeepExisting=&Keep the existing file (recommended) -ExistingFileNewerOverwriteOrKeepAll=&Do this for the next conflicts -ErrorChangingAttr=An error occurred while trying to change the attributes of the existing file: -ErrorCreatingTemp=An error occurred while trying to create a file in the destination directory: -ErrorReadingSource=An error occurred while trying to read the source file: -ErrorCopying=An error occurred while trying to copy a file: -ErrorReplacingExistingFile=An error occurred while trying to replace the existing file: -ErrorRestartReplace=RestartReplace failed: -ErrorRenamingTemp=An error occurred while trying to rename a file in the destination directory: -ErrorRegisterServer=Unable to register the DLL/OCX: %1 -ErrorRegSvr32Failed=RegSvr32 failed with exit code %1 -ErrorRegisterTypeLib=Unable to register the type library: %1 - -; *** Uninstall display name markings -; used for example as 'My Program (32-bit)' -UninstallDisplayNameMark=%1 (%2) -; used for example as 'My Program (32-bit, All users)' -UninstallDisplayNameMarks=%1 (%2, %3) -UninstallDisplayNameMark32Bit=32-bit -UninstallDisplayNameMark64Bit=64-bit -UninstallDisplayNameMarkAllUsers=All users -UninstallDisplayNameMarkCurrentUser=Current user - -; *** Post-installation errors -ErrorOpeningReadme=An error occurred while trying to open the README file. -ErrorRestartingComputer=Setup was unable to restart the computer. Please do this manually. - -; *** Uninstaller messages -UninstallNotFound=File "%1" does not exist. Cannot uninstall. -UninstallOpenError=File "%1" could not be opened. Cannot uninstall -UninstallUnsupportedVer=The uninstall log file "%1" is in a format not recognized by this version of the uninstaller. Cannot uninstall -UninstallUnknownEntry=An unknown entry (%1) was encountered in the uninstall log -ConfirmUninstall=Are you sure you want to completely remove %1 and all of its components? -UninstallOnlyOnWin64=This installation can only be uninstalled on 64-bit Windows. -OnlyAdminCanUninstall=This installation can only be uninstalled by a user with administrative privileges. -UninstallStatusLabel=Please wait while %1 is removed from your computer. -UninstalledAll=%1 was successfully removed from your computer. -UninstalledMost=%1 uninstall complete.%n%nSome elements could not be removed. These can be removed manually. -UninstalledAndNeedsRestart=To complete the uninstallation of %1, your computer must be restarted.%n%nWould you like to restart now? -UninstallDataCorrupted="%1" file is corrupted. Cannot uninstall - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=Remove Shared File? -ConfirmDeleteSharedFile2=The system indicates that the following shared file is no longer in use by any programs. Would you like for Uninstall to remove this shared file?%n%nIf any programs are still using this file and it is removed, those programs may not function properly. If you are unsure, choose No. Leaving the file on your system will not cause any harm. -SharedFileNameLabel=File name: -SharedFileLocationLabel=Location: -WizardUninstalling=Uninstall Status -StatusUninstalling=Uninstalling %1... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=Installing %1. -ShutdownBlockReasonUninstallingApp=Uninstalling %1. - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] - -NameAndVersion=%1 version %2 -AdditionalIcons=Additional shortcuts: -CreateDesktopIcon=Create a &desktop shortcut -CreateQuickLaunchIcon=Create a &Quick Launch shortcut -ProgramOnTheWeb=%1 on the Web -UninstallProgram=Uninstall %1 -LaunchProgram=Launch %1 -AssocFileExtension=&Associate %1 with the %2 file extension -AssocingFileExtension=Associating %1 with the %2 file extension... -AutoStartProgramGroupDescription=Startup: -AutoStartProgram=Automatically start %1 -AddonHostProgramNotFound=%1 could not be located in the folder you selected.%n%nDo you want to continue anyway? diff --git a/native/windows/inno-setup/ISCC.exe b/native/windows/inno-setup/ISCC.exe deleted file mode 100644 index acca24fc5..000000000 Binary files a/native/windows/inno-setup/ISCC.exe and /dev/null differ diff --git a/native/windows/inno-setup/ISCmplr.dll b/native/windows/inno-setup/ISCmplr.dll deleted file mode 100644 index d44589666..000000000 Binary files a/native/windows/inno-setup/ISCmplr.dll and /dev/null differ diff --git a/native/windows/inno-setup/ISPP.chm b/native/windows/inno-setup/ISPP.chm deleted file mode 100644 index 1b211d649..000000000 Binary files a/native/windows/inno-setup/ISPP.chm and /dev/null differ diff --git a/native/windows/inno-setup/ISPP.dll b/native/windows/inno-setup/ISPP.dll deleted file mode 100644 index 4ce5cb657..000000000 Binary files a/native/windows/inno-setup/ISPP.dll and /dev/null differ diff --git a/native/windows/inno-setup/ISPPBuiltins.iss b/native/windows/inno-setup/ISPPBuiltins.iss deleted file mode 100644 index d42d7e97f..000000000 --- a/native/windows/inno-setup/ISPPBuiltins.iss +++ /dev/null @@ -1,323 +0,0 @@ -// Inno Setup Preprocessor -// -// Inno Setup (C) 1997-2021 Jordan Russell. All Rights Reserved. -// Portions Copyright (C) 2000-2021 Martijn Laan. All Rights Reserved. -// Portions Copyright (C) 2001-2004 Alex Yackimoff. All Rights Reserved. -// -// See the ISPP help file for more documentation of the functions defined by this file -// -#if defined(ISPP_INVOKED) && !defined(_BUILTINS_ISS_) -// -#if PREPROCVER < 0x01000000 -# error Inno Setup Preprocessor version is outdated -#endif -// -#define _BUILTINS_ISS_ -// -#ifdef __OPT_E__ -# define private EnableOptE -# pragma option -e- -#endif - -#ifndef __POPT_P__ -# define private DisablePOptP -#else -# pragma parseroption -p- -#endif - -#define NewLine "\n" -#define Tab "\t" - -#pragma parseroption -p+ - -#pragma spansymbol "\" - -#define True 1 -#define False 0 -#define Yes True -#define No False - -#define MaxInt 0x7FFFFFFFFFFFFFFFL -#define MinInt 0x8000000000000000L - -#define NULL -#define void - -// TypeOf constants - -#define TYPE_ERROR 0 -#define TYPE_NULL 1 -#define TYPE_INTEGER 2 -#define TYPE_STRING 3 -#define TYPE_MACRO 4 -#define TYPE_FUNC 5 -#define TYPE_ARRAY 6 - -// Helper macro to find out the type of an array element or expression. TypeOf -// standard function only allows identifier as its parameter. Use this macro -// to convert an expression to identifier. - -#define TypeOf2(any Expr) TypeOf(Expr) - -// ReadReg constants - -#define HKEY_CLASSES_ROOT 0x80000000UL -#define HKEY_CURRENT_USER 0x80000001UL -#define HKEY_LOCAL_MACHINE 0x80000002UL -#define HKEY_USERS 0x80000003UL -#define HKEY_CURRENT_CONFIG 0x80000005UL -#define HKEY_CLASSES_ROOT_64 0x82000000UL -#define HKEY_CURRENT_USER_64 0x82000001UL -#define HKEY_LOCAL_MACHINE_64 0x82000002UL -#define HKEY_USERS_64 0x82000003UL -#define HKEY_CURRENT_CONFIG_64 0x82000005UL - -#define HKCR HKEY_CLASSES_ROOT -#define HKCU HKEY_CURRENT_USER -#define HKLM HKEY_LOCAL_MACHINE -#define HKU HKEY_USERS -#define HKCC HKEY_CURRENT_CONFIG -#define HKCR64 HKEY_CLASSES_ROOT_64 -#define HKCU64 HKEY_CURRENT_USER_64 -#define HKLM64 HKEY_LOCAL_MACHINE_64 -#define HKU64 HKEY_USERS_64 -#define HKCC64 HKEY_CURRENT_CONFIG_64 - -// Exec constants - -#define SW_HIDE 0 -#define SW_SHOWNORMAL 1 -#define SW_NORMAL 1 -#define SW_SHOWMINIMIZED 2 -#define SW_SHOWMAXIMIZED 3 -#define SW_MAXIMIZE 3 -#define SW_SHOWNOACTIVATE 4 -#define SW_SHOW 5 -#define SW_MINIMIZE 6 -#define SW_SHOWMINNOACTIVE 7 -#define SW_SHOWNA 8 -#define SW_RESTORE 9 -#define SW_SHOWDEFAULT 10 -#define SW_MAX 10 - -// Find constants - -#define FIND_MATCH 0x00 -#define FIND_BEGINS 0x01 -#define FIND_ENDS 0x02 -#define FIND_CONTAINS 0x03 -#define FIND_CASESENSITIVE 0x04 -#define FIND_SENSITIVE FIND_CASESENSITIVE -#define FIND_AND 0x00 -#define FIND_OR 0x08 -#define FIND_NOT 0x10 -#define FIND_TRIM 0x20 - -// FindFirst constants - -#define faReadOnly 0x00000001 -#define faHidden 0x00000002 -#define faSysFile 0x00000004 -#define faVolumeID 0x00000008 -#define faDirectory 0x00000010 -#define faArchive 0x00000020 -#define faSymLink 0x00000040 -#define faAnyFile 0x0000003F - -// GetStringFileInfo standard names - -#define COMPANY_NAME "CompanyName" -#define FILE_DESCRIPTION "FileDescription" -#define FILE_VERSION "FileVersion" -#define INTERNAL_NAME "InternalName" -#define LEGAL_COPYRIGHT "LegalCopyright" -#define ORIGINAL_FILENAME "OriginalFilename" -#define PRODUCT_NAME "ProductName" -#define PRODUCT_VERSION "ProductVersion" - -// GetStringFileInfo helpers - -#define GetFileCompany(str FileName) GetStringFileInfo(FileName, COMPANY_NAME) -#define GetFileDescription(str FileName) GetStringFileInfo(FileName, FILE_DESCRIPTION) -#define GetFileVersionString(str FileName) GetStringFileInfo(FileName, FILE_VERSION) -#define GetFileCopyright(str FileName) GetStringFileInfo(FileName, LEGAL_COPYRIGHT) -#define GetFileOriginalFilename(str FileName) GetStringFileInfo(FileName, ORIGINAL_FILENAME) -#define GetFileProductVersion(str FileName) GetStringFileInfo(FileName, PRODUCT_VERSION) - -#define DeleteToFirstPeriod(str *S) \ - Local[1] = Copy(S, 1, (Local[0] = Pos(".", S)) - 1), \ - S = Copy(S, Local[0] + 1), \ - Local[1] - -#define GetVersionComponents(str FileName, *Major, *Minor, *Rev, *Build) \ - Local[1] = Local[0] = GetVersionNumbersString(FileName), \ - Local[1] == "" ? "" : ( \ - Major = Int(DeleteToFirstPeriod(Local[1])), \ - Minor = Int(DeleteToFirstPeriod(Local[1])), \ - Rev = Int(DeleteToFirstPeriod(Local[1])), \ - Build = Int(Local[1]), \ - Local[0]) - -#define GetPackedVersion(str FileName, *Version) \ - Local[0] = GetVersionComponents(FileName, Local[1], Local[2], Local[3], Local[4]), \ - Version = PackVersionComponents(Local[1], Local[2], Local[3], Local[4]), \ - Local[0] - -#define GetVersionNumbers(str FileName, *MS, *LS) \ - Local[0] = GetPackedVersion(FileName, Local[1]), \ - UnpackVersionNumbers(Local[1], MS, LS), \ - Local[0] - -#define PackVersionNumbers(int VersionMS, int VersionLS) \ - VersionMS << 32 | (VersionLS & 0xFFFFFFFF) - -#define PackVersionComponents(int Major, int Minor, int Rev, int Build) \ - Major << 48 | (Minor & 0xFFFF) << 32 | (Rev & 0xFFFF) << 16 | (Build & 0xFFFF) - -#define UnpackVersionNumbers(int Version, *VersionMS, *VersionLS) \ - VersionMS = Version >> 32, \ - VersionLS = Version & 0xFFFFFFFF, \ - void - -#define UnpackVersionComponents(int Version, *Major, *Minor, *Rev, *Build) \ - Major = Version >> 48, \ - Minor = (Version >> 32) & 0xFFFF, \ - Rev = (Version >> 16) & 0xFFFF, \ - Build = Version & 0xFFFF, \ - void - -#define VersionToStr(int Version) \ - Str(Version >> 48 & 0xFFFF) + "." + Str(Version >> 32 & 0xFFFF) + "." + \ - Str(Version >> 16 & 0xFFFF) + "." + Str(Version & 0xFFFF) - -#define StrToVersion(str Version) \ - Local[0] = Version, \ - Local[1] = Int(DeleteToFirstPeriod(Local[0])), \ - Local[2] = Int(DeleteToFirstPeriod(Local[0])), \ - Local[3] = Int(DeleteToFirstPeriod(Local[0])), \ - Local[4] = Int(Local[0]), \ - PackVersionComponents(Local[1], Local[2], Local[3], Local[4]) - -#define EncodeVer(int Major, int Minor, int Revision = 0, int Build = -1) \ - (Major & 0xFF) << 24 | (Minor & 0xFF) << 16 | (Revision & 0xFF) << 8 | (Build >= 0 ? Build & 0xFF : 0) - -#define DecodeVer(int Version, int Digits = 3) \ - Str(Version >> 24 & 0xFF) + (Digits > 1 ? "." : "") + \ - (Digits > 1 ? \ - Str(Version >> 16 & 0xFF) + (Digits > 2 ? "." : "") : "") + \ - (Digits > 2 ? \ - Str(Version >> 8 & 0xFF) + (Digits > 3 && (Local = Version & 0xFF) ? "." : "") : "") + \ - (Digits > 3 && Local ? \ - Str(Version & 0xFF) : "") - -#define FindSection(str Section = "Files") \ - Find(0, "[" + Section + "]", FIND_MATCH | FIND_TRIM) + 1 - -#if VER >= 0x03000000 -# define FindNextSection(int Line) \ - Find(Line, "[", FIND_BEGINS | FIND_TRIM, "]", FIND_ENDS | FIND_AND) -# define FindSectionEnd(str Section = "Files") \ - FindNextSection(FindSection(Section)) -#else -# define FindSectionEnd(str Section = "Files") \ - FindSection(Section) + EntryCount(Section) -#endif - -#define FindCode() \ - Local[1] = FindSection("Code"), \ - Local[0] = Find(Local[1] - 1, "program", FIND_BEGINS, ";", FIND_ENDS | FIND_AND), \ - (Local[0] < 0 ? Local[1] : Local[0] + 1) - -#define ExtractFilePath(str PathName) \ - (Local[0] = \ - !(Local[1] = RPos("\", PathName)) ? \ - "" : \ - Copy(PathName, 1, Local[1] - 1)), \ - Local[0] + \ - ((Local[2] = Len(Local[0])) == 2 && Copy(Local[0], Local[2]) == ":" ? \ - "\" : \ - "") - -#define ExtractFileDir(str PathName) \ - RemoveBackslash(ExtractFilePath(PathName)) - -#define ExtractFileExt(str PathName) \ - Local[0] = RPos(".", PathName), \ - Copy(PathName, Local[0] + 1) - -#define ExtractFileName(str PathName) \ - !(Local[0] = RPos("\", PathName)) ? \ - PathName : \ - Copy(PathName, Local[0] + 1) - -#define ChangeFileExt(str FileName, str NewExt) \ - !(Local[0] = RPos(".", FileName)) ? \ - FileName + "." + NewExt : \ - Copy(FileName, 1, Local[0]) + NewExt - -#define RemoveFileExt(str FileName) \ - !(Local[0] = RPos(".", FileName)) ? \ - FileName : \ - Copy(FileName, 1, Local[0] - 1) - -#define AddBackslash(str S) \ - Copy(S, Len(S)) == "\" ? S : S + "\" - -#define RemoveBackslash(str S) \ - Local[0] = Len(S), \ - Local[0] > 0 ? \ - Copy(S, Local[0]) == "\" ? \ - (Local[0] == 3 && Copy(S, 2, 1) == ":" ? \ - S : \ - Copy(S, 1, Local[0] - 1)) : \ - S : \ - "" - -#define Delete(str *S, int Index, int Count = MaxInt) \ - S = Copy(S, 1, Index - 1) + Copy(S, Index + Count) - -#define Insert(str *S, int Index, str Substr) \ - Index > Len(S) + 1 ? \ - S : \ - S = Copy(S, 1, Index - 1) + SubStr + Copy(S, Index) - -#define YesNo(str S) \ - (S = LowerCase(S)) == "yes" || S == "true" || S == "1" - -#define IsDirSet(str SetupDirective) \ - YesNo(SetupSetting(SetupDirective)) - -#define Power(int X, int P = 2) \ - !P ? 1 : X * Power(X, P - 1) - -#define Min(int A, int B, int C = MaxInt) \ - A < B ? A < C ? Int(A) : Int(C) : Int(B) - -#define Max(int A, int B, int C = MinInt) \ - A > B ? A > C ? Int(A) : Int(C) : Int(B) - -#define SameText(str S1, str S2) \ - LowerCase(S1) == LowerCase(S2) - -#define SameStr(str S1, str S2) \ - S1 == S2 - -#define WarnRenamedVersion(str OldName, str NewName) \ - Warning("Function """ + OldName + """ has been renamed. Use """ + NewName + """ instead.") - -#define ParseVersion(str FileName, *Major, *Minor, *Rev, *Build) \ - WarnRenamedVersion("ParseVersion", "GetVersionComponents"), \ - GetVersionComponents(FileName, Major, Minor, Rev, Build) - -#define GetFileVersion(str FileName) \ - WarnRenamedVersion("GetFileVersion", "GetVersionNumbersString"), \ - GetVersionNumbersString(FileName) - -#ifdef DisablePOptP -# pragma parseroption -p- -#endif - -#ifdef EnableOptE -# pragma option -e+ -#endif -#endif \ No newline at end of file diff --git a/native/windows/inno-setup/ISetup.chm b/native/windows/inno-setup/ISetup.chm deleted file mode 100644 index 4021475e5..000000000 Binary files a/native/windows/inno-setup/ISetup.chm and /dev/null differ diff --git a/native/windows/inno-setup/LICENSE b/native/windows/inno-setup/LICENSE deleted file mode 100644 index c74bb0bdf..000000000 --- a/native/windows/inno-setup/LICENSE +++ /dev/null @@ -1,32 +0,0 @@ -Inno Setup License -================== - -Except where otherwise noted, all of the documentation and software included in the Inno Setup -package is copyrighted by Jordan Russell. - -Copyright (C) 1997-2022 Jordan Russell. All rights reserved. -Portions Copyright (C) 2000-2022 Martijn Laan. All rights reserved. - -This software is provided "as-is," without any express or implied warranty. In no event shall the -author be held liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, including commercial -applications, and to alter and redistribute it, provided that the following conditions are met: - -1. All redistributions of source code files must retain all copyright notices that are currently in - place, and this list of conditions without modification. - -2. All redistributions in binary form must retain all occurrences of the above copyright notice and - web site addresses that are currently in place (for example, in the About boxes). - -3. The origin of this software must not be misrepresented; you must not claim that you wrote the - original software. If you use this software to distribute a product, an acknowledgment in the - product documentation would be appreciated but is not required. - -4. Modified versions in source or binary form must be plainly marked as such, and must not be - misrepresented as being the original software. - - -Jordan Russell -jr-2020 AT jrsoftware.org -https://jrsoftware.org/ \ No newline at end of file diff --git a/native/windows/inno-setup/Setup.e32 b/native/windows/inno-setup/Setup.e32 deleted file mode 100644 index f4c7220a0..000000000 Binary files a/native/windows/inno-setup/Setup.e32 and /dev/null differ diff --git a/native/windows/inno-setup/SetupClassicIcon.ico b/native/windows/inno-setup/SetupClassicIcon.ico deleted file mode 100644 index b274e4c68..000000000 Binary files a/native/windows/inno-setup/SetupClassicIcon.ico and /dev/null differ diff --git a/native/windows/inno-setup/SetupLdr.e32 b/native/windows/inno-setup/SetupLdr.e32 deleted file mode 100644 index 50a45bdae..000000000 Binary files a/native/windows/inno-setup/SetupLdr.e32 and /dev/null differ diff --git a/native/windows/inno-setup/WizClassicImage-IS.bmp b/native/windows/inno-setup/WizClassicImage-IS.bmp deleted file mode 100644 index cf844e093..000000000 Binary files a/native/windows/inno-setup/WizClassicImage-IS.bmp and /dev/null differ diff --git a/native/windows/inno-setup/WizClassicImage.bmp b/native/windows/inno-setup/WizClassicImage.bmp deleted file mode 100644 index cb05a0632..000000000 Binary files a/native/windows/inno-setup/WizClassicImage.bmp and /dev/null differ diff --git a/native/windows/inno-setup/WizClassicSmallImage-IS.bmp b/native/windows/inno-setup/WizClassicSmallImage-IS.bmp deleted file mode 100644 index 1e8e49792..000000000 Binary files a/native/windows/inno-setup/WizClassicSmallImage-IS.bmp and /dev/null differ diff --git a/native/windows/inno-setup/WizClassicSmallImage.bmp b/native/windows/inno-setup/WizClassicSmallImage.bmp deleted file mode 100644 index 63f421040..000000000 Binary files a/native/windows/inno-setup/WizClassicSmallImage.bmp and /dev/null differ diff --git a/native/windows/inno-setup/isbunzip.dll b/native/windows/inno-setup/isbunzip.dll deleted file mode 100644 index 814e86801..000000000 Binary files a/native/windows/inno-setup/isbunzip.dll and /dev/null differ diff --git a/native/windows/inno-setup/isbzip.dll b/native/windows/inno-setup/isbzip.dll deleted file mode 100644 index 1afeefd54..000000000 Binary files a/native/windows/inno-setup/isbzip.dll and /dev/null differ diff --git a/native/windows/inno-setup/islzma.dll b/native/windows/inno-setup/islzma.dll deleted file mode 100644 index 81fd05ac6..000000000 Binary files a/native/windows/inno-setup/islzma.dll and /dev/null differ diff --git a/native/windows/inno-setup/islzma32.exe b/native/windows/inno-setup/islzma32.exe deleted file mode 100644 index 7562645e2..000000000 Binary files a/native/windows/inno-setup/islzma32.exe and /dev/null differ diff --git a/native/windows/inno-setup/islzma64.exe b/native/windows/inno-setup/islzma64.exe deleted file mode 100644 index fd58a59e0..000000000 Binary files a/native/windows/inno-setup/islzma64.exe and /dev/null differ diff --git a/native/windows/inno-setup/isscint.dll b/native/windows/inno-setup/isscint.dll deleted file mode 100644 index 5f8ef49b7..000000000 Binary files a/native/windows/inno-setup/isscint.dll and /dev/null differ diff --git a/native/windows/inno-setup/isunzlib.dll b/native/windows/inno-setup/isunzlib.dll deleted file mode 100644 index 8c4ed5101..000000000 Binary files a/native/windows/inno-setup/isunzlib.dll and /dev/null differ diff --git a/native/windows/inno-setup/iszlib.dll b/native/windows/inno-setup/iszlib.dll deleted file mode 100644 index b326e3a7d..000000000 Binary files a/native/windows/inno-setup/iszlib.dll and /dev/null differ diff --git a/native/windows/legup_inno_setup.iss b/native/windows/legup_inno_setup.iss deleted file mode 100644 index f85c7abdd..000000000 --- a/native/windows/legup_inno_setup.iss +++ /dev/null @@ -1,55 +0,0 @@ -; =========================================================================== -; | This implementation uses a standalone Legup.exe generated by launch4j. -; | Change MyJava below to match the path to the latest JRE version that -; | you have installed on your system. -; =========================================================================== - - -#define MyAppName "Legup" -#define MyAppVersion "3.0" -#define MyAppPublisher "Bram Hub" -#define MyAppURL "https://github.com/Bram-Hub/Legup/" -#define MyAppExeName "Legup.exe" -#define MyAppRoot "..\.." - -; ************* CHANGE ME!!!! ************* -#define MyJava "C:\Program Files\Java\jre1.8.0_333\" - -[Setup] -; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. -AppId={{A401504E-CBDA-4839-A782-980FC0C036D3} -AppName={#MyAppName} -AppVersion={#MyAppVersion} -;AppVerName={#MyAppName} {#MyAppVersion} -AppPublisher={#MyAppPublisher} -AppPublisherURL={#MyAppURL} -AppSupportURL={#MyAppURL} -AppUpdatesURL={#MyAppURL} -DefaultDirName={autopf}\{#MyAppName} -DisableProgramGroupPage=yes -; Uncomment the following line to run in non administrative install mode (install for current user only.) -PrivilegesRequired=lowest -OutputDir=bin -OutputBaseFilename=legup_installer -Compression=lzma -SolidCompression=yes -WizardStyle=modern - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked - -[Files] -Source: "{#MyAppRoot}\native\windows\bin\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion -;Source: "{#MyAppRoot}\build\libs\Legup.jar"; DestDir: "{app}"; Flags: ignoreversion -Source: "{#MyJava}*"; DestDir: "{app}\jre"; Flags: ignoreversion recursesubdirs createallsubdirs - -[Icons] -Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" -Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon - -[Run] -Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent - diff --git a/native/windows/legup_launch4j.xml b/native/windows/legup_launch4j.xml deleted file mode 100644 index 19d6215be..000000000 --- a/native/windows/legup_launch4j.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - true - gui - Legup.jar - C:\Users\Trevor\IdeaProjects\Legup\native\windows\bin\Legup.exe - - - . - normal - http://java.com/download - - false - false - - - - jre - true - false - 1.8.0_121 - - preferJre - 64/32 - - \ No newline at end of file diff --git a/native/windows/make_windows_installer.bat b/native/windows/make_windows_installer.bat deleted file mode 100644 index 6c0e55115..000000000 --- a/native/windows/make_windows_installer.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -inno-setup\ISCC.exe legup_inno_setup.iss \ No newline at end of file diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard new file mode 100644 index 000000000..a41ad749c --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/TestBoard @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion b/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion new file mode 100644 index 000000000..49dae4aa6 --- /dev/null +++ b/output_path/test/src/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/native/linux/.keep b/output_path/test/src/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/a similarity index 100% rename from native/linux/.keep rename to output_path/test/src/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/a diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 new file mode 100644 index 000000000..42ccf371b --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 new file mode 100644 index 000000000..d73caa5d2 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 2 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 new file mode 100644 index 000000000..99ec9769b --- /dev/null +++ b/puzzles files/binary/10x10 Binary Hard/10x10 Binary Hard 3 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 new file mode 100644 index 000000000..d203617c8 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 new file mode 100644 index 000000000..db56f04f3 --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 2 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 new file mode 100644 index 000000000..11940a6eb --- /dev/null +++ b/puzzles files/binary/10x10 Binary Medium/10x10 Binary Medium 3 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 b/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 new file mode 100644 index 000000000..828a450cf --- /dev/null +++ b/puzzles files/binary/10x10 Binary Very Hard/10x10 Binary Very Hard 1 @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 new file mode 100644 index 000000000..7b22ffc10 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 1 @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 new file mode 100644 index 000000000..ea8ef93b0 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 2 @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 new file mode 100644 index 000000000..0f0ff745e --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 3 @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 new file mode 100644 index 000000000..da76d067b --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 4 @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 new file mode 100644 index 000000000..a1ea13988 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Easy/6x6 Binary Easy 5 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 new file mode 100644 index 000000000..5f7f72a8a --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 new file mode 100644 index 000000000..a4ed30c31 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 new file mode 100644 index 000000000..fc0e413c1 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Hard/6x6 Binary Hard 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 new file mode 100644 index 000000000..a5ab8a2dc --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 new file mode 100644 index 000000000..4be5fdaad --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 new file mode 100644 index 000000000..eba370cab --- /dev/null +++ b/puzzles files/binary/6x6 Binary Medium/6x6 Binary Medium 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 new file mode 100644 index 000000000..faa68fa5e --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 1 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 new file mode 100644 index 000000000..3c707bdaa --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 2 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 new file mode 100644 index 000000000..217a032d8 --- /dev/null +++ b/puzzles files/binary/6x6 Binary Very Hard/6x6 Binary Very Hard 3 @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/6x6 easy/089764562 b/puzzles files/binary/6x6 easy/089764562 new file mode 100644 index 000000000..7b22ffc10 --- /dev/null +++ b/puzzles files/binary/6x6 easy/089764562 @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 easy/128903434 b/puzzles files/binary/6x6 easy/128903434 new file mode 100644 index 000000000..ea8ef93b0 --- /dev/null +++ b/puzzles files/binary/6x6 easy/128903434 @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 easy/876868768 b/puzzles files/binary/6x6 easy/876868768 new file mode 100644 index 000000000..0f0ff745e --- /dev/null +++ b/puzzles files/binary/6x6 easy/876868768 @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/6x6 easy/927364891 b/puzzles files/binary/6x6 easy/927364891 new file mode 100644 index 000000000..da76d067b --- /dev/null +++ b/puzzles files/binary/6x6 easy/927364891 @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 new file mode 100644 index 000000000..befd674f9 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 new file mode 100644 index 000000000..724426c26 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 new file mode 100644 index 000000000..92a96c72b --- /dev/null +++ b/puzzles files/binary/8x8 Binary Easy/8x8 Binary Easy 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 new file mode 100644 index 000000000..34eaf8388 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 new file mode 100644 index 000000000..9ef23277e --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 new file mode 100644 index 000000000..287ff6f68 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Hard/8x8 Binary Hard 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 new file mode 100644 index 000000000..47dae23dc --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 new file mode 100644 index 000000000..ae4cb8bb0 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 new file mode 100644 index 000000000..2f951ecc4 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Medium/8x8 Binary Medium 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 new file mode 100644 index 000000000..9c875523b --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 1 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 new file mode 100644 index 000000000..14f2e4ad2 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 2 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 new file mode 100644 index 000000000..ad319a4b7 --- /dev/null +++ b/puzzles files/binary/8x8 Binary Very Hard/8x8 Binary Very Hard 3 @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/light-color-theme.txt b/puzzles files/light-color-theme.txt new file mode 100644 index 000000000..5c45bc71b --- /dev/null +++ b/puzzles files/light-color-theme.txt @@ -0,0 +1,99 @@ +correct: BLUE +incorrect: RED +error: RED_700 +info: GRAY_900 +ui-movement: GRAY_300 +password-field-background: LIGHT_BLUE_400 +password-field-unfocused-background: GRAY_200 +progress-bar-background: GRAY_200 +progress-bar-foreground: LIGHT_BLUE_400 +text-field-background: LIGHT_BLUE_400 +text-field-unfocused-background: GRAY_200 +light-line-border: GRAY_200 +thick-line-border: GRAY_200 +data-selection-background: GRAY +element-view: BLACK +button-highlight: GRAY_300 +button-background: GRAY_200 +button-foreground: BLACK +checkbox-background: WHITE +checkbox-foreground: BLACK +combobox-background: WHITE +combobox-foreground: BLACK +combobox-button-background: GRAY_300 +combobox-selection-background: WHITE +combobox-selection-foreground: BLACK +combobox-selected-in-drop-down-background: GRAY_200 +label-background: WHITE +label-foreground: BLACK +menu-background: LIGHT_BLUE_100 +menu-foreground: BLACK +menu-selection-background: GRAY_200 +menu-selection-foreground: BLACK +menu-disabled-foreground: #000 +menu-bar-background: WHITE +menu-bar-foreground: BLACK +menu-item-disabled-foreground: #000 +menu-item-selection-background: GRAY_200 +menu-item-selection-foreground: BLACK +menu-item-background: WHITE +menu-item-foreground: BLACK +option-pane-background: WHITE +panel-background-color: WHITE +popup-menu-background: WHITE +popup-menu-foreground: BLACK +radio-button-background: WHITE +radio-button-foreground: BLACK +spinner-background: WHITE +spinner-foreground: BLACK +spinner-arrow-button-background: GRAY_200 +scroll-bar-track: GRAY_200 +scroll-bar-thumb: GRAY_300 +scroll-bar-thumb-dark-shadow: GRAY_300 +scroll-bar-thumb-highlight: GRAY_300 +scroll-bar-thumb-shadow: GRAY_300 +scroll-bar-arrow-button-background: GRAY_300 +scroll-pane-background: WHITE +slider-background: WHITE +slider-foreground: GRAY_700 +slider-track-color: BLACK +split-pane-background: WHITE +tabbed-pane-background: WHITE +tabbed-pane-foreground: BLACK +tabbed-pane-highlight: GRAY_200 +tabbed-pane-border-highlight: GRAY_300 +table-selection-background: GRAY_100 +table-selection-foreground: BLACK +table-background: WHITE +table-grid-color: GRAY_200 +table-header-background: GRAY_200 +text-area-background: GRAY_200 +text-area-foreground: BLACK +toggle-button-background: WHITE +toggle-button-foreground: BLACK +tool-bar-background: WHITE +tool-bar-foreground: BLACK +tool-bar-docking-background: LIGHT_GREEN_A100 +tool-bar-floating-background: GRAY_200 +tree-selection-foreground: BLACK +tree-foreground: BLACK +tree-selection-background: GRAY_200 +tree-background: WHITE +radio-button-menu-item-foreground: BLACK +radio-button-menu-item-selection-foreground: BLACK +radio-button-menu-item-selection-background: GRAY_200 +checkbox-menu-item-selection-background: GRAY_200 +checkbox-menu-item-foreground: BLACK +checkbox-menu-item-selection-foreground: BLACK +text-pane-background: GRAY_50 +text-pane-selection-background: LIGHT_BLUE_200 +text-pane-inactive-foreground: GRAY_500 +editor-pane-background: GRAY_50 +editor-pane-selection-background: LIGHT_BLUE_200 +editor-pane-inactive-foreground: GRAY_500 +separator-background: GRAY_300 +separator-foreground: GRAY_300 +tool-tip-background: GRAY_500 +tool-tip-foreground: GRAY_50 +color-chooser-background: WHITE +color-chooser-foreground: BLACK diff --git a/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 b/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 new file mode 100644 index 000000000..2aa0b46ab --- /dev/null +++ b/puzzles files/minesweeper/5x5 Minesweeper Easy/123456 @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/puzzles files/thermometer/therm_test.xml b/puzzles files/thermometer/therm_test.xml new file mode 100644 index 000000000..66e841dc5 --- /dev/null +++ b/puzzles files/thermometer/therm_test.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/puzzles files/treetent/8x8 TreeTent Easy/1646651 b/puzzles files/treetent/8x8 TreeTent Easy/1646651 index 36dbc7f1e..db70ca164 100644 --- a/puzzles files/treetent/8x8 TreeTent Easy/1646651 +++ b/puzzles files/treetent/8x8 TreeTent Easy/1646651 @@ -1,5 +1,6 @@ - + + @@ -38,5 +39,5 @@ - + diff --git a/src/main/java/edu/rpi/legup/Legup.java b/src/main/java/edu/rpi/legup/Legup.java index 49887de4f..79471286b 100644 --- a/src/main/java/edu/rpi/legup/Legup.java +++ b/src/main/java/edu/rpi/legup/Legup.java @@ -15,4 +15,4 @@ public static void main(String[] args) { GameBoardFacade.getInstance(); GameBoardFacade.setupConfig(); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ai/Solver.java b/src/main/java/edu/rpi/legup/ai/Solver.java index 68b934bfb..5b39c2008 100644 --- a/src/main/java/edu/rpi/legup/ai/Solver.java +++ b/src/main/java/edu/rpi/legup/ai/Solver.java @@ -1,4 +1,3 @@ package edu.rpi.legup.ai; -public class Solver { -} +public class Solver {} diff --git a/src/main/java/edu/rpi/legup/app/Config.java b/src/main/java/edu/rpi/legup/app/Config.java index 1847e14e4..1016838c7 100644 --- a/src/main/java/edu/rpi/legup/app/Config.java +++ b/src/main/java/edu/rpi/legup/app/Config.java @@ -2,21 +2,23 @@ import java.io.*; import java.util.*; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; - import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +/** + * The {@code Config} class manages the configuration for puzzles by loading configuration data + * from an XML file. It provides methods to access puzzle class names, display names, and their + * file creation statuses + */ public class Config { - private final static Logger Logger = LogManager.getLogger(Config.class.getName()); + private static final Logger Logger = LogManager.getLogger(Config.class.getName()); private Map puzzles; private Map fileCreationDisabledStatuses; @@ -43,8 +45,8 @@ public List getPuzzleClassNames() { } /** - * Returns a list of the names of the puzzles which can have puzzles created and edited - * within the proof editor. + * Returns a list of the names of the puzzles which can have puzzles created and edited within + * the proof editor. * * @return the aforementioned list of Strings */ @@ -59,8 +61,8 @@ public List getFileCreationEnabledPuzzles() { } /** - * Converts the class name of the puzzles to their display names. Some examples of the conversion: - * convertClassNameToDisplayName("TreeTent") will return "Tree Tent" + * Converts the class name of the puzzles to their display names. Some examples of the + * conversion: convertClassNameToDisplayName("TreeTent") will return "Tree Tent" * convertClassNameToDisplayName("Nurikabe") will return "Nurikabe" * * @param className the name of the class @@ -77,6 +79,13 @@ public static String convertClassNameToDisplayName(String className) { return displayName; } + /** + * Converts the display name of the puzzle back to its corresponding class name. + * For example: convertDisplayNameToClassName("Tree Tent") returns "TreeTent" + * + * @param displayName the display name of the puzzle + * @return the class name of the puzzle as a String + */ public static String convertDisplayNameToClassName(String displayName) { String className = ""; for (int i = 0; i < displayName.length(); i++) { @@ -87,6 +96,11 @@ public static String convertDisplayNameToClassName(String displayName) { return className; } + /** + * Gets a list of all available puzzle display names + * + * @return a List of puzzle display names as Strings + */ public List getPuzzleNames() { List names = new LinkedList(); for (String puzzle : this.getPuzzleClassNames()) { @@ -95,6 +109,12 @@ public List getPuzzleNames() { return names; } + /** + * Returns a list of the display names of the puzzles that can have files created and edited within + * the proof editor + * + * @return a List of puzzle display names as Strings with file creation enabled + */ public List getFileCreationEnabledPuzzleNames() { List names = new LinkedList(); for (String puzzle : this.getFileCreationEnabledPuzzles()) { @@ -140,15 +160,16 @@ private void loadConfig(InputStream stream) throws InvalidConfigException { Element puzzle = (Element) puzzleNodes.item(i); String name = puzzle.getAttribute("name"); String className = puzzle.getAttribute("qualifiedClassName"); - boolean status = Boolean.parseBoolean(puzzle.getAttribute("fileCreationDisabled").toLowerCase()); + boolean status = + Boolean.parseBoolean( + puzzle.getAttribute("fileCreationDisabled").toLowerCase()); Logger.debug("Class Name: " + className); this.puzzles.put(name, className); this.fileCreationDisabledStatuses.put(name, Boolean.valueOf(status)); } - } - catch (ParserConfigurationException | SAXException | IOException e) { + } catch (ParserConfigurationException | SAXException | IOException e) { throw new InvalidConfigException(e.getMessage()); } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java index 55273ab4f..835041c3c 100644 --- a/src/main/java/edu/rpi/legup/app/GameBoardFacade.java +++ b/src/main/java/edu/rpi/legup/app/GameBoardFacade.java @@ -11,16 +11,6 @@ import edu.rpi.legup.ui.LegupUI; import edu.rpi.legup.ui.ProofEditorPanel; import edu.rpi.legup.ui.PuzzleEditorPanel; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.xml.sax.SAXException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; import java.awt.*; import java.io.File; import java.io.FileInputStream; @@ -31,11 +21,24 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; +/** + * {@code GameBoardFacade} is a class designed to manage the game board operations within the application. + * It integrates various components such as UI elements, puzzle management, and history tracking + */ public class GameBoardFacade implements IHistorySubject { - private final static Logger LOGGER = LogManager.getLogger(GameBoardFacade.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(GameBoardFacade.class.getName()); - protected volatile static GameBoardFacade instance; + protected static volatile GameBoardFacade instance; private Config config; @@ -52,9 +55,7 @@ public class GameBoardFacade implements IHistorySubject { private History history; private List historyListeners; - /** - * Private GameBoardFacade Constructor creates a game board facade - */ + /** Private GameBoardFacade Constructor creates a game board facade */ protected GameBoardFacade() { history = new History(); historyListeners = new ArrayList<>(); @@ -68,52 +69,75 @@ protected GameBoardFacade() { * * @return single instance of GameBoardFacade */ - public synchronized static GameBoardFacade getInstance() { + public static synchronized GameBoardFacade getInstance() { if (instance == null) { instance = new GameBoardFacade(); } return instance; } + /** + * Initializes the UI components + */ public void initializeUI() { - EventQueue.invokeLater(() -> { - legupUI = new LegupUI(); - puzzleSolver = legupUI.getProofEditor(); - puzzleEditor = legupUI.getPuzzleEditor(); - addHistoryListener(legupUI.getProofEditor()); - addHistoryListener(legupUI.getPuzzleEditor()); - }); + EventQueue.invokeLater( + () -> { + legupUI = new LegupUI(); + puzzleSolver = legupUI.getProofEditor(); + puzzleEditor = legupUI.getPuzzleEditor(); + addHistoryListener(legupUI.getProofEditor()); + addHistoryListener(legupUI.getPuzzleEditor()); + }); } + /** + * Sets the current puzzle in the game board + * + * @param puzzle the Puzzle to set + */ public void setPuzzle(Puzzle puzzle) { this.puzzle = puzzle; this.puzzleSolver.setPuzzleView(puzzle); this.history.clear(); } + /** + * Clears the current puzzle + */ public void clearPuzzle() { this.puzzle = null; this.curFileName = null; this.history.clear(); } + /** + * Sets up the configuration by initializing the Config object + */ public static void setupConfig() { Config config = null; try { config = new Config(); - } - catch (InvalidConfigException e) { + } catch (InvalidConfigException e) { System.exit(1); } GameBoardFacade.getInstance().setConfig(config); } - + /** + * Sets the current puzzle editor with the given puzzle + * + * @param puzzle the Puzzle to set in the editor + */ public void setPuzzleEditor(Puzzle puzzle) { this.puzzle = puzzle; this.puzzleEditor.setPuzzleView(puzzle); } + /** + * Sets the configuration object for the GameBoardFacade + * + * @param config config the Config object to set + */ public void setConfig(Config config) { this.config = config; } @@ -121,11 +145,11 @@ public void setConfig(Config config) { /** * Validates the given dimensions for the given puzzle * - * @param game name of the puzzle - * @param rows the number of rows on the board + * @param game name of the puzzle + * @param rows the number of rows on the board * @param columns the number of columns on the board * @return true if it is possible to create a board for the given game with the given number of - * rows and columns, false otherwise + * rows and columns, false otherwise * @throws RuntimeException if any of the given input is invalid */ public boolean validateDimensions(String game, int rows, int columns) throws RuntimeException { @@ -135,9 +159,11 @@ public boolean validateDimensions(String game, int rows, int columns) throws Run Constructor constructor = c.getConstructor(); Puzzle puzzle = (Puzzle) constructor.newInstance(); return puzzle.isValidDimensions(rows, columns); - } - catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | - InstantiationException e) { + } catch (ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException + | InstantiationException e) { LOGGER.error(e); throw new RuntimeException("Error validating puzzle dimensions"); } @@ -146,10 +172,10 @@ public boolean validateDimensions(String game, int rows, int columns) throws Run /** * Validates the given text input for the given puzzle * - * @param game the name of the puzzle - * @param statements an array of statements - * @return true if it is possible to create a board for the given game with the given statements, - * false otherwise + * @param game the name of the puzzle + * @param statements an array of statements + * @return true if it is possible to create a board for the given game with the given + * statements, false otherwise * @throws RuntimeException if any of the input is invalid */ public boolean validateTextInput(String game, String[] statements) throws RuntimeException { @@ -159,59 +185,73 @@ public boolean validateTextInput(String game, String[] statements) throws Runtim Constructor constructor = c.getConstructor(); Puzzle puzzle = (Puzzle) constructor.newInstance(); return puzzle.isValidTextInput(statements); - } - catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | - InstantiationException e) { + } catch (ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException + | InstantiationException e) { LOGGER.error(e); throw new RuntimeException("Error validating puzzle text input"); } } /** - * Loads an empty puzzle + * Loads an empty puzzle with the specified dimensions * - * @param game name of the puzzle - * @param rows the number of rows on the board + * @param game name of the puzzle + * @param rows the number of rows on the board * @param columns the number of columns on the board */ public void loadPuzzle(String game, int rows, int columns) throws RuntimeException { - String qualifiedClassName = config.getPuzzleClassForName(game); - LOGGER.debug("Loading " + qualifiedClassName); + if (!game.equals("")) { + String qualifiedClassName = config.getPuzzleClassForName(game); + LOGGER.debug("Loading " + qualifiedClassName); - try { - Class c = Class.forName(qualifiedClassName); - Constructor cons = c.getConstructor(); - Puzzle puzzle = (Puzzle) cons.newInstance(); + try { + Class c = Class.forName(qualifiedClassName); + Constructor cons = c.getConstructor(); + Puzzle puzzle = (Puzzle) cons.newInstance(); - PuzzleImporter importer = puzzle.getImporter(); - if (importer == null) { - LOGGER.error("Puzzle importer is null"); - throw new RuntimeException("Puzzle importer null"); - } + PuzzleImporter importer = puzzle.getImporter(); + if (importer == null) { + LOGGER.error("Puzzle importer is null"); + throw new RuntimeException("Puzzle importer null"); + } - // Theoretically, this exception should never be thrown, since LEGUP should not be - // allowing the user to give row/column input for a puzzle that doesn't support it - if (!importer.acceptsRowsAndColumnsInput()) { - throw new IllegalArgumentException(puzzle.getName() + " does not accept rows and columns input"); - } + // Theoretically, this exception should never be thrown, since LEGUP should not be + // allowing the user to give row/column input for a puzzle that doesn't support it + if (!importer.acceptsRowsAndColumnsInput()) { + throw new IllegalArgumentException( + puzzle.getName() + " does not accept rows and columns input"); + } - setWindowTitle(puzzle.getName(), "New " + puzzle.getName() + " Puzzle"); - importer.initializePuzzle(rows, columns); + setWindowTitle(puzzle.getName(), "New " + puzzle.getName() + " Puzzle"); + importer.initializePuzzle(rows, columns); - puzzle.initializeView(); -// puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode()); - setPuzzleEditor(puzzle); - } - catch (IllegalArgumentException exception) { - throw new IllegalArgumentException(exception.getMessage()); - } - catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | - IllegalAccessException | InstantiationException e) { - LOGGER.error(e); - throw new RuntimeException("Puzzle creation error"); + puzzle.initializeView(); + // + // puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode()); + setPuzzleEditor(puzzle); + } catch (IllegalArgumentException exception) { + throw new IllegalArgumentException(exception.getMessage()); + } catch (ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException + | InstantiationException e) { + LOGGER.error(e); + throw new RuntimeException("Puzzle creation error"); + } } + } + /** + * Loads an empty puzzle with the specified input + * + * @param game name of the puzzle + * @param statements an array of statements to load the puzzle with + */ public void loadPuzzle(String game, String[] statements) { String qualifiedClassName = config.getPuzzleClassForName(game); LOGGER.debug("Loading " + qualifiedClassName); @@ -230,65 +270,76 @@ public void loadPuzzle(String game, String[] statements) { // Theoretically, this exception should never be thrown, since LEGUP should not be // allowing the user to give text input for a puzzle that doesn't support it if (!importer.acceptsTextInput()) { - throw new IllegalArgumentException(puzzle.getName() + " does not accept text input"); + throw new IllegalArgumentException( + puzzle.getName() + " does not accept text input"); } setWindowTitle(puzzle.getName(), "New " + puzzle.getName() + " Puzzle"); importer.initializePuzzle(statements); puzzle.initializeView(); -// puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode()); + // + // puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode()); setPuzzleEditor(puzzle); - } - catch (IllegalArgumentException exception) { + } catch (IllegalArgumentException exception) { throw new IllegalArgumentException(exception.getMessage()); - } - catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | - IllegalAccessException | InstantiationException e) { + } catch (ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException + | InstantiationException e) { LOGGER.error(e); throw new RuntimeException("Puzzle creation error"); } - } /** - * Loads a puzzle file + * Loads a puzzle file from the specified file * * @param fileName file name of the board file - * @throws InvalidFileFormatException if input is invalid + * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be created */ public void loadPuzzle(String fileName) throws InvalidFileFormatException { try { loadPuzzle(new FileInputStream(fileName)); curFileName = fileName; setWindowTitle(puzzle.getName(), fileName); - } - catch (IOException e) { + } catch (IOException e) { LOGGER.error("Invalid file " + fileName, e); throw new InvalidFileFormatException("Could not find file"); } } + /** + * Loads a puzzle into the editor from the specified file name + * + * @param fileName the name of the file to load + * @throws InvalidFileFormatException if the file format is invalid or if the file cannot be created + */ public void loadPuzzleEditor(String fileName) throws InvalidFileFormatException { try { loadPuzzleEditor(new FileInputStream(fileName)); curFileName = fileName; setWindowTitle(puzzle.getName(), fileName); - } - catch (IOException e) { + } catch (IOException e) { LOGGER.error("Invalid file " + fileName, e); throw new InvalidFileFormatException("Could not find file"); } } + /** + * Loads a puzzle into the editor from the specified input stream + * + * @param inputStream the input stream to load the puzzle from + * @throws InvalidFileFormatException if the input stream cannot be processed or the file format is invalid + */ public void loadPuzzleEditor(InputStream inputStream) throws InvalidFileFormatException { Document document; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse(inputStream); - } - catch (IOException | SAXException | ParserConfigurationException e) { + } catch (IOException | SAXException | ParserConfigurationException e) { LOGGER.error("Invalid file", e); throw new InvalidFileFormatException("Could not find file"); } @@ -297,12 +348,16 @@ public void loadPuzzleEditor(InputStream inputStream) throws InvalidFileFormatEx if (rootNode.getTagName().equals("Legup")) { try { Node node = rootNode.getElementsByTagName("puzzle").item(0); - String qualifiedClassName = config.getPuzzleClassForName(node.getAttributes().getNamedItem("name").getNodeValue()); + String qualifiedClassName = + config.getPuzzleClassForName( + node.getAttributes().getNamedItem("name").getNodeValue()); if (qualifiedClassName == null) { - throw new InvalidFileFormatException("Puzzle creation error: cannot find puzzle with that name"); + throw new InvalidFileFormatException( + "Puzzle creation error: cannot find puzzle with that name"); } - //Check if puzzle is a "FileCreationEnabled" puzzle (meaning it is editable). - String[] editablePuzzles = config.getFileCreationEnabledPuzzles().toArray(new String[0]); + // Check if puzzle is a "FileCreationEnabled" puzzle (meaning it is editable). + String[] editablePuzzles = + config.getFileCreationEnabledPuzzles().toArray(new String[0]); boolean isEditablePuzzle = false; for (int i = 0; i < editablePuzzles.length; i++) { if (qualifiedClassName.contains(editablePuzzles[i])) { @@ -314,7 +369,7 @@ public void loadPuzzleEditor(InputStream inputStream) throws InvalidFileFormatEx LOGGER.error("Puzzle is not editable"); throw new InvalidFileFormatException("Puzzle is not editable"); } - //If it is editable, start loading it + // If it is editable, start loading it LOGGER.debug("Loading " + qualifiedClassName); Class c = Class.forName(qualifiedClassName); @@ -330,14 +385,15 @@ public void loadPuzzleEditor(InputStream inputStream) throws InvalidFileFormatEx puzzle.initializeView(); puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode()); setPuzzleEditor(puzzle); - } - catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | - IllegalAccessException | InstantiationException e) { + } catch (ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException + | InstantiationException e) { LOGGER.error(e); throw new InvalidFileFormatException("Puzzle creation error"); } - } - else { + } else { LOGGER.error("Invalid file"); throw new InvalidFileFormatException("Invalid file: must be a Legup file"); } @@ -345,6 +401,7 @@ public void loadPuzzleEditor(InputStream inputStream) throws InvalidFileFormatEx /** * Loads a puzzle file from the input stream + * * @throws InvalidFileFormatException if input is invalid * @param inputStream input stream for the puzzle file */ @@ -354,8 +411,7 @@ public void loadPuzzle(InputStream inputStream) throws InvalidFileFormatExceptio DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse(inputStream); - } - catch (IOException | SAXException | ParserConfigurationException e) { + } catch (IOException | SAXException | ParserConfigurationException e) { LOGGER.error("Invalid file", e); throw new InvalidFileFormatException("Could not find file"); } @@ -364,9 +420,12 @@ public void loadPuzzle(InputStream inputStream) throws InvalidFileFormatExceptio if (rootNode.getTagName().equals("Legup")) { try { Node node = rootNode.getElementsByTagName("puzzle").item(0); - String qualifiedClassName = config.getPuzzleClassForName(node.getAttributes().getNamedItem("name").getNodeValue()); + String qualifiedClassName = + config.getPuzzleClassForName( + node.getAttributes().getNamedItem("name").getNodeValue()); if (qualifiedClassName == null) { - throw new InvalidFileFormatException("Puzzle creation error: cannot find puzzle with that name"); + throw new InvalidFileFormatException( + "Puzzle creation error: cannot find puzzle with that name"); } LOGGER.debug("Loading " + qualifiedClassName); @@ -383,25 +442,25 @@ public void loadPuzzle(InputStream inputStream) throws InvalidFileFormatExceptio puzzle.initializeView(); puzzle.getBoardView().onTreeElementChanged(puzzle.getTree().getRootNode()); setPuzzle(puzzle); - } - catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | - IllegalAccessException | InstantiationException e) { + } catch (ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException + | InstantiationException e) { LOGGER.error(e); throw new InvalidFileFormatException("Puzzle creation error"); } - } - else { + } else { LOGGER.error("Invalid file"); throw new InvalidFileFormatException("Invalid file: must be a Legup file"); } } /** - * Sets the window title to 'PuzzleName - FileName' - * Removes the extension + * Sets the window title to 'PuzzleName - FileName' Removes the extension * * @param puzzleName puzzle name for the file - * @param fileName file name of the edu.rpi.legup.puzzle + * @param fileName file name of the edu.rpi.legup.puzzle */ public void setWindowTitle(String puzzleName, String fileName) { File file = new File(fileName); @@ -514,4 +573,3 @@ public History getHistory() { return history; } } - diff --git a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java index a570e7d44..c66b23ec2 100644 --- a/src/main/java/edu/rpi/legup/app/InvalidConfigException.java +++ b/src/main/java/edu/rpi/legup/app/InvalidConfigException.java @@ -1,6 +1,14 @@ package edu.rpi.legup.app; +/** + * {@code InvalidConfigException} is a custom exception class for handling invalid configuration errors + */ public class InvalidConfigException extends Exception { + /** + * Constructs a new InvalidConfigException with the specified detail message + * + * @param message the detail message + */ public InvalidConfigException(String message) { super(message); } diff --git a/src/main/java/edu/rpi/legup/app/LegupPreferences.java b/src/main/java/edu/rpi/legup/app/LegupPreferences.java index 578cefc5b..03b8be8d9 100644 --- a/src/main/java/edu/rpi/legup/app/LegupPreferences.java +++ b/src/main/java/edu/rpi/legup/app/LegupPreferences.java @@ -4,13 +4,18 @@ import java.util.Map; import java.util.prefs.Preferences; +/** + * {@code LegupPreferences} is a class responsible for managing user preferences within the application. + * It uses Java's Preferences API to store and retrieve preferences, and it provides methods for accessing and updating these preferences. + */ public class LegupPreferences { private static LegupPreferences instance; private static String SAVED_PATH = ""; - private static final Preferences preferences = Preferences.userNodeForPackage(LegupPreferences.class); + private static final Preferences preferences = + Preferences.userNodeForPackage(LegupPreferences.class); private static final Map preferencesMap = new HashMap<>(); private static final Map defaultPreferencesMap = new HashMap<>(); @@ -26,7 +31,6 @@ public class LegupPreferences { public static final String IMMEDIATE_FEEDBACK = "immediate-feedback"; public static final String COLOR_BLIND = "color-blind"; - static { defaultPreferencesMap.put(WORK_DIRECTORY, System.getProperty("user.home")); defaultPreferencesMap.put(START_FULL_SCREEN, Boolean.toString(false)); @@ -41,22 +45,42 @@ public class LegupPreferences { } static { - preferencesMap.put(WORK_DIRECTORY, preferences.get(WORK_DIRECTORY, defaultPreferencesMap.get(WORK_DIRECTORY))); - preferencesMap.put(START_FULL_SCREEN, preferences.get(START_FULL_SCREEN, defaultPreferencesMap.get(START_FULL_SCREEN))); - preferencesMap.put(AUTO_UPDATE, preferences.get(AUTO_UPDATE, defaultPreferencesMap.get(AUTO_UPDATE))); - preferencesMap.put(DARK_MODE, preferences.get(DARK_MODE, defaultPreferencesMap.get(DARK_MODE))); - preferencesMap.put(SHOW_MISTAKES, preferences.get(SHOW_MISTAKES, defaultPreferencesMap.get(SHOW_MISTAKES))); - preferencesMap.put(SHOW_ANNOTATIONS, preferences.get(SHOW_ANNOTATIONS, defaultPreferencesMap.get(SHOW_ANNOTATIONS))); - preferencesMap.put(ALLOW_DEFAULT_RULES, preferences.get(ALLOW_DEFAULT_RULES, defaultPreferencesMap.get(ALLOW_DEFAULT_RULES))); - preferencesMap.put(AUTO_GENERATE_CASES, preferences.get(AUTO_GENERATE_CASES, defaultPreferencesMap.get(AUTO_GENERATE_CASES))); - preferencesMap.put(IMMEDIATE_FEEDBACK, preferences.get(IMMEDIATE_FEEDBACK, defaultPreferencesMap.get(IMMEDIATE_FEEDBACK))); - preferencesMap.put(COLOR_BLIND, preferences.get(COLOR_BLIND, defaultPreferencesMap.get(COLOR_BLIND))); + preferencesMap.put( + WORK_DIRECTORY, + preferences.get(WORK_DIRECTORY, defaultPreferencesMap.get(WORK_DIRECTORY))); + preferencesMap.put( + START_FULL_SCREEN, + preferences.get(START_FULL_SCREEN, defaultPreferencesMap.get(START_FULL_SCREEN))); + preferencesMap.put( + AUTO_UPDATE, preferences.get(AUTO_UPDATE, defaultPreferencesMap.get(AUTO_UPDATE))); + preferencesMap.put( + DARK_MODE, preferences.get(DARK_MODE, defaultPreferencesMap.get(DARK_MODE))); + preferencesMap.put( + SHOW_MISTAKES, + preferences.get(SHOW_MISTAKES, defaultPreferencesMap.get(SHOW_MISTAKES))); + preferencesMap.put( + SHOW_ANNOTATIONS, + preferences.get(SHOW_ANNOTATIONS, defaultPreferencesMap.get(SHOW_ANNOTATIONS))); + preferencesMap.put( + ALLOW_DEFAULT_RULES, + preferences.get( + ALLOW_DEFAULT_RULES, defaultPreferencesMap.get(ALLOW_DEFAULT_RULES))); + preferencesMap.put( + AUTO_GENERATE_CASES, + preferences.get( + AUTO_GENERATE_CASES, defaultPreferencesMap.get(AUTO_GENERATE_CASES))); + preferencesMap.put( + IMMEDIATE_FEEDBACK, + preferences.get(IMMEDIATE_FEEDBACK, defaultPreferencesMap.get(IMMEDIATE_FEEDBACK))); + preferencesMap.put( + COLOR_BLIND, preferences.get(COLOR_BLIND, defaultPreferencesMap.get(COLOR_BLIND))); } /** - * Gets the legup preferences singleton instance. + * Gets the legup preferences singleton instance + * This method ensures that only one instance of LegupPreferences exists * - * @return legup preferences + * @return the singleton instance of LegupPreferences */ public static LegupPreferences getInstance() { if (instance == null) { @@ -66,52 +90,65 @@ public static LegupPreferences getInstance() { } /** - * Private LegupPreferences Singleton Constructor + * Private constructor to prevent instantiation from outside the class + * Use {@link #getInstance()} to access the singleton instance */ - private LegupPreferences() { - - } + private LegupPreferences() {} /** * Gets the user preference by the string key * * @param key key name of the preference - * @return value of the preference + * @return value of the preference or {@code null} if the preference does not exist */ public String getUserPref(String key) { return preferencesMap.get(key); } /** - * Gets the user preference by the string key, value pair + * Sets the user preference for the specified key to the provided value * - * @param key key name of the preference - * @param value value of the preference + * @param key key to set for the preference + * @param value value to set for the preference */ public void setUserPref(String key, String value) { preferences.put(key, value); preferencesMap.put(key, value); } + /** + * Retrieves the user preference associated with the specified key as a boolean + * + * @param key the key for the preference to retrieve + * @return the boolean value of the preference + * @throws RuntimeException if the preference value cannot be interpreted as a boolean + */ public boolean getUserPrefAsBool(String key) { if (preferencesMap.get(key).equalsIgnoreCase(Boolean.toString(true))) { return true; - } - else { + } else { if (preferencesMap.get(key).equalsIgnoreCase(Boolean.toString(false))) { return false; - } - else { + } else { throw new RuntimeException("Cannot get user preference - " + key); } } } - + /** + * Gets the saved path + * + * @return the saved path as a String + */ public String getSavedPath() { return SAVED_PATH; } + /** + * Sets the saved path to the specified value + * + * @param path the new saved path + */ public void setSavedPath(String path) { SAVED_PATH = path; } diff --git a/src/main/java/edu/rpi/legup/app/PuzzleKeyAccelerator.java b/src/main/java/edu/rpi/legup/app/PuzzleKeyAccelerator.java index 36ffb08aa..f3945be22 100644 --- a/src/main/java/edu/rpi/legup/app/PuzzleKeyAccelerator.java +++ b/src/main/java/edu/rpi/legup/app/PuzzleKeyAccelerator.java @@ -1,22 +1,21 @@ package edu.rpi.legup.app; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.history.ICommand; -import edu.rpi.legup.history.ValidateDirectRuleCommand; import edu.rpi.legup.history.ValidateContradictionRuleCommand; -import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.history.ValidateDirectRuleCommand; import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.model.rules.RuleType; import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; - -import javax.swing.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.HashMap; import java.util.Map; - -import static edu.rpi.legup.app.GameBoardFacade.getInstance; +import javax.swing.*; public class PuzzleKeyAccelerator implements KeyListener { @@ -39,21 +38,17 @@ public void clearKeyMap() { } /** - * Invoked when a key has been typed. - * See the class description for {@link KeyEvent} for a definition of - * a key typed event. + * Invoked when a key has been typed. See the class description for {@link KeyEvent} for a + * definition of a key typed event. * * @param e the event to be processed */ @Override - public void keyTyped(KeyEvent e) { - - } + public void keyTyped(KeyEvent e) {} /** - * Invoked when a key has been pressed. - * See the class description for {@link KeyEvent} for a definition of - * a key pressed event. + * Invoked when a key has been pressed. See the class description for {@link KeyEvent} for a + * definition of a key pressed event. * * @param e the event to be processed */ @@ -62,35 +57,35 @@ public void keyPressed(KeyEvent e) { KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e); Rule rule = keyStrokeMap.get(keyStroke); if (rule != null) { - TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); + TreeView treeView = + GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); String update = ""; if (rule.getRuleType() == RuleType.CASE) { - // TODO: review this line of code and figure out what it's supposed to do (remove if necessary) -// handleCaseRule((CaseRule)rule); - } - else { + // TODO: review this line of code and figure out what it's supposed to do (remove if + // necessary) + // handleCaseRule((CaseRule)rule); + } else { if (rule.getRuleType() == RuleType.CONTRADICTION) { TreeViewSelection selection = treeView.getSelection(); - ICommand validate = new ValidateContradictionRuleCommand(selection, (ContradictionRule) rule); + ICommand validate = + new ValidateContradictionRuleCommand( + selection, (ContradictionRule) rule); if (validate.canExecute()) { getInstance().getHistory().pushChange(validate); validate.execute(); - } - else { + } else { update = validate.getError(); } - } - else { + } else { TreeViewSelection selection = treeView.getSelection(); ICommand validate = new ValidateDirectRuleCommand(selection, (DirectRule) rule); if (validate.canExecute()) { getInstance().getHistory().pushChange(validate); validate.execute(); - } - else { + } else { update = validate.getError(); } } @@ -100,14 +95,11 @@ public void keyPressed(KeyEvent e) { } /** - * Invoked when a key has been released. - * See the class description for {@link KeyEvent} for a definition of - * a key released event. + * Invoked when a key has been released. See the class description for {@link KeyEvent} for a + * definition of a key released event. * * @param e the event to be processed */ @Override - public void keyReleased(KeyEvent e) { - - } + public void keyReleased(KeyEvent e) {} } diff --git a/src/main/java/edu/rpi/legup/controller/BoardController.java b/src/main/java/edu/rpi/legup/controller/BoardController.java index f9c328a99..eaae3851d 100644 --- a/src/main/java/edu/rpi/legup/controller/BoardController.java +++ b/src/main/java/edu/rpi/legup/controller/BoardController.java @@ -3,16 +3,13 @@ import java.awt.*; import java.awt.event.*; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - public class BoardController extends Controller { protected Point lastLeftMousePoint; protected Point lastRightMousePoint; /** - * BoardController Constructor creates a controller object to listen - * to ui events from a ScrollView + * BoardController Constructor creates a controller object to listen to ui events from a + * ScrollView */ public BoardController() { super(); @@ -26,13 +23,10 @@ public BoardController() { * @param e MouseEvent object */ @Override - public void mouseClicked(MouseEvent e) { - - } + public void mouseClicked(MouseEvent e) {} /** - * Mouse Pressed event - sets the cursor to the move cursor and stores - * info for possible panning + * Mouse Pressed event - sets the cursor to the move cursor and stores info for possible panning * * @param e MouseEvent object */ @@ -42,8 +36,7 @@ public void mousePressed(MouseEvent e) { } /** - * Mouse Released event - sets the cursor back to the default cursor and reset - * info for panning + * Mouse Released event - sets the cursor back to the default cursor and reset info for panning * * @param e MouseEvent object */ @@ -58,9 +51,7 @@ public void mouseReleased(MouseEvent e) { * @param e MouseEvent object */ @Override - public void mouseEntered(MouseEvent e) { - - } + public void mouseEntered(MouseEvent e) {} /** * Mouse Exited event - no default action @@ -68,9 +59,7 @@ public void mouseEntered(MouseEvent e) { * @param e MouseEvent object */ @Override - public void mouseExited(MouseEvent e) { - - } + public void mouseExited(MouseEvent e) {} /** * Mouse Dragged event - adjusts the viewport @@ -88,9 +77,7 @@ public void mouseDragged(MouseEvent e) { * @param e MouseEvent object */ @Override - public void mouseMoved(MouseEvent e) { - - } + public void mouseMoved(MouseEvent e) {} /** * Mouse Wheel Moved event - zooms in on the viewport diff --git a/src/main/java/edu/rpi/legup/controller/Controller.java b/src/main/java/edu/rpi/legup/controller/Controller.java index 5eef8cc17..47ef70e17 100644 --- a/src/main/java/edu/rpi/legup/controller/Controller.java +++ b/src/main/java/edu/rpi/legup/controller/Controller.java @@ -1,24 +1,33 @@ package edu.rpi.legup.controller; import edu.rpi.legup.ui.ScrollView; - -import javax.swing.*; import java.awt.*; import java.awt.event.*; +import javax.swing.*; +/** + * {@code Controller} is an abstract class designed to handle various mouse events and provide control functionality for a {@code ScrollView}. + * It implements several mouse event interfaces to manage interactions such as panning and zooming within a {@code ScrollView} + */ public abstract class Controller implements MouseMotionListener, MouseListener, MouseWheelListener { protected ScrollView viewer; private int x, y; private boolean pan; /** - * Controller Constructor creates a controller object to listen to ui events from a {@link ScrollView} + * Controller Constructor creates a controller object to listen to ui events from a {@link + * ScrollView} */ public Controller() { x = y = -1; pan = false; } + /** + * Sets the ScrollView instance that this controller manages + * + * @param viewer The ScrollView instance to be set + */ public void setViewer(ScrollView viewer) { this.viewer = viewer; } @@ -29,13 +38,10 @@ public void setViewer(ScrollView viewer) { * @param e MouseEvent object */ @Override - public void mouseClicked(MouseEvent e) { - - } + public void mouseClicked(MouseEvent e) {} /** - * Mouse Pressed event sets the cursor to the move cursor and stores - * info for possible panning + * Mouse Pressed event sets the cursor to the move cursor and stores info for possible panning * * @param e MouseEvent object */ @@ -50,8 +56,7 @@ public void mousePressed(MouseEvent e) { } /** - * Mouse Released event sets the cursor back to the default cursor and reset - * info for panning + * Mouse Released event sets the cursor back to the default cursor and reset info for panning * * @param e MouseEvent object */ @@ -69,9 +74,7 @@ public void mouseReleased(MouseEvent e) { * @param e MouseEvent object */ @Override - public void mouseEntered(MouseEvent e) { - - } + public void mouseEntered(MouseEvent e) {} /** * Mouse Exited event no default action @@ -79,9 +82,7 @@ public void mouseEntered(MouseEvent e) { * @param e MouseEvent object */ @Override - public void mouseExited(MouseEvent e) { - - } + public void mouseExited(MouseEvent e) {} /** * Mouse Dragged event adjusts the viewport @@ -106,9 +107,7 @@ public void mouseDragged(MouseEvent e) { * @param e MouseEvent object */ @Override - public void mouseMoved(MouseEvent e) { - - } + public void mouseMoved(MouseEvent e) {} /** * Mouse Wheel Moved event zooms in on the viewport @@ -122,11 +121,10 @@ public void mouseWheelMoved(MouseWheelEvent e) { if (e.getWheelRotation() != 0) { viewer.zoom(e.getWheelRotation() * 2, e.getPoint()); } - } - else { + } else { if (e.getWheelRotation() != 0) { viewer.zoom(e.getWheelRotation(), e.getPoint()); } } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/controller/CursorController.java b/src/main/java/edu/rpi/legup/controller/CursorController.java index 0c9a644ed..6a3ab018d 100644 --- a/src/main/java/edu/rpi/legup/controller/CursorController.java +++ b/src/main/java/edu/rpi/legup/controller/CursorController.java @@ -2,15 +2,18 @@ import java.awt.Component; import java.awt.Cursor; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Timer; import java.util.TimerTask; +/** + * {@code CursorController} provides functionality for managing the cursor appearance during actions that take a certain amount of time. + * It allows for the display of a busy cursor while an action is being processed and reverts to the default cursor afterward + */ public class CursorController { public static final Cursor BUSY_CURSOR = new Cursor(Cursor.WAIT_CURSOR); public static final Cursor DEFAULT_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR); - public static final int DELAY = 200; // in milliseconds + public static final int DELAY = 200; // in milliseconds private CursorController() { // Intentionally left empty @@ -18,36 +21,38 @@ private CursorController() { /** * Creates an ActionListener that will still do the same action processing as the given - * ActionListener while also displaying a loading cursor if the time it takes to execute - * the given process exceeds the time (in milliseconds) specified in this.DELAY - *

- * Sources consulted: http://www.catalysoft.com/articles/busycursor.html + * ActionListener while also displaying a loading cursor if the time it takes to execute the + * given process exceeds the time (in milliseconds) specified in this.DELAY * - * @param component The component you want to set the cursor for + *

Sources consulted: http://www.catalysoft.com/articles/busycursor.html + * + * @param component The component you want to set the cursor for * @param mainActionListener The ActionListener that does the intended action processing - * @return An ActionListener object that does the same action processing - * as mainActionListener while also modifying the cursor if needed + * @return An ActionListener object that does the same action processing as mainActionListener + * while also modifying the cursor if needed */ - public static ActionListener createListener(final Component component, final ActionListener mainActionListener) { - ActionListener actionListener = e -> { - TimerTask timerTask = new TimerTask() { - @Override - public void run() { - component.setCursor(BUSY_CURSOR); - } - }; + public static ActionListener createListener( + final Component component, final ActionListener mainActionListener) { + ActionListener actionListener = + e -> { + TimerTask timerTask = + new TimerTask() { + @Override + public void run() { + component.setCursor(BUSY_CURSOR); + } + }; - Timer timer = new Timer(); - try { - timer.schedule(timerTask, DELAY); - mainActionListener.actionPerformed(e); - } - finally { - timer.cancel(); - component.setCursor(DEFAULT_CURSOR); - } - }; + Timer timer = new Timer(); + try { + timer.schedule(timerTask, DELAY); + mainActionListener.actionPerformed(e); + } finally { + timer.cancel(); + component.setCursor(DEFAULT_CURSOR); + } + }; return actionListener; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/controller/EditorElementController.java b/src/main/java/edu/rpi/legup/controller/EditorElementController.java index 80e7dd35a..040610137 100644 --- a/src/main/java/edu/rpi/legup/controller/EditorElementController.java +++ b/src/main/java/edu/rpi/legup/controller/EditorElementController.java @@ -1,32 +1,18 @@ package edu.rpi.legup.controller; -import edu.rpi.legup.app.GameBoardFacade; -import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.history.*; -import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.elements.Element; -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.CaseBoard; -import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.*; -import edu.rpi.legup.model.tree.TreeElement; -import edu.rpi.legup.model.tree.TreeElementType; -import edu.rpi.legup.ui.proofeditorui.rulesview.RuleButton; -import edu.rpi.legup.ui.proofeditorui.treeview.TreeElementView; -import edu.rpi.legup.ui.proofeditorui.treeview.TreePanel; -import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; -import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; import edu.rpi.legup.ui.puzzleeditorui.elementsview.ElementButton; - -import javax.swing.*; -import javax.swing.border.Border; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.List; - -import static edu.rpi.legup.app.GameBoardFacade.getInstance; +import javax.swing.*; +/** + * {@code EditorElementController} manages actions related to UI elements within the puzzle editor environment. + * It handles button presses, updates element selection, and manages visual states of buttons + */ public class EditorElementController implements ActionListener { protected Object lastSource; protected ElementController elementController; @@ -38,19 +24,33 @@ public EditorElementController() { prevButton = null; } + /** + * Sets the ElementController instance for this controller + * + * @param elementController the ElementController instance to be set + */ public void setElementController(ElementController elementController) { this.elementController = elementController; } + /** + * Handles the event when a button associated with an Element is pressed + * + * @param element the Element associated with the button that was pressed + */ public void buttonPressed(Element element) { // TODO: implement what happens when element is pressed - System.out.printf("%s button pressed!\n", element.getElementName()); if (elementController != null) { elementController.setSelectedElement(element); } } + /** + * Handles action events triggered by buttons + * + * @param e the event to be processed + */ @Override public void actionPerformed(ActionEvent e) { lastSource = e.getSource(); @@ -66,6 +66,5 @@ public void actionPerformed(ActionEvent e) { button.setBorderToSelected(); this.prevButton = button; - } } diff --git a/src/main/java/edu/rpi/legup/controller/ElementController.java b/src/main/java/edu/rpi/legup/controller/ElementController.java index 50fa7d1b9..436b078b9 100644 --- a/src/main/java/edu/rpi/legup/controller/ElementController.java +++ b/src/main/java/edu/rpi/legup/controller/ElementController.java @@ -1,10 +1,12 @@ package edu.rpi.legup.controller; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.ui.ScrollView; +import static edu.rpi.legup.app.GameBoardFacade.*; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.history.AutoCaseRuleCommand; +import edu.rpi.legup.history.EditDataCommand; +import edu.rpi.legup.history.ICommand; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.Board; @@ -14,26 +16,28 @@ import edu.rpi.legup.model.tree.TreeElement; import edu.rpi.legup.model.tree.TreeElementType; import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.ui.DynamicView; import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.boardview.ElementSelection; import edu.rpi.legup.ui.boardview.ElementView; import edu.rpi.legup.ui.boardview.SelectionItemView; import edu.rpi.legup.ui.proofeditorui.treeview.*; -import edu.rpi.legup.history.ICommand; -import edu.rpi.legup.history.EditDataCommand; - import java.awt.*; import java.awt.event.*; -import static edu.rpi.legup.app.GameBoardFacade.*; - -public class ElementController implements MouseListener, MouseMotionListener, ActionListener, KeyListener { +/** + * The ElementController class manages UI interactions related to elements in a {@link BoardView}. + * It handles mouse events, key events, and actions related to element selection and manipulation + */ +public class ElementController + implements MouseListener, MouseMotionListener, ActionListener, KeyListener { protected BoardView boardView; private Element selectedElement; /** - * ElementController Constructor controller to handles ui events associated interacting with a {@link BoardView} + * ElementController Constructor controller to handle ui events associated interacting with a + * {@link BoardView} */ public ElementController() { this.boardView = null; @@ -59,9 +63,7 @@ public void setBoardView(BoardView boardView) { * @param e the event to be processed */ @Override - public void mouseClicked(MouseEvent e) { - - } + public void mouseClicked(MouseEvent e) {} /** * Invoked when a mouse button has been pressed on a component. @@ -69,9 +71,7 @@ public void mouseClicked(MouseEvent e) { * @param e the event to be processed */ @Override - public void mousePressed(MouseEvent e) { - - } + public void mousePressed(MouseEvent e) {} /** * Invoked when a mouse button has been released on a component. @@ -90,6 +90,7 @@ public void mouseReleased(MouseEvent e) { if (boardView == null) { boardView = getInstance().getLegupUI().getEditorBoardView(); } + Board board = boardView.getBoard(); ElementView elementView = boardView.getElement(e.getPoint()); TreeViewSelection selection = null; @@ -100,21 +101,21 @@ public void mouseReleased(MouseEvent e) { if (elementView != null) { if (board instanceof CaseBoard) { CaseBoard caseBoard = (CaseBoard) board; - AutoCaseRuleCommand autoCaseRuleCommand = new AutoCaseRuleCommand(elementView, selection, caseBoard.getCaseRule(), caseBoard, e); + AutoCaseRuleCommand autoCaseRuleCommand = + new AutoCaseRuleCommand( + elementView, selection, caseBoard.getCaseRule(), caseBoard, e); if (autoCaseRuleCommand.canExecute()) { autoCaseRuleCommand.execute(); getInstance().getHistory().pushChange(autoCaseRuleCommand); if (treePanel != null) { treePanel.updateError(""); } - } - else { + } else { if (treePanel != null) { treePanel.updateError(autoCaseRuleCommand.getError()); } } - } - else { + } else { if (selection != null) { ICommand edit = new EditDataCommand(elementView, selection, e); if (edit.canExecute()) { @@ -123,8 +124,7 @@ public void mouseReleased(MouseEvent e) { if (treePanel != null) { treePanel.updateError(""); } - } - else { + } else { if (treePanel != null) { treePanel.updateError(edit.getError()); } @@ -132,20 +132,18 @@ public void mouseReleased(MouseEvent e) { } } } -// if (selectedElement != null) { + // if (selectedElement != null) { GridBoard b = (GridBoard) this.boardView.getBoard(); Point point = e.getPoint(); - Point scaledPoint = new Point((int) Math.floor(point.x / (30 * this.boardView.getScale())), (int) Math.floor(point.y / (30 * this.boardView.getScale()))); + Point scaledPoint = + new Point( + (int) Math.floor(point.x / (30 * this.boardView.getScale())), + (int) Math.floor(point.y / (30 * this.boardView.getScale()))); if (this.boardView.getBoard() instanceof TreeTentBoard) { scaledPoint.setLocation(scaledPoint.getX() - 1, scaledPoint.getY() - 1); } - System.out.printf("selected Element is NOT null, attempting to change board at (%d, %d)\n", scaledPoint.x, scaledPoint.y); -// System.out.println("Before: " + b.getCell(scaledPoint.x, scaledPoint.y).getData()); + b.setCell(scaledPoint.x, scaledPoint.y, this.selectedElement, e); -// System.out.println("After: " + b.getCell(scaledPoint.x, scaledPoint.y).getData()); -// } else { -// System.out.println("selected Element is null!"); -// } boardView.repaint(); } @@ -175,7 +173,9 @@ public void mouseEntered(MouseEvent e) { selection.newHover(elementView); if (LegupPreferences.getInstance().getUserPrefAsBool(LegupPreferences.SHOW_MISTAKES)) { PuzzleElement element = elementView.getPuzzleElement(); - if (treeElement != null && treeElement.getType() == TreeElementType.TRANSITION && board.getModifiedData().contains(element)) { + if (treeElement != null + && treeElement.getType() == TreeElementType.TRANSITION + && board.getModifiedData().contains(element)) { TreeTransition transition = (TreeTransition) treeElement; if (transition.isJustified() && !transition.isCorrect()) { error = transition.getRule().checkRuleAt(transition, element); @@ -183,8 +183,7 @@ public void mouseEntered(MouseEvent e) { } if (error != null) { dynamicView.updateError(error); - } - else { + } else { dynamicView.resetStatus(); } } @@ -222,9 +221,7 @@ public void mouseExited(MouseEvent e) { * @param e the event to be processed */ @Override - public void mouseDragged(MouseEvent e) { - - } + public void mouseDragged(MouseEvent e) {} /** * Invoked when the mouse moved @@ -250,7 +247,9 @@ public void mouseMoved(MouseEvent e) { selection.newHover(elementView); if (LegupPreferences.getInstance().getUserPrefAsBool(LegupPreferences.SHOW_MISTAKES)) { PuzzleElement element = elementView.getPuzzleElement(); - if (treeElement != null && treeElement.getType() == TreeElementType.TRANSITION && board.getModifiedData().contains(element)) { + if (treeElement != null + && treeElement.getType() == TreeElementType.TRANSITION + && board.getModifiedData().contains(element)) { TreeTransition transition = (TreeTransition) treeElement; if (transition.isJustified() && !transition.isCorrect()) { error = transition.getRule().checkRuleAt(transition, element); @@ -258,8 +257,7 @@ public void mouseMoved(MouseEvent e) { } if (error != null) { dynamicView.updateError(error); - } - else { + } else { dynamicView.resetStatus(); } } @@ -267,9 +265,7 @@ public void mouseMoved(MouseEvent e) { } } - public void changeCell(MouseEvent e, PuzzleElement data) { - - } + public void changeCell(MouseEvent e, PuzzleElement data) {} /** * Invoked when an action occurs. @@ -299,8 +295,7 @@ public void actionPerformed(ActionEvent e) { if (puzzleElement.equalsData(prevBord.getPuzzleElement(puzzleElement))) { puzzleElement.setModified(false); - } - else { + } else { puzzleElement.setModified(true); } @@ -311,33 +306,26 @@ public void actionPerformed(ActionEvent e) { } /** - * Invoked when a key has been typed. - * See the class description for {@link KeyEvent} for a definition of - * a key typed event. + * Invoked when a key has been typed. See the class description for {@link KeyEvent} for a + * definition of a key typed event. * * @param e the event to be processed */ @Override - public void keyTyped(KeyEvent e) { - - } + public void keyTyped(KeyEvent e) {} /** - * Invoked when a key has been pressed. - * See the class description for {@link KeyEvent} for a definition of - * a key pressed event. + * Invoked when a key has been pressed. See the class description for {@link KeyEvent} for a + * definition of a key pressed event. * * @param e the event to be processed */ @Override - public void keyPressed(KeyEvent e) { - - } + public void keyPressed(KeyEvent e) {} /** - * Invoked when a key has been released. - * See the class description for {@link KeyEvent} for a definition of - * a key released event. + * Invoked when a key has been released. See the class description for {@link KeyEvent} for a + * definition of a key released event. * * @param e the event to be processed */ diff --git a/src/main/java/edu/rpi/legup/controller/RuleController.java b/src/main/java/edu/rpi/legup/controller/RuleController.java index fef6fca45..491e02f74 100644 --- a/src/main/java/edu/rpi/legup/controller/RuleController.java +++ b/src/main/java/edu/rpi/legup/controller/RuleController.java @@ -1,5 +1,7 @@ package edu.rpi.legup.controller; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.history.*; @@ -10,19 +12,21 @@ import edu.rpi.legup.ui.proofeditorui.rulesview.RuleButton; import edu.rpi.legup.ui.proofeditorui.rulesview.RulePanel; import edu.rpi.legup.ui.proofeditorui.treeview.*; - import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - +/** + * The RuleController class is responsible for handling UI events related to rule buttons + * in the RulePanel of the Legup application. It implements ActionListener to process action + * events triggered by rule buttons and applies rules to the puzzle accordingly + */ public class RuleController implements ActionListener { protected Object lastSource; /** - * RuleController Constructor creates a controller object to listen - * to ui events from a {@link RulePanel} + * RuleController Constructor creates a controller object to listen to ui events from a {@link + * RulePanel} */ public RuleController() { super(); @@ -51,56 +55,56 @@ public void buttonPressed(Rule rule) { if (caseRuleCommand.canExecute()) { caseRuleCommand.execute(); getInstance().getHistory().pushChange(caseRuleCommand); - } - else { + } else { updateErrorString = caseRuleCommand.getError(); } - } - else { - if (LegupPreferences.getInstance().getUserPref(LegupPreferences.AUTO_GENERATE_CASES).equalsIgnoreCase(Boolean.toString(true))) { + } else { + if (LegupPreferences.getInstance() + .getUserPref(LegupPreferences.AUTO_GENERATE_CASES) + .equalsIgnoreCase(Boolean.toString(true))) { CaseBoard caseBoard = caseRule.getCaseBoard(element.getBoard()); if (caseBoard != null && caseBoard.getCount() > 0) { - puzzle.notifyBoardListeners(listener -> listener.onCaseBoardAdded(caseBoard)); - } - else { + puzzle.notifyBoardListeners( + listener -> listener.onCaseBoardAdded(caseBoard)); + } else { updateErrorString = "This board cannot be applied with this case rule."; } - } - else { - updateErrorString = "Auto generated case rules are turned off in preferences."; + } else { + updateErrorString = + "Auto generated case rules are turned off in preferences."; } } - } - else { + } else { ICommand caseRuleCommand = new ValidateCaseRuleCommand(selection, caseRule); if (caseRuleCommand.canExecute()) { caseRuleCommand.execute(); getInstance().getHistory().pushChange(caseRuleCommand); - } - else { + } else { updateErrorString = caseRuleCommand.getError(); } } - } - else { + } else { if (rule.getRuleType() == RuleType.CONTRADICTION) { - ICommand validate = new ValidateContradictionRuleCommand(selection, (ContradictionRule) rule); + ICommand validate = + new ValidateContradictionRuleCommand(selection, (ContradictionRule) rule); if (validate.canExecute()) { getInstance().getHistory().pushChange(validate); validate.execute(); - } - else { + } else { updateErrorString = validate.getError(); } - } - else { - boolean def = LegupPreferences.getInstance().getUserPrefAsBool(LegupPreferences.ALLOW_DEFAULT_RULES); - ICommand validate = def ? new ApplyDefaultDirectRuleCommand(selection, (DirectRule) rule) : new ValidateDirectRuleCommand(selection, (DirectRule) rule); + } else { + boolean def = + LegupPreferences.getInstance() + .getUserPrefAsBool(LegupPreferences.ALLOW_DEFAULT_RULES); + ICommand validate = + def + ? new ApplyDefaultDirectRuleCommand(selection, (DirectRule) rule) + : new ValidateDirectRuleCommand(selection, (DirectRule) rule); if (validate.canExecute()) { getInstance().getHistory().pushChange(validate); validate.execute(); - } - else { + } else { updateErrorString = validate.getError(); } } diff --git a/src/main/java/edu/rpi/legup/controller/ToolbarController.java b/src/main/java/edu/rpi/legup/controller/ToolbarController.java index 2ee4ee25e..6cbb5ee60 100644 --- a/src/main/java/edu/rpi/legup/controller/ToolbarController.java +++ b/src/main/java/edu/rpi/legup/controller/ToolbarController.java @@ -1,19 +1,15 @@ package edu.rpi.legup.controller; import edu.rpi.legup.ui.LegupUI; - import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - public class ToolbarController implements ActionListener { private LegupUI legupUI; /** - * ToolbarController Constructor - creates a new {@link ToolbarController} to listen - * for button pressed from the tool mBar + * ToolbarController Constructor - creates a new {@link ToolbarController} to listen for button + * pressed from the tool mBar * * @param legupUI legupUI */ @@ -27,7 +23,5 @@ public ToolbarController(LegupUI legupUI) { * @param e action event */ @Override - public void actionPerformed(ActionEvent e) { - - } + public void actionPerformed(ActionEvent e) {} } diff --git a/src/main/java/edu/rpi/legup/controller/TreeController.java b/src/main/java/edu/rpi/legup/controller/TreeController.java index 6eae4ac3b..2b12268ac 100644 --- a/src/main/java/edu/rpi/legup/controller/TreeController.java +++ b/src/main/java/edu/rpi/legup/controller/TreeController.java @@ -1,25 +1,26 @@ package edu.rpi.legup.controller; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.tree.Tree; -import edu.rpi.legup.model.tree.TreeElementType; import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.proofeditorui.treeview.*; - -import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; +import javax.swing.*; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - +/** + * The TreeController class handles UI events from a TreePanel. + * It extends the Controller class to provide specific behavior for tree interactions + */ public class TreeController extends Controller { /** - * TreeController Constructor creates a controller object to listen to ui events from a {@link TreePanel} + * TreeController Constructor creates a controller object to listen to ui events from a {@link + * TreePanel} */ - public TreeController() { - - } + public TreeController() {} /** * Mouse Clicked event no default action @@ -27,9 +28,7 @@ public TreeController() { * @param e MouseEvent object */ @Override - public void mouseClicked(MouseEvent e) { - - } + public void mouseClicked(MouseEvent e) {} /** * Mouse Pressed event sets the cursor to the move cursor and stores info for possible panning @@ -44,6 +43,7 @@ public void mousePressed(MouseEvent e) { /** * Mouse Released event sets the cursor back to the default cursor and reset info for panning * Set board modifiability + * * @param e MouseEvent object */ @Override @@ -58,19 +58,19 @@ public void mouseReleased(MouseEvent e) { if (treeElementView != null) { if (e.isShiftDown()) { selection.addToSelection(treeElementView); - } - else { + } else { if (e.isControlDown()) { - if (!(selection.getSelectedViews().size() == 1 && treeElementView == selection.getFirstSelection())) { + if (!(selection.getSelectedViews().size() == 1 + && treeElementView == selection.getFirstSelection())) { selection.toggleSelection(treeElementView); } - } - else { + } else { selection.newSelection(treeElementView); } } puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(treeElementView.getTreeElement())); + puzzle.notifyBoardListeners( + listener -> listener.onTreeElementChanged(treeElementView.getTreeElement())); } } @@ -88,7 +88,8 @@ public void mouseEntered(MouseEvent e) { TreeElementView treeElementView = treeView.getTreeElementView(point); Puzzle puzzle = getInstance().getPuzzleModule(); if (treeElementView != null) { - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(treeElementView.getTreeElement())); + puzzle.notifyBoardListeners( + listener -> listener.onTreeElementChanged(treeElementView.getTreeElement())); } } @@ -108,7 +109,8 @@ public void mouseExited(MouseEvent e) { selection.setMousePoint(null); if (elementView != null) { TreeElementView selectedView = selection.getFirstSelection(); - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(selectedView.getTreeElement())); + puzzle.notifyBoardListeners( + listener -> listener.onTreeElementChanged(selectedView.getTreeElement())); } } @@ -137,15 +139,20 @@ public void mouseMoved(MouseEvent e) { TreeViewSelection selection = treeView.getSelection(); selection.setMousePoint(treeView.getActualPoint(e.getPoint())); if (treeElementView != null && treeElementView != selection.getHover()) { - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(treeElementView.getTreeElement())); + puzzle.notifyBoardListeners( + listener -> + listener.onTreeElementChanged(treeElementView.getTreeElement())); selection.newHover(treeElementView); puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); - } - else { + } else { if (treeElementView == null && selection.getHover() != null) { - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(selection.getFirstSelection().getTreeElement())); + puzzle.notifyBoardListeners( + listener -> + listener.onTreeElementChanged( + selection.getFirstSelection().getTreeElement())); selection.clearHover(); - puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); + puzzle.notifyTreeListeners( + listener -> listener.onTreeSelectionChanged(selection)); } } } diff --git a/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java index 0aa6f416d..92a887f71 100644 --- a/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/AddTreeElementCommand.java @@ -6,11 +6,15 @@ import edu.rpi.legup.ui.proofeditorui.treeview.TreeElementView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; - import java.util.HashMap; import java.util.List; import java.util.Map; + +/** + * The AddTreeElementCommand class represents a command to add tree elements to the proof tree. + * It extends the PuzzleCommand class to handle the addition of tree elements and undo operation. + */ public class AddTreeElementCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -18,7 +22,8 @@ public class AddTreeElementCommand extends PuzzleCommand { private Map addChild; /** - * AddTreeElementCommand Constructor creates a command for adding a tree element to the proof tree + * AddTreeElementCommand Constructor creates a command for adding a tree element to the proof + * tree * * @param selection selection of tree elements views */ @@ -28,7 +33,8 @@ public AddTreeElementCommand(TreeViewSelection selection) { } /** - * Executes an command + * Executes the command to add selected tree elements to the tree. + * Updates the puzzle and tree view accordingly */ @Override public void executeCommand() { @@ -43,12 +49,11 @@ public void executeCommand() { TreeElement child = addChild.get(treeElement); if (child == null) { child = tree.addTreeElement(treeElement); - } - else { + } else { + if (treeElement.getType() == TreeElementType.NODE) { child = tree.addTreeElement((TreeNode) treeElement, (TreeTransition) child); - } - else { + } else { child = tree.addTreeElement((TreeTransition) treeElement, (TreeNode) child); } } @@ -69,15 +74,14 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { List selectedViews = selection.getSelectedViews(); if (selectedViews.isEmpty()) { return CommandError.NO_SELECTED_VIEWS.toString(); - } - else { + } else { for (TreeElementView view : selectedViews) { TreeElement element = view.getTreeElement(); if (element.getType() == TreeElementType.TRANSITION) { @@ -85,8 +89,7 @@ public String getErrorString() { if (transition.getChildNode() != null) { return CommandError.ADD_WITH_CHILD.toString(); } - } - else { + } else { TreeNode node = (TreeNode) element; if (!node.getChildren().isEmpty()) { TreeTransition transition = node.getChildren().get(0); @@ -101,7 +104,8 @@ public String getErrorString() { } /** - * Undoes an command + * Undoes the command by removing the added tree elements. + * Updates the puzzle and tree view accordingly */ @Override public void undoCommand() { @@ -119,4 +123,4 @@ public void undoCommand() { } puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java index bc4c89741..ad89ab636 100644 --- a/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ApplyDefaultDirectRuleCommand.java @@ -1,128 +1,140 @@ -package edu.rpi.legup.history; - -import edu.rpi.legup.app.GameBoardFacade; -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.*; -import edu.rpi.legup.ui.proofeditorui.treeview.*; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ApplyDefaultDirectRuleCommand extends PuzzleCommand { - - private TreeViewSelection selection; - private DirectRule rule; - private Map addMap; - - /** - * ApplyDefaultDirectRuleCommand Constructor creates a command for applying the default of a basic rule - * - * @param selection selection of tree element views - * @param rule basic rule for the command - */ - public ApplyDefaultDirectRuleCommand(TreeViewSelection selection, DirectRule rule) { - this.selection = selection.copy(); - this.rule = rule; - this.addMap = new HashMap<>(); - } - - /** - * Gets the reason why the command cannot be executed - * - * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed - */ - @Override - public String getErrorString() { - List selectedViews = selection.getSelectedViews(); - if (selectedViews.isEmpty()) { - return CommandError.DEFAULT_APPLICATION + " - " + CommandError.NO_SELECTED_VIEWS.toString(); - } - else { - for (TreeElementView view : selectedViews) { - TreeElement element = view.getTreeElement(); - if (element.getType() == TreeElementType.NODE) { - TreeNode node = (TreeNode) element; - if (!node.getChildren().isEmpty()) { - return CommandError.DEFAULT_APPLICATION + " - " + CommandError.NO_CHILDREN.toString(); - } - else { - if (rule.getDefaultBoard(node) == null) { - return CommandError.DEFAULT_APPLICATION + " - " + "This selection contains a tree element that this rule cannot be applied to."; - } - } - } - else { - return CommandError.DEFAULT_APPLICATION + " - " + CommandError.SELECTION_CONTAINS_TRANSITION.toString(); - } - } - } - return null; - } - - /** - * Executes an command - */ - @Override - public void executeCommand() { - Tree tree = GameBoardFacade.getInstance().getTree(); - TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); - Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); - final TreeViewSelection newSelection = new TreeViewSelection(); - - for (TreeElementView selectedView : selection.getSelectedViews()) { - TreeNodeView nodeView = (TreeNodeView) selectedView; - TreeNode node = nodeView.getTreeElement(); - TreeTransition transition = addMap.get(node); - TreeNode childNode; - if (transition == null) { - transition = (TreeTransition) tree.addTreeElement(node); - childNode = (TreeNode) tree.addTreeElement(transition); - addMap.put(node, transition); - } - else { - tree.addTreeElement(node, transition); - childNode = transition.getChildNode(); - } - - transition.setRule(rule); - Board defaultBoard = rule.getDefaultBoard(node); - transition.setBoard(defaultBoard); - Board copyBoard = defaultBoard.copy(); - copyBoard.setModifiable(false); - childNode.setBoard(copyBoard); - - final TreeTransition finalTran = transition; - puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(finalTran)); - - newSelection.addToSelection(treeView.getElementView(childNode)); - } - - final TreeElement finalTreeElement = newSelection.getFirstSelection().getTreeElement(); - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); - puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); - } - - /** - * Undoes an command - */ - @Override - public void undoCommand() { - Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); - - for (TreeElementView selectedView : selection.getSelectedViews()) { - TreeNodeView nodeView = (TreeNodeView) selectedView; - TreeNode node = nodeView.getTreeElement(); - final TreeTransition transition = addMap.get(node); - - puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(transition)); - } - - final TreeElement finalTreeElement = selection.getFirstSelection().getTreeElement(); - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); - puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); - } -} +package edu.rpi.legup.history; + +import edu.rpi.legup.app.GameBoardFacade; +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.*; +import edu.rpi.legup.ui.proofeditorui.treeview.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The ApplyDefaultDirectRuleCommand class represents a command to apply a default direct rule + * to selected tree nodes in the proof tree. + * It extends the PuzzleCommand class to handle rule application and undo operation. + */ +public class ApplyDefaultDirectRuleCommand extends PuzzleCommand { + + private TreeViewSelection selection; + private DirectRule rule; + private Map addMap; + + /** + * ApplyDefaultDirectRuleCommand Constructor creates a command for applying the default of a + * basic rule + * + * @param selection selection of tree element views + * @param rule basic rule for the command + */ + public ApplyDefaultDirectRuleCommand(TreeViewSelection selection, DirectRule rule) { + this.selection = selection.copy(); + this.rule = rule; + this.addMap = new HashMap<>(); + } + + /** + * Gets the reason why the command cannot be executed + * + * @return if command cannot be executed, returns reason for why the command cannot be executed, + * otherwise null if command can be executed + */ + @Override + public String getErrorString() { + List selectedViews = selection.getSelectedViews(); + if (selectedViews.isEmpty()) { + return CommandError.DEFAULT_APPLICATION + + " - " + + CommandError.NO_SELECTED_VIEWS.toString(); + } else { + for (TreeElementView view : selectedViews) { + TreeElement element = view.getTreeElement(); + if (element.getType() == TreeElementType.NODE) { + TreeNode node = (TreeNode) element; + if (!node.getChildren().isEmpty()) { + + return CommandError.DEFAULT_APPLICATION + + " - " + + CommandError.NO_CHILDREN.toString(); + } else { + if (rule.getDefaultBoard(node) == null) { + return CommandError.DEFAULT_APPLICATION + + " - This selection contains a tree element that this rule" + + " cannot be applied to."; + } + } + } else { + return CommandError.DEFAULT_APPLICATION + + " - " + + CommandError.SELECTION_CONTAINS_TRANSITION.toString(); + } + } + } + return null; + } + + /** + * Executes the command to apply the default rule to the selected tree nodes. + * Updates the puzzle and tree view accordingly. + */ + @Override + public void executeCommand() { + Tree tree = GameBoardFacade.getInstance().getTree(); + TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); + Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); + final TreeViewSelection newSelection = new TreeViewSelection(); + + for (TreeElementView selectedView : selection.getSelectedViews()) { + TreeNodeView nodeView = (TreeNodeView) selectedView; + TreeNode node = nodeView.getTreeElement(); + TreeTransition transition = addMap.get(node); + TreeNode childNode; + if (transition == null) { + transition = (TreeTransition) tree.addTreeElement(node); + childNode = (TreeNode) tree.addTreeElement(transition); + addMap.put(node, transition); + } else { + tree.addTreeElement(node, transition); + childNode = transition.getChildNode(); + } + + transition.setRule(rule); + Board defaultBoard = rule.getDefaultBoard(node); + transition.setBoard(defaultBoard); + Board copyBoard = defaultBoard.copy(); + copyBoard.setModifiable(false); + childNode.setBoard(copyBoard); + + final TreeTransition finalTran = transition; + puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(finalTran)); + + newSelection.addToSelection(treeView.getElementView(childNode)); + } + + final TreeElement finalTreeElement = newSelection.getFirstSelection().getTreeElement(); + puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); + puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); + } + + /** + * Undoes the command by removing the applied default rule from the tree nodes. + * Updates the puzzle and tree view accordingly. + */ + @Override + public void undoCommand() { + Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); + + for (TreeElementView selectedView : selection.getSelectedViews()) { + TreeNodeView nodeView = (TreeNodeView) selectedView; + TreeNode node = nodeView.getTreeElement(); + final TreeTransition transition = addMap.get(node); + + puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(transition)); + } + + final TreeElement finalTreeElement = selection.getFirstSelection().getTreeElement(); + puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); + puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); + } +} diff --git a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java index a4c157c77..b86cda6ea 100644 --- a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java @@ -1,5 +1,7 @@ package edu.rpi.legup.history; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.gameboard.Board; @@ -8,12 +10,14 @@ import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.boardview.ElementView; import edu.rpi.legup.ui.proofeditorui.treeview.*; - import java.awt.event.MouseEvent; import java.util.*; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - +/** + * The AutoCaseRuleCommand class represents a command to automatically apply a case rule to a + * selected tree node in the proof tree. + * It extends the PuzzleCommand class to handle case rule application and undo operation. + */ public class AutoCaseRuleCommand extends PuzzleCommand { private ElementView elementView; @@ -24,18 +28,21 @@ public class AutoCaseRuleCommand extends PuzzleCommand { private List caseTrans; - private static final int MAX_CASES = 10; - /** * AutoCaseRuleCommand Constructor creates a command for validating a case rule * * @param elementView currently selected puzzle puzzleElement view that is being edited - * @param selection currently selected tree puzzleElement views that is being edited + * @param selection currently selected tree puzzleElement views that is being edited * @param caseRule currently selected caseRule puzzleElement view that is being edited * @param caseBoard currently selected caseBoard puzzleElement view that is being edited * @param mouseEvent currently selected mouseEvent puzzleElement view that is being edited */ - public AutoCaseRuleCommand(ElementView elementView, TreeViewSelection selection, CaseRule caseRule, CaseBoard caseBoard, MouseEvent mouseEvent) { + public AutoCaseRuleCommand( + ElementView elementView, + TreeViewSelection selection, + CaseRule caseRule, + CaseBoard caseBoard, + MouseEvent mouseEvent) { this.elementView = elementView; this.selection = selection.copy(); this.caseRule = caseRule; @@ -45,7 +52,8 @@ public AutoCaseRuleCommand(ElementView elementView, TreeViewSelection selection, } /** - * Executes an command + * Executes the command to apply the case rule to the selected tree node. + * Updates the puzzle and tree view accordingly. */ @Override public void executeCommand() { @@ -59,7 +67,7 @@ public void executeCommand() { List cases = caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()); for (Board board : cases) { final TreeTransition transition = (TreeTransition) tree.addTreeElement(node); - board.setModifiable(false); + //board.setModifiable(false); transition.setBoard(board); transition.setRule(caseRule); transition.setSelection(elementView.getPuzzleElement().copy()); @@ -70,8 +78,7 @@ public void executeCommand() { puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(transition)); newSelection.addToSelection(treeView.getElementView(childNode)); } - } - else { + } else { for (final TreeTransition transition : caseTrans) { tree.addTreeElement(node, transition); TreeNode childNode = transition.getChildNode(); @@ -89,7 +96,7 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { @@ -115,15 +122,21 @@ public String getErrorString() { return "The selection must produce at least one case"; } - if (caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size() > MAX_CASES) { - return "The selection can produce a max of " + MAX_CASES + " cases"; + int numberOfCaseRules = caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size(); + System.out.println("Number of cases:" + numberOfCaseRules); + if (numberOfCaseRules > caseRule.MAX_CASES) { + return "The selection can produce a max of " + caseRule.MAX_CASES + " cases"; + } + if (numberOfCaseRules < caseRule.MIN_CASES) { + return "The selection must produce a minimum of " + caseRule.MIN_CASES + " cases"; } return null; } /** - * Undoes an command + * Undoes the command by removing the applied case rules from the tree node. + * Updates the puzzle and tree view accordingly */ @Override public void undoCommand() { diff --git a/src/main/java/edu/rpi/legup/history/CommandError.java b/src/main/java/edu/rpi/legup/history/CommandError.java index 90c9db526..26959cccd 100644 --- a/src/main/java/edu/rpi/legup/history/CommandError.java +++ b/src/main/java/edu/rpi/legup/history/CommandError.java @@ -1,11 +1,16 @@ package edu.rpi.legup.history; +/** + * The CommandError enum represents various error conditions that can occur when executing or + * validating commands related to tree elements in the proof tree. + * Each error condition is associated with a descriptive message. + */ public enum CommandError { - NO_SELECTED_VIEWS("The selection does not have any tree elements."), ONE_SELECTED_VIEW("The selection must have exactly one tree element."), UNMODIFIABLE_BOARD("The selection contains a board which is not modifiable."), UNMODIFIABLE_DATA("The selection contains a board where the data element is not modifiable."), + UNMODIFIABLE_DATA_CASE_RULE("The proof tree contains a future case rule, causing previous transitions to become unmodifiable."), CONTAINS_ROOT("The selection contains the root tree node."), ONE_CHILD("The selection contains a tree node that does not have exactly one child."), ADD_WITH_CHILD("The selection contains a tree transition that already has a child tree node."), @@ -19,10 +24,20 @@ public enum CommandError { private String value; + /** + * Constructs a CommandError with the specified error message + * + * @param value The error message associated with the command error + */ CommandError(String value) { this.value = value; } + /** + * Returns the error message associated with this CommandError + * + * @return The error message + */ @Override public String toString() { return value; diff --git a/src/main/java/edu/rpi/legup/history/CommandState.java b/src/main/java/edu/rpi/legup/history/CommandState.java index b7c2ff938..326490e28 100644 --- a/src/main/java/edu/rpi/legup/history/CommandState.java +++ b/src/main/java/edu/rpi/legup/history/CommandState.java @@ -1,14 +1,31 @@ package edu.rpi.legup.history; +/** + * The CommandState enum represents the various states that a command can be in during its lifecycle. + * Each state is associated with a descriptive name. + */ public enum CommandState { - CREATED("Created"), EXECUTED("Executed"), UNDOED("Undoed"), REDOED("Redoed"); + CREATED("Created"), + EXECUTED("Executed"), + UNDOED("Undoed"), + REDOED("Redoed"); private String value; + /** + * Constructs a CommandState with the specified state name + * + * @param value The name associated with the command state + */ CommandState(String value) { this.value = value; } + /** + * Returns the name associated with this CommandState + * + * @return The state name + */ @Override public String toString() { return value; diff --git a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java index 80cad9b24..e82197898 100644 --- a/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java +++ b/src/main/java/edu/rpi/legup/history/DeleteTreeElementCommand.java @@ -5,14 +5,19 @@ import edu.rpi.legup.model.observer.ITreeListener; import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.proofeditorui.treeview.*; - import java.util.List; +/** + * The DeleteTreeElementCommand class represents a command to delete tree elements from a proof tree. + * It extends PuzzleCommand and implements the functionality to remove selected tree elements and + * handle undo operations. + */ public class DeleteTreeElementCommand extends PuzzleCommand { private TreeViewSelection selection; /** - * DeleteTreeElementCommand Constructor creates a PuzzleCommand for deleting a tree puzzleElement + * DeleteTreeElementCommand Constructor creates a PuzzleCommand for deleting a tree + * puzzleElement * * @param selection the currently selected tree elements before the command is executed */ @@ -21,7 +26,7 @@ public DeleteTreeElementCommand(TreeViewSelection selection) { } /** - * Executes an command + * Executes the delete command, removing the selected tree elements from the tree. */ @Override public void executeCommand() { @@ -29,19 +34,24 @@ public void executeCommand() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); List selectedViews = selection.getSelectedViews(); + if (selectedViews.isEmpty()) { + return; + } TreeElementView firstSelectedView = selectedViews.get(0); TreeElementView newSelectedView; if (firstSelectedView.getType() == TreeElementType.NODE) { + //System.out.println("FIRST SELECTION NODE, total selection views: " + selectedViews.size()); TreeNodeView nodeView = (TreeNodeView) firstSelectedView; newSelectedView = nodeView.getParentView(); - } - else { + } else { + //System.out.println("FIRST SELECTION TRANS, total selection views: " + selectedViews.size()); TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; newSelectedView = transitionView.getParentViews().get(0); } for (TreeElementView selectedView : selectedViews) { + System.out.println("DELETED"); TreeElement element = selectedView.getTreeElement(); tree.removeTreeElement(element); puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(element)); @@ -56,7 +66,7 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { @@ -75,7 +85,7 @@ public String getErrorString() { } /** - * Undoes an command + * Undoes the delete command, re-adding the previously deleted tree elements. */ @Override public void undoCommand() { @@ -89,8 +99,7 @@ public void undoCommand() { node.getParent().setChildNode(node); puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(node)); - } - else { + } else { TreeTransition transition = (TreeTransition) element; transition.getParents().forEach(node -> node.addChild(transition)); transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); @@ -99,7 +108,10 @@ public void undoCommand() { } } - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(selection.getFirstSelection().getTreeElement())); + puzzle.notifyBoardListeners( + listener -> + listener.onTreeElementChanged( + selection.getFirstSelection().getTreeElement())); puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); } } diff --git a/src/main/java/edu/rpi/legup/history/EditDataCommand.java b/src/main/java/edu/rpi/legup/history/EditDataCommand.java index 328cc050d..a629aa085 100644 --- a/src/main/java/edu/rpi/legup/history/EditDataCommand.java +++ b/src/main/java/edu/rpi/legup/history/EditDataCommand.java @@ -1,5 +1,7 @@ package edu.rpi.legup.history; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; @@ -7,13 +9,19 @@ import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.boardview.ElementView; +import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.proofeditorui.treeview.*; +import javax.swing.*; +import java.awt.*; import java.awt.event.MouseEvent; import java.util.List; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - +/** + * The EditDataCommand class represents a command to edit the data of a puzzle element within + * a tree transition. It extends PuzzleCommand and provides functionality to execute and undo + * changes made to puzzle elements. + */ public class EditDataCommand extends PuzzleCommand { private TreeTransition transition; private PuzzleElement savePuzzleElement; @@ -27,8 +35,8 @@ public class EditDataCommand extends PuzzleCommand { * EditDataCommand Constructor create a puzzle command for editing a board * * @param elementView currently selected puzzle puzzleElement view that is being edited - * @param selection currently selected tree puzzleElement views that is being edited - * @param event mouse event + * @param selection currently selected tree puzzleElement views that are being edited + * @param event mouse event */ public EditDataCommand(ElementView elementView, TreeViewSelection selection, MouseEvent event) { this.elementView = elementView; @@ -40,7 +48,7 @@ public EditDataCommand(ElementView elementView, TreeViewSelection selection, Mou } /** - * Executes a command + * Executes the edit data command, modifying the puzzle element and propagating changes */ @SuppressWarnings("unchecked") @Override @@ -57,33 +65,27 @@ public void executeCommand() { if (treeElement.getType() == TreeElementType.NODE) { TreeNode treeNode = (TreeNode) treeElement; - if (treeNode.getChildren().isEmpty()) { if (transition == null) { transition = tree.addNewTransition(treeNode); } puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(transition)); } - board = transition.getBoard(); - puzzleElement = board.getPuzzleElement(selectedPuzzleElement); savePuzzleElement = puzzleElement.copy(); - } - else { + } else { transition = (TreeTransition) treeElement; puzzleElement = board.getPuzzleElement(selectedPuzzleElement); savePuzzleElement = puzzleElement.copy(); } Board prevBoard = transition.getParents().get(0).getBoard(); - boardView.getElementController().changeCell(event, puzzleElement); if (prevBoard.getPuzzleElement(selectedPuzzleElement).equalsData(puzzleElement)) { board.removeModifiedData(puzzleElement); - } - else { + } else { board.addModifiedData(puzzleElement); } transition.propagateChange(puzzleElement); @@ -92,7 +94,8 @@ public void executeCommand() { puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); puzzle.notifyBoardListeners(listener -> listener.onBoardDataChanged(puzzleElement)); - final TreeViewSelection newSelection = new TreeViewSelection(treeView.getElementView(transition)); + final TreeViewSelection newSelection = + new TreeViewSelection(treeView.getElementView(transition)); puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } @@ -100,37 +103,39 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { List selectedViews = selection.getSelectedViews(); if (selectedViews.size() != 1) { + flashTreeViewRed(); return CommandError.ONE_SELECTED_VIEW.toString(); } TreeElementView selectedView = selection.getFirstSelection(); Board board = selectedView.getTreeElement().getBoard(); PuzzleElement selectedPuzzleElement = elementView.getPuzzleElement(); if (selectedView.getType() == TreeElementType.NODE) { - TreeNodeView nodeView = (TreeNodeView) selectedView; if (!nodeView.getChildrenViews().isEmpty()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_BOARD.toString(); + } else if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { + flashTreeViewRed(); + return CommandError.UNMODIFIABLE_DATA.toString(); } - else { - if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { - return CommandError.UNMODIFIABLE_DATA.toString(); - } - } - } - else { + } else { TreeTransitionView transitionView = (TreeTransitionView) selectedView; if (!transitionView.getTreeElement().getBoard().isModifiable()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_BOARD.toString(); - } - else { + } else { if (!board.getPuzzleElement(selectedPuzzleElement).isModifiable()) { + flashTreeViewRed(); return CommandError.UNMODIFIABLE_DATA.toString(); + } else if (!board.getPuzzleElement(selectedPuzzleElement).isModifiableCaseRule()) { + flashTreeViewRed(); + return CommandError.UNMODIFIABLE_DATA_CASE_RULE.toString(); } } } @@ -138,7 +143,19 @@ public String getErrorString() { } /** - * Undoes an command + * Causes the TreeView background to flash red for a short duration when an error occurs. + */ + private void flashTreeViewRed() { + TreeView treeView = getInstance().getLegupUI().getTreePanel().getTreeView(); + Color originalColor = treeView.getBackground(); + treeView.setBackground(MaterialColors.RED_700); + Timer timer = new Timer(400, e -> treeView.setBackground(originalColor)); + timer.setRepeats(false); + timer.start(); + } + + /** + * Undoes the edit data command, restoring the previous state of the puzzle element. */ @SuppressWarnings("unchecked") @Override @@ -152,7 +169,8 @@ public void undoCommand() { if (selectedView.getType() == TreeElementType.NODE) { tree.removeTreeElement(transition); - puzzle.notifyTreeListeners((ITreeListener listener) -> listener.onTreeElementRemoved(transition)); + puzzle.notifyTreeListeners( + (ITreeListener listener) -> listener.onTreeElementRemoved(transition)); } Board prevBoard = transition.getParents().get(0).getBoard(); @@ -162,8 +180,7 @@ public void undoCommand() { if (prevBoard.getPuzzleElement(selectedPuzzleElement).equalsData(puzzleElement)) { board.removeModifiedData(puzzleElement); - } - else { + } else { board.addModifiedData(puzzleElement); } transition.propagateChange(puzzleElement); diff --git a/src/main/java/edu/rpi/legup/history/History.java b/src/main/java/edu/rpi/legup/history/History.java index 77e3fae94..b244e8f88 100644 --- a/src/main/java/edu/rpi/legup/history/History.java +++ b/src/main/java/edu/rpi/legup/history/History.java @@ -1,13 +1,15 @@ package edu.rpi.legup.history; import edu.rpi.legup.app.GameBoardFacade; - import java.util.ArrayList; import java.util.List; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +/** + * The History class manages a stack of commands for undo and redo operations on the board and tree structure. + * It maintains a list of commands and a current index to track the position in the history stack. + */ public class History { private static final Logger LOGGER = LogManager.getLogger(History.class.getName()); @@ -16,10 +18,8 @@ public class History { private int curIndex; /** - * History Constructor this holds information about changes to the board - * and Tree structure for undoing and redoing operations. Though history is - * an List, it is implemented like a stack. The curIndex points to the - * top of the stack (where the last change was made). + * Constructs a History object to keep track of changes and allow undo and redo operations. + * The history is implemented as a stack, with curIndex pointing to the top of the stack. */ public History() { history = new ArrayList<>(); @@ -27,9 +27,9 @@ public History() { } /** - * Pushes a change to the history list and increments the current index. - * If the current index does not point to the top of the stack, then at least - * 1 undo operation was called and that information will be lost by the next change + * Pushes a change to the history list and increments the current index. If the current index + * does not point to the top of the stack, then at least 1 undo operation was called and that + * information will be lost by the next change * * @param command command to be pushed onto the stack */ @@ -48,7 +48,8 @@ public void pushChange(ICommand command) { } /** - * Undoes an action + * Undoes the last action by calling the undo method of the command at the current index. + * Updates the current index and notifies listeners. */ public void undo() { synchronized (lock) { @@ -56,13 +57,18 @@ public void undo() { ICommand command = history.get(curIndex--); command.undo(); LOGGER.info("Undoed " + command.getClass().getSimpleName()); - GameBoardFacade.getInstance().notifyHistoryListeners(l -> l.onUndo(curIndex < 0, curIndex == history.size() - 1)); + + + GameBoardFacade.getInstance() + .notifyHistoryListeners( + l -> l.onUndo(curIndex < 0, curIndex == history.size() - 1)); } } } /** - * Redoes an action + * Redoes the next action by calling the redo method of the command at the current index. + * Updates the current index and notifies listeners. */ public void redo() { synchronized (lock) { @@ -70,13 +76,15 @@ public void redo() { ICommand command = history.get(++curIndex); command.redo(); LOGGER.info("Redoed " + command.getClass().getSimpleName()); - GameBoardFacade.getInstance().notifyHistoryListeners(l -> l.onRedo(curIndex < 0, curIndex == history.size() - 1)); + GameBoardFacade.getInstance() + .notifyHistoryListeners( + l -> l.onRedo(curIndex < 0, curIndex == history.size() - 1)); } } } /** - * Clears all actions from the history stack + * Clears all actions from the history stack and resets the current index */ public void clear() { history.clear(); diff --git a/src/main/java/edu/rpi/legup/history/ICommand.java b/src/main/java/edu/rpi/legup/history/ICommand.java index bc82c4df5..4f867dbab 100644 --- a/src/main/java/edu/rpi/legup/history/ICommand.java +++ b/src/main/java/edu/rpi/legup/history/ICommand.java @@ -1,13 +1,18 @@ package edu.rpi.legup.history; +/** + * The ICommand interface defines the structure for command objects in a command pattern. + * It provides methods to execute, undo, redo commands, and to check if a command can be executed. + */ public interface ICommand { /** - * Executes a command + * Executes the command. The specific behavior depends on the implementation */ void execute(); /** * Determines whether this command can be executed + * * @return true if can execute, false otherwise */ boolean canExecute(); @@ -16,17 +21,17 @@ public interface ICommand { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ String getError(); /** - * Undoes a command + * Undoes the command. Reverts the changes made by the execute method */ void undo(); /** - * Redoes a command + * Redoes the command. Re-applies the changes made by the execute method after undoing */ void redo(); -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/history/IHistoryListener.java b/src/main/java/edu/rpi/legup/history/IHistoryListener.java index 5201a09c5..48690168d 100644 --- a/src/main/java/edu/rpi/legup/history/IHistoryListener.java +++ b/src/main/java/edu/rpi/legup/history/IHistoryListener.java @@ -1,31 +1,37 @@ package edu.rpi.legup.history; +/** + * The IHistoryListener interface defines methods for listening to changes in the history of commands. + * Implementations of this interface can respond to events related to command history such as pushing, + * undoing, redoing commands, and clearing the history. + */ public interface IHistoryListener { + /** - * Called when a action is pushed onto the edu.rpi.legup.history stack + * Called when a command is pushed onto the history stack. * - * @param command action to push onto the stack + * @param command the command that was pushed onto the stack */ void onPushChange(ICommand command); /** - * Called when an action is undone + * Called when a command is undone. * * @param isBottom true if there are no more actions to undo, false otherwise - * @param isTop true if there are no more changes to redo, false otherwise + * @param isTop true if there are no more changes to redo, false otherwise */ void onUndo(boolean isBottom, boolean isTop); /** - * Called when an action is redone + * Called when a command is redone. * * @param isBottom true if there are no more actions to undo, false otherwise - * @param isTop true if there are no more changes to redo, false otherwise + * @param isTop true if there are no more changes to redo, false otherwise */ void onRedo(boolean isBottom, boolean isTop); /** - * Called when the edu.rpi.legup.history is cleared + * Called when the history stack is cleared. */ void onClearHistory(); } diff --git a/src/main/java/edu/rpi/legup/history/IHistorySubject.java b/src/main/java/edu/rpi/legup/history/IHistorySubject.java index 78fefff00..431adbb93 100644 --- a/src/main/java/edu/rpi/legup/history/IHistorySubject.java +++ b/src/main/java/edu/rpi/legup/history/IHistorySubject.java @@ -2,25 +2,31 @@ import java.util.function.Consumer; +/** + * The IHistorySubject interface defines methods for managing and notifying listeners + * about changes in the command history. Implementations of this interface can add, remove, + * and notify history listeners. + */ public interface IHistorySubject { + /** - * Adds a history listener + * Adds a history listener to receive updates about changes in the command history. * - * @param listener listener to add + * @param listener the listener to add */ void addHistoryListener(IHistoryListener listener); /** - * Removes a history listener + * Removes a history listener, so it no longer receives updates about changes in the command history. * - * @param listener listener to remove + * @param listener the listener to remove */ void removeHistoryListener(IHistoryListener listener); /** - * Notifies listeners + * Notifies all registered listeners about a change in the command history. * - * @param algorithm algorithm to notify the listeners with + * @param algorithm a Consumer function that takes an IHistoryListener and performs some action with it */ void notifyHistoryListeners(Consumer algorithm); } diff --git a/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java b/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java index 7e79814a6..201babb9e 100644 --- a/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java +++ b/src/main/java/edu/rpi/legup/history/InvalidCommandStateTransition.java @@ -1,8 +1,26 @@ package edu.rpi.legup.history; +/** + * The InvalidCommandStateTransition exception is thrown when an invalid state transition + * is attempted on a PuzzleCommand + */ public class InvalidCommandStateTransition extends RuntimeException { - public InvalidCommandStateTransition(PuzzleCommand puzzleCommand, CommandState from, CommandState to) { - super("PuzzleCommand - " + puzzleCommand.getClass().getSimpleName() + " - Attempted invalid command state transition from " + from + " to " + to); + /** + * Constructs a new InvalidCommandStateTransition exception with a detailed message + * + * @param puzzleCommand the PuzzleCommand involved in the invalid transition + * @param from the state from which the transition was attempted + * @param to the state to which the transition was attempted + */ + public InvalidCommandStateTransition( + PuzzleCommand puzzleCommand, CommandState from, CommandState to) { + super( + "PuzzleCommand - " + + puzzleCommand.getClass().getSimpleName() + + " - Attempted invalid command state transition from " + + from + + " to " + + to); } } diff --git a/src/main/java/edu/rpi/legup/history/MergeCommand.java b/src/main/java/edu/rpi/legup/history/MergeCommand.java index 2091ecf0a..c2851bced 100644 --- a/src/main/java/edu/rpi/legup/history/MergeCommand.java +++ b/src/main/java/edu/rpi/legup/history/MergeCommand.java @@ -6,11 +6,14 @@ import edu.rpi.legup.model.rules.MergeRule; import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.proofeditorui.treeview.*; - import java.util.ArrayList; import java.util.List; import java.util.Set; +/** + * The MergeCommand class represents a command to merge selected tree nodes into a single node + * and create a transition to represent the merge + */ public class MergeCommand extends PuzzleCommand { private TreeViewSelection selection; private TreeTransition transition; @@ -26,7 +29,7 @@ public MergeCommand(TreeViewSelection selection) { } /** - * Executes an command + * Executes the merge command */ @Override public void executeCommand() { @@ -55,8 +58,7 @@ public void executeCommand() { transition.setRule(new MergeRule()); transition.setChildNode(mergedNode); mergedNode.setParent(transition); - } - else { + } else { mergedNode = transition.getChildNode(); } @@ -76,14 +78,15 @@ public void executeCommand() { } /** - * Undoes an command + * Undoes the merge command */ @Override public void undoCommand() { Tree tree = GameBoardFacade.getInstance().getTree(); Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); - TreeTransition transition = ((TreeNode) selection.getFirstSelection().getTreeElement()).getChildren().get(0); + TreeTransition transition = + ((TreeNode) selection.getFirstSelection().getTreeElement()).getChildren().get(0); tree.removeTreeElement(transition); puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(transition)); @@ -94,7 +97,7 @@ public void undoCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { @@ -112,8 +115,7 @@ public String getErrorString() { return CommandError.NO_CHILDREN.toString(); } nodeList.add(nodeView.getTreeElement()); - } - else { + } else { return CommandError.SELECTION_CONTAINS_TRANSITION.toString(); } } @@ -130,12 +132,12 @@ public String getErrorString() { } Set leafNodes = tree.getLeafTreeElements(lca); if (leafNodes.size() != mergingNodes.size()) { -// return "Unable to merge tree elements."; + // return "Unable to merge tree elements."; } for (TreeNode node : mergingNodes) { if (!leafNodes.contains(node)) { -// return "Unable to merge tree elements."; + // return "Unable to merge tree elements."; } } diff --git a/src/main/java/edu/rpi/legup/history/PuzzleCommand.java b/src/main/java/edu/rpi/legup/history/PuzzleCommand.java index 0c96b16f5..d4385b3e8 100644 --- a/src/main/java/edu/rpi/legup/history/PuzzleCommand.java +++ b/src/main/java/edu/rpi/legup/history/PuzzleCommand.java @@ -1,15 +1,17 @@ package edu.rpi.legup.history; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - +/** + * The PuzzleCommand class is an abstract base class for commands that can be executed, undone, and redone + * within the puzzle model. It implements the ICommand interface and maintains the state and error handling + * for the command. + */ public abstract class PuzzleCommand implements ICommand { private CommandState state; private boolean isCached; private String cachedError; /** - * Puzzle Command Constructor for creating an undoable and redoable change to the model. + * Puzzle Command Constructor for creating an undoable and redoable change to the model */ protected PuzzleCommand() { this.state = CommandState.CREATED; @@ -18,7 +20,7 @@ protected PuzzleCommand() { } /** - * Executes an command + * Executes the command if it can be executed */ @Override public final void execute() { @@ -29,7 +31,7 @@ public final void execute() { } /** - * Determines whether this command can be executed + * Determines whether the command can be executed by checking the error state */ @Override public final boolean canExecute() { @@ -42,14 +44,13 @@ public final boolean canExecute() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public final String getError() { if (isCached) { return cachedError; - } - else { + } else { return getErrorString(); } } @@ -58,57 +59,56 @@ public final String getError() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ public abstract String getErrorString(); /** - * Executes an command + * Executes the command. + * This method must be implemented by subclasses to define the command's execution behavior. */ public abstract void executeCommand(); /** - * Undoes an command + * Undoes the command. + * This method must be implemented by subclasses to define the command's undo behavior. */ public abstract void undoCommand(); /** - * Redoes an command + * Redoes the command. This method is called if the command was previously undone. */ public void redoCommand() { if (state == CommandState.UNDOED) { executeCommand(); state = CommandState.REDOED; - } - else { + } else { throw new InvalidCommandStateTransition(this, state, CommandState.REDOED); } } /** - * Undoes an command + * Undoes the command if it was executed or redone */ @Override public final void undo() { if (state == CommandState.EXECUTED || state == CommandState.REDOED) { undoCommand(); state = CommandState.UNDOED; - } - else { + } else { throw new InvalidCommandStateTransition(this, state, CommandState.UNDOED); } } /** - * Redoes an command + * Redoes the command if it was previously undone. */ public final void redo() { if (state == CommandState.UNDOED) { redoCommand(); state = CommandState.REDOED; - } - else { + } else { throw new InvalidCommandStateTransition(this, state, CommandState.REDOED); } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java index 398f17478..6827436e8 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateCaseRuleCommand.java @@ -1,18 +1,21 @@ package edu.rpi.legup.history; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.proofeditorui.treeview.*; - import java.util.HashMap; import java.util.List; import java.util.Map; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - +/** + * The ValidateCaseRuleCommand class represents a command for validating a CaseRule in the tree structure. + * It extends the PuzzleCommand class and implements the ICommand interface. + */ public class ValidateCaseRuleCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -35,7 +38,7 @@ public ValidateCaseRuleCommand(TreeViewSelection selection, CaseRule caseRule) { } /** - * Executes an command + * Executes the command to validate the CaseRule */ @Override public void executeCommand() { @@ -58,8 +61,7 @@ public void executeCommand() { if (childNode == null) { childNode = (TreeNode) tree.addTreeElement(transition); addNode.put(transition, childNode); - } - else { + } else { childNode = (TreeNode) tree.addTreeElement(transition, childNode); } @@ -75,8 +77,7 @@ public void executeCommand() { if (firstSelectedView.getType() == TreeElementType.NODE) { TreeNodeView nodeView = (TreeNodeView) firstSelectedView; finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); - } - else { + } else { TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; finalTreeElement = transitionView.getChildView().getTreeElement(); } @@ -88,7 +89,7 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { @@ -100,8 +101,7 @@ public String getErrorString() { for (TreeElementView view : selectedViews) { if (view.getType() == TreeElementType.NODE) { return CommandError.SELECTION_CONTAINS_NODE.toString(); - } - else { + } else { TreeTransitionView transView = (TreeTransitionView) view; if (transView.getParentViews().size() > 1) { return CommandError.CONTAINS_MERGE.toString(); @@ -111,8 +111,9 @@ public String getErrorString() { return null; } + /** - * Undoes an command + * Undoes the validation command, restoring the previous state */ @Override public void undoCommand() { @@ -136,4 +137,4 @@ public void undoCommand() { puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java index 23f8dce21..b106a6072 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateContradictionRuleCommand.java @@ -5,12 +5,15 @@ import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.model.tree.*; import edu.rpi.legup.ui.proofeditorui.treeview.*; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +/** + * The ValidateContradictionRuleCommand class represents a command for validating and applying a ContradictionRule + * within a tree structure. It extends the PuzzleCommand class and implements the ICommand interface. + */ public class ValidateContradictionRuleCommand extends PuzzleCommand { private TreeViewSelection selection; @@ -19,10 +22,11 @@ public class ValidateContradictionRuleCommand extends PuzzleCommand { private Map addTran; /** - * ValidateContradictionRuleCommand Constructor creates a puzzle command for verifying a contradiction rule + * ValidateContradictionRuleCommand Constructor creates a puzzle command for verifying a + * contradiction rule * * @param selection currently selected tree puzzleElement views - * @param rule contradiction rule to be set to all the tree elements + * @param rule contradiction rule to be set to all the tree elements */ public ValidateContradictionRuleCommand(TreeViewSelection selection, ContradictionRule rule) { this.selection = selection.copy(); @@ -32,7 +36,7 @@ public ValidateContradictionRuleCommand(TreeViewSelection selection, Contradicti } /** - * Executes a command + * Executes the command to validate and apply the ContradictionRule. */ @Override public void executeCommand() { @@ -48,8 +52,7 @@ public void executeCommand() { if (treeElement.getType() == TreeElementType.TRANSITION) { TreeTransition transition = (TreeTransition) treeElement; treeNode = transition.getParents().get(0); - } - else { + } else { treeNode = (TreeNode) treeElement; } @@ -58,7 +61,11 @@ public void executeCommand() { saveElements.put(treeNode, save); } - treeNode.getChildren().forEach(n -> puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(n))); + treeNode.getChildren() + .forEach( + n -> + puzzle.notifyTreeListeners( + listener -> listener.onTreeElementRemoved(n))); treeNode.getChildren().clear(); @@ -68,8 +75,7 @@ public void executeCommand() { transition.setRule(newRule); transition.getBoard().setModifiable(false); tree.addTreeElement(transition); - } - else { + } else { transition.getBoard().setModifiable(false); tree.addTreeElement(treeNode, transition); } @@ -84,20 +90,24 @@ public void executeCommand() { final TreeElement finalTreeElement; if (firstSelectedView.getType() == TreeElementType.NODE) { TreeNodeView nodeView = (TreeNodeView) firstSelectedView; - finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); - } - else { + if (!nodeView.getChildrenViews().isEmpty()) { + finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); + } + else { + finalTreeElement = null; + } + } else { TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; if (transitionView.getChildView() != null) { finalTreeElement = transitionView.getChildView().getTreeElement(); - } - else { + } else { finalTreeElement = null; } } if (finalTreeElement != null) { - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); + puzzle.notifyBoardListeners( + listener -> listener.onTreeElementChanged(finalTreeElement)); } puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } @@ -106,7 +116,7 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { @@ -127,7 +137,7 @@ public String getErrorString() { } /** - * Undoes a command + * Undoes the validation command, restoring the previous state. */ @Override public void undoCommand() { @@ -140,18 +150,25 @@ public void undoCommand() { if (element.getType() == TreeElementType.TRANSITION) { TreeTransition transition = (TreeTransition) element; node = transition.getParents().get(0); - } - else { + } else { node = (TreeNode) element; } - node.getChildren().forEach(n -> puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(n))); + node.getChildren() + .forEach( + n -> + puzzle.notifyTreeListeners( + listener -> listener.onTreeElementRemoved(n))); node.getChildren().clear(); ArrayList save = saveElements.get(node); if (save != null) { node.getChildren().addAll(save); - node.getChildren().forEach(n -> puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(n))); + node.getChildren() + .forEach( + n -> + puzzle.notifyTreeListeners( + listener -> listener.onTreeElementAdded(n))); } } diff --git a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java index 61babe883..f7694cc0a 100644 --- a/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java +++ b/src/main/java/edu/rpi/legup/history/ValidateDirectRuleCommand.java @@ -1,152 +1,182 @@ -package edu.rpi.legup.history; - -import edu.rpi.legup.app.GameBoardFacade; -import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.Rule; -import edu.rpi.legup.model.tree.*; -import edu.rpi.legup.ui.proofeditorui.treeview.*; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ValidateDirectRuleCommand extends PuzzleCommand { - private TreeViewSelection selection; - - private Map oldRules; - private Map addNode; - private DirectRule newRule; - - /** - * ValidateDesireRuleCommand Constructor creates a command for verifying a basic rule - * - * @param selection selection of tree elements - * @param rule basic rule - */ - public ValidateDirectRuleCommand(TreeViewSelection selection, DirectRule rule) { - this.selection = selection.copy(); - this.newRule = rule; - this.oldRules = new HashMap<>(); - this.addNode = new HashMap<>(); - } - - /** - * Executes an command - */ - @Override - public void executeCommand() { - Tree tree = GameBoardFacade.getInstance().getTree(); - TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); - Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); - final TreeViewSelection newSelection = new TreeViewSelection(); - - List selectedViews = selection.getSelectedViews(); - for (TreeElementView selectedView : selectedViews) { - TreeElement element = selectedView.getTreeElement(); - TreeTransitionView transitionView; - if (element.getType() == TreeElementType.NODE) { - TreeNodeView nodeView = (TreeNodeView) selectedView; - transitionView = nodeView.getChildrenViews().get(0); - } - else { - transitionView = (TreeTransitionView) selectedView; - } - TreeTransition transition = transitionView.getTreeElement(); - - oldRules.put(transition, transition.getRule()); - transition.setRule(newRule); - - TreeNode childNode = transition.getChildNode(); - if (childNode == null) { - childNode = addNode.get(transition); - if (childNode == null) { - childNode = (TreeNode) tree.addTreeElement(transition); - addNode.put(transition, childNode); - } - else { - tree.addTreeElement(transition, childNode); - } - - final TreeNode finalNode = childNode; - puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(finalNode)); - } - newSelection.addToSelection(treeView.getElementView(childNode)); - } - TreeElementView firstSelectedView = selection.getFirstSelection(); - final TreeElement finalTreeElement; - if (firstSelectedView.getType() == TreeElementType.NODE) { - TreeNodeView nodeView = (TreeNodeView) firstSelectedView; - finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); - } - else { - TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; - finalTreeElement = transitionView.getChildView().getTreeElement(); - } - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); - puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); - } - - /** - * Gets the reason why the command cannot be executed - * - * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed - */ - @Override - public String getErrorString() { - List selectedViews = selection.getSelectedViews(); - if (selectedViews.isEmpty()) { - return CommandError.NO_SELECTED_VIEWS.toString(); - } - - for (TreeElementView view : selectedViews) { - if (view.getType() == TreeElementType.NODE) { - TreeNodeView nodeView = (TreeNodeView) view; - if (nodeView.getChildrenViews().size() != 1) { - return CommandError.ONE_CHILD.toString(); - } - } - else { - TreeTransitionView transView = (TreeTransitionView) view; - if (transView.getParentViews().size() > 1) { - return CommandError.CONTAINS_MERGE.toString(); - } - } - } - return null; - } - - /** - * Undoes an command - */ - @Override - public void undoCommand() { - Tree tree = GameBoardFacade.getInstance().getTree(); - Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); - - for (TreeElementView selectedView : selection.getSelectedViews()) { - TreeElement element = selectedView.getTreeElement(); - TreeTransitionView transitionView; - if (element.getType() == TreeElementType.NODE) { - TreeNodeView nodeView = (TreeNodeView) selectedView; - transitionView = nodeView.getChildrenViews().get(0); - } - else { - transitionView = (TreeTransitionView) selectedView; - } - TreeTransition transition = transitionView.getTreeElement(); - transition.setRule(oldRules.get(transition)); - - if (addNode.get(transition) != null) { - final TreeNode childNode = transition.getChildNode(); - tree.removeTreeElement(childNode); - puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(childNode)); - } - } - - final TreeElement finalTreeElement = selection.getFirstSelection().getTreeElement(); - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); - puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); - } -} +package edu.rpi.legup.history; + +import edu.rpi.legup.app.GameBoardFacade; +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.rules.Rule; +import edu.rpi.legup.model.tree.*; +import edu.rpi.legup.ui.proofeditorui.treeview.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The ValidateDirectRuleCommand class represents a command for validating and applying a DirectRule + * to a set of selected tree elements. It extends the PuzzleCommand class and implements the ICommand interface. + */ +public class ValidateDirectRuleCommand extends PuzzleCommand { + private static final Logger LOGGER = LogManager.getLogger(History.class.getName()); + private TreeViewSelection selection; + + private Map oldRules; + private Map addNode; + private DirectRule newRule; + + /** + * ValidateDesireRuleCommand Constructor creates a command for verifying a basic rule + * + * @param selection selection of tree elements + * @param rule basic rule + */ + public ValidateDirectRuleCommand(TreeViewSelection selection, DirectRule rule) { + this.selection = selection.copy(); + this.newRule = rule; + this.oldRules = new HashMap<>(); + this.addNode = new HashMap<>(); + } + + /** + * Executes the command to validate and apply the DirectRule. + */ + @Override + public void executeCommand() { + Tree tree = GameBoardFacade.getInstance().getTree(); + TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); + Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); + final TreeViewSelection newSelection = new TreeViewSelection(); + + List selectedViews = selection.getSelectedViews(); + for (TreeElementView selectedView : selectedViews) { + TreeElement element = selectedView.getTreeElement(); + TreeTransitionView transitionView; + + if (element.getType() == TreeElementType.NODE) { + TreeNodeView nodeView = (TreeNodeView) selectedView; + transitionView = nodeView.getChildrenViews().get(0); + } else { + transitionView = (TreeTransitionView) selectedView; + } + + TreeTransition transition = transitionView.getTreeElement(); + oldRules.put(transition, transition.getRule()); + transition.setRule(newRule); + + TreeNode childNode = transition.getChildNode(); + if (childNode == null) { + childNode = addNode.get(transition); + if (childNode == null) { + childNode = (TreeNode) tree.addTreeElement(transition); + addNode.put(transition, childNode); + } else { + tree.addTreeElement(transition, childNode); + } + + final TreeNode finalNode = childNode; + puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(finalNode)); + } + + TreeElementView childView = treeView.getElementView(childNode); + if (childView == null) { + LOGGER.error("Child view is null for child node: " + childNode); + continue; + } + newSelection.addToSelection(childView); + } + + TreeElementView firstSelectedView = selection.getFirstSelection(); + + final TreeElement finalTreeElement; + if (firstSelectedView.getType() == TreeElementType.NODE) { + TreeNodeView nodeView = (TreeNodeView) firstSelectedView; + if (nodeView.getChildrenViews().isEmpty()) { + LOGGER.error("NodeView has no children views"); + return; + } + finalTreeElement = nodeView.getChildrenViews().get(0).getTreeElement(); + } else { + TreeTransitionView transitionView = (TreeTransitionView) firstSelectedView; + TreeNodeView childView = transitionView.getChildView(); + if (childView == null) { + LOGGER.error("Child view is null for transition view: " + transitionView); + TreeNode childNode = transitionView.getTreeElement().getChildNode(); + childView = (TreeNodeView) treeView.getElementView(childNode); + transitionView.setChildView(childView); + } + TreeTransition transition = transitionView.getTreeElement(); + if (transition.getParents().get(0).getChildren().isEmpty()) { + transition.getParents().get(0).addChild(transition); + } + finalTreeElement = transitionView.getChildView().getTreeElement(); + } + + puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); + puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); + } + + + /** + * Gets the reason why the command cannot be executed + * + * @return if command cannot be executed, returns reason for why the command cannot be executed, + * otherwise null if command can be executed + */ + @Override + public String getErrorString() { + List selectedViews = selection.getSelectedViews(); + if (selectedViews.isEmpty()) { + return CommandError.NO_SELECTED_VIEWS.toString(); + } + + for (TreeElementView view : selectedViews) { + if (view.getType() == TreeElementType.NODE) { + TreeNodeView nodeView = (TreeNodeView) view; + if (nodeView.getChildrenViews().size() != 1) { + return CommandError.ONE_CHILD.toString(); + } + } else { + TreeTransitionView transView = (TreeTransitionView) view; + if (transView.getParentViews().size() > 1) { + return CommandError.CONTAINS_MERGE.toString(); + } + } + } + return null; + } + + /** + * Undoes the validation command, restoring the previous state. + */ + @Override + public void undoCommand() { + Tree tree = GameBoardFacade.getInstance().getTree(); + Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); + + for (TreeElementView selectedView : selection.getSelectedViews()) { + TreeElement element = selectedView.getTreeElement(); + TreeTransitionView transitionView; + if (element.getType() == TreeElementType.NODE) { + TreeNodeView nodeView = (TreeNodeView) selectedView; + transitionView = nodeView.getChildrenViews().get(0); + } else { + transitionView = (TreeTransitionView) selectedView; + + } + TreeTransition transition = transitionView.getTreeElement(); + + transition.setRule(oldRules.get(transition)); + + if (addNode.get(transition) != null) { + final TreeNode childNode = transition.getChildNode(); + tree.removeTreeElement(childNode); + puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(childNode)); + } + } + + final TreeElement finalTreeElement = selection.getFirstSelection().getTreeElement(); + puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(finalTreeElement)); + puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(selection)); + } +} diff --git a/src/main/java/edu/rpi/legup/model/Puzzle.java b/src/main/java/edu/rpi/legup/model/Puzzle.java index 18614131b..6cc92f347 100644 --- a/src/main/java/edu/rpi/legup/model/Puzzle.java +++ b/src/main/java/edu/rpi/legup/model/Puzzle.java @@ -1,6 +1,7 @@ package edu.rpi.legup.model; import edu.rpi.legup.model.elements.*; +import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.observer.IBoardListener; @@ -12,33 +13,33 @@ import edu.rpi.legup.model.tree.TreeElement; import edu.rpi.legup.model.tree.TreeElementType; import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -import edu.rpi.legup.ui.puzzleeditorui.elementsview.NonPlaceableElementPanel; -import edu.rpi.legup.utility.LegupUtils; -import org.w3c.dom.Document; -import edu.rpi.legup.model.elements.Element; -import org.w3c.dom.Node; import edu.rpi.legup.save.InvalidFileFormatException; import edu.rpi.legup.ui.boardview.BoardView; -import org.xml.sax.SAXException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; +import edu.rpi.legup.utility.LegupUtils; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; - +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; +/** + * Abstract class representing a puzzle. + * The Puzzle class manages the core components of a puzzle game, including the board, rules, and elements. + * It also handles importing and exporting puzzle configurations and notifies listeners about changes. + */ public abstract class Puzzle implements IBoardSubject, ITreeSubject { private static final Logger LOGGER = LogManager.getLogger(Puzzle.class.getName()); @@ -57,11 +58,8 @@ public abstract class Puzzle implements IBoardSubject, ITreeSubject { protected List contradictionRules; protected List caseRules; protected List placeableElements; - protected List nonPlaceableElements; - /** - * Puzzle Constructor - creates a new Puzzle - */ + /** Puzzle Constructor - creates a new Puzzle */ public Puzzle() { this.boardListeners = new ArrayList<>(); this.treeListeners = new ArrayList<>(); @@ -71,12 +69,15 @@ public Puzzle() { this.caseRules = new ArrayList<>(); this.placeableElements = new ArrayList<>(); - this.nonPlaceableElements = new ArrayList<>(); registerRules(); registerPuzzleElements(); } + /** + * Registers puzzle elements from the package of the derived class. + * Scans for classes annotated with {@link RegisterElement} and initializes them. + */ private void registerPuzzleElements() { String packageName = this.getClass().getPackage().toString().replace("package ", ""); @@ -85,9 +86,13 @@ private void registerPuzzleElements() { for (Class c : possElements) { + String classPackageName = c.getPackage().getName(); + if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") || !classPackageName.endsWith(".elements")) { + continue; + } System.out.println("possible element: " + c.getName()); - //check that the element is not abstract + // check that the element is not abstract if (Modifier.isAbstract(c.getModifiers())) continue; for (Annotation a : c.getAnnotations()) { @@ -101,31 +106,25 @@ private void registerPuzzleElements() { case PLACEABLE: this.addPlaceableElement((PlaceableElement) element); break; - case NONPLACEABLE: - this.addNonPlaceableElement((NonPlaceableElement) element); - break; default: break; } - } - catch (InvocationTargetException e) { + } catch (InvocationTargetException e) { System.out.println(" Failed "); e.getTargetException().printStackTrace(); } } } } - -// } catch (IOException | ClassNotFoundException | NoSuchMethodException | -// InstantiationException | IllegalAccessException | InvocationTargetException e) { -// LOGGER.error("Unable to find rules for " + this.getClass().getSimpleName(), e); -// } - } - catch (Exception e) { + } catch (Exception e) { LOGGER.error("Unable to find elements for " + this.getClass().getSimpleName(), e); } } + /** + * Registers rules from the package of the derived class. + * Scans for classes annotated with {@link RegisterRule} and initializes them. + */ private void registerRules() { String packageName = this.getClass().getPackage().toString().replace("package ", ""); @@ -134,9 +133,13 @@ private void registerRules() { for (Class c : possRules) { + String classPackageName = c.getPackage().getName(); + if (!classPackageName.startsWith("edu.rpi.legup.puzzle.") || !classPackageName.endsWith(".rules")) { + continue; + } System.out.println("possible rule: " + c.getName()); - //check that the rule is not abstract + // check that the rule is not abstract if (Modifier.isAbstract(c.getModifiers())) continue; for (Annotation a : c.getAnnotations()) { @@ -161,21 +164,14 @@ private void registerRules() { default: break; } - } - catch (InvocationTargetException e) { + } catch (InvocationTargetException e) { System.out.println(" Failed "); e.getTargetException().printStackTrace(); } } } } - -// } catch (IOException | ClassNotFoundException | NoSuchMethodException | -// InstantiationException | IllegalAccessException | InvocationTargetException e) { -// LOGGER.error("Unable to find rules for " + this.getClass().getSimpleName(), e); -// } - } - catch (Exception e) { + } catch (Exception e) { LOGGER.error("Unable to find rules for " + this.getClass().getSimpleName(), e); } } @@ -196,7 +192,7 @@ private void registerRules() { /** * Checks if the given height and width are valid board dimensions for the given puzzle * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @return true if the given dimensions are valid for the given puzzle, false otherwise */ @@ -205,10 +201,10 @@ public boolean isValidDimensions(int rows, int columns) { } /** - * Checks if the given array of statements is valid text input for the given puzzle + * Checks if the provided text input is valid for the puzzle. * - * @param statements - * @return + * @param statements array of statements to check + * @return true if input is valid, false otherwise */ public boolean isValidTextInput(String[] statements) { return statements.length > 0; @@ -230,13 +226,13 @@ public boolean isPuzzleComplete() { if (leaf.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) leaf; if (!node.isRoot()) { - isComplete &= node.getParent().isContradictoryBranch() || isBoardComplete(node.getBoard()); - } - else { + isComplete &= + node.getParent().isContradictoryBranch() + || isBoardComplete(node.getBoard()); + } else { isComplete &= isBoardComplete(node.getBoard()); } - } - else { + } else { isComplete = false; } } @@ -268,8 +264,7 @@ public boolean isPuzzleComplete() { public void importPuzzle(String fileName) throws InvalidFileFormatException { try { importPuzzle(new FileInputStream(fileName)); - } - catch (IOException e) { + } catch (IOException e) { LOGGER.error("Importing puzzle error", e); throw new InvalidFileFormatException("Could not find file"); } @@ -287,8 +282,7 @@ public void importPuzzle(InputStream inputStream) throws InvalidFileFormatExcept DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse(inputStream); - } - catch (IOException | SAXException | ParserConfigurationException e) { + } catch (IOException | SAXException | ParserConfigurationException e) { LOGGER.error("Importing puzzle error", e); throw new InvalidFileFormatException("Could not find file"); } @@ -300,8 +294,7 @@ public void importPuzzle(InputStream inputStream) throws InvalidFileFormatExcept throw new InvalidFileFormatException("Puzzle importer null"); } importer.initializePuzzle(node); - } - else { + } else { LOGGER.error("Invalid file"); throw new InvalidFileFormatException("Invalid file: must be a Legup file"); } @@ -343,15 +336,15 @@ public List getDirectRules() { return directRules; } + /** + * Gets the list of placeable elements. + * + * @return list of PlaceableElement instances + */ public List getPlaceableElements() { return placeableElements; } - public List getNonPlaceableElements() { - return nonPlaceableElements; - } - - /** * Sets the list of direct rules * @@ -370,14 +363,15 @@ public void addDirectRule(DirectRule rule) { directRules.add(rule); } + /** + * Adds a placeable element to this puzzle. + * + * @param element PlaceableElement to add + */ public void addPlaceableElement(PlaceableElement element) { placeableElements.add(element); } - public void addNonPlaceableElement(NonPlaceableElement element) { - nonPlaceableElements.add(element); - } - /** * Remove a basic rule from this Puzzle * @@ -590,9 +584,10 @@ public void setFactory(ElementFactory factory) { } /** - * Adds a board listener + * Adds a board listener to the list of listeners. + * This allows the puzzle to notify the listener about changes to the board. * - * @param listener listener to add + * @param listener The IBoardListener to be added to the list of listeners. */ @Override public void addBoardListener(IBoardListener listener) { @@ -600,9 +595,10 @@ public void addBoardListener(IBoardListener listener) { } /** - * Removes a board listener + * Removes a board listener from the list of listeners. + * This prevents the puzzle from notifying the listener about future changes to the board. * - * @param listener listener to remove + * @param listener The IBoardListener to be removed from the list of listeners. */ @Override public void removeBoardListener(IBoardListener listener) { @@ -610,9 +606,10 @@ public void removeBoardListener(IBoardListener listener) { } /** - * Notifies listeners + * Notifies all registered board listeners about changes. + * The provided algorithm is applied to each listener to process the notification. * - * @param algorithm algorithm to notify the listeners with + * @param algorithm A Consumer function that takes an IBoardListener and performs operations to notify the listener. */ @Override public void notifyBoardListeners(Consumer algorithm) { @@ -620,9 +617,10 @@ public void notifyBoardListeners(Consumer algorithm) { } /** - * Adds a board listener + * Adds a tree listener to the list of listeners. + * This allows the puzzle to notify the listener about changes to the tree. * - * @param listener listener to add + * @param listener The ITreeListener to be added to the list of listeners. */ @Override public void addTreeListener(ITreeListener listener) { @@ -630,9 +628,10 @@ public void addTreeListener(ITreeListener listener) { } /** - * Removes a tree listener + * Removes a tree listener from the list of listeners. + * This prevents the puzzle from notifying the listener about future changes to the tree. * - * @param listener listener to remove + * @param listener The ITreeListener to be removed from the list of listeners. */ @Override public void removeTreeListener(ITreeListener listener) { @@ -640,9 +639,10 @@ public void removeTreeListener(ITreeListener listener) { } /** - * Notifies listeners + * Notifies all registered tree listeners about changes. + * The provided algorithm is applied to each listener to process the notification. * - * @param algorithm algorithm to notify the listeners with + * @param algorithm A Consumer function that takes an ITreeListener and performs operations to notify the listener. */ @Override public void notifyTreeListeners(Consumer algorithm) { @@ -650,9 +650,10 @@ public void notifyTreeListeners(Consumer algorithm) { } /** - * Check if the puzzle is valid + * Checks if the puzzle is valid. + * The implementation of this method can vary based on the specific criteria for puzzle validity. * - * @return if the puzzle is valid + * @return true if the puzzle is valid, false otherwise. */ public boolean checkValidity() { return true; diff --git a/src/main/java/edu/rpi/legup/model/PuzzleExporter.java b/src/main/java/edu/rpi/legup/model/PuzzleExporter.java index 613d2ed1c..234d0f25c 100644 --- a/src/main/java/edu/rpi/legup/model/PuzzleExporter.java +++ b/src/main/java/edu/rpi/legup/model/PuzzleExporter.java @@ -3,25 +3,28 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.w3c.dom.Document; import edu.rpi.legup.save.ExportFileException; - +import java.io.File; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import java.io.File; -import java.util.*; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.ZoneId; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.w3c.dom.Document; import org.w3c.dom.Element; +/** + * Abstract class for exporting puzzle data to XML format. + * This class provides functionality to export a puzzle object, including its board and tree structure, to an XML file. + * Subclasses must implement methods to create specific elements for the board and the tree. + */ public abstract class PuzzleExporter { private static final Logger LOGGER = LogManager.getLogger(PuzzleExporter.class.getName()); @@ -60,7 +63,8 @@ public void exportPuzzle(String fileName) throws ExportFileException { legupElement.appendChild(puzzleElement); puzzleElement.appendChild(createBoardElement(newDocument)); - if (puzzle.getTree() != null && !puzzle.getTree().getRootNode().getChildren().isEmpty()) { + if (puzzle.getTree() != null + && !puzzle.getTree().getRootNode().getChildren().isEmpty()) { puzzleElement.appendChild(createProofElement(newDocument)); } @@ -84,18 +88,30 @@ public void exportPuzzle(String fileName) throws ExportFileException { StreamResult result = new StreamResult(new File(fileName)); transformer.transform(source, result); - } - catch (ParserConfigurationException | TransformerException e) { + } catch (ParserConfigurationException | TransformerException e) { throw new ExportFileException("Puzzle Exporter: parser configuration exception"); - } - catch (Exception e) { + } catch (Exception e) { throw e; - //throw new ExportFileException(e.getMessage()); + // throw new ExportFileException(e.getMessage()); } } + /** + * Creates an XML element representing the board of the puzzle. + * Subclasses must implement this method to provide the XML structure for the board. + * + * @param newDocument The XML document to create elements within. + * @return An XML element representing the puzzle's board. + */ protected abstract Element createBoardElement(Document newDocument); + /** + * Creates an XML element representing the proof of the puzzle, including its tree structure. + * This method is used to generate the proof section of the XML, which contains the tree representation. + * + * @param newDocument The XML document to create elements within. + * @return An XML element representing the proof of the puzzle. + */ protected Element createProofElement(Document newDocument) { org.w3c.dom.Element proofElement = newDocument.createElement("proof"); org.w3c.dom.Element treeElement = createTreeElement(newDocument); @@ -103,6 +119,13 @@ protected Element createProofElement(Document newDocument) { return proofElement; } + /** + * Creates an XML element representing the tree structure of the puzzle. + * This method traverses the tree nodes and transitions, and creates XML elements for each. + * + * @param newDocument The XML document to create elements within. + * @return An XML element representing the puzzle's tree structure. + */ protected Element createTreeElement(Document newDocument) { org.w3c.dom.Element treeElement = newDocument.createElement("tree"); diff --git a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java index 327a92773..b1e8a2dd9 100644 --- a/src/main/java/edu/rpi/legup/model/PuzzleImporter.java +++ b/src/main/java/edu/rpi/legup/model/PuzzleImporter.java @@ -6,14 +6,19 @@ import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.model.tree.*; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.util.*; - +/** + * Abstract class for importing puzzle data from various sources into a puzzle object. + * This class provides methods to initialize and set up a puzzle, including its board and proof structure, + * from different input formats such as dimensions, statements, or XML files. + * Subclasses must implement methods to handle specific formats for board initialization and proof creation. + */ public abstract class PuzzleImporter { private static final Logger LOGGER = LogManager.getLogger(PuzzleImporter.class.getName()); @@ -35,20 +40,27 @@ public PuzzleImporter(Puzzle puzzle) { /** * Initializes an empty puzzle * - * @param rows number of rows on the puzzle + * @param rows number of rows on the puzzle * @param columns number of columns on the puzzle * @throws RuntimeException if puzzle can not be made */ public void initializePuzzle(int rows, int columns) throws RuntimeException { if (this.puzzle.isValidDimensions(rows, columns)) { initializeBoard(rows, columns); - } - else { + } else { throw new IllegalArgumentException("Invalid dimensions provided"); } } - public void initializePuzzle(String[] statements) throws InputMismatchException, IllegalArgumentException { + /** + * Initializes the puzzle with the given array of statements + * + * @param statements the statements used to initialize the puzzle + * @throws InputMismatchException if the input statements are invalid + * @throws IllegalArgumentException if the statements are not suitable for initializing the puzzle + */ + public void initializePuzzle(String[] statements) + throws InputMismatchException, IllegalArgumentException { // Note: Error checking for the statements will be left up to the puzzles that support // text input. For example, some puzzles may be okay with "blank" statements (Strings with // length = 0) while others may not. @@ -56,10 +68,10 @@ public void initializePuzzle(String[] statements) throws InputMismatchException, } /** - * Initializes the puzzle attributes + * Initializes the puzzle attributes from the XML document node * - * @param node xml document node - * @throws InvalidFileFormatException if file is invalid + * @param node the XML document node representing the puzzle + * @throws InvalidFileFormatException if the file format is invalid */ public void initializePuzzle(Node node) throws InvalidFileFormatException { if (node.getNodeName().equalsIgnoreCase("puzzle")) { @@ -72,60 +84,85 @@ public void initializePuzzle(Node node) throws InvalidFileFormatException { Node n = childNodes.item(i); if (n.getNodeName().equalsIgnoreCase("board")) { if (initBoard) { - throw new InvalidFileFormatException("Puzzle creation error: duplicate board puzzleElement found"); + throw new InvalidFileFormatException( + "Puzzle creation error: duplicate board puzzleElement found"); } initializeBoard(n); initBoard = true; - } - else { + } else { if (n.getNodeName().equalsIgnoreCase("proof")) { if (initProof) { - throw new InvalidFileFormatException("Puzzle creation error: duplicate proof puzzleElement found"); + throw new InvalidFileFormatException( + "Puzzle creation error: duplicate proof puzzleElement found"); } if (!initBoard) { - throw new InvalidFileFormatException("Puzzle creation error: could not find board puzzleElement"); + throw new InvalidFileFormatException( + "Puzzle creation error: could not find board puzzleElement"); } initializeProof(n); initProof = true; - } - else { + } else { if (!n.getNodeName().equalsIgnoreCase("#text")) { - throw new InvalidFileFormatException("Puzzle creation error: unknown node found in file"); + throw new InvalidFileFormatException( + "Puzzle creation error: unknown node found in file"); } } } } if (!initBoard) { - throw new InvalidFileFormatException("Puzzle creation error: could not find board puzzleElement"); + throw new InvalidFileFormatException( + "Puzzle creation error: could not find board puzzleElement"); } if (!initProof) { createDefaultTree(); } - } - else { - throw new InvalidFileFormatException("Invalid file format; does not contain \"puzzle\" node"); + } else { + throw new InvalidFileFormatException( + "Invalid file format; does not contain \"puzzle\" node"); } } /** - * Creates the board for building + * Initializes the board with the specified number of rows and columns. * - * @param rows number of rows on the puzzle - * @param columns number of columns on the puzzle - * @throws RuntimeException if board can not be created + * @param rows the number of rows on the puzzle + * @param columns the number of columns on the puzzle + * @throws RuntimeException if the board cannot be created with the provided dimensions */ public abstract void initializeBoard(int rows, int columns); /** - * Creates an empty board for building + * Initializes the board from the XML document node. * - * @param node xml document node - * @throws InvalidFileFormatException if file is invalid + * @param node the XML document node representing the board + * @throws InvalidFileFormatException if the file format is invalid */ public abstract void initializeBoard(Node node) throws InvalidFileFormatException; - public abstract void initializeBoard(String[] statements) throws UnsupportedOperationException, IllegalArgumentException; + /** + * Initializes the board using an array of statements. + * + * @param statements the statements used to initialize the board + * @throws UnsupportedOperationException if the operation is not supported + * @throws IllegalArgumentException if the statements are not suitable for initializing the board + */ + public abstract void initializeBoard(String[] statements) + throws UnsupportedOperationException, IllegalArgumentException; + + /** + * Used to check that elements in the proof tree are saved properly. + * + *

Make sure the list elements are lowercase + * + * @return A list of elements that will change when solving the puzzle * e.g. {"cell"}, {"cell", + * "line"} + */ + public List getImporterElements() { + List elements = new ArrayList<>(); + elements.add("cell"); + return elements; + } /** * Creates the proof for building @@ -143,21 +180,22 @@ public void initializeProof(Node node) throws InvalidFileFormatException { Node n = treeList.item(i); if (n.getNodeName().equalsIgnoreCase("tree")) { if (initTree) { - throw new InvalidFileFormatException("Proof Tree construction error: duplicate tree puzzleElement"); + throw new InvalidFileFormatException( + "Proof Tree construction error: duplicate tree puzzleElement"); } createTree(n); initTree = true; - } - else { - throw new InvalidFileFormatException("Proof Tree construction error: unknown puzzleElement found"); + } else { + throw new InvalidFileFormatException( + "Proof Tree construction error: unknown puzzleElement found"); } } if (!initTree) { createDefaultTree(); } - } - else { - throw new InvalidFileFormatException("Invalid file format; does not contain \"proof\" node"); + } else { + throw new InvalidFileFormatException( + "Invalid file format; does not contain \"proof\" node"); } } @@ -171,7 +209,8 @@ protected void setCells(Node node) throws InvalidFileFormatException { NodeList dataList = ((org.w3c.dom.Element) node).getElementsByTagName("cell"); Board board = puzzle.getCurrentBoard(); for (int i = 0; i < dataList.getLength(); i++) { - PuzzleElement data = puzzle.getFactory().importCell(dataList.item(i), puzzle.getCurrentBoard()); + PuzzleElement data = + puzzle.getFactory().importCell(dataList.item(i), puzzle.getCurrentBoard()); board.setPuzzleElement(data.getIndex(), data); } } @@ -199,15 +238,18 @@ protected void createTree(Node node) throws InvalidFileFormatException { String nodeId = treeNodeElement.getAttribute("id"); String isRoot = treeNodeElement.getAttribute("root"); if (nodeId.isEmpty()) { - throw new InvalidFileFormatException("Proof Tree construction error: cannot find node ID"); + throw new InvalidFileFormatException( + "Proof Tree construction error: cannot find node ID"); } if (treeNodes.containsKey(nodeId)) { - throw new InvalidFileFormatException("Proof Tree construction error: duplicate tree node ID found"); + throw new InvalidFileFormatException( + "Proof Tree construction error: duplicate tree node ID found"); } TreeNode treeNode = new TreeNode(puzzle.getCurrentBoard().copy()); if (isRoot.equalsIgnoreCase("true")) { if (tree.getRootNode() != null) { - throw new InvalidFileFormatException("Proof Tree construction error: multiple root nodes declared"); + throw new InvalidFileFormatException( + "Proof Tree construction error: multiple root nodes declared"); } treeNode.setRoot(true); tree.setRootNode(treeNode); @@ -215,7 +257,6 @@ protected void createTree(Node node) throws InvalidFileFormatException { treeNodes.put(nodeId, treeNode); } - for (int i = 0; i < nodeList.getLength(); i++) { org.w3c.dom.Element treeNodeElement = (org.w3c.dom.Element) nodeList.item(i); String nodeId = treeNodeElement.getAttribute("id"); @@ -231,11 +272,10 @@ protected void createTree(Node node) throws InvalidFileFormatException { transition.addParent(treeNode); treeNode.addChild(transition); continue; + } else { + throw new InvalidFileFormatException( + "Proof Tree construction error: duplicate transition ID found"); } - else { - throw new InvalidFileFormatException("Proof Tree construction error: duplicate transition ID found"); - } - } String childId = trans.getAttribute("child"); @@ -250,7 +290,8 @@ protected void createTree(Node node) throws InvalidFileFormatException { if (!ruleName.isEmpty()) { rule = puzzle.getRuleByID(ruleId); if (rule == null) { - throw new InvalidFileFormatException("Proof Tree construction error: could not find rule by ID"); + throw new InvalidFileFormatException( + "Proof Tree construction error: could not find rule by ID"); } transition.setRule(rule); } @@ -266,14 +307,17 @@ protected void createTree(Node node) throws InvalidFileFormatException { } } - //validateTreeStructure(treeNodes, treeTransitions); + // validateTreeStructure(treeNodes, treeTransitions); System.err.println("Tree Size: " + treeTransitions.size()); for (Map.Entry entry : nodeChanges.entrySet()) { makeTransitionChanges(entry.getKey(), entry.getValue()); } } - protected void validateTreeStructure(HashMap nodes, HashMap transitions) throws InvalidFileFormatException { + + protected void validateTreeStructure( + HashMap nodes, HashMap transitions) + throws InvalidFileFormatException { Tree tree = puzzle.getTree(); if (tree == null) { @@ -300,25 +344,27 @@ protected void validateTreeStructure(HashMap nodes, HashMap nodes, HashMap mergingNodes = transition.getParents(); List mergingBoards = new ArrayList<>(); @@ -349,7 +405,8 @@ protected void makeTransitionChanges(TreeTransition transition, Node transElemen TreeNode lca = Tree.getLowestCommonAncestor(mergingNodes); if (lca == null) { - throw new InvalidFileFormatException("Proof Tree construction error: unable to find merge node"); + throw new InvalidFileFormatException( + "Proof Tree construction error: unable to find merge node"); } Board lcaBoard = lca.getBoard(); @@ -360,28 +417,32 @@ protected void makeTransitionChanges(TreeTransition transition, Node transElemen if (childNode != null) { childNode.setBoard(mergedBoard.copy()); } - } - else { + } else { NodeList cellList = transElement.getChildNodes(); for (int i = 0; i < cellList.getLength(); i++) { Node node = cellList.item(i); - if (node.getNodeName().equalsIgnoreCase("cell")) { + List elements = getImporterElements(); + if (elements.contains(node.getNodeName().toLowerCase())) { Board board = transition.getBoard(); PuzzleElement cell = puzzle.getFactory().importCell(node, board); board.setPuzzleElement(cell.getIndex(), cell); board.addModifiedData(cell); transition.propagateChange(cell); - } - else { + } else { if (!node.getNodeName().equalsIgnoreCase("#text")) { - throw new InvalidFileFormatException("Proof Tree construction error: unknown node in transition"); + throw new InvalidFileFormatException( + "Proof Tree construction error: unknown node in transition"); } } } } } + /** + * Creates a default proof tree with a single root node. The root node is initialized with the current board state. + * The created tree is then set as the proof tree for the puzzle. + */ protected void createDefaultTree() { TreeNode root = new TreeNode(puzzle.getCurrentBoard()); root.setRoot(true); @@ -391,7 +452,7 @@ protected void createDefaultTree() { } /** - * Gets the result of building the Puzzle + * Gets the result of building the Puzzle object. * * @return puzzle */ diff --git a/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java b/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java index 32f01edbc..c473e0ecd 100644 --- a/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java +++ b/src/main/java/edu/rpi/legup/model/RegisterPuzzle.java @@ -5,8 +5,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Annotation for registering puzzle classes with the puzzle framework. + */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -public @interface RegisterPuzzle { - -} +public @interface RegisterPuzzle {} diff --git a/src/main/java/edu/rpi/legup/model/elements/Element.java b/src/main/java/edu/rpi/legup/model/elements/Element.java index 7ab502c63..0adbbaf91 100644 --- a/src/main/java/edu/rpi/legup/model/elements/Element.java +++ b/src/main/java/edu/rpi/legup/model/elements/Element.java @@ -1,11 +1,13 @@ package edu.rpi.legup.model.elements; -import edu.rpi.legup.model.rules.RuleType; - -import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; +import javax.swing.*; +/** + * The Element class serves as an abstract base class for various elements used in the system. + * It handles basic properties such as ID, name, description, and image associated with the element. + */ @RegisterElement public abstract class Element { protected String elementID; @@ -19,6 +21,14 @@ public abstract class Element { private final String INVALID_USE_MESSAGE; + /** + * Constructs an Element with the specified ID, name, description, and image name + * + * @param elementID Unique identifier for the element + * @param elementName Name of the element + * @param description Description of the element + * @param imageName File name of the image associated with the element + */ public Element(String elementID, String elementName, String description, String imageName) { this.elementID = elementID; this.elementName = elementName; @@ -28,13 +38,17 @@ public Element(String elementID, String elementName, String description, String loadImage(); } + /** + * Loads the image for the element and resizes it to a width of 100 pixels while maintaining aspect ratio + */ private void loadImage() { if (imageName != null) { this.image = new ImageIcon(ClassLoader.getSystemClassLoader().getResource(imageName)); - //Resize images to be 100px wide + // Resize images to be 100px wide Image image = this.image.getImage(); if (this.image.getIconWidth() < 120) return; - int height = (int) (100 * ((double) this.image.getIconHeight() / this.image.getIconWidth())); + int height = + (int) (100 * ((double) this.image.getIconHeight() / this.image.getIconWidth())); if (height == 0) { System.out.println("height is 0 error"); System.out.println("height: " + this.image.getIconHeight()); @@ -48,30 +62,65 @@ private void loadImage() { } } + /** + * Gets the name of the element + * + * @return The name of the element + */ public String getElementName() { return elementName; } + /** + * Sets the name of the element + * + * @param elementName The new name for the element + */ public void setElementName(String elementName) { this.elementName = elementName; } + /** + * Gets the unique identifier of the element + * + * @return The ID of the element + */ public String getElementID() { return elementID; } + /** + * Gets the description of the element + * + * @return The description of the element + */ public String getDescription() { return description; } + /** + * Gets the image icon associated with the element + * + * @return The ImageIcon for the element + */ public ImageIcon getImageIcon() { return image; } + /** + * Gets the type of the element + * + * @return The ElementType of the element + */ public ElementType getElementType() { return elementType; } + /** + * Gets the message for invalid use of the rule + * + * @return The invalid use message + */ public String getInvalidUseOfRuleMessage() { return this.INVALID_USE_MESSAGE; } diff --git a/src/main/java/edu/rpi/legup/model/elements/ElementType.java b/src/main/java/edu/rpi/legup/model/elements/ElementType.java index ea47ca0eb..4fee79d4f 100644 --- a/src/main/java/edu/rpi/legup/model/elements/ElementType.java +++ b/src/main/java/edu/rpi/legup/model/elements/ElementType.java @@ -1,5 +1,9 @@ package edu.rpi.legup.model.elements; +/** + * Enum representing the different types of elements that can be used in the system + */ public enum ElementType { - PLACEABLE, NONPLACEABLE + PLACEABLE + //NONPLACEABLE COMBINED ALL PLACEABLE AND NONPLACEABLE INTO JUST ONE CATEGORY } diff --git a/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java b/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java index 87859991f..019001128 100644 --- a/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/NonPlaceableElement.java @@ -1,8 +1,9 @@ -package edu.rpi.legup.model.elements; - -public abstract class NonPlaceableElement extends Element { - public NonPlaceableElement(String elementID, String elementName, String description, String imageName) { - super(elementID, elementName, description, imageName); - this.elementType = ElementType.NONPLACEABLE; - } -} +//package edu.rpi.legup.model.elements; +// +//public abstract class NonPlaceableElement extends Element { +// public NonPlaceableElement( +// String elementID, String elementName, String description, String imageName) { +// super(elementID, elementName, description, imageName); +// this.elementType = ElementType.PLACEABLE; +// } +//} diff --git a/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java b/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java index 2d018ddbb..79a0dcff8 100644 --- a/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/PlaceableElement.java @@ -1,7 +1,21 @@ package edu.rpi.legup.model.elements; +/** + * Abstract class representing elements that can be placed within the system. + * Inherits from the {@link Element} class and sets the {@link ElementType} to {@link ElementType#PLACEABLE}. + */ public abstract class PlaceableElement extends Element { - public PlaceableElement(String elementID, String elementName, String description, String imageName) { + + /** + * Constructs a PlaceableElement with the specified details + * + * @param elementID Unique identifier for the element + * @param elementName Name of the element + * @param description Description of the element + * @param imageName Name of the image file representing the element + */ + public PlaceableElement( + String elementID, String elementName, String description, String imageName) { super(elementID, elementName, description, imageName); this.elementType = ElementType.PLACEABLE; } diff --git a/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java b/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java index bda3f3070..5f59ad795 100644 --- a/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java +++ b/src/main/java/edu/rpi/legup/model/elements/RegisterElement.java @@ -3,9 +3,12 @@ import java.lang.annotation.*; import java.lang.annotation.ElementType; +/** + * Annotation to mark classes as elements that should be registered. + * This annotation is used to indicate that a class is an element within the system and should be registered + * for use within the application. + */ @Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -public @interface RegisterElement { - -} +public @interface RegisterElement {} diff --git a/src/main/java/edu/rpi/legup/model/gameboard/Board.java b/src/main/java/edu/rpi/legup/model/gameboard/Board.java index 4bf2ff548..4544caa36 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/Board.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/Board.java @@ -5,15 +5,18 @@ import java.util.List; import java.util.Set; +/** + * Abstract class representing a game board. + * This class provides functionality for managing puzzle elements, tracking modifications, + * and determining if the board is modifiable. + */ public abstract class Board { protected List puzzleElements; protected Set modifiedData; protected boolean isModifiable; - /** - * Board Constructor creates an empty board. - */ + /** Board Constructor creates an empty board. */ public Board() { this.puzzleElements = new ArrayList<>(); this.modifiedData = new HashSet<>(); @@ -33,21 +36,24 @@ public Board(int size) { } /** - * Gets a specific {@link PuzzleElement} on this board. + * Gets a specific {@link PuzzleElement} from the board. * - * @param puzzleElement equivalent puzzleElement - * @return equivalent puzzleElement on this board + * @param puzzleElement the puzzle element to retrieve + * @return the puzzle element at the corresponding index, or null if not found */ public PuzzleElement getPuzzleElement(PuzzleElement puzzleElement) { + if (puzzleElement == null) { + return null; + } int index = puzzleElement.getIndex(); return index < puzzleElements.size() ? puzzleElements.get(index) : null; } /** - * Sets a specific {@link PuzzleElement} on the board. + * Sets a specific {@link PuzzleElement} on the board * - * @param index index of the puzzleElement - * @param puzzleElement new puzzleElement at the index + * @param index index of the puzzleElement + * @param puzzleElement the puzzleElement to set at the index */ public void setPuzzleElement(int index, PuzzleElement puzzleElement) { if (index < puzzleElements.size()) { @@ -56,7 +62,7 @@ public void setPuzzleElement(int index, PuzzleElement puzzleElement) { } /** - * Gets the number of elements on the board. + * Gets the number of elements on the board * * @return number of elements on the board */ @@ -139,8 +145,8 @@ public void removeModifiedData(PuzzleElement data) { } /** - * Called when a {@link PuzzleElement} data on this has changed and passes in the equivalent puzzle element with - * the new data. + * Called when a {@link PuzzleElement} data on this has changed and passes in the equivalent + * puzzle element with the new data. * * @param puzzleElement equivalent puzzle element with the new data. */ @@ -150,22 +156,20 @@ public void notifyChange(PuzzleElement puzzleElement) { } /** - * Called when a {@link PuzzleElement} has been added and passes in the equivalent puzzle element with the data. + * Called when a {@link PuzzleElement} has been added and passes in the equivalent puzzle + * element with the data. * * @param puzzleElement equivalent puzzle element with the data. */ - public void notifyAddition(PuzzleElement puzzleElement) { - - } + public void notifyAddition(PuzzleElement puzzleElement) {} /** - * Called when a {@link PuzzleElement} has been deleted and passes in the equivalent puzzle element with the data. + * Called when a {@link PuzzleElement} has been deleted and passes in the equivalent puzzle + * element with the data. * * @param puzzleElement equivalent puzzle element with the data. */ - public void notifyDeletion(PuzzleElement puzzleElement) { - - } + public void notifyDeletion(PuzzleElement puzzleElement) {} @SuppressWarnings("unchecked") public Board mergedBoard(Board lca, List boards) { diff --git a/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java b/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java index 799825025..14dcb8609 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/CaseBoard.java @@ -1,54 +1,112 @@ package edu.rpi.legup.model.gameboard; import edu.rpi.legup.model.rules.CaseRule; - import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; +/** + * Represents a game board with specific rules for selecting puzzle elements. + * Extends the abstract `Board` class and adds functionality for handling pickable elements and case rules. + */ public class CaseBoard extends Board { protected Board baseBoard; protected CaseRule caseRule; protected Set pickablePuzzleElements; + /** + * Constructs a CaseBoard with a base board and a case rule. + * + * @param baseBoard the base board to use for this CaseBoard + * @param caseRule the case rule applied to this CaseBoard + */ public CaseBoard(Board baseBoard, CaseRule caseRule) { this.baseBoard = baseBoard; this.caseRule = caseRule; this.pickablePuzzleElements = new HashSet<>(); } + /** + * Adds a puzzle element to the set of pickable elements. + * + * @param puzzleElement the puzzle element to add + */ public void addPickableElement(PuzzleElement puzzleElement) { pickablePuzzleElements.add(puzzleElement); } + /** + * Removes a puzzle element from the set of pickable elements. + * + * @param puzzleElement the puzzle element to remove + */ public void removePickableElement(PuzzleElement puzzleElement) { pickablePuzzleElements.remove(puzzleElement); } + /** + * Checks if a puzzle element is pickable based on the mouse event. + * + * @param puzzleElement the puzzle element to check + * @param e the mouse event + * @return true if the puzzle element is pickable, false otherwise + */ public boolean isPickable(PuzzleElement puzzleElement, MouseEvent e) { return pickablePuzzleElements.contains(baseBoard.getPuzzleElement(puzzleElement)); } + /** + * Retrieves the base board for this CaseBoard. + * + * @return the base board + */ public Board getBaseBoard() { return baseBoard; } + /** + * Sets the base board for this CaseBoard. + * + * @param baseBoard the new base board + */ public void setBaseBoard(Board baseBoard) { this.baseBoard = baseBoard; } + /** + * Retrieves the case rule for this CaseBoard. + * + * @return the case rule + */ public CaseRule getCaseRule() { return caseRule; } + /** + * Sets the case rule for this CaseBoard. + * + * @param caseRule the new case rule + */ public void setCaseRule(CaseRule caseRule) { this.caseRule = caseRule; } + /** + * Gets the count of pickable puzzle elements. + * + * @return the number of pickable elements + */ public int getCount() { return pickablePuzzleElements.size(); } + + /** + * Performs a deep copy of this CaseBoard. + * CURRENTLY NOT IMPLEMENTED AND RETURNS NULL + * + * @return a new copy of the CaseBoard + */ public CaseBoard copy() { return null; } diff --git a/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java b/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java index 99e9bf65a..131feb122 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/ElementFactory.java @@ -1,28 +1,33 @@ package edu.rpi.legup.model.gameboard; +import edu.rpi.legup.save.InvalidFileFormatException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; -import edu.rpi.legup.save.InvalidFileFormatException; +/** + * ElementFactory is an abstract class for importing and exporting {@link PuzzleElement} instances. + */ public abstract class ElementFactory { /** * Creates a {@link PuzzleElement} based on the xml document Node and adds it to the board. * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node - * @throws InvalidFileFormatException thrown if the xml node is invalid for the specific puzzle element + * @throws InvalidFileFormatException thrown if the xml node is invalid for the specific puzzle + * element */ - public abstract PuzzleElement importCell(Node node, Board board) throws InvalidFileFormatException; + public abstract PuzzleElement importCell(Node node, Board board) + throws InvalidFileFormatException; /** * Creates a xml document {@link PuzzleElement} from a cell for exporting. * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ public abstract Element exportCell(Document document, PuzzleElement puzzleElement); -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java b/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java index d31e8185a..7338132f8 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridBoard.java @@ -1,13 +1,16 @@ package edu.rpi.legup.model.gameboard; import edu.rpi.legup.model.elements.Element; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.TreeTentClue; - import java.awt.*; import java.awt.event.MouseEvent; +/** + * GridBoard represents a grid-based board where each cell can be manipulated based on its + * coordinates. The board supports operations such as getting and setting cells, and provides + * dimensions of the grid. It also supports deep copying of the board. + */ public class GridBoard extends Board { protected Dimension dimension; @@ -15,7 +18,7 @@ public class GridBoard extends Board { /** * GridBoard Constructor creates a board for grid using puzzles from a width and height. * - * @param width width of the board + * @param width width of the board * @param height height of the board */ public GridBoard(int width, int height) { @@ -43,83 +46,88 @@ public GridBoard(int size) { * @return grid cell at location (x, y) */ public GridCell getCell(int x, int y) { - if (y * dimension.width + x >= puzzleElements.size() || x >= dimension.width || - y >= dimension.height || x < 0 || y < 0) { - System.err.printf("not in bounds, bounds are %dx%d\n", dimension.width, dimension.height); + if (y * dimension.width + x >= puzzleElements.size() + || x >= dimension.width + || y >= dimension.height + || x < 0 + || y < 0) { + System.err.printf( + "not in bounds, bounds are %dx%d\n", dimension.width, dimension.height); return null; } return (GridCell) puzzleElements.get(y * dimension.width + x); } /** - * Sets the {@link GridCell} at the location (x,y). This method does not set the cell if the location specified is - * out of bounds. + * Sets the {@link GridCell} at the location (x,y). This method does not set the cell if the + * location specified is out of bounds. * - * @param x x location of the cell - * @param y y location of the cell + * @param x x location of the cell + * @param y y location of the cell * @param cell grid cell to set at location (x,y) */ public void setCell(int x, int y, GridCell cell) { - if (y * dimension.width + x >= puzzleElements.size() || x >= dimension.width || - y >= dimension.height || x < 0 || y < 0) { + if (y * dimension.width + x >= puzzleElements.size() + || x >= dimension.width + || y >= dimension.height + || x < 0 + || y < 0) { return; } puzzleElements.set(y * dimension.width + x, cell); } public void setCell(int x, int y, Element e, MouseEvent m) { - if (this instanceof TreeTentBoard && ((y == dimension.height && 0 <= x && x < dimension.width) || (x == dimension.width && 0 <= y && y < dimension.height))) { + if (this instanceof TreeTentBoard + && ((y == dimension.height && 0 <= x && x < dimension.width) + || (x == dimension.width && 0 <= y && y < dimension.height))) { TreeTentBoard treeTentBoard = ((TreeTentBoard) this); TreeTentClue clue = treeTentBoard.getClue(x, y); if (y == dimension.height) { if (m.getButton() == MouseEvent.BUTTON1) { if (clue.getData() < dimension.height) { clue.setData(clue.getData() + 1); - } - else { + } else { clue.setData(0); } - } - else { + } else { if (clue.getData() > 0) { clue.setData(clue.getData() - 1); - } - else { + } else { clue.setData(dimension.height); } } - } - else { //x == dimension.width + } else { // x == dimension.width if (m.getButton() == MouseEvent.BUTTON1) { if (clue.getData() < dimension.width) { clue.setData(clue.getData() + 1); - } - else { + } else { clue.setData(0); } - } - else { + } else { if (clue.getData() > 0) { clue.setData(clue.getData() - 1); - } - else { + } else { clue.setData(dimension.width); } } } - } - else { - if (e != null && y * dimension.width + x >= puzzleElements.size() || x >= dimension.width || - y >= dimension.height || x < 0 || y < 0) { + } else { + if (e != null && y * dimension.width + x >= puzzleElements.size() + || x >= dimension.width + || y >= dimension.height + || x < 0 + || y < 0) { return; - } - else { + } else { if (e != null) { puzzleElements.get(y * dimension.width + x).setType(e, m); } } } -// puzzleElements.set(y * dimension.width + x, puzzleElements.get(y * dimension.width + x)); + // puzzleElements.set(y * dimension.width + x, puzzleElements.get(y * dimension.width + // + + // x)); } /** @@ -163,4 +171,4 @@ public GridBoard copy() { } return newGridBoard; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java b/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java index 8209c0b6f..5d6fe1ff3 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridCell.java @@ -2,13 +2,20 @@ import java.awt.*; +/** + * GridCell represents a cell within a grid-based board. It holds data of type T and tracks its location + * on the board using a {@link Point}. The class extends from PuzzleElement and supports deep copying of + * the grid cell. + * + * @param the type of data held by the GridCell + */ public class GridCell extends PuzzleElement { protected Point location; /** * GridCell Constructor creates a grid cell at the specified location given as a {@link Point} * - * @param value data value that represents the grid cell + * @param value data value that represents the grid cell * @param location location on the board */ public GridCell(T value, Point location) { @@ -20,8 +27,8 @@ public GridCell(T value, Point location) { * GridCell Constructor creates a grid cell at the specified location given as x,y pair * * @param value data value that represents the grid cell - * @param x x location - * @param y y location + * @param x x location + * @param y y location */ public GridCell(T value, int x, int y) { this(value, new Point(x, y)); @@ -59,4 +66,3 @@ public GridCell copy() { return copy; } } - diff --git a/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java new file mode 100644 index 000000000..b2a10a153 --- /dev/null +++ b/src/main/java/edu/rpi/legup/model/gameboard/GridRegion.java @@ -0,0 +1,56 @@ +package edu.rpi.legup.model.gameboard; + +import java.util.ArrayList; +import java.util.List; + +/** + * GridRegion represents a collection of cells within a grid. It manages a list of cells and provides + * methods to add, remove, and retrieve cells from the region. + * + * @param the type of cell managed by the GridRegion + */ +public abstract class GridRegion { + + protected List regionCells; + + /** Region Constructor */ + public GridRegion() { + this.regionCells = new ArrayList<>(); + } + + /** + * Adds the cell to the region + * + * @param cell cell to be added to the region + */ + public void addCell(T cell) { + regionCells.add(cell); + } + + /** + * Removes the cell from the region + * + * @param cell cell to be removed from the region + */ + public void removeCell(T cell) { + regionCells.remove(cell); + } + + /** + * Returns the list of cells in the region + * + * @return list of cells in region + */ + public List getCells() { + return regionCells; + } + + /** + * Returns the number of cells in the region + * + * @return number of cells in the region + */ + public int getSize() { + return regionCells.size(); + } +} diff --git a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java index 3d84287e3..a92b3efb0 100644 --- a/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java +++ b/src/main/java/edu/rpi/legup/model/gameboard/PuzzleElement.java @@ -1,25 +1,30 @@ package edu.rpi.legup.model.gameboard; import edu.rpi.legup.model.elements.Element; - import java.awt.event.MouseEvent; +/** + * PuzzleElement represents a single element in a puzzle grid. It holds data and provides various + * methods to manage and retrieve its properties, including modifiability, modification status, and validity. + * + * @param the type of data held by the PuzzleElement + */ public abstract class PuzzleElement { protected int index; protected T data; protected boolean isModifiable; protected boolean isModified; + protected boolean isModifiableCaseRule; protected boolean isGiven; protected boolean isValid; protected int casesDepended; - /** - * PuzzleElement Constructor creates a new puzzle element. - */ + /** PuzzleElement Constructor creates a new puzzle element. */ public PuzzleElement() { this.index = -1; this.data = null; this.isModifiable = true; + this.isModifiableCaseRule = true; this.isModified = false; this.isGiven = false; this.isValid = true; @@ -76,6 +81,24 @@ public void setModifiable(boolean isModifiable) { this.isModifiable = isModifiable; } + /** + * Gets whether this puzzle element is modifiable as a result of a case rule. + * + * @return true if this puzzle element is modifiable, false otherwise + */ + public boolean isModifiableCaseRule() { + return isModifiableCaseRule; + } + + /** + * Sets whether this puzzle element is modifiable as a result of a case rule. + * + * @param isModifiableCaseRule true if this puzzle element is modifiable, false otherwise + */ + public void setModifiableCaseRule(boolean isModifiableCaseRule) { + this.isModifiableCaseRule = isModifiableCaseRule; + } + /** * Gets whether the puzzle element has been modified. * @@ -131,8 +154,8 @@ public void setGiven(boolean given) { } /** - * Get whether this puzzle element data is a valid change according to the rule applied to the transition that - * this puzzle element is contained in. + * Get whether this puzzle element data is a valid change according to the rule applied to the + * transition that this puzzle element is contained in. * * @return true if the puzzle element logically follows from the rule, otherwise false. */ @@ -141,8 +164,8 @@ public boolean isValid() { } /** - * Sets whether this puzzle element data is a valid change according to the rule applied to the transition that - * this puzzle element is contained in. + * Sets whether this puzzle element data is a valid change according to the rule applied to the + * transition that this puzzle element is contained in. * * @param isValid true if the puzzle element logically follows from the rule, otherwise false. */ diff --git a/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java b/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java index 461128562..fa440369c 100644 --- a/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java +++ b/src/main/java/edu/rpi/legup/model/observer/IBoardListener.java @@ -4,6 +4,10 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.tree.TreeElement; +/** + * IBoardListener defines methods for receiving notifications about changes to the board, + * including updates to tree elements, case boards, and puzzle elements. + */ public interface IBoardListener { /** * Called when the tree element has changed. @@ -13,7 +17,7 @@ public interface IBoardListener { void onTreeElementChanged(TreeElement treeElement); /** - * Called when the a case board has been added to the view. + * Called when a case board has been added to the view. * * @param caseBoard case board to be added */ diff --git a/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java b/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java index c7bf13141..53bfe444b 100644 --- a/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java +++ b/src/main/java/edu/rpi/legup/model/observer/IBoardSubject.java @@ -2,6 +2,10 @@ import java.util.function.Consumer; +/** + * IBoardSubject defines methods for managing and notifying board listeners. + * It allows for adding and removing listeners, and for notifying them using a specified algorithm. + */ public interface IBoardSubject { /** * Adds a board listener. @@ -18,7 +22,7 @@ public interface IBoardSubject { void removeBoardListener(IBoardListener listener); /** - * Notifies all of the listeners using the specified algorithm. + * Notifies all the listeners using the specified algorithm. * * @param algorithm algorithm used to notify the listeners */ diff --git a/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java b/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java index d8fa24166..c5a0355ca 100644 --- a/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java +++ b/src/main/java/edu/rpi/legup/model/observer/ITreeListener.java @@ -3,6 +3,10 @@ import edu.rpi.legup.model.tree.TreeElement; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; +/** + * ITreeListener defines methods for handling events related to changes in the tree. + * Implementations of this interface are notified of additions, removals, and selection changes in the tree. + */ public interface ITreeListener { /** * Called when a {@link TreeElement} is added to the tree. @@ -25,8 +29,6 @@ public interface ITreeListener { */ void onTreeSelectionChanged(TreeViewSelection selection); - /** - * Called when the model has finished updating the tree. - */ + /** Called when the model has finished updating the tree. */ void onUpdateTree(); } diff --git a/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java b/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java index 66d5d9a5e..0b0aee348 100644 --- a/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java +++ b/src/main/java/edu/rpi/legup/model/observer/ITreeSubject.java @@ -2,9 +2,13 @@ import java.util.function.Consumer; +/** + * ITreeSubject defines methods for managing and notifying listeners about changes to the tree model. + * Implementations of this interface handle adding, removing, and notifying listeners. + */ public interface ITreeSubject { /** - * Adds a board listener. + * Adds a tree listener. * * @param listener listener to add */ @@ -18,7 +22,7 @@ public interface ITreeSubject { void removeTreeListener(ITreeListener listener); /** - * Notifies all of the listeners using the specified algorithm. + * Notifies all the tree listeners using the specified algorithm. * * @param algorithm algorithm used to notify the listeners */ diff --git a/src/main/java/edu/rpi/legup/model/rules/CaseRule.java b/src/main/java/edu/rpi/legup/model/rules/CaseRule.java index a01db2b6d..ee5c91229 100644 --- a/src/main/java/edu/rpi/legup/model/rules/CaseRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/CaseRule.java @@ -1,37 +1,45 @@ package edu.rpi.legup.model.rules; +import static edu.rpi.legup.model.rules.RuleType.CASE; + import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.ArrayList; import java.util.List; import java.util.Set; -import static edu.rpi.legup.model.rules.RuleType.CASE; - +/** + * CaseRule is an abstract class representing a rule that can be applied with multiple cases in a puzzle board. + * It defines methods for applying and checking the rule, as well as retrieving the necessary elements. + */ public abstract class CaseRule extends Rule { private final String INVALID_USE_MESSAGE; + public int MAX_CASES; + public int MIN_CASES; /** * CaseRule Constructor creates a new case rule. * - * @param ruleID ID of the rule - * @param ruleName name of the rule + * @param ruleID ID of the rule + * @param ruleName name of the rule * @param description description of the rule - * @param imageName file name of the image + * @param imageName file name of the image */ public CaseRule(String ruleID, String ruleName, String description, String imageName) { super(ruleID, ruleName, description, imageName); this.ruleType = CASE; this.INVALID_USE_MESSAGE = "Invalid use of the case rule " + this.ruleName; + this.MAX_CASES = 10; + this.MIN_CASES = 1; // By default, this will not actually have any effect } /** - * Gets the case board that indicates where this case rule can be applied on the given {@link Board}. + * Gets the case board that indicates where this case rule can be applied on the given {@link + * Board}. * * @param board board to find locations where this case rule can be applied * @return a case board @@ -39,16 +47,18 @@ public CaseRule(String ruleID, String ruleName, String description, String image public abstract CaseBoard getCaseBoard(Board board); /** - * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on this case rule. + * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on + * this case rule. * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ public abstract List getCases(Board board, PuzzleElement puzzleElement); /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -61,11 +71,11 @@ public String checkRule(TreeTransition transition) { } for (TreeTransition childTrans : parentNodes.get(0).getChildren()) { - if (childTrans.getRule() == null || !childTrans.getRule().getClass().equals(this.getClass())) { + if (childTrans.getRule() == null + || !childTrans.getRule().getClass().equals(this.getClass())) { return "All children nodes must be justified with the same case rule."; } } - String check = checkRuleRaw(transition); // Mark transition and new data as valid or not @@ -81,8 +91,8 @@ public String checkRule(TreeTransition transition) { } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -91,13 +101,13 @@ public String checkRule(TreeTransition transition) { public abstract String checkRuleRaw(TreeTransition transition); /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -105,34 +115,35 @@ public String checkRuleAt(TreeTransition transition, PuzzleElement puzzleElement } /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. This method is the one that should overridden in child classes. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. This method is the one that should overridden in child + * classes. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public abstract String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement); /** - * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid - * Overridden by case rules dependent on more than just the modified data + * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be + * valid Overridden by case rules dependent on more than just the modified data * - * @param board board state at application + * @param board board state at application * @param puzzleElement selected puzzleElement - * @return List of puzzle elements (typically cells) this application of the case rule depends upon. - * Defaults to any element modified by any case + * @return List of puzzle elements (typically cells) this application of the case rule depends + * upon. Defaults to any element modified by any case */ public List dependentElements(Board board, PuzzleElement puzzleElement) { List elements = new ArrayList<>(); - List cases = getCases(board,puzzleElement); + List cases = getCases(board, puzzleElement); for (Board caseBoard : cases) { Set data = caseBoard.getModifiedData(); for (PuzzleElement element : data) { - if(!elements.contains(board.getPuzzleElement(element))){ + if (!elements.contains(board.getPuzzleElement(element))) { elements.add(board.getPuzzleElement(element)); } } @@ -141,5 +152,3 @@ public List dependentElements(Board board, PuzzleElement puzzleEl return elements; } } - - diff --git a/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java b/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java index 0d3a79a98..cd2e20081 100644 --- a/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/ContradictionRule.java @@ -1,22 +1,27 @@ package edu.rpi.legup.model.rules; +import static edu.rpi.legup.model.rules.RuleType.CONTRADICTION; + import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.tree.TreeTransition; -import static edu.rpi.legup.model.rules.RuleType.CONTRADICTION; - +/** + * ContradictionRule is an abstract class representing a rule that identifies contradictions in a puzzle. + * It provides methods to check for contradictions both globally and at specific puzzle elements. + */ public abstract class ContradictionRule extends Rule { - private final String NO_CONTRADICTION_MESSAGE = "No instance of the contradiction " + this.ruleName + " here"; + private final String NO_CONTRADICTION_MESSAGE = + "No instance of the contradiction " + this.ruleName + " here"; /** * ContradictionRule Constructor creates a new contradiction rule * - * @param ruleID ID of the rule - * @param ruleName name of the rule + * @param ruleID ID of the rule + * @param ruleName name of the rule * @param description description of the rule - * @param imageName file name of the image + * @param imageName file name of the image */ public ContradictionRule(String ruleID, String ruleName, String description, String imageName) { super(ruleID, ruleName, description, imageName); @@ -35,13 +40,13 @@ public String checkRule(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -49,8 +54,8 @@ public String checkRuleAt(TreeTransition transition, PuzzleElement puzzleElement } /** - * Checks whether the transition logically follows from the parent node using this rule. - * This method is the one that should overridden in child classes + * Checks whether the transition logically follows from the parent node using this rule. This + * method is the one that should overridden in child classes * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -61,14 +66,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -96,13 +101,13 @@ public String getNoContradictionMessage() { } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ public abstract String checkContradictionAt(Board board, PuzzleElement puzzleElement); - } diff --git a/src/main/java/edu/rpi/legup/model/rules/DirectRule.java b/src/main/java/edu/rpi/legup/model/rules/DirectRule.java index 847764b7b..613574989 100644 --- a/src/main/java/edu/rpi/legup/model/rules/DirectRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/DirectRule.java @@ -1,105 +1,108 @@ -package edu.rpi.legup.model.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -import static edu.rpi.legup.model.rules.RuleType.BASIC; - -public abstract class DirectRule extends Rule { - /** - * DirectRule Constructor creates a new basic rule. - * - * @param ruleID ID of the rule - * @param ruleName name of the rule - * @param description description of the rule - * @param imageName file name of the image - */ - public DirectRule(String ruleID, String ruleName, String description, String imageName) { - super(ruleID, ruleName, description, imageName); - this.ruleType = BASIC; - } - - /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. - * - * @param transition transition to check - * @return null if the child node logically follow from the parent node, otherwise error message - */ - public String checkRule(TreeTransition transition) { - Board finalBoard = transition.getBoard(); - if (transition.getParents().size() != 1 || - transition.getParents().get(0).getChildren().size() != 1) { - return "State must have only 1 parent and 1 child"; - } - else if (finalBoard.getModifiedData().isEmpty()) { - // null transition - return null; - } - else { - return checkRuleRaw(transition); - } - } - - /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. - * - * @param transition transition to check - * @return null if the child node logically follow from the parent node, otherwise error message - */ - public String checkRuleRaw(TreeTransition transition) { - Board finalBoard = transition.getBoard(); - String checkStr = null; - - // Go directly to specific direct rule's judgement if no cell's are edited - if (finalBoard.getModifiedData().size() == 0) { - checkStr = checkRuleRawAt(transition, null); - } - for (PuzzleElement puzzleElement : finalBoard.getModifiedData()) { - String tempStr = checkRuleAt(transition, puzzleElement); - if (tempStr != null) { - checkStr = tempStr; - } - } - return checkStr; - } - - /** - * Checks whether the child node logically follows from the parent node at the specific {@link PuzzleElement} using - * this rule. - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - public String checkRuleAt(TreeTransition transition, PuzzleElement puzzleElement) { - Board finalBoard = transition.getBoard(); - puzzleElement = finalBoard.getPuzzleElement(puzzleElement); - String checkStr; - if (!puzzleElement.isModified()) { - checkStr = "PuzzleElement must be modified"; - } - else { - if (transition.getParents().size() != 1 || - transition.getParents().get(0).getChildren().size() != 1) { - checkStr = "State must have only 1 parent and 1 child"; - } - else { - checkStr = checkRuleRawAt(transition, puzzleElement); - } - } - puzzleElement.setValid(checkStr == null); - return checkStr; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - public abstract Board getDefaultBoard(TreeNode node); -} +package edu.rpi.legup.model.rules; + +import static edu.rpi.legup.model.rules.RuleType.BASIC; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +/** + * DirectRule is an abstract class representing a direct rule for transitions in a puzzle. + * It provides methods for checking whether transitions and specific puzzle elements follow the rule. + */ +public abstract class DirectRule extends Rule { + /** + * DirectRule Constructor creates a new basic rule. + * + * @param ruleID ID of the rule + * @param ruleName name of the rule + * @param description description of the rule + * @param imageName file name of the image + */ + public DirectRule(String ruleID, String ruleName, String description, String imageName) { + super(ruleID, ruleName, description, imageName); + this.ruleType = BASIC; + } + + /** + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + public String checkRule(TreeTransition transition) { + Board finalBoard = transition.getBoard(); + // System.out.println(finalBoard.getModifiedData().size()); + if (transition.getParents().size() != 1 + || transition.getParents().get(0).getChildren().size() != 1) { + return "State must have only 1 parent and 1 child"; + } else if (finalBoard.getModifiedData().isEmpty()) { + // null transition + return null; + } else { + return checkRuleRaw(transition); + } + } + + /** + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + public String checkRuleRaw(TreeTransition transition) { + Board finalBoard = transition.getBoard(); + String checkStr = null; + + // Go directly to specific direct rule's judgement if no cell's are edited + if (finalBoard.getModifiedData().size() == 0) { + checkStr = checkRuleRawAt(transition, null); + } + for (PuzzleElement puzzleElement : finalBoard.getModifiedData()) { + String tempStr = checkRuleAt(transition, puzzleElement); + if (tempStr != null) { + checkStr = tempStr; + } + } + return checkStr; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific {@link + * PuzzleElement} using this rule. + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + public String checkRuleAt(TreeTransition transition, PuzzleElement puzzleElement) { + Board finalBoard = transition.getBoard(); + puzzleElement = finalBoard.getPuzzleElement(puzzleElement); + String checkStr; + if (!puzzleElement.isModified()) { + checkStr = "PuzzleElement must be modified"; + } else { + if (transition.getParents().size() != 1 + || transition.getParents().get(0).getChildren().size() != 1) { + checkStr = "State must have only 1 parent and 1 child"; + } else { + checkStr = checkRuleRawAt(transition, puzzleElement); + } + } + puzzleElement.setValid(checkStr == null); + return checkStr; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + public abstract Board getDefaultBoard(TreeNode node); +} diff --git a/src/main/java/edu/rpi/legup/model/rules/MergeRule.java b/src/main/java/edu/rpi/legup/model/rules/MergeRule.java index 9ae18648e..f7bd887f3 100644 --- a/src/main/java/edu/rpi/legup/model/rules/MergeRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/MergeRule.java @@ -1,33 +1,33 @@ package edu.rpi.legup.model.rules; +import static edu.rpi.legup.model.rules.RuleType.MERGE; + import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.tree.Tree; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.ArrayList; import java.util.List; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import static edu.rpi.legup.model.rules.RuleType.MERGE; - +/** + * MergeRule is an implementation of a rule that merges multiple nodes into one. + * It validates if the merging of nodes is done correctly. + */ public class MergeRule extends Rule { - /** - * MergeRule Constructor merges to board states together - */ + /** MergeRule Constructor merges to board states together */ public MergeRule() { - super("MERGE", "Merge Rule", + super( + "MERGE", + "Merge Rule", "Merge any number of nodes into one", "edu/rpi/legup/images/Legup/MergeRule.png"); this.ruleType = MERGE; } /** - * Checks whether the transition logically follows from the parent node using this rule. - * This method is the one that should overridden in child classes + * Checks whether the transition logically follows from the parent node using this rule. This + * method is the one that should have overridden in child classes * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -61,14 +61,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -87,13 +87,13 @@ public String checkRule(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleAt(TreeTransition transition, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java b/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java index 40def6edd..d357e0d86 100644 --- a/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java +++ b/src/main/java/edu/rpi/legup/model/rules/RegisterRule.java @@ -2,9 +2,12 @@ import java.lang.annotation.*; +/** + * Annotation to register a class as a rule in the system. + * This annotation can be applied to rule classes to indicate that they should be registered + * in the rule system. + */ @Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -public @interface RegisterRule { - -} +public @interface RegisterRule {} diff --git a/src/main/java/edu/rpi/legup/model/rules/Rule.java b/src/main/java/edu/rpi/legup/model/rules/Rule.java index 50f2cf962..107e72712 100644 --- a/src/main/java/edu/rpi/legup/model/rules/Rule.java +++ b/src/main/java/edu/rpi/legup/model/rules/Rule.java @@ -1,18 +1,19 @@ package edu.rpi.legup.model.rules; +import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.tree.TreeTransition; - -import edu.rpi.legup.app.LegupPreferences; - -import javax.swing.ImageIcon; -import java.awt.image.BufferedImage; -import java.awt.Image; import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; +import javax.swing.ImageIcon; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - +/** + * Abstract base class for defining rules. + * This class encapsulates the common functionality and attributes of all rules, + * including rule identification, description, image handling, and validation logic. + * Subclasses must provide implementations for specific rule checking logic. + */ @RegisterRule public abstract class Rule { protected String ruleID; @@ -27,10 +28,10 @@ public abstract class Rule { /** * Rule Constructor creates a new rule * - * @param ruleID ID of the rule - * @param ruleName name of the rule + * @param ruleID ID of the rule + * @param ruleName name of the rule * @param description description of the rule - * @param imageName file name of the image + * @param imageName file name of the image */ public Rule(String ruleID, String ruleName, String description, String imageName) { this.ruleID = ruleID; @@ -50,8 +51,8 @@ public Rule(String ruleID, String ruleName, String description, String imageName public abstract String checkRule(TreeTransition transition); /** - * Checks whether the transition logically follows from the parent node using this rule. - * This method is the one that should overridden in child classes + * Checks whether the transition logically follows from the parent node using this rule. This + * method is the one that should overridden in child classes * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -59,43 +60,44 @@ public Rule(String ruleID, String ruleName, String description, String imageName protected abstract String checkRuleRaw(TreeTransition transition); /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ public abstract String checkRuleAt(TreeTransition transition, PuzzleElement puzzleElement); /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ - protected abstract String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement); + protected abstract String checkRuleRawAt( + TreeTransition transition, PuzzleElement puzzleElement); - /** - * Loads the image file - */ + /** Loads the image file */ public void loadImage() { if (imageName != null) { String name = imageName; LegupPreferences prefs = LegupPreferences.getInstance(); - if (name.contains("shorttruthtable") && prefs.getUserPref(LegupPreferences.COLOR_BLIND).equals("true")) { + if (name.contains("shorttruthtable") + && prefs.getUserPref(LegupPreferences.COLOR_BLIND).equals("true")) { name = name.replace("ruleimages", "ruleimages_cb"); } this.image = new ImageIcon(ClassLoader.getSystemClassLoader().getResource(name)); - //Resize images to be 100px wide + // Resize images to be 100px wide Image image = this.image.getImage(); if (this.image.getIconWidth() < 120) return; - int height = (int) (100 * ((double) this.image.getIconHeight() / this.image.getIconWidth())); + int height = + (int) (100 * ((double) this.image.getIconHeight() / this.image.getIconWidth())); if (height == 0) { System.out.println("height is 0 error"); System.out.println("height: " + this.image.getIconHeight()); @@ -163,7 +165,12 @@ public RuleType getRuleType() { return ruleType; } + /** + * Gets the message indicating an invalid use of the rule. + * + * @return the invalid use message + */ public String getInvalidUseOfRuleMessage() { return this.INVALID_USE_MESSAGE; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/model/rules/RuleType.java b/src/main/java/edu/rpi/legup/model/rules/RuleType.java index b7ce315cf..e72118e3c 100644 --- a/src/main/java/edu/rpi/legup/model/rules/RuleType.java +++ b/src/main/java/edu/rpi/legup/model/rules/RuleType.java @@ -1,5 +1,12 @@ package edu.rpi.legup.model.rules; +/** + * Enumeration representing different types of rules in the rule-based system. + * This enum categorizes rules into various types based on their functionality and application. + */ public enum RuleType { - BASIC, CASE, CONTRADICTION, MERGE + BASIC, + CASE, + CONTRADICTION, + MERGE } diff --git a/src/main/java/edu/rpi/legup/model/tree/Tree.java b/src/main/java/edu/rpi/legup/model/tree/Tree.java index 79c0bcece..3e68015a1 100644 --- a/src/main/java/edu/rpi/legup/model/tree/Tree.java +++ b/src/main/java/edu/rpi/legup/model/tree/Tree.java @@ -1,12 +1,20 @@ package edu.rpi.legup.model.tree; +import edu.rpi.legup.controller.TreeController; import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +/** + * Represents a tree structure in a puzzle. + * The tree consists of {@link TreeNode}s and {@link TreeTransition}s + * and allows adding, removing, and validating elements. + */ public class Tree { private TreeNode rootNode; @@ -20,13 +28,17 @@ public Tree(Board initBoard) { this.rootNode.setRoot(true); } - /** - * Tree Constructor creates the tree structure with null root node - */ + /** Tree Constructor creates the tree structure with null root node */ public Tree() { this.rootNode = null; } + /** + * Adds a new transition to the specified node. + * + * @param treeNode the node to add a transition to + * @return the created transition + */ public TreeTransition addNewTransition(TreeNode treeNode) { TreeTransition transition = new TreeTransition(treeNode, treeNode.getBoard().copy()); treeNode.addChild(transition); @@ -34,53 +46,76 @@ public TreeTransition addNewTransition(TreeNode treeNode) { return transition; } - public TreeNode addNode(TreeTransition transition) { - TreeNode treeNode = new TreeNode(transition.getBoard().copy()); - transition.setChildNode(treeNode); - treeNode.setParent(transition); - return treeNode; - } - + /** + * Adds a tree element (node or transition) to the tree. + * + * @param element the tree element to add + * @return the added tree element + */ public TreeElement addTreeElement(TreeElement element) { if (element.getType() == TreeElementType.NODE) { TreeNode treeNode = (TreeNode) element; - return addTreeElement(treeNode, new TreeTransition(treeNode, treeNode.getBoard().copy())); - } - else { + return addTreeElement( + treeNode, new TreeTransition(treeNode, treeNode.getBoard().copy())); + } else { TreeTransition transition = (TreeTransition) element; Board copyBoard = transition.board.copy(); - copyBoard.setModifiable(false); + copyBoard.setModifiable(true); return addTreeElement(transition, new TreeNode(copyBoard)); } } + /** + * Adds a tree node and its associated transition to the tree. + * + * @param treeNode the tree node to add + * @param transition the transition to associate with the node + * @return the added transition + */ public TreeElement addTreeElement(TreeNode treeNode, TreeTransition transition) { treeNode.addChild(transition); treeNode.getChildren().forEach(TreeTransition::reverify); return transition; } + /** + * Adds a transition and its associated tree node to the tree. + * + * @param transition the transition to add + * @param treeNode the tree node to associate with the transition + * @return the added tree node + */ public TreeElement addTreeElement(TreeTransition transition, TreeNode treeNode) { transition.setChildNode(treeNode); treeNode.setParent(transition); return treeNode; } + /** + * Removes a tree element (node or transition) from the tree. + * + * @param element the tree element to remove + */ public void removeTreeElement(TreeElement element) { if (element.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) element; + + node.getParent().removeChild(node); node.getParent().setChildNode(null); - } - else { + } else { TreeTransition transition = (TreeTransition) element; + transition.getParents().forEach(n -> n.removeChild(transition)); + TreeController treeController = new TreeController(); + TreeView treeView = new TreeView(treeController); + treeView.removeTreeTransition(transition); transition.getParents().get(0).getChildren().forEach(TreeTransition::reverify); } } /** - * Determines if the tree is valid by checking whether this tree puzzleElement and - * all descendants of this tree puzzleElement is justified and justified correctly + * Determines if the tree is valid by checking whether this tree puzzleElement and all + * descendants of this tree puzzleElement is justified and justified correctly * * @return true if tree is valid, false otherwise */ @@ -100,10 +135,10 @@ public Set getLeafTreeElements() { } /** - * Gets a Set of TreeNodes that are leaf nodes from the sub tree rooted at the specified node + * Gets a Set of TreeNodes that are leaf nodes from the subtree rooted at the specified node * * @param node node that is input - * @return Set of TreeNodes that are leaf nodes from the sub tree + * @return Set of TreeNodes that are leaf nodes from the subtree */ public Set getLeafTreeElements(TreeNode node) { Set leafs = new HashSet<>(); @@ -114,7 +149,7 @@ public Set getLeafTreeElements(TreeNode node) { /** * Recursively gets a Set of TreeNodes that are leaf nodes * - * @param leafs Set of TreeNodes that are leaf nodes + * @param leafs Set of TreeNodes that are leaf nodes * @param element current TreeNode being evaluated */ private void getLeafTreeElements(Set leafs, TreeElement element) { @@ -123,41 +158,37 @@ private void getLeafTreeElements(Set leafs, TreeElement element) { List childTrans = node.getChildren(); if (childTrans.isEmpty()) { leafs.add(node); - } - else { + } else { childTrans.forEach(t -> getLeafTreeElements(leafs, t)); } - } - else { + } else { TreeTransition transition = (TreeTransition) element; TreeNode childNode = transition.getChildNode(); if (childNode == null) { leafs.add(transition); - } - else { + } else { getLeafTreeElements(leafs, childNode); } } } /** - * Gets the lowest common ancestor (LCA) among the list of {@link TreeNode} passed into - * the function. This lowest common ancestor is the most immediate ancestor - * node such that the list of tree nodes specified are descendants of the node. - * This will return null if no such ancestor exists + * Gets the lowest common ancestor (LCA) among the list of {@link TreeNode} passed into the + * function. This lowest common ancestor is the most immediate ancestor node such that the list + * of tree nodes specified are descendants of the node. This will return null if no such + * ancestor exists * * @param nodes list of tree nodes to find the LCA - * @return the first ancestor node that all tree nodes have in common, otherwise null if none exists + * @return the first ancestor node that all tree nodes have in common, otherwise null if none + * exists */ public static TreeNode getLowestCommonAncestor(List nodes) { if (nodes.isEmpty()) { return null; - } - else { + } else { if (nodes.size() == 1) { return nodes.get(0); - } - else { + } else { List> ancestors = new ArrayList<>(); for (TreeNode node : nodes) { ancestors.add(node.getAncestors()); diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeElement.java b/src/main/java/edu/rpi/legup/model/tree/TreeElement.java index 17168ac98..2f6f45e4d 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeElement.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeElement.java @@ -2,6 +2,9 @@ import edu.rpi.legup.model.gameboard.Board; +/** + * Represents an element in a tree structure, which can be either a {@link TreeNode} or a {@link TreeTransition}. + */ public abstract class TreeElement { protected TreeElementType type; protected Board board; @@ -16,27 +19,28 @@ public TreeElement(TreeElementType type) { } /** - * Determines if this tree node leads to a contradiction. Every path from this tree node - * must lead to a contradiction including all of its children + * Determines if this tree node leads to a contradiction. Every path from this tree node must + * lead to a contradiction including all of its children * * @return true if this tree node leads to a contradiction, false otherwise */ public abstract boolean isContradictoryBranch(); /** - * Recursively determines if the sub-tree rooted at this tree puzzleElement is valid by checking + * Recursively determines if the subtree rooted at this tree puzzleElement is valid by checking * whether this tree puzzleElement and all descendants of this tree puzzleElement is justified * and justified correctly * - * @return true if this tree puzzleElement and all descendants of this tree puzzleElement is valid, - * false otherwise + * @return true if this tree puzzleElement and all descendants of this tree puzzleElement is + * valid, false otherwise */ public abstract boolean isValidBranch(); /** * Gets the type of tree puzzleElement * - * @return NODE if this tree puzzleElement is a tree node, TRANSITION, if this tree puzzleElement is a transition + * @return NODE if this tree puzzleElement is a tree node, TRANSITION, if this tree + * puzzleElement is a transition */ public TreeElementType getType() { return type; diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java b/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java index ad93f16b6..3a6dbb124 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeElementType.java @@ -1,5 +1,10 @@ package edu.rpi.legup.model.tree; +/** + * Enum representing the type of a tree element. + * Tree elements can be either nodes or transitions in the tree structure. + */ public enum TreeElementType { - NODE, TRANSITION + NODE, + TRANSITION } diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeNode.java b/src/main/java/edu/rpi/legup/model/tree/TreeNode.java index 59f6e736e..85a5e717b 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeNode.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeNode.java @@ -2,9 +2,13 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.utility.DisjointSets; - import java.util.*; +/** + * Represents a node in a tree structure. Extends {@link TreeElement}. + * A {@code TreeNode} contains a board, references to its parent and children transitions, and indicates + * if it is the root node of the tree. + */ public class TreeNode extends TreeElement { private TreeTransition parent; private List children; @@ -24,8 +28,8 @@ public TreeNode(Board board) { } /** - * Determines if this tree node leads to a contradiction. Every path from this tree node - * must lead to a contradiction including all of its children + * Determines if this tree node leads to a contradiction. Every path from this tree node must + * lead to a contradiction including all of its children * * @return true if this tree node leads to a contradiction, false otherwise */ @@ -43,8 +47,8 @@ public boolean isContradictoryBranch() { * whether this tree puzzleElement and all descendants of this tree puzzleElement is justified * and justified correctly * - * @return true if this tree puzzleElement and all descendants of this tree puzzleElement is valid, - * false otherwise + * @return true if this tree puzzleElement and all descendants of this tree puzzleElement is + * valid, false otherwise */ @Override public boolean isValidBranch() { @@ -57,9 +61,9 @@ public boolean isValidBranch() { } /** - * Gets all of the ancestors of this node + * Gets a list of the ancestors of this node * - * @return list of all of the ancestors for this node + * @return list of all the ancestors for this node */ public List getAncestors() { List ancestors = new ArrayList<>(); @@ -104,8 +108,7 @@ public List getDescendants() { it.add(transition); } } - } - else { + } else { TreeTransition trans = (TreeTransition) next; TreeNode childNode = trans.getChildNode(); if (childNode != null && !descendants.contains(childNode)) { @@ -118,9 +121,9 @@ public List getDescendants() { } /** - * Gets a DisjointSets containing the children of this node such that the sets contained within the DisjointSets - * are such that elements in the same set are branches of this tree node that will eventually merge. This could - * mean that multiple merges take place before this happens. + * Gets a DisjointSets containing the children of this node such that the sets contained within + * the DisjointSets are such that elements in the same set are branches of this tree node that + * will eventually merge. This could mean that multiple merges take place before this happens. * * @return DisjointSets of tree transitions containing unique non-merging branches */ @@ -143,8 +146,7 @@ public DisjointSets findMergingBranches() { if (element.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) element; nodes.addAll(node.getChildren()); - } - else { + } else { TreeTransition childTran = (TreeTransition) element; if (childTran.getChildNode() != null) { nodes.add(childTran.getChildNode()); @@ -169,8 +171,8 @@ public DisjointSets findMergingBranches() { } /** - * Finds the point at which the set of tree elements passed in will merge. This must be a set gotten from - * findMergingBranches method DisjointSets + * Finds the point at which the set of tree elements passed in will merge. This must be a set + * gotten from findMergingBranches method DisjointSets * * @param branches tree elements to find the merging point * @return tree transition of the merging point or null if no such point exists @@ -186,14 +188,15 @@ public static TreeTransition findMergingPoint(Set branche mergeSet.createSet(element); if (element.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) element; - node.getDescendants().forEach((TreeElement e) -> { - if (!mergeSet.contains(e)) { - mergeSet.createSet(e); - } - mergeSet.union(element, e); - }); - } - else { + node.getDescendants() + .forEach( + (TreeElement e) -> { + if (!mergeSet.contains(e)) { + mergeSet.createSet(e); + } + mergeSet.union(element, e); + }); + } else { TreeTransition transition = (TreeTransition) element; TreeNode childNode = transition.getChildNode(); if (childNode != null) { @@ -228,8 +231,7 @@ public static TreeTransition findMergingPoint(Set branche if (element.getType() == TreeElementType.NODE) { TreeNode node = (TreeNode) element; next.addAll(node.getChildren()); - } - else { + } else { TreeTransition tran = (TreeTransition) element; next.add(tran.getChildNode()); } @@ -329,8 +331,11 @@ public void setRoot(boolean isRoot) { this.isRoot = isRoot; } + /** + * Clears all children transitions from this tree node. + * After calling this method, the node will have no child transitions. + */ public void clearChildren() { this.children.clear(); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java b/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java index 72572ac72..9e441ac55 100644 --- a/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java +++ b/src/main/java/edu/rpi/legup/model/tree/TreeTransition.java @@ -5,10 +5,14 @@ import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.model.rules.RuleType; - import java.util.ArrayList; import java.util.List; +/** + * Represents a transition between two nodes in a tree structure within a game. + * A transition is responsible for propagating changes through the tree and managing + * and verifying the associated rules and puzzle elements. + */ public class TreeTransition extends TreeElement { private ArrayList parents; private TreeNode childNode; @@ -38,7 +42,7 @@ public TreeTransition(Board board) { * TreeTransition Constructor - create a transition from one node to another * * @param parent parent tree node associated with the transition - * @param board board state of the transition + * @param board board state of the transition */ public TreeTransition(TreeNode parent, Board board) { this(board); @@ -71,8 +75,7 @@ public void propagateChange(PuzzleElement element) { board.removeModifiedData(element); board.notifyChange(element); changed = true; - } - else { + } else { if (!lcaElement.equalsData(element)) { mergedData.setData(element.getData()); board.addModifiedData(mergedData); @@ -89,8 +92,7 @@ public void propagateChange(PuzzleElement element) { } } } - } - else { + } else { // Overwrite previous modifications to this element board.removeModifiedData(board.getPuzzleElement(element)); @@ -98,7 +100,8 @@ public void propagateChange(PuzzleElement element) { board.notifyChange(element); // mark first transition as modified - if (!board.getPuzzleElement(element).equalsData(parents.get(0).getBoard().getPuzzleElement(element))) { + if (!board.getPuzzleElement(element) + .equalsData(parents.get(0).getBoard().getPuzzleElement(element))) { board.addModifiedData(element); } @@ -116,8 +119,7 @@ public void propagateChange(PuzzleElement element) { // Set as modifiable if reverted to starting value (and started modifiable) if (headBoard.getPuzzleElement(element).equalsData(element)) { copy.setModifiable(headBoard.getPuzzleElement(element).isModifiable()); - } - else{ + } else { copy.setModifiable(false); } @@ -159,8 +161,7 @@ public void propagateAddition(PuzzleElement element) { board.removeModifiedData(element); board.notifyDeletion(element); changed = true; - } - else { + } else { if (!lcaElement.equalsData(element)) { mergedData.setData(element.getData()); board.addModifiedData(mergedData); @@ -175,8 +176,7 @@ public void propagateAddition(PuzzleElement element) { } } } - } - else { + } else { if (childNode != null) { board.notifyAddition(element); childNode.getBoard().notifyAddition(element.copy()); @@ -214,8 +214,7 @@ public void propagateDeletion(PuzzleElement element) { board.removeModifiedData(element); board.notifyDeletion(element); changed = true; - } - else { + } else { if (!lcaElement.equalsData(element)) { mergedData.setData(element.getData()); board.addModifiedData(mergedData); @@ -230,8 +229,7 @@ public void propagateDeletion(PuzzleElement element) { } } } - } - else { + } else { if (childNode != null) { board.notifyDeletion(element); childNode.getBoard().notifyDeletion(element.copy()); @@ -244,8 +242,8 @@ public void propagateDeletion(PuzzleElement element) { } /** - * Determines if this tree node leads to a contradiction. Every path from this tree node - * must lead to a contradiction including all of its children + * Determines if this tree node leads to a contradiction. Every path from this tree node must + * lead to a contradiction including all of its children * * @return true if this tree node leads to a contradiction, false otherwise */ @@ -253,12 +251,10 @@ public void propagateDeletion(PuzzleElement element) { public boolean isContradictoryBranch() { if (isJustified() && isCorrect() && rule.getRuleType() == RuleType.CONTRADICTION) { return true; - } - else { + } else { if (childNode == null) { return false; - } - else { + } else { return childNode.isContradictoryBranch() && isJustified() && isCorrect(); } } @@ -269,8 +265,8 @@ public boolean isContradictoryBranch() { * whether this tree puzzleElement and all descendants of this tree puzzleElement is justified * and justified correctly * - * @return true if this tree puzzleElement and all descendants of this tree puzzleElement is valid, - * false otherwise + * @return true if this tree puzzleElement and all descendants of this tree puzzleElement is + * valid, false otherwise */ @Override public boolean isValidBranch() { @@ -341,6 +337,25 @@ public void setChildNode(TreeNode childNode) { this.childNode = childNode; } + /** + * Removes the child to this tree transition + * + * @param child child to remove + */ + public void removeChild(TreeNode child) { + parents.remove(child); + } + + /** + * Add the child to this tree transition + * + * @param child child to add + */ + public void addChild(TreeNode child) { + parents.add(child); + } + + /** * Gets the rule associated with this transition * diff --git a/src/main/java/edu/rpi/legup/puzzle/PuzzleElementTypes.java b/src/main/java/edu/rpi/legup/puzzle/PuzzleElementTypes.java index f2ddb056c..f0dd5a6e9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/PuzzleElementTypes.java +++ b/src/main/java/edu/rpi/legup/puzzle/PuzzleElementTypes.java @@ -1,4 +1,3 @@ package edu.rpi.legup.puzzle; -public enum PuzzleElementTypes { -} +public enum PuzzleElementTypes {} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/Battleship.java b/src/main/java/edu/rpi/legup/puzzle/battleship/Battleship.java index 22a980251..41af3f626 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/Battleship.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/Battleship.java @@ -17,9 +17,7 @@ public Battleship() { this.factory = new BattleshipCellFactory(); } - /** - * Initializes the game board. Called by the invoker of the class - */ + /** Initializes the game board. Called by the invoker of the class */ @Override public void initializeView() { boardView = new BattleshipView((BattleshipBoard) currentBoard); @@ -35,8 +33,8 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Battleship * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Battleship, false otherwise */ public boolean isValidDimensions(int rows, int columns) { @@ -74,84 +72,98 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { + public void onBoardChange(Board board) {} - } -// -// @Override -// public void onTreeSelectionChange(ArrayList newSelection) -// { -// -// } + // + // @Override + // public void onTreeSelectionChange(ArrayList newSelection) + // { + // + // } @Override public void importPuzzle(String fileName) { -// if(fileName != null) -// { -// InputStream inputStream = new FileInputStream(fileName); -// DocumentBuilder builder = null;//factory.newDocumentBuilder(); -// Document document = builder.parse(inputStream); -// -// BattleShipBoard battleShipBoard; -// -// PuzzleElement rootNode = document.getDocumentElement(); -// PuzzleElement puzzleElement = (PuzzleElement) rootNode.getElementsByTagName("edu.rpi.legup.puzzle").item(0); -// PuzzleElement boardElement = (PuzzleElement) puzzleElement.getElementsByTagName("board").item(0); -// PuzzleElement axesElement = (PuzzleElement) boardElement.getElementsByTagName("axes").item(0); -// PuzzleElement shipElement = (PuzzleElement) boardElement.getElementsByTagName("ships").item(0); -// PuzzleElement cellElement = (PuzzleElement) boardElement.getElementsByTagName("cells").item(0); -// PuzzleElement rightElement = (PuzzleElement) axesElement.getElementsByTagName("right").item(0); -// PuzzleElement bottomElement = (PuzzleElement) axesElement.getElementsByTagName("bottom").item(0); -// NodeList rightClueList = rightElement.getElementsByTagName("clue"); -// NodeList bottomClueList = bottomElement.getElementsByTagName("clue"); -// NodeList shipList = shipElement.getElementsByTagName("ship"); -// NodeList cells = cellElement.getElementsByTagName("cell"); -// -// int size = Integer.valueOf(boardElement.getAttribute("size")); -// battleShipBoard = new BattleShipBoard(size); -// -// ArrayList battleShipData = new ArrayList<>(); -// for(int i = 0; i < size * size; i++) -// { -// battleShipData.add(null); -// } -// -// for (int i = 0; i < rightClueList.getLength(); i++) { -// battleShipBoard.getRight()[i] = Integer.valueOf(rightClueList.item(i).getAttributes().getNamedItem("value").getNodeValue()); -// } -// -// for (int i = 0; i < bottomClueList.getLength(); i++) { -// battleShipBoard.getBottom()[i] = Integer.valueOf(bottomClueList.item(i).getAttributes().getNamedItem("value").getNodeValue()); -// } -// -// for (int i = 0; i < shipList.getLength(); i++) { -// int length = Integer.valueOf(shipList.item(i).getAttributes().getNamedItem("length").getNodeValue()); -// int count = Integer.valueOf(shipList.item(i).getAttributes().getNamedItem("count").getNodeValue()); -// battleShipBoard.getShips().add(new Ship(length, count)); -// } -// -// for (int i = 0; i < cells.getLength(); i++) { -// int x = Integer.valueOf(cells.item(i).getAttributes().getNamedItem("x").getNodeValue()); -// int y = Integer.valueOf(cells.item(i).getAttributes().getNamedItem("y").getNodeValue()); -// String value = cells.item(i).getAttributes().getNamedItem("value").getNodeValue().toUpperCase(); -// -// BattleShipCell cell = new BattleShipCell(BattleShipType.valueOf(value).ordinal(), new Point(x, y)); -// battleShipBoard.setCell(x, y, cell); -// cell.setModifiable(false); -// cell.setGiven(true); -// } -// -// for (int x = 0; x < size; x++) { -// for (int y = 0; y < size; y++) { -// if (battleShipBoard.getCell(x, y) == null) { -// BattleShipCell cell = new BattleShipCell(9, new Point(x, y)); -// cell.setModifiable(true); -// battleShipBoard.setCell(x, y, cell); -// } -// } -// } -// this.currentBoard = battleShipBoard; -// this.tree = new Tree(currentBoard); -// } + // if(fileName != null) + // { + // InputStream inputStream = new FileInputStream(fileName); + // DocumentBuilder builder = null;//factory.newDocumentBuilder(); + // Document document = builder.parse(inputStream); + // + // BattleShipBoard battleShipBoard; + // + // PuzzleElement rootNode = document.getDocumentElement(); + // PuzzleElement puzzleElement = (PuzzleElement) + // rootNode.getElementsByTagName("edu.rpi.legup.puzzle").item(0); + // PuzzleElement boardElement = (PuzzleElement) + // puzzleElement.getElementsByTagName("board").item(0); + // PuzzleElement axesElement = (PuzzleElement) + // boardElement.getElementsByTagName("axes").item(0); + // PuzzleElement shipElement = (PuzzleElement) + // boardElement.getElementsByTagName("ships").item(0); + // PuzzleElement cellElement = (PuzzleElement) + // boardElement.getElementsByTagName("cells").item(0); + // PuzzleElement rightElement = (PuzzleElement) + // axesElement.getElementsByTagName("right").item(0); + // PuzzleElement bottomElement = (PuzzleElement) + // axesElement.getElementsByTagName("bottom").item(0); + // NodeList rightClueList = rightElement.getElementsByTagName("clue"); + // NodeList bottomClueList = bottomElement.getElementsByTagName("clue"); + // NodeList shipList = shipElement.getElementsByTagName("ship"); + // NodeList cells = cellElement.getElementsByTagName("cell"); + // + // int size = Integer.valueOf(boardElement.getAttribute("size")); + // battleShipBoard = new BattleShipBoard(size); + // + // ArrayList battleShipData = new ArrayList<>(); + // for(int i = 0; i < size * size; i++) + // { + // battleShipData.add(null); + // } + // + // for (int i = 0; i < rightClueList.getLength(); i++) { + // battleShipBoard.getRight()[i] = + // Integer.valueOf(rightClueList.item(i).getAttributes().getNamedItem("value").getNodeValue()); + // } + // + // for (int i = 0; i < bottomClueList.getLength(); i++) { + // battleShipBoard.getBottom()[i] = + // Integer.valueOf(bottomClueList.item(i).getAttributes().getNamedItem("value").getNodeValue()); + // } + // + // for (int i = 0; i < shipList.getLength(); i++) { + // int length = + // Integer.valueOf(shipList.item(i).getAttributes().getNamedItem("length").getNodeValue()); + // int count = + // Integer.valueOf(shipList.item(i).getAttributes().getNamedItem("count").getNodeValue()); + // battleShipBoard.getShips().add(new Ship(length, count)); + // } + // + // for (int i = 0; i < cells.getLength(); i++) { + // int x = + // Integer.valueOf(cells.item(i).getAttributes().getNamedItem("x").getNodeValue()); + // int y = + // Integer.valueOf(cells.item(i).getAttributes().getNamedItem("y").getNodeValue()); + // String value = + // cells.item(i).getAttributes().getNamedItem("value").getNodeValue().toUpperCase(); + // + // BattleShipCell cell = new + // BattleShipCell(BattleShipType.valueOf(value).ordinal(), new Point(x, y)); + // battleShipBoard.setCell(x, y, cell); + // cell.setModifiable(false); + // cell.setGiven(true); + // } + // + // for (int x = 0; x < size; x++) { + // for (int y = 0; y < size; y++) { + // if (battleShipBoard.getCell(x, y) == null) { + // BattleShipCell cell = new BattleShipCell(9, new Point(x, y)); + // cell.setModifiable(true); + // battleShipBoard.setCell(x, y, cell); + // } + // } + // } + // this.currentBoard = battleShipBoard; + // this.tree = new Tree(currentBoard); + // } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipBoard.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipBoard.java index 5965f7055..555c8471f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipBoard.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.*; import java.util.ArrayList; import java.util.List; @@ -15,7 +14,7 @@ public class BattleshipBoard extends GridBoard { /** * Constructor for creating a rectangular battleship board. * - * @param width width of the board + * @param width width of the board * @param height height of the board */ public BattleshipBoard(int width, int height) { @@ -44,8 +43,7 @@ public BattleshipBoard(int size) { /** * Gets the east {@link BattleshipClue} * - * @return List of BattleShipClue objects on the east - * side of the board + * @return List of BattleShipClue objects on the east side of the board */ public List getEast() { return east; @@ -90,8 +88,7 @@ public BattleshipBoard copy() { * Get a list of all orthogonally adjacent cells. * * @param cell The cell to get adjacent cells from. - * @return List of adjacent cells in clockwise order: - * { up, right, down, left } + * @return List of adjacent cells in clockwise order: { up, right, down, left } */ public List getAdjOrthogonals(BattleshipCell cell) { List adj = new ArrayList<>(); @@ -111,8 +108,8 @@ public List getAdjOrthogonals(BattleshipCell cell) { * Get a list of all diagonally adjacent cells. * * @param cell The cell to get diagonally adjacent cells from. - * @return List of diagonally adjacent cells in clockwise order: - * { upRight, downRight, downLeft, upLeft } + * @return List of diagonally adjacent cells in clockwise order: + * { upRight, downRight, downLeft, upLeft } */ public List getAdjDiagonals(BattleshipCell cell) { List dia = new ArrayList<>(); @@ -155,4 +152,4 @@ public List getColumn(int x) { } return column; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCell.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCell.java index 5f2c5b975..5a5b86094 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCell.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.battleship; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; public class BattleshipCell extends GridCell { @@ -9,7 +8,7 @@ public class BattleshipCell extends GridCell { /** * BattleShipCell Constructor - creates a BattleShipCell from the specified value and location * - * @param value value of the BattleShipCell + * @param value value of the BattleShipCell * @param location position of the BattleShipCell */ public BattleshipCell(BattleshipType value, Point location) { diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCellController.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCellController.java index 89b5fa19a..9db0cca84 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCellController.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCellController.java @@ -2,39 +2,39 @@ import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.event.MouseEvent; public class BattleshipCellController extends ElementController { /** - * Controller class for the Battleship puzzle - - * receives user mouse input and changes what's shown on the GUI + * Controller class for the Battleship puzzle - receives user mouse input and changes what's + * shown on the GUI * * @param data the PuzzleElement to be changed - * @param e the user mouse input + * @param e the user mouse input */ @Override public void changeCell(MouseEvent e, PuzzleElement data) { BattleshipCell cell = (BattleshipCell) data; if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { - this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); - } - else { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { if (cell.getData() == BattleshipType.SHIP_MIDDLE) { cell.setData(BattleshipType.UNKNOWN); - } - else { + } else { cell.setData(BattleshipType.getType(cell.getData().value + 1)); } } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() == BattleshipType.UNKNOWN) { cell.setData(BattleshipType.SHIP_MIDDLE); - } - else { + } else { cell.setData(BattleshipType.getType(cell.getData().value - 1)); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCellFactory.java index 81629c360..1b3b6c427 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipCellFactory.java @@ -4,23 +4,23 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class BattleshipCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid */ @Override - public PuzzleElement importCell(Node node, Board board) throws InvalidFileFormatException { + public PuzzleElement importCell(Node node, Board board) + throws InvalidFileFormatException { try { BattleshipBoard battleShipBoard = (BattleshipBoard) board; int width = battleShipBoard.getWidth(); @@ -32,24 +32,25 @@ public PuzzleElement importCell(Node node, Board board) throws I int x = Integer.parseInt(attributeList.getNamedItem("x").getNodeValue()); int y = Integer.parseInt(attributeList.getNamedItem("y").getNodeValue()); if (x >= width || y >= height) { - throw new InvalidFileFormatException("BattleShip Factory: cell location out of bounds"); + throw new InvalidFileFormatException( + "BattleShip Factory: cell location out of bounds"); } if (value < 0 || value > 3) { throw new InvalidFileFormatException("BattleShip Factory: cell unknown value"); } - BattleshipCell cell = new BattleshipCell(BattleshipType.getType(value), new Point(x, y)); + BattleshipCell cell = + new BattleshipCell(BattleshipType.getType(value), new Point(x, y)); cell.setIndex(y * height + x); return cell; + } else { + throw new InvalidFileFormatException( + "BattleShip Factory: unknown puzzleElement puzzleElement"); } - else { - throw new InvalidFileFormatException("BattleShip Factory: unknown puzzleElement puzzleElement"); - } - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("BattleShip Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "BattleShip Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("BattleShip Factory: could not find attribute(s)"); } } @@ -57,7 +58,7 @@ public PuzzleElement importCell(Node node, Board board) throws I /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipClueView.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipClueView.java index 6a29eb7a3..788c860f3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipClueView.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipClueView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.battleship; import edu.rpi.legup.ui.boardview.ElementView; - import java.awt.*; public class BattleshipClueView extends ElementView { @@ -26,6 +25,7 @@ public BattleshipClue getPuzzleElement() { @Override /** * Draws the clue from the PuzzleElement associated with this view on the given frame + * * @param graphics2D the frame the clue is to be drawn on */ public void draw(Graphics2D graphics2D) { diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipElementView.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipElementView.java index d66f159d7..1898468ce 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.battleship; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class BattleshipElementView extends GridElementView { @@ -22,6 +21,7 @@ public BattleshipElementView(BattleshipCell cell) { @Override /** * Draws on the given frame based on the type of the cell of the current puzzleElement + * * @param graphics2D the frame to be drawn on */ public void drawElement(Graphics2D graphics2D) { @@ -39,37 +39,60 @@ public void drawElement(Graphics2D graphics2D) { break; case SHIP_UNKNOWN: graphics2D.setColor(SHIP_COLOR); - graphics2D.fillRect(location.x + 3 * size.width / 8, location.y + 3 * size.height / 8, - size.width / 4, size.height / 4); + graphics2D.fillRect( + location.x + 3 * size.width / 8, + location.y + 3 * size.height / 8, + size.width / 4, + size.height / 4); graphics2D.setColor(FONT_COLOR); graphics2D.setFont(FONT); FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = "?"; int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + int yText = + location.y + + ((size.height - metrics.getHeight()) / 2) + + metrics.getAscent(); graphics2D.drawString(value, xText, yText); break; case SUBMARINE: graphics2D.setColor(SHIP_COLOR); - graphics2D.fillOval(location.x + size.width / 4, location.y + size.width / 4, - size.width / 2, size.height / 2); + graphics2D.fillOval( + location.x + size.width / 4, + location.y + size.width / 4, + size.width / 2, + size.height / 2); break; case SHIP_TOP: graphics2D.setColor(SHIP_COLOR); - graphics2D.fillArc(location.x, location.y - size.height / 2, size.width, size.height, 180, 180); + graphics2D.fillArc( + location.x, + location.y - size.height / 2, + size.width, + size.height, + 180, + 180); break; case SHIP_RIGHT: graphics2D.setColor(SHIP_COLOR); - graphics2D.fillArc(location.x + size.height / 2, location.y, size.width, size.height, 90, 180); + graphics2D.fillArc( + location.x + size.height / 2, location.y, size.width, size.height, 90, 180); break; case SHIP_BOTTOM: graphics2D.setColor(SHIP_COLOR); - graphics2D.fillArc(location.x, location.y + size.height / 2, size.width, size.height, 0, 180); + graphics2D.fillArc( + location.x, location.y + size.height / 2, size.width, size.height, 0, 180); break; case SHIP_LEFT: graphics2D.setColor(SHIP_COLOR); - graphics2D.fillArc(location.x - size.height / 2, location.y, size.width, size.height, 270, 180); + graphics2D.fillArc( + location.x - size.height / 2, + location.y, + size.width, + size.height, + 270, + 180); break; case SHIP_MIDDLE: graphics2D.setColor(SHIP_COLOR); @@ -84,4 +107,4 @@ public void drawElement(Graphics2D graphics2D) { graphics2D.setStroke(OUTLINE_STROKE); graphics2D.drawRect(location.x, location.y, size.width, size.height); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipExporter.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipExporter.java index 4205d0125..cbc364842 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipExporter.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import org.w3c.dom.Document; public class BattleshipExporter extends PuzzleExporter { @@ -22,8 +21,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { BattleshipBoard board; if (puzzle.getTree() != null) { board = (BattleshipBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (BattleshipBoard) puzzle.getBoardView().getBoard(); } @@ -35,7 +33,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { BattleshipCell cell = (BattleshipCell) puzzleElement; if (cell.getData() != BattleshipType.getType(0)) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipImporter.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipImporter.java index 749ceaaa9..cbc1dd02b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipImporter.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class BattleshipImporter extends PuzzleImporter { public BattleshipImporter(Battleship battleShip) { super(battleShip); @@ -26,14 +25,12 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException if board can not be created */ @Override - public void initializeBoard(int rows, int columns) { - - } + public void initializeBoard(int rows, int columns) {} /** * Creates the board for building @@ -45,46 +42,43 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "BattleShip Importer: " + "cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "no puzzleElement found for board"); + throw new InvalidFileFormatException( + "BattleShip Importer: " + "no puzzleElement found for board"); } - Element dataElement = (Element) boardElement.getElementsByTagName( - "cells").item(0); + Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); NodeList elementDataList = dataElement.getElementsByTagName("cell"); BattleshipBoard battleShipBoard = null; if (!boardElement.getAttribute("size").isEmpty()) { - int size = Integer.valueOf(boardElement.getAttribute( - "size")); + int size = Integer.valueOf(boardElement.getAttribute("size")); battleShipBoard = new BattleshipBoard(size); - } - else { + } else { if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { - int width = Integer.valueOf(boardElement.getAttribute( - "width")); - int height = Integer.valueOf(boardElement.getAttribute( - "height")); + int width = Integer.valueOf(boardElement.getAttribute("width")); + int height = Integer.valueOf(boardElement.getAttribute("height")); battleShipBoard = new BattleshipBoard(width, height); } } if (battleShipBoard == null) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "invalid board dimensions"); + throw new InvalidFileFormatException( + "BattleShip Importer: " + "invalid board dimensions"); } int width = battleShipBoard.getWidth(); int height = battleShipBoard.getHeight(); for (int i = 0; i < elementDataList.getLength(); i++) { - BattleshipCell cell = (BattleshipCell) puzzle.getFactory() - .importCell(elementDataList.item(i), battleShipBoard); + BattleshipCell cell = + (BattleshipCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), battleShipBoard); Point loc = cell.getLocation(); if (cell.getData() != BattleshipType.getType(0)) { cell.setModifiable(false); @@ -96,8 +90,8 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (battleShipBoard.getCell(x, y) == null) { - BattleshipCell cell = new BattleshipCell( - BattleshipType.UNKNOWN, new Point(x, y)); + BattleshipCell cell = + new BattleshipCell(BattleshipType.UNKNOWN, new Point(x, y)); cell.setIndex(y * height + x); cell.setModifiable(true); battleShipBoard.setCell(x, y, cell); @@ -107,59 +101,58 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { NodeList axes = boardElement.getElementsByTagName("axis"); if (axes.getLength() != 2) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "cannot find axes"); + throw new InvalidFileFormatException("BattleShip Importer: " + "cannot find axes"); } Element axis1 = (Element) axes.item(0); Element axis2 = (Element) axes.item(1); - if (!axis1.hasAttribute("side") || !axis2.hasAttribute( - "side")) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "side attribute of axis not specified"); + if (!axis1.hasAttribute("side") || !axis2.hasAttribute("side")) { + throw new InvalidFileFormatException( + "BattleShip Importer: " + "side attribute of axis not specified"); } String side1 = axis1.getAttribute("side"); String side2 = axis2.getAttribute("side"); if (side1.equalsIgnoreCase(side2) - || !(side1.equalsIgnoreCase("east") - || side1.equalsIgnoreCase("south")) - || !(side2.equalsIgnoreCase("east") - || side2.equalsIgnoreCase("south"))) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "axes must be different and be {east | south}"); + || !(side1.equalsIgnoreCase("east") || side1.equalsIgnoreCase("south")) + || !(side2.equalsIgnoreCase("east") || side2.equalsIgnoreCase("south"))) { + throw new InvalidFileFormatException( + "BattleShip Importer: " + "axes must be different and be {east | south}"); } - NodeList eastClues = side1.equalsIgnoreCase("east") - ? axis1.getElementsByTagName("clue") : - axis2.getElementsByTagName("clue"); - NodeList southClues = side1.equalsIgnoreCase("south") - ? axis1.getElementsByTagName("clue") : - axis2.getElementsByTagName("clue"); + NodeList eastClues = + side1.equalsIgnoreCase("east") + ? axis1.getElementsByTagName("clue") + : axis2.getElementsByTagName("clue"); + NodeList southClues = + side1.equalsIgnoreCase("south") + ? axis1.getElementsByTagName("clue") + : axis2.getElementsByTagName("clue"); if (eastClues.getLength() != battleShipBoard.getHeight() || southClues.getLength() != battleShipBoard.getWidth()) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "there must be same number of clues as the dimension " + - "of the board"); + throw new InvalidFileFormatException( + "BattleShip Importer: " + + "there must be same number of clues as the dimension " + + "of the board"); } for (int i = 0; i < eastClues.getLength(); i++) { Element clue = (Element) eastClues.item(i); int value = Integer.valueOf(clue.getAttribute("value")); - int index = BattleshipClue.colStringToColNum( - clue.getAttribute("index")); + int index = BattleshipClue.colStringToColNum(clue.getAttribute("index")); if (index - 1 < 0 || index - 1 > battleShipBoard.getHeight()) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "clue index out of bounds"); + throw new InvalidFileFormatException( + "BattleShip Importer: " + "clue index out of bounds"); } if (battleShipBoard.getEast().get(index - 1) != null) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "duplicate clue index"); + throw new InvalidFileFormatException( + "BattleShip Importer: " + "duplicate clue index"); } - battleShipBoard.getEast().set(index - 1, new BattleshipClue( - value, index, BattleshipType.CLUE_EAST)); + battleShipBoard + .getEast() + .set(index - 1, new BattleshipClue(value, index, BattleshipType.CLUE_EAST)); } for (int i = 0; i < southClues.getLength(); i++) { @@ -168,23 +161,25 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int index = Integer.valueOf(clue.getAttribute("index")); if (index - 1 < 0 || index - 1 > battleShipBoard.getWidth()) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "clue index out of bounds"); + throw new InvalidFileFormatException( + "BattleShip Importer: " + "clue index out of bounds"); } if (battleShipBoard.getSouth().get(index - 1) != null) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "duplicate clue index"); + throw new InvalidFileFormatException( + "BattleShip Importer: " + "duplicate clue index"); } - battleShipBoard.getSouth().set(index - 1, new BattleshipClue( - value, index, BattleshipType.CLUE_SOUTH)); + battleShipBoard + .getSouth() + .set( + index - 1, + new BattleshipClue(value, index, BattleshipType.CLUE_SOUTH)); } puzzle.setCurrentBoard(battleShipBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("BattleShip Importer: " + - "unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "BattleShip Importer: " + "unknown value where integer expected"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipType.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipType.java index 6994222e3..0d505f43c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipType.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipType.java @@ -1,9 +1,19 @@ package edu.rpi.legup.puzzle.battleship; public enum BattleshipType { - UNKNOWN, WATER, SUBMARINE, SHIP_UNKNOWN, - SHIP_TOP, SHIP_RIGHT, SHIP_BOTTOM, SHIP_LEFT, SHIP_MIDDLE, - CLUE_NORTH, CLUE_EAST, CLUE_SOUTH, CLUE_WEST; + UNKNOWN, + WATER, + SUBMARINE, + SHIP_UNKNOWN, + SHIP_TOP, + SHIP_RIGHT, + SHIP_BOTTOM, + SHIP_LEFT, + SHIP_MIDDLE, + CLUE_NORTH, + CLUE_EAST, + CLUE_SOUTH, + CLUE_WEST; public int value; @@ -13,6 +23,7 @@ public enum BattleshipType { /** * Gets the enum of this BattleShipType + * * @param value the integer value input * @return enum equivalent BattleShipType of integer value */ @@ -31,7 +42,11 @@ public static BattleshipType getType(int value) { * @return true if the type is a ship, false otherwise */ public static boolean isShip(BattleshipType type) { - return type == SHIP_UNKNOWN || type == SHIP_TOP || type == SHIP_RIGHT - || type == SHIP_BOTTOM || type == SHIP_LEFT || type == SHIP_MIDDLE; + return type == SHIP_UNKNOWN + || type == SHIP_TOP + || type == SHIP_RIGHT + || type == SHIP_BOTTOM + || type == SHIP_LEFT + || type == SHIP_MIDDLE; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipView.java b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipView.java index fbae2fa99..4095db54a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipView.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/BattleshipView.java @@ -3,7 +3,6 @@ import edu.rpi.legup.controller.BoardController; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.ui.boardview.GridBoardView; - import java.awt.*; public class BattleshipView extends GridBoardView { @@ -17,7 +16,8 @@ public BattleshipView(BattleshipBoard board) { BattleshipElementView elementView = new BattleshipElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); elementViews.add(elementView); } } @@ -26,4 +26,4 @@ public BattleshipView(BattleshipBoard board) { public void drawBoard(Graphics2D graphics2D) { super.drawBoard(graphics2D); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/AdjacentShipsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/AdjacentShipsContradictionRule.java index 49bee101a..f1ecd6685 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/AdjacentShipsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/AdjacentShipsContradictionRule.java @@ -6,31 +6,29 @@ import edu.rpi.legup.puzzle.battleship.BattleshipBoard; import edu.rpi.legup.puzzle.battleship.BattleshipCell; import edu.rpi.legup.puzzle.battleship.BattleshipType; - import java.util.List; public class AdjacentShipsContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE - = "No instance of the contradiction " + this.ruleName + " here"; + private final String NO_CONTRADICTION_MESSAGE = + "No instance of the contradiction " + this.ruleName + " here"; public AdjacentShipsContradictionRule() { - super("BTSP-CONT-0001", + super( + "BTSP-CONT-0001", "Adjacent Ships", "Cells next to the battleship must be water.", - "edu/rpi/legup/images/battleship/contradictions" + - "/AdjacentShips.png"); + "edu/rpi/legup/images/battleship/contradictions" + "/AdjacentShips.png"); } /** - * Checks whether the transition has a contradiction at the specific - * {@link PuzzleElement} index using this rule. + * Checks whether the transition has a contradiction at the specific {@link PuzzleElement} index + * using this rule. * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent {@link PuzzleElement} - * @return null if the transition contains a - * contradiction at the specified {@link PuzzleElement}, - * otherwise return a no contradiction message. + * @return null if the transition contains a contradiction at the specified {@link + * PuzzleElement}, otherwise return a no contradiction message. */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -43,19 +41,20 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } // check orthogonally adjacent cells - List orthoAdjCells - = bsBoard.getAdjOrthogonals(cell); + List orthoAdjCells = bsBoard.getAdjOrthogonals(cell); BattleshipCell up = orthoAdjCells.get(0); BattleshipCell right = orthoAdjCells.get(1); BattleshipCell down = orthoAdjCells.get(2); BattleshipCell left = orthoAdjCells.get(3); - boolean isVertical = (up != null && BattleshipType.isShip(up.getData())) - || (down != null && BattleshipType.isShip(down.getData())); + boolean isVertical = + (up != null && BattleshipType.isShip(up.getData())) + || (down != null && BattleshipType.isShip(down.getData())); - boolean isHorizontal = (left != null && BattleshipType.isShip(left.getData())) - || (right != null && BattleshipType.isShip(right.getData())); + boolean isHorizontal = + (left != null && BattleshipType.isShip(left.getData())) + || (right != null && BattleshipType.isShip(right.getData())); // ships cannot be both vertical and horizontal if (isVertical && isHorizontal) { @@ -63,8 +62,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } // check diagonally adjacent cells - List diagAdjCells - = bsBoard.getAdjDiagonals(cell); + List diagAdjCells = bsBoard.getAdjDiagonals(cell); BattleshipCell upRight = diagAdjCells.get(0); BattleshipCell downRight = diagAdjCells.get(1); diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ContinueShipDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ContinueShipDirectRule.java index 18c55d635..670a136a4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ContinueShipDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ContinueShipDirectRule.java @@ -1,43 +1,45 @@ -package edu.rpi.legup.puzzle.battleship.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class ContinueShipDirectRule extends DirectRule { - - public ContinueShipDirectRule() { - super("BTSP-BASC-0001", - "Continue Ship", - "", - "edu/rpi/legup/images/battleship/rules/ContinueShip.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should be overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.battleship.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class ContinueShipDirectRule extends DirectRule { + + public ContinueShipDirectRule() { + super( + "BTSP-BASC-0001", + "Continue Ship", + "", + "edu/rpi/legup/images/battleship/rules/ContinueShip.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should be overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/FinishWithShipsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/FinishWithShipsDirectRule.java index 3374d1806..9bc4065aa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/FinishWithShipsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/FinishWithShipsDirectRule.java @@ -1,116 +1,108 @@ -package edu.rpi.legup.puzzle.battleship.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.battleship.BattleshipBoard; -import edu.rpi.legup.puzzle.battleship.BattleshipCell; -import edu.rpi.legup.puzzle.battleship.BattleshipClue; -import edu.rpi.legup.puzzle.battleship.BattleshipType; - -import java.awt.*; -import java.util.List; - -public class FinishWithShipsDirectRule extends DirectRule { - - public FinishWithShipsDirectRule() { - super("BTSP-BASC-0002", - "Finish with Ships", - "The number of undetermined squares is equal to the number " + - "of segments remaining for each clue.", - "edu/rpi/legup/images/battleship/rules/finishShip.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should be overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node - * at the specified puzzleElement, otherwise error message. - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, - PuzzleElement puzzleElement) { - BattleshipBoard initBoard = (BattleshipBoard) transition.getParents() - .get(0).getBoard(); - BattleshipCell initCell = (BattleshipCell) initBoard - .getPuzzleElement(puzzleElement); - BattleshipBoard finalBoard = (BattleshipBoard) transition.getBoard(); - BattleshipCell finalCell = (BattleshipCell) finalBoard - .getPuzzleElement(puzzleElement); - if (!(initCell.getType() == BattleshipType.UNKNOWN - && BattleshipType.isShip(finalCell.getType()))) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be a ship."; - } - - if (isForced(initBoard, initCell)) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to" + - "be a ship segment."; - } - } - - private boolean isForced(BattleshipBoard board, BattleshipCell cell) { - Point loc = cell.getLocation(); - - // count the number of ship segments and unknowns in the row - List row = board.getRow(loc.y); - int rowCount = 0; - for (BattleshipCell c : row) { - if (c.getType() == BattleshipType.SHIP_UNKNOWN - || BattleshipType.isShip(c.getType())) { - rowCount++; - } - } - - // count the number of ship segments and unknowns in the column - List col = board.getColumn(loc.x); - int colCount = 0; - for (BattleshipCell c : col) { - if (c.getType() == BattleshipType.SHIP_UNKNOWN - || BattleshipType.isShip(c.getType())) { - colCount++; - } - } - - // compare the counts with the clues - BattleshipClue east = board.getEast().get(loc.y); - BattleshipClue south = board.getSouth().get(loc.x); - - return rowCount <= east.getData() && colCount <= south.getData(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the - * {@link TreeNode}. - * - * @param node tree node used to create default transition board. - * @return default board or null if this rule cannot be applied to this tree - * node. - */ - @Override - public Board getDefaultBoard(TreeNode node) { - BattleshipBoard board = (BattleshipBoard) node.getBoard().copy(); - for (PuzzleElement element : board.getPuzzleElements()) { - BattleshipCell cell = (BattleshipCell) element; - if (cell.getType() == BattleshipType.UNKNOWN && isForced(board, cell)) { - cell.setData(BattleshipType.SHIP_UNKNOWN); - board.addModifiedData(cell); - } - } - - if (board.getModifiedData().isEmpty()) { - return null; - } - else { - return board; - } - } -} +package edu.rpi.legup.puzzle.battleship.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.battleship.BattleshipBoard; +import edu.rpi.legup.puzzle.battleship.BattleshipCell; +import edu.rpi.legup.puzzle.battleship.BattleshipClue; +import edu.rpi.legup.puzzle.battleship.BattleshipType; +import java.awt.*; +import java.util.List; + +public class FinishWithShipsDirectRule extends DirectRule { + + public FinishWithShipsDirectRule() { + super( + "BTSP-BASC-0002", + "Finish with Ships", + "The number of undetermined squares is equal to the number " + + "of segments remaining for each clue.", + "edu/rpi/legup/images/battleship/rules/finishShip.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should be overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message. + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BattleshipBoard initBoard = (BattleshipBoard) transition.getParents().get(0).getBoard(); + BattleshipCell initCell = (BattleshipCell) initBoard.getPuzzleElement(puzzleElement); + BattleshipBoard finalBoard = (BattleshipBoard) transition.getBoard(); + BattleshipCell finalCell = (BattleshipCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(initCell.getType() == BattleshipType.UNKNOWN + && BattleshipType.isShip(finalCell.getType()))) { + return super.getInvalidUseOfRuleMessage() + ": This cell must be a ship."; + } + + if (isForced(initBoard, initCell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + + ": This cell is not forced to" + + "be a ship segment."; + } + } + + private boolean isForced(BattleshipBoard board, BattleshipCell cell) { + Point loc = cell.getLocation(); + + // count the number of ship segments and unknowns in the row + List row = board.getRow(loc.y); + int rowCount = 0; + for (BattleshipCell c : row) { + if (c.getType() == BattleshipType.SHIP_UNKNOWN || BattleshipType.isShip(c.getType())) { + rowCount++; + } + } + + // count the number of ship segments and unknowns in the column + List col = board.getColumn(loc.x); + int colCount = 0; + for (BattleshipCell c : col) { + if (c.getType() == BattleshipType.SHIP_UNKNOWN || BattleshipType.isShip(c.getType())) { + colCount++; + } + } + + // compare the counts with the clues + BattleshipClue east = board.getEast().get(loc.y); + BattleshipClue south = board.getSouth().get(loc.x); + + return rowCount <= east.getData() && colCount <= south.getData(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board. + * @return default board or null if this rule cannot be applied to this tree node. + */ + @Override + public Board getDefaultBoard(TreeNode node) { + BattleshipBoard board = (BattleshipBoard) node.getBoard().copy(); + for (PuzzleElement element : board.getPuzzleElements()) { + BattleshipCell cell = (BattleshipCell) element; + if (cell.getType() == BattleshipType.UNKNOWN && isForced(board, cell)) { + cell.setData(BattleshipType.SHIP_UNKNOWN); + board.addModifiedData(cell); + } + } + + if (board.getModifiedData().isEmpty()) { + return null; + } else { + return board; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/FinishWithWaterDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/FinishWithWaterDirectRule.java index 157b13d01..99e5925e0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/FinishWithWaterDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/FinishWithWaterDirectRule.java @@ -1,43 +1,45 @@ -package edu.rpi.legup.puzzle.battleship.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class FinishWithWaterDirectRule extends DirectRule { - - public FinishWithWaterDirectRule() { - super("BTSP-BASC-0003", - "Finish with Water", - "", - "edu/rpi/legup/images/battleship/rules/finishWater.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.battleship.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class FinishWithWaterDirectRule extends DirectRule { + + public FinishWithWaterDirectRule() { + super( + "BTSP-BASC-0003", + "Finish with Water", + "", + "edu/rpi/legup/images/battleship/rules/finishWater.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/IncompleteShipContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/IncompleteShipContradictionRule.java index 4a6cb3d15..e8cfebb90 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/IncompleteShipContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/IncompleteShipContradictionRule.java @@ -7,19 +7,21 @@ public class IncompleteShipContradictionRule extends ContradictionRule { public IncompleteShipContradictionRule() { - super("BTSP-CONT-0002", + super( + "BTSP-CONT-0002", "Incomplete Ship", "", "edu/rpi/legup/images/battleship/contradictions/IncompleteShip.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SegmentTypeCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SegmentTypeCaseRule.java index 3850ee39f..93079fb71 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SegmentTypeCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SegmentTypeCaseRule.java @@ -5,20 +5,20 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.List; public class SegmentTypeCaseRule extends CaseRule { public SegmentTypeCaseRule() { - super("BTSP-CASE-0001", + super( + "BTSP-CASE-0001", "Segment Type", "", "edu/rpi/legup/images/battleship/cases/SegmentType.png"); } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -29,13 +29,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. This method is the one that should overridden in child classes. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. This method is the one that should overridden in child + * classes. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -43,7 +44,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Gets the case board that indicates where this case rule can be applied on the given {@link Board}. + * Gets the case board that indicates where this case rule can be applied on the given {@link + * Board}. * * @param board board to find locations where this case rule can be applied * @return a case board @@ -54,9 +56,10 @@ public CaseBoard getCaseBoard(Board board) { } /** - * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on this case rule. + * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on + * this case rule. * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SegmentTypeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SegmentTypeDirectRule.java index f90dea1bd..8576ef722 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SegmentTypeDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SegmentTypeDirectRule.java @@ -1,43 +1,45 @@ -package edu.rpi.legup.puzzle.battleship.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class SegmentTypeDirectRule extends DirectRule { - - public SegmentTypeDirectRule() { - super("BTSP-BASC-0004", - "Segment Type", - "", - "edu/rpi/legup/images/battleship/rules/SegmentChoice.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.battleship.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class SegmentTypeDirectRule extends DirectRule { + + public SegmentTypeDirectRule() { + super( + "BTSP-BASC-0004", + "Segment Type", + "", + "edu/rpi/legup/images/battleship/rules/SegmentChoice.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ShipLocationCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ShipLocationCaseRule.java index f21488cca..da8f33cc2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ShipLocationCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ShipLocationCaseRule.java @@ -5,21 +5,21 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.List; public class ShipLocationCaseRule extends CaseRule { public ShipLocationCaseRule() { - super("BTSP-CASE-0002", + super( + "BTSP-CASE-0002", "Ship Location", "", "edu/rpi/legup/images/battleship/cases/ShipLocations.png"); } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -30,13 +30,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. This method is the one that should overridden in child classes. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. This method is the one that should overridden in child + * classes. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -44,7 +45,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Gets the case board that indicates where this case rule can be applied on the given {@link Board}. + * Gets the case board that indicates where this case rule can be applied on the given {@link + * Board}. * * @param board board to find locations where this case rule can be applied * @return a case board @@ -55,9 +57,10 @@ public CaseBoard getCaseBoard(Board board) { } /** - * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on this case rule. + * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on + * this case rule. * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ShipOrWaterCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ShipOrWaterCaseRule.java index a419b831f..3c123d7c1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ShipOrWaterCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/ShipOrWaterCaseRule.java @@ -5,21 +5,21 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.List; public class ShipOrWaterCaseRule extends CaseRule { public ShipOrWaterCaseRule() { - super("BTSP-CASE-0003", + super( + "BTSP-CASE-0003", "Ship or Water", "", "edu/rpi/legup/images/battleship/cases/ShipOrWater.png"); } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -30,13 +30,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. This method is the one that should overridden in child classes. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. This method is the one that should overridden in child + * classes. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -44,7 +45,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Gets the case board that indicates where this case rule can be applied on the given {@link Board}. + * Gets the case board that indicates where this case rule can be applied on the given {@link + * Board}. * * @param board board to find locations where this case rule can be applied * @return a case board @@ -55,9 +57,10 @@ public CaseBoard getCaseBoard(Board board) { } /** - * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on this case rule. + * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on + * this case rule. * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SurroundShipDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SurroundShipDirectRule.java index 57ad42121..d26c3ed29 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SurroundShipDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/SurroundShipDirectRule.java @@ -1,43 +1,45 @@ -package edu.rpi.legup.puzzle.battleship.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class SurroundShipDirectRule extends DirectRule { - - public SurroundShipDirectRule() { - super("BTSP-BASC-0005", - "Surround Ship", - "", - "edu/rpi/legup/images/battleship/rules/SurroundShip.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.battleship.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class SurroundShipDirectRule extends DirectRule { + + public SurroundShipDirectRule() { + super( + "BTSP-BASC-0005", + "Surround Ship", + "", + "edu/rpi/legup/images/battleship/rules/SurroundShip.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooFewInFleetContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooFewInFleetContradictionRule.java index 5a4eb187e..d10e086d2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooFewInFleetContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooFewInFleetContradictionRule.java @@ -7,19 +7,21 @@ public class TooFewInFleetContradictionRule extends ContradictionRule { public TooFewInFleetContradictionRule() { - super("BTSP-CONT-0003", + super( + "BTSP-CONT-0003", "Too Few in Fleet", "", "edu/rpi/legup/images/battleship/contradictions/too_few_in_fleet.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooFewRowColContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooFewRowColContradictionRule.java index 7c2fa7819..382ba6e39 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooFewRowColContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooFewRowColContradictionRule.java @@ -7,19 +7,21 @@ public class TooFewRowColContradictionRule extends ContradictionRule { public TooFewRowColContradictionRule() { - super("BTSP-CONT-0004", + super( + "BTSP-CONT-0004", "Too few in row/col", "", "edu/rpi/legup/images/battleship/contradictions/too_few_segments.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooManyInFleetContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooManyInFleetContradictionRule.java index 3aad88613..d58701c0b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooManyInFleetContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooManyInFleetContradictionRule.java @@ -7,19 +7,21 @@ public class TooManyInFleetContradictionRule extends ContradictionRule { public TooManyInFleetContradictionRule() { - super("BTSP-CONT-0005", + super( + "BTSP-CONT-0005", "Too Many in Fleet", "", "edu/rpi/legup/images/battleship/contradictions/too_many_in_fleet.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooManyRowColContradiction.java b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooManyRowColContradiction.java index 0970c9c69..27caa0524 100644 --- a/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooManyRowColContradiction.java +++ b/src/main/java/edu/rpi/legup/puzzle/battleship/rules/TooManyRowColContradiction.java @@ -7,19 +7,21 @@ public class TooManyRowColContradiction extends ContradictionRule { public TooManyRowColContradiction() { - super("BTSP-CONT-0006", + super( + "BTSP-CONT-0006", "Too Many row/col", "", "edu/rpi/legup/images/battleship/contradictions/too_many_segments.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java new file mode 100644 index 000000000..d2dd0b181 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/Binary.java @@ -0,0 +1,83 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; + +public class Binary extends Puzzle { + public Binary() { + super(); + + this.name = "Binary"; + + this.importer = new BinaryImporter(this); + this.exporter = new BinaryExporter(this); + + this.factory = new BinaryCellFactory(); + } + + /** Initializes the game board. Called by the invoker of the class */ + @Override + public void initializeView() { + boardView = new BinaryView((BinaryBoard) currentBoard); + boardView.setBoard(currentBoard); + addBoardListener(boardView); + } + + /** + * Generates a random edu.rpi.legup.puzzle based on the difficulty + * + * @param difficulty level of difficulty (1-10) + * @return board of the random edu.rpi.legup.puzzle + */ + @Override + public Board generatePuzzle(int difficulty) { + return null; + } + + /** + * Determines if the current board is a valid state + * + * @param board board to check for validity + * @return true if board is valid, false otherwise + */ + @Override + public boolean isBoardComplete(Board board) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + for (ContradictionRule rule : contradictionRules) { + if (rule.checkContradiction(binaryBoard) == null) { + return false; + } + } + for (PuzzleElement data : binaryBoard.getPuzzleElements()) { + BinaryCell cell = (BinaryCell) data; + if (cell.getType() == BinaryType.UNKNOWN) { + return false; + } + } + return true; + } + + /** + * Callback for when the board puzzleElement changes + * + * @param board the board that has changed + */ + @Override + public void onBoardChange(Board board) {} + + + /** + * Determines if the given dimensions are valid for Binary + * + * @param rows the number of rows + * @param columns the number of columns + * @return true if the given dimensions are valid for Binary, false otherwise + */ + @Override + public boolean isValidDimensions(int rows, int columns){ + return rows >= 2 && rows % 2 == 0 && rows == columns; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java new file mode 100644 index 000000000..34819410b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryBoard.java @@ -0,0 +1,118 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.gameboard.GridBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +public class BinaryBoard extends GridBoard { + private int size; + + public BinaryBoard(int width, int height) { + super(width, height); + this.size = width; + } + + public BinaryBoard(int size) { + super(size, size); + this.size = size; + } + + /** + * Gets the cell at the (x,y) position + * + * @param x x-coordinate + * @param y y-coordinate + * @return BinaryCell cell at (x,y) + */ + @Override + public BinaryCell getCell(int x, int y) { + if (y * dimension.width + x >= puzzleElements.size() + || x >= dimension.width + || y >= dimension.height + || x < 0 + || y < 0) { + return null; + } + return (BinaryCell) super.getCell(x, y); + } + + /** + * Get all the binary cells in a row + * + * @param rowNum row number + * @return set of all binary cells in specified rowNum + */ + public Set getRowCells(int rowNum) { + Set row = new HashSet<>(); + for (int i = 0; i < size; i++) { + BinaryCell cell = getCell(i, rowNum); + row.add(cell); + } + return row; + } + + /** + * Get all the binary cells in a column + * + * @param colNum column number + * @return set of all binary cells in specified colNum + */ + public Set getColCells(int colNum) { + Set col = new HashSet<>(); + for (int i = 0; i < size; i++) { + col.add(getCell(colNum, i)); + } + return col; + } + + /** + * Get all the binary types in a row + * + * @param rowNum row number + * @return ArrayList of all binary types in specified rowNum + */ + public ArrayList getRowTypes(int rowNum) { + ArrayList row = new ArrayList(); + for (int i = 0; i < size; i++) { + BinaryCell cell = getCell(i, rowNum); + row.add(cell.getType()); + } + return row; + } + + /** + * Get all the binary types in a column + * + * @param colNum column number + * @return ArrayList of all binary types in specified colNum + */ + public ArrayList getColTypes(int colNum) { + ArrayList col = new ArrayList(); + for (int i = 0; i < size; i++) { + BinaryCell cell = getCell(colNum, i); + col.add(cell.getType()); + } + return col; + } + + /** + * Get a copy of the binary board + * @return copy of current BinaryBoard + */ + @Override + public BinaryBoard copy() { + BinaryBoard copy = new BinaryBoard(dimension.width, dimension.height); + for (int x = 0; x < this.dimension.width; x++) { + for (int y = 0; y < this.dimension.height; y++) { + copy.setCell(x, y, getCell(x, y).copy()); + } + } + for (PuzzleElement e : modifiedData) { + copy.getPuzzleElement(e).setModifiable(false); + } + return copy; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java new file mode 100644 index 000000000..d09f7115e --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCell.java @@ -0,0 +1,86 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.elements.Element; +import edu.rpi.legup.model.gameboard.GridCell; +import java.awt.Point; +import java.awt.event.MouseEvent; + + +public class BinaryCell extends GridCell { + /** + * BinaryCell Constructor - creates a BinaryCell from the specified value and location + * + * @param value value of the BinaryCell + * @param location position of the BinaryCell + */ + public BinaryCell(int value, Point location) { + super(value, location); + } + + /** + * Gets the type of this BinaryCell + * + * @return type of BinaryCell + */ + public BinaryType getType() { + switch (data) { + case 0: + return BinaryType.ZERO; + case 1: + return BinaryType.ONE; + case 2: + return BinaryType.UNKNOWN; + default: + if (data > 1) { + return BinaryType.UNKNOWN; + } + } + return null; + } + + /** + * Performs a deep copy on the BinaryCell + * + * @return a new copy of the BinaryCell that is independent of this one + */ + @Override + public BinaryCell copy() { + BinaryCell copy = new BinaryCell(data, (Point) location.clone()); + copy.setIndex(index); + copy.setModifiable(isModifiable); + copy.setGiven(isGiven); + return copy; + } + + /** + * Sets the type of this BinaryCell + * + * @param e element to set the type of this binary cell to + */ + @Override + public void setType(Element e, MouseEvent m) { + if (e.getElementName().equals("Number Tile")) { + if (m.getButton() == MouseEvent.BUTTON1) { + if (this.data == 2) { + this.data = 0; + } + else { + this.data = this.data + 1; + } + } + else { + if (m.getButton() == MouseEvent.BUTTON3) { + if (this.data > 0) { + this.data = this.data - 1; + } + else { + this.data = 2; + } + } + } + } + else { // unknown tile + this.data = 2; + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java new file mode 100644 index 000000000..a819177d6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryCellFactory.java @@ -0,0 +1,73 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.ElementFactory; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public class BinaryCellFactory extends ElementFactory { + /** + * Creates a puzzleElement based on the xml document Node and adds it to the board + * + * @param node node that represents the puzzleElement + * @param board board to add the newly created cell + * @return newly created cell from the xml document Node + * @throws InvalidFileFormatException if file is invalid + */ + public BinaryCell importCell(Node node, Board board) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("cell")) { + throw new InvalidFileFormatException( + "binary Factory: unknown puzzleElement puzzleElement"); + } + + BinaryBoard binaryBoard = (BinaryBoard) board; + int width = binaryBoard.getWidth(); + int height = binaryBoard.getHeight(); + + NamedNodeMap attributeList = node.getAttributes(); + int value = Integer.valueOf(attributeList.getNamedItem("value").getNodeValue()); + int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); + int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); + + if (x >= width || y >= height) { + throw new InvalidFileFormatException("binary Factory: cell location out of bounds"); + } + if (value < -2) { + throw new InvalidFileFormatException("binary Factory: cell unknown value"); + } + + BinaryCell cell = new BinaryCell(value, new Point(x, y)); + cell.setIndex(y * height + x); + return cell; + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "binary Factory: unknown value where integer expected"); + } catch (NullPointerException e) { + throw new InvalidFileFormatException("binary Factory: could not find attribute(s)"); + } + } + + /** + * Creates a xml document puzzleElement from a cell for exporting + * + * @param document xml document + * @param puzzleElement PuzzleElement cell + * @return xml PuzzleElement + */ + public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleElement) { + org.w3c.dom.Element cellElement = document.createElement("cell"); + + BinaryCell cell = (BinaryCell) puzzleElement; + Point loc = cell.getLocation(); + cellElement.setAttribute("value", String.valueOf(cell.getData())); + cellElement.setAttribute("x", String.valueOf(loc.x)); + cellElement.setAttribute("y", String.valueOf(loc.y)); + + return cellElement; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java new file mode 100644 index 000000000..caf62f3fe --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryController.java @@ -0,0 +1,55 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.controller.ElementController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import java.awt.event.MouseEvent; + +public class BinaryController extends ElementController { + + /** + * Handles cell state changes in the binary puzzle when a mouse event occurs + * If the left mouse button is clicked: + * - If the control key is held down, shows a context menu at the mouse position + * - Otherwise, toggles the cell data state between 0, 1, and 2 in a cyclic manner + * If the right mouse button is clicked, the cell state is also toggled between 2, 1, and 0 + * + * @param e MouseEvent triggered by the user interaction + * @param data PuzzleElement representing the cell being modified + */ + @Override + public void changeCell(MouseEvent e, PuzzleElement data) { + BinaryCell cell = (BinaryCell) data; + if (e.getButton() == MouseEvent.BUTTON1) { + if (e.isControlDown()) { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { + if (cell.getData() == 0) { + data.setData(1); + } else { + if (cell.getData() == 1) { + data.setData(2); + } else { + data.setData(0); + } + } + } + } else { + if (e.getButton() == MouseEvent.BUTTON3) { + if (cell.getData() == 2) { + data.setData(1); + } else { + if (cell.getData() == 1) { + data.setData(0); + } else { + data.setData(2); + } + } + } + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java new file mode 100644 index 000000000..f5ea33d4a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryElementView.java @@ -0,0 +1,89 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.ui.boardview.GridElementView; +import java.awt.*; + +public class BinaryElementView extends GridElementView { + + private static final Font FONT = new Font("TimesRoman", Font.BOLD, 17); + private static final Color FONT_COLOR = Color.BLACK; + private static final Color GIVEN_COLOR = Color.LIGHT_GRAY; + private static final Color ELEMENT_COLOR = Color.WHITE; + + public BinaryElementView(BinaryCell cell) { + super(cell); + } + + /** + * Gets the PuzzleElement associated with this view + * + * @return PuzzleElement associated with this view + */ + @Override + public BinaryCell getPuzzleElement() { + return (BinaryCell) super.getPuzzleElement(); + } + + + /** + * Draws the cells provided in the puzzle's .xml file with light gray background + * + * @param graphics2D The graphics object to draw on + */ + @Override + public void drawGiven(Graphics2D graphics2D) { + drawCell(graphics2D, GIVEN_COLOR); + } + + /** + * Draws new cells being added to board with white background + * + * @param graphics2D The graphics object to draw on + */ + @Override + public void drawElement(Graphics2D graphics2D) { + drawCell(graphics2D, ELEMENT_COLOR); + } + + /** + * Helper method to handle drawing the cell based on its type and background color + * + * @param graphics2D The graphics object to draw on + * @param bgColor The background color for the cell + */ + private void drawCell(Graphics2D graphics2D, Color bgColor) { + BinaryCell cell = (BinaryCell) puzzleElement; + BinaryType type = cell.getType(); + + if (type == BinaryType.ZERO || type == BinaryType.ONE) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(bgColor); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + drawCenteredText(graphics2D); + } else if (type == BinaryType.UNKNOWN) { + graphics2D.setStroke(new BasicStroke(0)); + graphics2D.setColor(Color.WHITE); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + } + } + + /** + * Helper method to draw the centered text within the cell + * + * @param graphics2D The graphics object to draw on + */ + private void drawCenteredText(Graphics2D graphics2D) { + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + String value = String.valueOf(puzzleElement.getData()); + int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.drawString(value, xText, yText); + } +} + diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java new file mode 100644 index 000000000..f12a07378 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryExporter.java @@ -0,0 +1,46 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.PuzzleExporter; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import org.w3c.dom.Document; + +public class BinaryExporter extends PuzzleExporter { + + public BinaryExporter(Binary binary) { + super(binary); + } + + /** + * Generates an XML element for the binary puzzle board, including its dimensions and the + * state of each cell. Binary cells that are not in the `UNKNOWN` state are included in the XML. + * + * @param newDocument The XML document to which the board element belongs. + * @return The XML element representing the board. + */ + @Override + protected org.w3c.dom.Element createBoardElement(Document newDocument) { + BinaryBoard board; + if (puzzle.getTree() != null) { + board = (BinaryBoard) puzzle.getTree().getRootNode().getBoard(); + } else { + board = (BinaryBoard) puzzle.getBoardView().getBoard(); + } + + org.w3c.dom.Element boardElement = newDocument.createElement("board"); + boardElement.setAttribute("width", String.valueOf(board.getWidth())); + boardElement.setAttribute("height", String.valueOf(board.getHeight())); + + org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + BinaryCell cell = (BinaryCell) puzzleElement; + if (cell.getData() != BinaryType.UNKNOWN.toValue()) { + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); + cellsElement.appendChild(cellElement); + } + } + + boardElement.appendChild(cellsElement); + return boardElement; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java new file mode 100644 index 000000000..8a4bad01e --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryImporter.java @@ -0,0 +1,139 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.model.PuzzleImporter; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class BinaryImporter extends PuzzleImporter { + public BinaryImporter(Binary binary) { + super(binary); + } + + /** + * Determines if puzzle uses row and column input + * + * @return true if row and column input is used, false otherwise + */ + @Override + public boolean acceptsRowsAndColumnsInput() { + return true; + } + + /** + * Determines if puzzle uses text input + * + * @return true if text input is used, false otherwise + */ + @Override + public boolean acceptsTextInput() { + return false; + } + + /** + * Creates an empty board for building + * + * @param rows the number of rows on the board + * @param columns the number of columns on the board + * @throws RuntimeException if board can not be created + */ + @Override + public void initializeBoard(int rows, int columns) { + BinaryBoard binaryBoard = new BinaryBoard(columns, rows); + + for (int y = 0; y < rows; y++) { + for (int x = 0; x < columns; x++) { + BinaryCell cell = new BinaryCell(BinaryType.UNKNOWN.toValue(), new Point(x, y)); + cell.setIndex(y * columns + x); + cell.setModifiable(true); + binaryBoard.setCell(x, y, cell); + } + } + puzzle.setCurrentBoard(binaryBoard); + } + + /** + * Creates the board for building + * + * @param node xml document node + * @throws InvalidFileFormatException if file is invalid + */ + @Override + public void initializeBoard(Node node) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("board")) { + throw new InvalidFileFormatException( + "Binary Importer: cannot find board puzzleElement"); + } + Element boardElement = (Element) node; + if (boardElement.getElementsByTagName("cells").getLength() == 0) { + throw new InvalidFileFormatException( + "Binary Importer: no puzzleElement found for board"); + } + + Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); + NodeList elementDataList = dataElement.getElementsByTagName("cell"); + + BinaryBoard binaryBoard = null; + if (!boardElement.getAttribute("size").isEmpty()) { + int size = Integer.valueOf(boardElement.getAttribute("size")); + binaryBoard = new BinaryBoard(size); + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { + int width = Integer.valueOf(boardElement.getAttribute("width")); + int height = Integer.valueOf(boardElement.getAttribute("height")); + binaryBoard = new BinaryBoard(width, height); + } + } + + int width = binaryBoard.getWidth(); + int height = binaryBoard.getHeight(); + + if (binaryBoard == null || width % 2 != 0 || height % 2 != 0) { + throw new InvalidFileFormatException("Binary Importer: invalid board dimensions"); + } + + for (int i = 0; i < elementDataList.getLength(); i++) { + BinaryCell cell = + (BinaryCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), binaryBoard); + Point loc = cell.getLocation(); + if (cell.getData() != BinaryType.UNKNOWN.toValue()) { + cell.setModifiable(false); + cell.setGiven(true); + } + binaryBoard.setCell(loc.x, loc.y, cell); + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (binaryBoard.getCell(x, y) == null) { + BinaryCell cell = + new BinaryCell(BinaryType.UNKNOWN.toValue(), new Point(x, y)); + cell.setIndex(y * height + x); + cell.setModifiable(true); + binaryBoard.setCell(x, y, cell); + } + } + } + puzzle.setCurrentBoard(binaryBoard); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "binary Importer: unknown value where integer expected"); + } + } + + /** + * Initializes a board with text + * @param statements the text being used + * @throws UnsupportedOperationException Binary does not use text input + */ + @Override + public void initializeBoard(String[] statements) throws UnsupportedOperationException { + throw new UnsupportedOperationException("Binary cannot accept text input"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java new file mode 100644 index 000000000..f03f2ee08 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryType.java @@ -0,0 +1,24 @@ +package edu.rpi.legup.puzzle.binary; + +/** + * Enum representing the possible states of a binary puzzle cell + * + * The states include: + * - ZERO: Represents a cell with a value of 0 + * - ONE: Represents a cell with a value of 1 + * - UNKNOWN: Represents an empty cell + * + */ +public enum BinaryType { + ZERO, // Enum constant 0 + ONE, // Enum constant 1 + UNKNOWN; // Enum constant 2 + + /** + * The `toValue` method returns the ordinal value of the enum constant, + * which can be used to convert the enum to an integer representation. + */ + public int toValue() { + return this.ordinal(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java new file mode 100644 index 000000000..e1869de6b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/BinaryView.java @@ -0,0 +1,31 @@ +package edu.rpi.legup.puzzle.binary; + +import edu.rpi.legup.controller.BoardController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.ui.boardview.GridBoardView; +import java.awt.*; + +public class BinaryView extends GridBoardView { + + /** Creates and arranges the visual components for each cell in the binary puzzle. Initializes + * the view by setting up the board controller, binary controller, and the grid dimensions. + * For each cell in the BinaryBoard, it creates a corresponding BinaryElementView, sets its index, + * size, and location, and adds it to the list of element views to be displayed. + * + * @param board The BinaryBoard representing the current state of the binary puzzle + */ + public BinaryView(BinaryBoard board) { + super(new BoardController(), new BinaryController(), board.getDimension()); + + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + BinaryCell cell = (BinaryCell) puzzleElement; + Point loc = cell.getLocation(); + BinaryElementView elementView = new BinaryElementView(cell); + elementView.setIndex(cell.getIndex()); + elementView.setSize(elementSize); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(elementView); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java new file mode 100644 index 000000000..e996e246b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/NumberTile.java @@ -0,0 +1,14 @@ + +package edu.rpi.legup.puzzle.binary.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class NumberTile extends PlaceableElement { + public NumberTile() { + super( + "BINA-ELEM-0001", + "Number Tile", + "A number tile", + "edu/rpi/legup/images/binary/tiles/NumberTile.png"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java new file mode 100644 index 000000000..8c60ea8c3 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/UnknownTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.binary.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class UnknownTile extends PlaceableElement { + public UnknownTile() { + super( + "BINA-ELEM-0002", + "Unknown Tile", + "A blank tile", + "edu/rpi/legup/images/binary/tiles/UnknownTile.png"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt new file mode 100644 index 000000000..54db0ee0b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/elements/binary_elements_reference_sheet.txt @@ -0,0 +1,2 @@ +BINA-ELEM-0001 : NumberTile +BINA-ELEM-0002 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java new file mode 100644 index 000000000..359433685 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/CompleteRowColumnDirectRule.java @@ -0,0 +1,60 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; + +public class CompleteRowColumnDirectRule extends DirectRule { + + public CompleteRowColumnDirectRule() { + super( + "BINA-BASC-0003", + "Complete Row/Column", + "If a row/column of length n contains n/2 of a single value, the remaining " + + "cells must contain the other value", + "edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new UnbalancedRowColumnContradictionRule(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + BinaryBoard modified = origBoard.copy(); + + // Flip the cell and check to see if there will be an unbalanced row/column contradiction, + // if so the rule is applied correctly + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + if (contraRule.checkContradictionAt(modified, puzzleElement) == null) { + return null; + } + + return "Unbalanced row/column found"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java new file mode 100644 index 000000000..02c1c2c31 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/EliminateTheImpossibleDirectRule.java @@ -0,0 +1,201 @@ +//package edu.rpi.legup.puzzle.binary.rules; +// +//import edu.rpi.legup.model.gameboard.Board; +//import edu.rpi.legup.model.gameboard.PuzzleElement; +//import edu.rpi.legup.model.rules.DirectRule; +//import edu.rpi.legup.model.tree.TreeNode; +//import edu.rpi.legup.model.tree.TreeTransition; +//import edu.rpi.legup.puzzle.binary.BinaryBoard; +//import edu.rpi.legup.puzzle.binary.BinaryCell; +//import edu.rpi.legup.puzzle.binary.BinaryType; +// +//import java.util.LinkedList; +//import java.util.Queue; +//import java.lang.Math.*; +//import java.lang.reflect.Array; +//import java.util.ArrayList; +// +//public class EliminateTheImpossibleDirectRule extends DirectRule { +// private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; +// +// public EliminateTheImpossibleDirectRule() { +// super( +// "BINA-BASC-0004", +// "Eliminate The Impossible", +// "Out of the remaining empty cells in this row or column, this digit must go here, otherwise there will be a future contradiction", +// "edu/rpi/legup/images/binary/rules/EliminateTheImpossibleDirectRule.png"); +// } +// +// // Function to generate all binary strings +// void generatePossibilitites(int spots, ArrayList possibilities, int zeroCount, int oneCount) +// // This function generates all the possible combinations of 0s and 1s for a +// // certain size, it does this +// // by basically just counting from 0 to the number - 1, so if you want all the +// // possible combinations for 3 +// // spots, you can just count in binary from 0 to 7 (taking 3 spots, so from 000 +// // to 111). To be practical, +// // the function does not return an array with all the possibilities as an array, +// // but populates the +// // arraylist you pass in (possibilities) +// { +// if (zeroCount + oneCount != spots) { +// System.out.println("INVALID INPUT"); +// return; +// } +// +// if (zeroCount == spots) { +// String zero = ""; +// for (int i = 0; i < spots; i++) { +// zero = zero + "0"; +// } +// possibilities.add(zero); +// +// } +// int count = (int) Math.pow(2, spots) - 1; +// int finalLen = spots; +// Queue q = new LinkedList(); +// q.add("1"); +// +// while (count-- > 0) { +// String s1 = q.peek(); +// q.remove(); +// +// String newS1 = s1; +// int curLen = newS1.length(); +// int runFor = spots - curLen; +// if (curLen < finalLen) { +// for (int i = 0; i < runFor; i++) { +// newS1 = "0" + newS1; +// } +// } +// int curZeros = 0; +// int curOnes = 0; +// +// for (int i = 0; i < spots; i++) { +// if (newS1.charAt(i) == '0') { +// curZeros++; +// } +// if (newS1.charAt(i) == '1') { +// curOnes++; +// } +// } +// +// if (zeroCount == curZeros && oneCount == curOnes) { +// possibilities.add(newS1); +// } +// String s2 = s1; +// q.add(s1 + "0"); +// q.add(s2 + "1"); +// } +// } +// +// @Override +// public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { +// // This function should first check if there are three open spaces, if so, +// // continue, else figure out +// // how many spots are open, all the possible binary combinations that could be +// // put there, and by +// // analyzing the common factors, logically determine which number has a set +// // spot, meaning that we know +// // that a certain spot must be a zero or a one +// +// BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); +// BinaryCell binaryCell = (BinaryCell) puzzleElement; +// +// //Getting the row where the user clicked +// ArrayList row = origBoard.listRowCells(binaryCell.getLocation().y); +// int size = row.size(); +// int rowNumZeros = 0; +// int rowNumOnes = 0; +// +// for (BinaryCell item : row) { +// if (item.getType() == BinaryType.ZERO) { +// rowNumZeros++; +// } else if (item.getType() == BinaryType.ONE) { +// rowNumOnes++; +// } +// } +// +// ArrayList rowResult = new ArrayList(); +// +// // To call generatePossibilitites(), you must call it and pass in the amount of +// // unknown spots left, +// // an ArrayList that will be populated with the possible results (in String +// // form), the amount of zeros left and ones left +// generatePossibilitites((size - rowNumZeros - rowNumOnes), rowResult, size / 2 - rowNumZeros, size / 2 - rowNumOnes); +// +// // Create deep copies of each row +// ArrayList> rowCopies = new ArrayList<>(); +// for (int i = 0; i < rowResult.size(); i++) { +// ArrayList newRow = new ArrayList<>(); +// for (BinaryCell cell : row) { +// newRow.add(cell.copy()); +// } +// rowCopies.add(newRow); +// } +// +// System.out.println("Number of possible binary combinations: " + rowCopies.size()); +// +// ArrayList> nonContraRows = new ArrayList<>(); +// int rowIdx = 0; +// for(ArrayList curRow : rowCopies){ +// int charIdx = 0; +// System.out.println(rowResult.get(rowIdx)); +// for(int i = 0; i < curRow.size(); i++) { +// if (curRow.get(i).getData() == 2) { +// if (rowResult.get(rowIdx).charAt(charIdx) == '0') { +// curRow.get(i).setData(0); +// } +// else if (rowResult.get(rowIdx).charAt(charIdx) == '1') { +// curRow.get(i).setData(1); +// } +// charIdx++; +// } +// System.out.print(curRow.get(i).getData() + " "); +// } +// +// boolean threeAdjacent = false; +// int count = 1; +// for(int i = 1; i < curRow.size(); i++) { +// if (curRow.get(i).getData() == curRow.get(i-1).getData()) { +// count++; +// if (count == 3) { +// threeAdjacent = true; +// break; +// } +// } else { +// count = 1; +// } +// } +// +// if (!threeAdjacent) { +// nonContraRows.add(curRow); +// } +// +// rowIdx++; +// System.out.println(); +// } +// +// System.out.println("Number of non contradiction rows: " + nonContraRows.size()); +// int colNum = binaryCell.getLocation().x; +// boolean invalid = false; +// for(int i = 0; i < nonContraRows.size(); i++) { +// if (nonContraRows.get(i).get(colNum).getData() != binaryCell.getData()) { +// invalid = true; +// break; +// } +// } +// +// if (!invalid) { +// return null; +// } +// +// return "This cell can either be a 0 or a 1"; +// +// } +// +// @Override +// public Board getDefaultBoard(TreeNode node) { +// return null; +// } +//} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java new file mode 100644 index 000000000..745e35d4e --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/PreventTrioDirectRule.java @@ -0,0 +1,58 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; + +public class PreventTrioDirectRule extends DirectRule { + private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; + + public PreventTrioDirectRule() { + super( + "BINA-BASC-0001", + "Prevent Trio", + "If a trio contradiction state could appear, use the opposite digit to prevent the trio", + "edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + TrioContradictionRule contraRule = new TrioContradictionRule(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + BinaryBoard modified = origBoard.copy(); + + // Flip the cell and check to see if there will be a trio contradiction, if so the rule is applied correctly + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + if (contraRule.checkContradictionAt(modified, binaryCell) == null) { + return null; + } + + return "Trio Found"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java new file mode 100644 index 000000000..13eb35283 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/RepeatedRowColumnContradictionRule.java @@ -0,0 +1,63 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.ArrayList; + +public class RepeatedRowColumnContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; + + public RepeatedRowColumnContradictionRule() { + super( + "BINA-CONT-0003", + "Repeated Row/Column", + "There must not be two of the same row or two of the same column in the puzzle", + "edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + + // Compare each row with row of current cell to see if they are equal, if so the rule is applied correctly + ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); + int size = row.size(); + for (int i = 0; i < size; i++) { + if (i != cell.getLocation().y) { + ArrayList currRow = binaryBoard.getRowTypes(i); + if (currRow.equals(row)) { + return null; + } + } + } + + // Compare each column with column of current cell to see if they are equal, if so the rule is applied correctly + ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); + for (int i = 0; i < size; i++) { + if (i != cell.getLocation().x) { + ArrayList currCol = binaryBoard.getColTypes(i); + if (currCol.equals(col)) { + return null; + } + } + } + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java new file mode 100644 index 000000000..5f76c4f59 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/SaveBlockerDirectRule.java @@ -0,0 +1,60 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; + +public class SaveBlockerDirectRule extends DirectRule { + + private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; + + public SaveBlockerDirectRule() { + super( + "BINA-BASC-0003", + "Save Blocker", + "If a future trio could appear in this row/col, save the digit that could block that trio", + "edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + WastedBlockerContradictionRule contraRule = new WastedBlockerContradictionRule(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + BinaryBoard modified = origBoard.copy(); + + // Flip the cell and check to see if a blocker digit is wasted, if so the rule is applied correctly + modified.getPuzzleElement(puzzleElement).setData(Math.abs(binaryCell.getData() - 1)); + if (contraRule.checkContradictionAt(modified, binaryCell) == null) { + return null; + } + + return "Wasted Digit Found"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } + + +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java new file mode 100644 index 000000000..dce7fe371 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/TrioContradictionRule.java @@ -0,0 +1,185 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +public class TrioContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Contradiction must be a zero or one"; + + public TrioContradictionRule() { + super( + "BINA-CONT-0001", + "Trio", + "There must not be three adjacent zeros or three adjacent ones in a row or column", + "edu/rpi/legup/images/binary/rules/TrioContradictionRule.png"); + } + + /** + * This method checks the surrounding cells of a given puzzle element at a specified distance + * in both the vertical and horizontal directions + * + * @param board The board where the puzzle elements are located + * @param puzzleElement The puzzle element from which the distance is calculated + * @param n The distance away from the puzzle element to retrieve the surrounding cells + * @return An array of BinaryCells representing the surrounding cells + */ + public BinaryCell[] getCellsNAway(Board board, PuzzleElement puzzleElement, int n) { + BinaryBoard binaryBoard = (BinaryBoard) board; + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + int cellX = cell.getLocation().x; + int cellY = cell.getLocation().y; + + BinaryCell[] cells = new BinaryCell[4]; // [0] up x, [1] down x, [2] right x, [3] left x + cells[0] = null; + cells[1] = null; + cells[2] = null; + cells[3] = null; + + if (binaryBoard.getCell(cellX, cellY + n) != null) { + cells[0] = binaryBoard.getCell(cellX, cellY + n); + } + if (binaryBoard.getCell(cellX, cellY - n) != null) { + cells[1] = binaryBoard.getCell(cellX, cellY - n); + } + if (binaryBoard.getCell(cellX + n, cellY) != null) { + cells[2] = binaryBoard.getCell(cellX + n, cellY); + } + if (binaryBoard.getCell(cellX - n, cellY) != null) { + cells[3] = binaryBoard.getCell(cellX - n, cellY); + } + + return cells; + } + + /** + * Checks whether the cell and its two surrounding cells form a trio of zeros or ones; + * If a trio is found, it indicates a contradiction + * + * @param board The board where the puzzle elements are located + * @param puzzleElement The puzzle element to check for contradiction + * @return true if no contradiction is found, false if contradiction detected + */ + public boolean checkSurroundPair(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + + // [0] up n, [1] down n, [2] right n, [3] left n + BinaryCell[] cellsOneAway = getCellsNAway(board, puzzleElement, 1); + BinaryCell[] cellsTwoAway = getCellsNAway(board, puzzleElement, 2); + + if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { + // left one and left two + if (cellsOneAway[3] != null + && cellsTwoAway[3] != null + && cellsOneAway[3].getType() != BinaryType.UNKNOWN + && cellsTwoAway[3].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[3].getType() == cell.getType() + && cellsTwoAway[3].getType() == cell.getType()) { + return false; + } + } + // right one and right two + if (cellsOneAway[2] != null + && cellsTwoAway[2] != null + && cellsOneAway[2].getType() != BinaryType.UNKNOWN + && cellsTwoAway[2].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[2].getType() == cell.getType() + && cellsTwoAway[2].getType() == cell.getType()) { + return false; + } + } + // down one and down two + if (cellsOneAway[1] != null + && cellsTwoAway[1] != null + && cellsOneAway[1].getType() != BinaryType.UNKNOWN + && cellsTwoAway[1].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[1].getType() == cell.getType() + && cellsTwoAway[1].getType() == cell.getType()) { + return false; + } + } + // up one and up two + if (cellsOneAway[0] != null + && cellsTwoAway[0] != null + && cellsOneAway[0].getType() != BinaryType.UNKNOWN + && cellsTwoAway[0].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[0].getType() == cell.getType() + && cellsTwoAway[0].getType() == cell.getType()) { + return false; + } + } + } + + return true; + } + + /** + * Checks whether there are two of the same cell type separated by one cell that also has + * the same type in any direction. If a trio is found, it indicates a contradiction + * + * @param board The board where the puzzle elements are located + * @param puzzleElement The puzzle element to check for contradiction + * @return true if no contradiction is found, false if contradiction detected + */ + public boolean checkOneTileGap(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + + // [0] up n, [1] down n, [2] right n, [3] left n + BinaryCell[] cellsOneAway = getCellsNAway(board, puzzleElement, 1); + + if (cell.getType() == BinaryType.ONE || cell.getType() == BinaryType.ZERO) { + // left one and right one + if (cellsOneAway[3] != null + && cellsOneAway[2] != null + && cellsOneAway[3].getType() != BinaryType.UNKNOWN + && cellsOneAway[2].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[3].getType() == cell.getType() + && cellsOneAway[2].getType() == cell.getType()) { + return false; + } + } + // down one and up one + if (cellsOneAway[1] != null + && cellsOneAway[0] != null + && cellsOneAway[1].getType() != BinaryType.UNKNOWN + && cellsOneAway[0].getType() != BinaryType.UNKNOWN) { + if (cellsOneAway[1].getType() == cell.getType() + && cellsOneAway[0].getType() == cell.getType()) { + return false; + } + } + } + return true; + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + + boolean surroundPairValid = checkSurroundPair(board, puzzleElement); + if (!surroundPairValid) { + return null; + } + boolean oneTileGapValid = checkOneTileGap(board, puzzleElement); + if (!oneTileGapValid) { + return null; + } + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java new file mode 100644 index 000000000..82f658013 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UnbalancedRowColumnContradictionRule.java @@ -0,0 +1,81 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.Set; + +public class UnbalancedRowColumnContradictionRule extends ContradictionRule { + + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Row or column must have a value in each cell"; + + public UnbalancedRowColumnContradictionRule() { + super( + "BINA-CONT-0002", + "Unbalanced Row/Column", + "Each row or column must contain an equal number of zeros and ones", + "edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + BinaryBoard binaryBoard = (BinaryBoard) board; + + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + Set row = binaryBoard.getRowCells(cell.getLocation().y); + + int size = row.size(); + int rowNumZeros = 0; + int rowNumOnes = 0; + + for (BinaryCell item : row) { + if (item.getType() == BinaryType.ZERO) { + rowNumZeros++; + } else if (item.getType() == BinaryType.ONE) { + rowNumOnes++; + } + } + + // if there are too many zeros or ones in this row + if (rowNumZeros > size / 2 || rowNumOnes > size / 2) { + return null; + } + + + Set col = binaryBoard.getColCells(cell.getLocation().x); + + size = col.size(); + int colNumZeros = 0; + int colNumOnes = 0; + + for (BinaryCell item : col) { + if (item.getType() == BinaryType.ZERO) { + colNumZeros++; + } else if (item.getType() == BinaryType.ONE) { + colNumOnes++; + } + } + + // if there are too many zeros or ones in this column + if (colNumZeros > size / 2 || colNumOnes > size / 2) { + return null; + } + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java new file mode 100644 index 000000000..3f90510e3 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/UniqueRowColumnDirectRule.java @@ -0,0 +1,288 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.Binary; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.lang.reflect.Array; +import java.util.ArrayList; + +public class UniqueRowColumnDirectRule extends DirectRule { + private final String INVALID_USE_MESSAGE = "Number at cell is incorrect"; + + public UniqueRowColumnDirectRule() { + super( + "BINA-BASC-0004", + "Unique Row/Column", + "If an unfinished row/column only differs by empty cells from a finished one, " + + "fill contradicting empty cells with opposite digit to prevent a repeated row/column", + "edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png"); + } + + /** + * Counts the number of empty (UNKNOWN) cells in a given sequence + * + * @param seq The sequence of BinaryType elements to check + * @return The number of empty (UNKNOWN) cells in the sequence + */ + private int getNumEmpty(ArrayList seq) { + int numEmpty = 0; + for (BinaryType t : seq) { + if (t.equals(BinaryType.UNKNOWN)) { + numEmpty++; + } + } + return numEmpty; + } + + /** + * Checks if there is a valid opposite digit to prevent a repeated row/column + * + * @param seq The sequence (row or column) to check + * @param origBoard The original board + * @param binaryCell The binary cell being checked + * @param rowOrColumn Flag to indicate whether checking a row (0) or a column (1) + * @return Null if a valid opposite digit is found, otherwise an error message + */ + private String checkOppositeDigitDifference(ArrayList seq, BinaryBoard origBoard, + BinaryCell binaryCell, int rowOrColumn) { + // rowOrColumn : 0 for row, 1 for column + + int numEmpty = getNumEmpty(seq); + if (numEmpty > 2) { + return "Row/Column must have at most 2 empty cells"; + } + + boolean valid = false; + for (int i = 0; i < seq.size(); i++) { + ArrayList currSeq; + // Get the sequence (row or column) from the original board to compare + if (rowOrColumn == 0) { + if (i == binaryCell.getLocation().y) { + continue; + } + currSeq = origBoard.getRowTypes(i); + } else { + if (i == binaryCell.getLocation().x) { + continue; + } + currSeq = origBoard.getColTypes(i); + } + + int numDifferentCells = 0; + for (int j = 0; j < currSeq.size(); j++) { + int numEmptyInCurrSeq = getNumEmpty(currSeq); + // If the current sequence has empty cells, it's not valid for comparison + if (numEmptyInCurrSeq != 0) { + valid = false; + break; + } + // Count differences between the sequences, stopping if more than 1 difference is found + if (!seq.get(j).equals(currSeq.get(j)) && !seq.get(j).equals(BinaryType.UNKNOWN)) { + if (++numDifferentCells > 1 || numEmpty != 1) { + valid = false; + break; + } + } + + // Check if there's a contradiction with the current cell, if not mark as valid + if (currSeq.get(j).equals(BinaryType.ZERO) && seq.get(j).equals(BinaryType.UNKNOWN) + && binaryCell.getType().equals(BinaryType.ONE)) { + if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 + && binaryCell.getLocation().y == j) { + valid = true; + } + } + else if (currSeq.get(j).equals(BinaryType.ONE) && seq.get(j).equals(BinaryType.UNKNOWN) + && binaryCell.getType().equals(BinaryType.ZERO)) { + if ((rowOrColumn == 0 && binaryCell.getLocation().x == j) || rowOrColumn == 1 + && binaryCell.getLocation().y == j) { + valid = true; + } + } + } + // Exit if a valid sequence is found + if (valid) { + break; + } + } + + if (valid) { + return null; + } + return "There does not exist an opposite digit difference in "; + } + + /** + * Checks if there is one digit remaining in a sequence that can be filled to avoid repeating + * another sequence on the board + * + * @param seq The sequence (row or column) to check + * @param origBoard The original board + * @param binaryCell The binary cell being checked + * @param rowOrColumn Flag to indicate whether checking a row (0) or a column (1) + * @param zeroOrOne Flag to indicate whether checking for 0s (0) or 1s (1) + * @return Null if the rule can be applied, otherwise an error message + */ + private String checkRemainingOneDigitDifference(ArrayList seq, BinaryBoard origBoard, + BinaryCell binaryCell, int rowOrColumn, int zeroOrOne) { + // zeroOrOne: zero for 0, one for 1 + + for (int i = 0; i < seq.size(); i++) { + ArrayList currSeq; + if (rowOrColumn == 0) { + if (i == binaryCell.getLocation().y) { + continue; + } + currSeq = origBoard.getRowTypes(i); + } + else { + if (i == binaryCell.getLocation().x) { + continue; + } + currSeq = origBoard.getColTypes(i); + } + + boolean valid = true; + for (int j = 0; j < currSeq.size(); j++) { + int numEmptyInCurrSeq = getNumEmpty(currSeq); + // If the current sequence has empty cells, it's not valid for comparison + if (numEmptyInCurrSeq != 0) { + valid = false; + break; + } + // Check if there is a cell difference from this seq and current seq + if (!seq.get(j).equals(currSeq.get(j)) && !seq.get(j).equals(BinaryType.UNKNOWN)) { + valid = false; + break; + } + } + // Determine if the current sequence can be modified to prevent repetition + if (valid) { + BinaryType currSeqCell = currSeq.get(binaryCell.getLocation().x); + if (rowOrColumn == 0) { + currSeqCell = currSeq.get(binaryCell.getLocation().x); + } else if (rowOrColumn == 1) { + currSeqCell = currSeq.get(binaryCell.getLocation().y); + } + + // Check if this sequence has only one more zero remaining and current sequence fills that zero in, + // if so, zero in this seq must go in another cell to prevent repetition + if (zeroOrOne == 0) { + if (currSeqCell.equals(BinaryType.ZERO) && binaryCell.getType().equals(BinaryType.ONE)) { + return null; + } + } + // Check if this sequence has only one more one remaining and current sequence fills that one in, + // if so, one in this seq must go in another cell to prevent repetition + else if (zeroOrOne == 1) { + if (currSeqCell.equals(BinaryType.ONE) && binaryCell.getType().equals(BinaryType.ZERO)) { + return null; + } + } + } + } + + + return "There does not exist a sequence that can be prevented by a remaining digit difference"; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + BinaryBoard origBoard = (BinaryBoard) transition.getParents().get(0).getBoard(); + BinaryCell binaryCell = (BinaryCell) puzzleElement; + + // Check if filling the current cell with the opposite digit would prevent repetition with another row + ArrayList row = origBoard.getRowTypes(binaryCell.getLocation().y); + if (checkOppositeDigitDifference(row, origBoard, binaryCell, 0) == null) { + return null; + } + int numZeros = 0; + int numOnes = 0; + for (int i = 0; i < row.size(); i++) { + if (row.get(i).equals(BinaryType.ZERO)) { + numZeros++; + } + else if (row.get(i).equals(BinaryType.ONE)) { + numOnes++; + } + } + + // Check if only one more zero is needed, then see this row will be repeated by another row + // if current cell is filled in with last zero as well + if (numZeros == row.size()/2 - 1) { + if (checkRemainingOneDigitDifference(row, origBoard, binaryCell, 0, 0) == null) { + return null; + } + } + + // Check if only one more one is needed, then see this row will be repeated by another row + // if current cell is filled in with last one as well + if (numOnes == row.size()/2 - 1) { + if (checkRemainingOneDigitDifference(row, origBoard, binaryCell, 0, 1) == null) { + return null; + } + } + + // Check if filling the current cell with the opposite digit would prevent repetition with another column + ArrayList col = origBoard.getColTypes(binaryCell.getLocation().x); + if (checkOppositeDigitDifference(col, origBoard, binaryCell, 1) == null) { + return null; + } + + numZeros = 0; + numOnes = 0; + for (int i = 0; i < col.size(); i++) { + if (col.get(i).equals(BinaryType.ZERO)) { + numZeros++; + } + else if (col.get(i).equals(BinaryType.ONE)) { + numOnes++; + } + } + + // Check if only one more zero is needed, then see this column will be repeated by another column + // if current cell is filled in with last zero as well + if (numZeros == col.size()/2 - 1) { + if (checkRemainingOneDigitDifference(col, origBoard, binaryCell, 1, 0) == null) { + return null; + } + } + + // Check if only one more one is needed, then see this column will be repeated by another column + // if current cell is filled in with last one as well + if (numOnes == col.size()/2 - 1) { + if (checkRemainingOneDigitDifference(col, origBoard, binaryCell, 1, 1) == null) { + return null; + } + } + + return "There is no row/column that forces this cell to be a " + binaryCell.getData().toString(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java new file mode 100644 index 000000000..e7ab51b41 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/WastedBlockerContradictionRule.java @@ -0,0 +1,178 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; + +import java.util.ArrayList; + +public class WastedBlockerContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + + public WastedBlockerContradictionRule() { + super( + "BINA-CONT-0004", + "Wasted Blocker", + "There exists a cell in this row/column that allocates a digit unnecessarily and" + + " will cause a future trio to appear", + "edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png"); + } + + /* + i [ n ] j + i -> digit on left (0 if no digit exists) + n -> number of empty cells + j -> digit on right (0 if no digit exists) + neededZeros = ( n + i + j ) / 3 + */ + /** + * Calculates the number of zeros needed in a sequence based on the values on either side and the number of empty cells. + * + * @param leftVal The value on the left side of the empty cells + * @param rightVal The value on the right side of the empty cells + * @param emptyCellsInCurSec The number of empty cells in the current section + * @return The number of zeros needed in the sequence + */ + private int calculateNeededZeros(int leftVal, int rightVal, int emptyCellsInCurSec) { + int leftCopy = leftVal; + int rightCopy = rightVal; + if (leftCopy == -1) { + leftCopy = 0; + } + if (rightCopy == -1) { + rightCopy = 0; + } + return ((emptyCellsInCurSec + leftCopy + rightCopy) / 3); + } + + /* + i [ n ] j + i -> digit on left (1 if no digit exists) + n -> number of empty cells + j -> digit on right (1 if no digit exists) + neededOnes = ( n + ( 1 - i ) + ( 1 - j ) ) / 3 + */ + /** + * Calculates the number of ones needed in a sequence based on the values on either side and the number of empty cells + * + * @param leftVal The value on the left side of the empty cells + * @param rightVal The value on the right side of the empty cells + * @param emptyCellsInCurSec The number of empty cells in the current section + * @return The number of ones needed in the sequence + */ + private int calculateNeededOnes(int leftVal, int rightVal, int emptyCellsInCurSec) { + int leftCopy = leftVal; + int rightCopy = rightVal; + if (leftCopy == -1) { + leftCopy = 1; + } + if (rightCopy == -1) { + rightCopy = 1; + } + return ((emptyCellsInCurSec + (1 - leftCopy) + (1 - rightCopy)) / 3); + } + + /** + * Checks a sequence (row or column) to see if a wasted blocker digit is used + * + * @param seq The sequence to check + * @return Null if the sequence contains a contradiction, otherwise an error message + */ + private String checkSequence(ArrayList seq) { + int numZeros = 0; + int numOnes = 0; + boolean emptyCell = false; + int emptyCellsInCurSec = 0; + int neededZeros = 0; + int neededOnes = 0; + + for (int i = 0; i < seq.size(); i++) { + if (seq.get(i).equals(BinaryType.ZERO) || seq.get(i).equals(BinaryType.ONE)) { + if (seq.get(i).equals(BinaryType.ZERO)) { + numZeros++; + } else if (seq.get(i).equals(BinaryType.ONE)) { + numOnes++; + } + + if (emptyCell) { + if (emptyCellsInCurSec > 1) { // Ignore case where there is only one empty cell + int leftVal; + int rightVal; + // Check if left cell is out of bounds + if (i-emptyCellsInCurSec-1 < 0) { + leftVal = -1; + } else { + leftVal = seq.get(i-emptyCellsInCurSec-1).toValue(); + } + rightVal = seq.get(i).toValue(); + neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); + neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); + } + emptyCell = false; + emptyCellsInCurSec = 0; + } + } else { + if (!emptyCell) { + emptyCell = true; + } + emptyCellsInCurSec++; + } + } + + // Check last cell is empty + if (emptyCell) { + if (emptyCellsInCurSec > 1) { // Ignore case where there is only one empty cell + int leftVal; + int rightVal; + // Check if left cell is out of bounds + if (seq.size()-1-emptyCellsInCurSec-1 < 0) { + leftVal = -1; + } else { + leftVal = seq.get(seq.size()-1-emptyCellsInCurSec).toValue(); + } + rightVal = -1; + neededZeros += calculateNeededZeros(leftVal, rightVal, emptyCellsInCurSec); + neededOnes += calculateNeededOnes(leftVal, rightVal, emptyCellsInCurSec); + } + } + + // Check if the number of needed zeros or ones exceeds half the sequence length + // If so, return null to indicate contradiction has occurred + if ((numZeros + neededZeros > seq.size()/2) || (numOnes + neededOnes > seq.size()/2)) { + return null; + } + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + + BinaryBoard binaryBoard = (BinaryBoard) board; + BinaryCell cell = (BinaryCell) binaryBoard.getPuzzleElement(puzzleElement); + + ArrayList row = binaryBoard.getRowTypes(cell.getLocation().y); + if (checkSequence(row) == null) { + return null; + } + + ArrayList col = binaryBoard.getColTypes(cell.getLocation().x); + if (checkSequence(col) == null) { + return null; + } + + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java new file mode 100644 index 000000000..3ae7a424d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/ZeroOrOneCaseRule.java @@ -0,0 +1,121 @@ +package edu.rpi.legup.puzzle.binary.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.binary.BinaryBoard; +import edu.rpi.legup.puzzle.binary.BinaryCell; +import edu.rpi.legup.puzzle.binary.BinaryType; +import java.util.ArrayList; +import java.util.List; + +public class ZeroOrOneCaseRule extends CaseRule { + + public ZeroOrOneCaseRule() { + super( + "BINA-CASE-0001", + "Zero Or One", + "Each blank cell is either a zero or a one", + "edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png"); + } + + /** + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should be overridden in child classes. + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + List childTransitions = transition.getParents().get(0).getChildren(); + if (childTransitions.size() != 2) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must have 2 children."; + } + + TreeTransition case1 = childTransitions.get(0); + TreeTransition case2 = childTransitions.get(1); + if (case1.getBoard().getModifiedData().size() != 1 + || case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case."; + } + + BinaryCell mod1 = (BinaryCell) case1.getBoard().getModifiedData().iterator().next(); + BinaryCell mod2 = (BinaryCell) case2.getBoard().getModifiedData().iterator().next(); + if (!mod1.getLocation().equals(mod2.getLocation())) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; + } + + if (!((mod1.getType() == BinaryType.ZERO && mod2.getType() == BinaryType.ONE) + || (mod2.getType() == BinaryType.ZERO && mod1.getType() == BinaryType.ONE))) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must modify an empty cell."; + } + + return null; + } + + /** + * Generates a {@link CaseBoard} that includes all blank cells from the given board that this + * case rule can be applied to + * + * @param board The board to find locations where this case rule can be applied + * @return A CaseBoard containing pickable elements where the case rule can be applied + */ + @Override + public CaseBoard getCaseBoard(Board board) { + BinaryBoard binaryBoard = (BinaryBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(binaryBoard, this); + binaryBoard.setModifiable(false); + for (PuzzleElement element : binaryBoard.getPuzzleElements()) { + if (((BinaryCell) element).getType() == BinaryType.UNKNOWN) { + caseBoard.addPickableElement(element); + } + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + + Board case1 = board.copy(); + PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); + data1.setData(BinaryType.ONE.toValue()); + case1.addModifiedData(data1); + cases.add(case1); + + Board case2 = board.copy(); + PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); + data2.setData(BinaryType.ZERO.toValue()); + case2.addModifiedData(data2); + cases.add(case2); + + return cases; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt new file mode 100644 index 000000000..619d183a5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/binary/rules/binary_reference_sheet.txt @@ -0,0 +1,11 @@ +BINA-BASC-0001 : PreventTrioContradictionRule +BINA-BASC-0002 : CompleteRowColumnDirectRule +BINA-BASC-0003 : SaveBlockerDirectRule +BINA-BASC-0004 : UniqueRowColumnDirectRule + +BINA-CONT-0001 : TrioContradictionRule +BINA-CONT-0002 : UnbalancedRowColumnContradictionRule +BINA-CONT-0003 : RepeatedRowColumnContradictionRule +BINA-CONT-0004 : WastedBlockerContradictionRule + +BINA-CASE-0001 : ZeroOrOneCaseRule \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/Fillapix.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/Fillapix.java index ef78f66aa..79574caa6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/Fillapix.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/Fillapix.java @@ -6,9 +6,7 @@ import edu.rpi.legup.model.rules.ContradictionRule; public class Fillapix extends Puzzle { - /** - * Fillapix Constructor - */ + /** Fillapix Constructor */ public Fillapix() { super(); @@ -20,9 +18,7 @@ public Fillapix() { this.factory = new FillapixCellFactory(); } - /** - * Initializes the game board - */ + /** Initializes the game board */ @Override public void initializeView() { boardView = new FillapixView((FillapixBoard) currentBoard); @@ -39,8 +35,8 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Fillapix * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Fillapix, false otherwise */ public boolean isValidDimensions(int rows, int columns) { @@ -65,7 +61,5 @@ public boolean isBoardComplete(Board board) { } @Override - public void onBoardChange(Board board) { - - } -} \ No newline at end of file + public void onBoardChange(Board board) {} +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixBoard.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixBoard.java index 67987a6fd..a6672bd4f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixBoard.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.*; import java.util.logging.Logger; public class FillapixBoard extends GridBoard { - private final static Logger LOGGER = Logger.getLogger(FillapixBoard.class.getName()); + private static final Logger LOGGER = Logger.getLogger(FillapixBoard.class.getName()); public FillapixBoard(int width, int height) { super(width, height); diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java index 5e6d4b9ed..40c5e4a54 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCell.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; import java.awt.event.MouseEvent; import java.util.Objects; @@ -42,14 +41,14 @@ public void setCellType(FillapixCellType type) { @Override public void setType(Element e, MouseEvent m) { - switch(e.getElementID()) { - case "FPIX-PLAC-0001": + switch (e.getElementID()) { + case "FPIX-ELEM-0001": this.setCellType(FillapixCellType.BLACK); break; - case "FPIX-PLAC-0002": + case "FPIX-ELEM-0004": this.setCellType(FillapixCellType.WHITE); break; - case "FPIX-UNPL-0001": + case "FPIX-ELEM-0002": int n = this.getNumber(); switch (m.getButton()) { case MouseEvent.BUTTON1: @@ -88,9 +87,11 @@ public FillapixCell copy() { } public boolean equals(FillapixCell otherCell) { -// return this.location.equals(otherCell.location) && this.index == otherCell.index && this.data == otherCell.data; - //return this.index == otherCell.index && this.data == otherCell.data; - //return this.index == otherCell.index; + // return this.location.equals(otherCell.location) && this.index == otherCell.index + // && + // this.data == otherCell.data; + // return this.index == otherCell.index && this.data == otherCell.data; + // return this.index == otherCell.index; return this.location.x == otherCell.location.x && this.location.y == otherCell.location.y; } @@ -101,4 +102,4 @@ public int compareTo(FillapixCell otherCell) { public int hashCode() { return Objects.hash(this.index); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellController.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellController.java index df3bba403..f59c0df47 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellController.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellController.java @@ -2,7 +2,6 @@ import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.event.MouseEvent; public class FillapixCellController extends ElementController { @@ -11,34 +10,33 @@ public void changeCell(MouseEvent e, PuzzleElement puzzleElement) { FillapixCell cell = (FillapixCell) puzzleElement; if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { - this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); - } - else { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { if (cell.getType() == FillapixCellType.UNKNOWN) { cell.setCellType(FillapixCellType.BLACK); - } - else { + } else { if (cell.getType() == FillapixCellType.BLACK) { cell.setCellType(FillapixCellType.WHITE); - } - else { + } else { if (cell.getType() == FillapixCellType.WHITE) { cell.setCellType(FillapixCellType.UNKNOWN); } } } } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getType() == FillapixCellType.UNKNOWN) { cell.setCellType(FillapixCellType.WHITE); - } - else { + } else { if (cell.getType() == FillapixCellType.BLACK) { cell.setCellType(FillapixCellType.UNKNOWN); - } - else { + } else { if (cell.getType() == FillapixCellType.WHITE) { cell.setCellType(FillapixCellType.BLACK); } @@ -47,4 +45,4 @@ public void changeCell(MouseEvent e, PuzzleElement puzzleElement) { } } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellFactory.java index fcc48bccd..9f689bc96 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellFactory.java @@ -4,17 +4,16 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class FillapixCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid @@ -23,7 +22,8 @@ public class FillapixCellFactory extends ElementFactory { public FillapixCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("Fillapix Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "Fillapix Factory: unknown puzzleElement puzzleElement"); } FillapixBoard fillapixBoard = (FillapixBoard) board; @@ -35,7 +35,8 @@ public FillapixCell importCell(Node node, Board board) throws InvalidFileFormatE int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); if (x >= width || y >= height) { - throw new InvalidFileFormatException("Fillapix Factory: cell location out of bounds"); + throw new InvalidFileFormatException( + "Fillapix Factory: cell location out of bounds"); } if (value / 100 > 2 || value % 100 > 10) { throw new InvalidFileFormatException("Fillapix Factory: cell unknown value"); @@ -44,11 +45,10 @@ public FillapixCell importCell(Node node, Board board) throws InvalidFileFormatE FillapixCell cell = new FillapixCell(value, new Point(x, y)); cell.setIndex(y * height + x); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Fillapix Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Fillapix Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("Fillapix Factory: could not find attribute(s)"); } } @@ -56,7 +56,7 @@ public FillapixCell importCell(Node node, Board board) throws InvalidFileFormatE /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellType.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellType.java index 3789fe339..28a263467 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellType.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixCellType.java @@ -1,7 +1,9 @@ package edu.rpi.legup.puzzle.fillapix; public enum FillapixCellType { - UNKNOWN(0), BLACK(1), WHITE(2); + UNKNOWN(0), + BLACK(1), + WHITE(2); public int value; diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixElementView.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixElementView.java index 93fa0d451..47465a522 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.fillapix; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class FillapixElementView extends GridElementView { @@ -53,10 +52,11 @@ public void drawElement(Graphics2D graphics2D) { FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = String.valueOf(cell.getNumber()); int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(value, xText, yText); } graphics2D.setColor(BLACK_COLOR); graphics2D.drawRect(location.x, location.y, size.width, size.height); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixExporter.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixExporter.java index 757d14cd8..ffabd8762 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixExporter.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import org.w3c.dom.Document; public class FillapixExporter extends PuzzleExporter { @@ -16,8 +15,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { FillapixBoard board; if (puzzle.getTree() != null) { board = (FillapixBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (FillapixBoard) puzzle.getBoardView().getBoard(); } @@ -29,7 +27,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { FillapixCell cell = (FillapixCell) puzzleElement; if (cell.getNumber() != -1 || cell.getType() != FillapixCellType.UNKNOWN) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixImporter.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixImporter.java index 5213e7139..d16bc8219 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixImporter.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class FillapixImporter extends PuzzleImporter { public FillapixImporter(Fillapix fillapix) { super(fillapix); @@ -26,7 +25,7 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException if board can not be made */ @@ -36,7 +35,8 @@ public void initializeBoard(int rows, int columns) { for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { - FillapixCell cell = new FillapixCell(FillapixCellType.UNKNOWN.value, new Point(x, y)); + FillapixCell cell = + new FillapixCell(FillapixCellType.UNKNOWN.value, new Point(x, y)); cell.setIndex(y * columns + x); cell.setNumber(FillapixCell.DEFAULT_VALUE); cell.setModifiable(true); @@ -56,11 +56,13 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("Fillapix Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "Fillapix Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("Fillapix Importer: no puzzleElement found for board"); + throw new InvalidFileFormatException( + "Fillapix Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); NodeList elementDataList = dataElement.getElementsByTagName("cell"); @@ -69,9 +71,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { if (!boardElement.getAttribute("size").isEmpty()) { int size = Integer.valueOf(boardElement.getAttribute("size")); fillapixBoard = new FillapixBoard(size); - } - else { - if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { int width = Integer.valueOf(boardElement.getAttribute("width")); int height = Integer.valueOf(boardElement.getAttribute("height")); fillapixBoard = new FillapixBoard(width, height); @@ -86,7 +88,10 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int height = fillapixBoard.getHeight(); for (int i = 0; i < elementDataList.getLength(); i++) { - FillapixCell cell = (FillapixCell) puzzle.getFactory().importCell(elementDataList.item(i), fillapixBoard); + FillapixCell cell = + (FillapixCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), fillapixBoard); Point loc = cell.getLocation(); cell.setModifiable(true); cell.setGiven(true); @@ -96,7 +101,8 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (fillapixBoard.getCell(x, y) == null) { - FillapixCell cell = new FillapixCell(FillapixCell.DEFAULT_VALUE, new Point(x, y)); + FillapixCell cell = + new FillapixCell(FillapixCell.DEFAULT_VALUE, new Point(x, y)); cell.setIndex(y * height + x); cell.setModifiable(true); fillapixBoard.setCell(x, y, cell); @@ -104,9 +110,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } puzzle.setCurrentBoard(fillapixBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Fillapix Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Fillapix Importer: unknown value where integer expected"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixUtilities.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixUtilities.java index a7feac91d..571a0c7f7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixUtilities.java @@ -3,14 +3,14 @@ import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.fillapix.rules.TooFewBlackCellsContradictionRule; import edu.rpi.legup.puzzle.fillapix.rules.TooManyBlackCellsContradictionRule; - import java.awt.*; import java.util.ArrayList; public class FillapixUtilities { public static boolean isForcedBlack(FillapixBoard board, FillapixCell cell) { - TooFewBlackCellsContradictionRule tooManyBlackCells = new TooFewBlackCellsContradictionRule(); + TooFewBlackCellsContradictionRule tooManyBlackCells = + new TooFewBlackCellsContradictionRule(); FillapixBoard whiteCaseBoard = board.copy(); FillapixCell whiteCell = (FillapixCell) whiteCaseBoard.getPuzzleElement(cell); whiteCell.setCellType(FillapixCellType.WHITE); @@ -24,7 +24,8 @@ public static boolean isForcedBlack(FillapixBoard board, FillapixCell cell) { } public static boolean isForcedWhite(FillapixBoard board, FillapixCell cell) { - TooManyBlackCellsContradictionRule tooManyBlackCells = new TooManyBlackCellsContradictionRule(); + TooManyBlackCellsContradictionRule tooManyBlackCells = + new TooManyBlackCellsContradictionRule(); FillapixBoard blackCaseBoard = board.copy(); FillapixCell blackCell = (FillapixCell) blackCaseBoard.getPuzzleElement(cell); blackCell.setCellType(FillapixCellType.BLACK); @@ -59,15 +60,16 @@ public static boolean hasEmptyAdjacent(FillapixBoard board, FillapixCell cell) { return false; } - /** - * Gets all cells adjacent to a specific cell. The cell itself will be included. - */ + /** Gets all cells adjacent to a specific cell. The cell itself will be included. */ public static ArrayList getAdjacentCells(FillapixBoard board, FillapixCell cell) { ArrayList adjCells = new ArrayList(); Point cellLoc = cell.getLocation(); - for (int i=-1; i <= 1; i++) { - for (int j=-1; j <= 1; j++) { - if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (cellLoc.getX() + i < 0 + || cellLoc.y + j < 0 + || cellLoc.x + i >= board.getWidth() + || cellLoc.y + j >= board.getHeight()) { continue; } FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j); @@ -81,22 +83,34 @@ public static ArrayList getAdjacentCells(FillapixBoard board, Fill } /** - * Gets all cells that are contained in the square defined as having 'distance' - * cells between the center and the outer wall. For example, distance = 1:

- * |X|X|X|X|X|

- * |X| | | |X|

- * |X| |O| |X|

- * |X| | | |X|

- * |X|X|X|X|X|

- * O is 'cell', and all 'X' will be returned in the ArrayList + * Gets all cells that are contained in the square defined as having 'distance' cells between + * the center and the outer wall. For example, distance = 1: + * + *

|X|X|X|X|X| + * + *

|X| | | |X| + * + *

|X| |O| |X| + * + *

|X| | | |X| + * + *

|X|X|X|X|X| + * + *

O is 'cell', and all 'X' will be returned in the ArrayList */ - public static ArrayList getCellsAtDistance(FillapixBoard board, FillapixCell cell, int distance) { + public static ArrayList getCellsAtDistance( + FillapixBoard board, FillapixCell cell, int distance) { ArrayList adjCells = new ArrayList(); Point cellLoc = cell.getLocation(); int i = 0, j = 0; // top line - for (i = cellLoc.x - (distance), j = cellLoc.y - (distance+1); i <= cellLoc.x + (distance+1); i++) { - if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + for (i = cellLoc.x - (distance), j = cellLoc.y - (distance + 1); + i <= cellLoc.x + (distance + 1); + i++) { + if (cellLoc.getX() + i < 0 + || cellLoc.y + j < 0 + || cellLoc.x + i >= board.getWidth() + || cellLoc.y + j >= board.getHeight()) { continue; } FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j); @@ -106,8 +120,13 @@ public static ArrayList getCellsAtDistance(FillapixBoard board, Fi adjCells.add(adjCell); } // right line - for (i = cellLoc.x + (distance+1), j = cellLoc.y - (distance); j <= cellLoc.y + (distance+1); j++) { - if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + for (i = cellLoc.x + (distance + 1), j = cellLoc.y - (distance); + j <= cellLoc.y + (distance + 1); + j++) { + if (cellLoc.getX() + i < 0 + || cellLoc.y + j < 0 + || cellLoc.x + i >= board.getWidth() + || cellLoc.y + j >= board.getHeight()) { continue; } FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j); @@ -115,10 +134,15 @@ public static ArrayList getCellsAtDistance(FillapixBoard board, Fi continue; } adjCells.add(adjCell); - } + } // bottom line - for (i = cellLoc.x + (distance), j = cellLoc.y + (distance+1); i <= cellLoc.x - (distance+1); i--) { - if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + for (i = cellLoc.x + (distance), j = cellLoc.y + (distance + 1); + i <= cellLoc.x - (distance + 1); + i--) { + if (cellLoc.getX() + i < 0 + || cellLoc.y + j < 0 + || cellLoc.x + i >= board.getWidth() + || cellLoc.y + j >= board.getHeight()) { continue; } FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j); @@ -126,10 +150,15 @@ public static ArrayList getCellsAtDistance(FillapixBoard board, Fi continue; } adjCells.add(adjCell); - } + } // left line - for (i = cellLoc.x - (distance+1), j = cellLoc.y + (distance); j <= cellLoc.y - (distance+1); j--) { - if (cellLoc.getX() + i < 0 || cellLoc.y + j < 0 || cellLoc.x + i >= board.getWidth() || cellLoc.y + j >= board.getHeight()) { + for (i = cellLoc.x - (distance + 1), j = cellLoc.y + (distance); + j <= cellLoc.y - (distance + 1); + j--) { + if (cellLoc.getX() + i < 0 + || cellLoc.y + j < 0 + || cellLoc.x + i >= board.getWidth() + || cellLoc.y + j >= board.getHeight()) { continue; } FillapixCell adjCell = board.getCell(cellLoc.x + i, cellLoc.y + j); @@ -137,25 +166,25 @@ public static ArrayList getCellsAtDistance(FillapixBoard board, Fi continue; } adjCells.add(adjCell); - } + } return adjCells; - } + } /** - * Finds all possible combinations of chosenNumObj items can be - * chosen from totalNumObj total items. - * For example, if 1 item is chosen from 2 possible items, the combinations - * are: + * Finds all possible combinations of chosenNumObj items can be chosen from + * totalNumObj total items. For example, if 1 item is chosen from 2 possible items, the + * combinations are: + * *

[ [true,false], [false,true] ]
- * + * * @param totalNumItems the total number of items that can possibly be chosen * @param chosenNumItems the number of items to be chosen - * - * @return an ArrayList of Boolean arrays. Each index in the ArrayList represents - * a distinct combination. Each Boolean array will be totalNumItems - * long and each index will be true if the corresponding item is - * included in that combination, and false otherwise. + * @return an ArrayList of Boolean arrays. Each index in the ArrayList represents a distinct + * combination. Each Boolean array will be totalNumItems long and each index + * will be true if the corresponding item is included in that combination, and + * + * false otherwise. */ public static ArrayList getCombinations(int chosenNumItems, int totalNumItems) { ArrayList combinations = new ArrayList(); @@ -165,9 +194,15 @@ public static ArrayList getCombinations(int chosenNumItems, int total recurseCombinations(combinations, 0, chosenNumItems, 0, totalNumItems, array); return combinations; - } + } - private static void recurseCombinations(ArrayList result, int curIndex, int maxBlack, int numBlack, int len, boolean[] workingArray) { + private static void recurseCombinations( + ArrayList result, + int curIndex, + int maxBlack, + int numBlack, + int len, + boolean[] workingArray) { if (curIndex == len) { // complete, but not valid solution if (numBlack != maxBlack) { @@ -184,19 +219,19 @@ private static void recurseCombinations(ArrayList result, int curInde if (numBlack < maxBlack) { workingArray[curIndex] = true; - recurseCombinations(result, curIndex+1, maxBlack, numBlack+1, len, workingArray); + recurseCombinations(result, curIndex + 1, maxBlack, numBlack + 1, len, workingArray); } workingArray[curIndex] = false; - recurseCombinations(result, curIndex+1, maxBlack, numBlack, len, workingArray); + recurseCombinations(result, curIndex + 1, maxBlack, numBlack, len, workingArray); } - + public static boolean checkBoardForContradiction(FillapixBoard board) { ContradictionRule tooManyBlack = new TooManyBlackCellsContradictionRule(); ContradictionRule tooManyWhite = new TooFewBlackCellsContradictionRule(); - for (int i= 0; i < board.getWidth(); i++) { - for (int j=0; j < board.getHeight(); j++) { - if (tooManyBlack.checkContradictionAt(board, board.getCell(i, j)) == null || - tooManyWhite.checkContradictionAt(board, board.getCell(i, j)) == null) { + for (int i = 0; i < board.getWidth(); i++) { + for (int j = 0; j < board.getHeight(); j++) { + if (tooManyBlack.checkContradictionAt(board, board.getCell(i, j)) == null + || tooManyWhite.checkContradictionAt(board, board.getCell(i, j)) == null) { return true; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixView.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixView.java index 7e6453f58..55332e47d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixView.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/FillapixView.java @@ -3,7 +3,6 @@ import edu.rpi.legup.controller.BoardController; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.ui.boardview.GridBoardView; - import java.awt.*; public class FillapixView extends GridBoardView { @@ -16,8 +15,9 @@ public FillapixView(FillapixBoard board) { FillapixElementView elementView = new FillapixElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); elementViews.add(elementView); } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java index 7e43fc6b4..a6993778d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/BlackTile.java @@ -4,6 +4,10 @@ public class BlackTile extends PlaceableElement { public BlackTile() { - super("FPIX-PLAC-0001", "Black Tile", "The black tile", "edu/rpi/legup/images/fillapix/tiles/BlackTile.png"); + super( + "FPIX-ELEM-0001", + "Black Tile", + "The black tile", + "edu/rpi/legup/images/fillapix/tiles/BlackTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java index beee70e21..5852c1ad7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/NumberTile.java @@ -1,12 +1,16 @@ package edu.rpi.legup.puzzle.fillapix.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { private int object_num; public NumberTile() { - super("FPIX-UNPL-0001", "Number Tile", "A numbered tile", "edu/rpi/legup/images/fillapix/tiles/NumberTile.png"); + super( + "FPIX-ELEM-0002", + "Number Tile", + "A numbered tile", + "edu/rpi/legup/images/fillapix/tiles/NumberTile.png"); object_num = 0; } @@ -23,5 +27,4 @@ public int getTileNumber() { public void setTileNumber(int num) { object_num = num; } - } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java index ef754782f..82d0dffb9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/UnknownTile.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.fillapix.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { - super("FPIX-UNPL-0002", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); + super( + "FPIX-ELEM-0003", + "Unknown Tile", + "A blank tile", + "edu/rpi/legup/images/fillapix/tiles/UnknownTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java index dd27d2834..b2eedfc09 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/WhiteTile.java @@ -4,6 +4,10 @@ public class WhiteTile extends PlaceableElement { public WhiteTile() { - super("FPIX-PLAC-0002", "White Tile", "The white tile", "edu/rpi/legup/images/fillapix/tiles/WhiteTile.png"); + super( + "FPIX-ELEM-0004", + "White Tile", + "The white tile", + "edu/rpi/legup/images/fillapix/tiles/WhiteTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt index 0409fa800..1aece4b97 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/elements/fillapix_elements_reference_sheet.txt @@ -1,5 +1,4 @@ -FPIX-PLAC-0001 : BlackTile -FPIX-PLAC-0002 : WhiteTile - -FPIX-UNPL-0001 : NumberTile -FPIX-UNPL-0002 : UnknownTile \ No newline at end of file +FPIX-ELEM-0001 : BlackTile +FPIX-ELEM-0002 : NumberTile +FPIX-ELEM-0003 : UnknownTile +FPIX-ELEM-0004 : WhiteTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java index 1e5151c48..f0194bd39 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/BlackOrWhiteCaseRule.java @@ -8,13 +8,13 @@ import edu.rpi.legup.puzzle.fillapix.FillapixBoard; import edu.rpi.legup.puzzle.fillapix.FillapixCell; import edu.rpi.legup.puzzle.fillapix.FillapixCellType; - import java.util.ArrayList; import java.util.List; public class BlackOrWhiteCaseRule extends CaseRule { public BlackOrWhiteCaseRule() { - super("FPIX-CASE-0001", + super( + "FPIX-CASE-0001", "Black or White", "Each cell is either black or white.", "edu/rpi/legup/images/fillapix/cases/BlackOrWhite.png"); @@ -37,6 +37,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } Board case1 = board.copy(); FillapixCell cell1 = (FillapixCell) case1.getPuzzleElement(puzzleElement); @@ -62,20 +65,24 @@ public String checkRuleRaw(TreeTransition transition) { TreeTransition case1 = childTransitions.get(0); TreeTransition case2 = childTransitions.get(1); - if (case1.getBoard().getModifiedData().size() != 1 || - case2.getBoard().getModifiedData().size() != 1) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case."; + if (case1.getBoard().getModifiedData().size() != 1 + || case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; } FillapixCell mod1 = (FillapixCell) case1.getBoard().getModifiedData().iterator().next(); FillapixCell mod2 = (FillapixCell) case2.getBoard().getModifiedData().iterator().next(); if (!mod1.getLocation().equals(mod2.getLocation())) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; } if (!((mod1.getType() == FillapixCellType.BLACK && mod2.getType() == FillapixCellType.WHITE) - || (mod2.getType() == FillapixCellType.BLACK && mod1.getType() == FillapixCellType.WHITE))) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must an empty cell and a lit cell."; + || (mod2.getType() == FillapixCellType.BLACK + && mod1.getType() == FillapixCellType.WHITE))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must an empty cell and a lit cell."; } return null; @@ -85,4 +92,4 @@ public String checkRuleRaw(TreeTransition transition) { public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { return null; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithBlackDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithBlackDirectRule.java index 06a8045ed..ccc002f46 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithBlackDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithBlackDirectRule.java @@ -1,63 +1,66 @@ -package edu.rpi.legup.puzzle.fillapix.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.fillapix.FillapixBoard; -import edu.rpi.legup.puzzle.fillapix.FillapixCell; -import edu.rpi.legup.puzzle.fillapix.FillapixCellType; -import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; - -public class FinishWithBlackDirectRule extends DirectRule { - public FinishWithBlackDirectRule() { - super("FPIX-BASC-0001", - "Finish with Black", - "The remaining unknowns around and on a cell must be black to satisfy the number", - "edu/rpi/legup/images/fillapix/rules/FinishWithBlack.png"); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - FillapixBoard board = (FillapixBoard) transition.getBoard(); - FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard(); - FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); - FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); - - if (!(parentCell.getType() == FillapixCellType.UNKNOWN && cell.getType() == FillapixCellType.BLACK)) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be black to be applicable with this rule."; - } - - if (FillapixUtilities.isForcedBlack(parentBoard, cell)) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be black"; - } - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - FillapixBoard fillapixBoard = (FillapixBoard) node.getBoard().copy(); - for (PuzzleElement element : fillapixBoard.getPuzzleElements()) { - FillapixCell cell = (FillapixCell) element; - if (cell.getType() == FillapixCellType.UNKNOWN && FillapixUtilities.isForcedBlack((FillapixBoard) node.getBoard(), cell)) { - cell.setCellType(FillapixCellType.BLACK); - fillapixBoard.addModifiedData(cell); - } - } - if (fillapixBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return fillapixBoard; - } - } -} \ No newline at end of file +package edu.rpi.legup.puzzle.fillapix.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.fillapix.FillapixBoard; +import edu.rpi.legup.puzzle.fillapix.FillapixCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; +import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; + +public class FinishWithBlackDirectRule extends DirectRule { + public FinishWithBlackDirectRule() { + super( + "FPIX-BASC-0001", + "Finish with Black", + "The remaining unknowns around and on a cell must be black to satisfy the number", + "edu/rpi/legup/images/fillapix/rules/FinishWithBlack.png"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + FillapixBoard board = (FillapixBoard) transition.getBoard(); + FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard(); + FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); + FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); + + if (!(parentCell.getType() == FillapixCellType.UNKNOWN + && cell.getType() == FillapixCellType.BLACK)) { + return super.getInvalidUseOfRuleMessage() + + ": This cell must be black to be applicable with this rule."; + } + + if (FillapixUtilities.isForcedBlack(parentBoard, cell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be black"; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + FillapixBoard fillapixBoard = (FillapixBoard) node.getBoard().copy(); + for (PuzzleElement element : fillapixBoard.getPuzzleElements()) { + FillapixCell cell = (FillapixCell) element; + if (cell.getType() == FillapixCellType.UNKNOWN + && FillapixUtilities.isForcedBlack((FillapixBoard) node.getBoard(), cell)) { + cell.setCellType(FillapixCellType.BLACK); + fillapixBoard.addModifiedData(cell); + } + } + if (fillapixBoard.getModifiedData().isEmpty()) { + return null; + } else { + return fillapixBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithWhiteDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithWhiteDirectRule.java index 7e213a59c..6735fb8f4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithWhiteDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/FinishWithWhiteDirectRule.java @@ -1,63 +1,66 @@ -package edu.rpi.legup.puzzle.fillapix.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.fillapix.FillapixBoard; -import edu.rpi.legup.puzzle.fillapix.FillapixCell; -import edu.rpi.legup.puzzle.fillapix.FillapixCellType; -import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; - -public class FinishWithWhiteDirectRule extends DirectRule { - public FinishWithWhiteDirectRule() { - super("FPIX-BASC-0002", - "Finish with White", - "The remaining unknowns around and on a cell must be white to satisfy the number", - "edu/rpi/legup/images/fillapix/rules/FinishWithWhite.png"); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - FillapixBoard board = (FillapixBoard) transition.getBoard(); - FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard(); - FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); - FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); - - if (!(parentCell.getType() == FillapixCellType.UNKNOWN && cell.getType() == FillapixCellType.WHITE)) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be white to be applicable with this rule"; - } - - if (FillapixUtilities.isForcedWhite(parentBoard, cell)) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be white"; - } - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - FillapixBoard fillapixBoard = (FillapixBoard) node.getBoard().copy(); - for (PuzzleElement element : fillapixBoard.getPuzzleElements()) { - FillapixCell cell = (FillapixCell) element; - if (cell.getType() == FillapixCellType.UNKNOWN && FillapixUtilities.isForcedWhite((FillapixBoard) node.getBoard(), cell)) { - cell.setCellType(FillapixCellType.WHITE); - fillapixBoard.addModifiedData(cell); - } - } - if (fillapixBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return fillapixBoard; - } - } -} \ No newline at end of file +package edu.rpi.legup.puzzle.fillapix.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.fillapix.FillapixBoard; +import edu.rpi.legup.puzzle.fillapix.FillapixCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; +import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; + +public class FinishWithWhiteDirectRule extends DirectRule { + public FinishWithWhiteDirectRule() { + super( + "FPIX-BASC-0002", + "Finish with White", + "The remaining unknowns around and on a cell must be white to satisfy the number", + "edu/rpi/legup/images/fillapix/rules/FinishWithWhite.png"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + FillapixBoard board = (FillapixBoard) transition.getBoard(); + FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard(); + FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); + FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); + + if (!(parentCell.getType() == FillapixCellType.UNKNOWN + && cell.getType() == FillapixCellType.WHITE)) { + return super.getInvalidUseOfRuleMessage() + + ": This cell must be white to be applicable with this rule"; + } + + if (FillapixUtilities.isForcedWhite(parentBoard, cell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be white"; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + FillapixBoard fillapixBoard = (FillapixBoard) node.getBoard().copy(); + for (PuzzleElement element : fillapixBoard.getPuzzleElements()) { + FillapixCell cell = (FillapixCell) element; + if (cell.getType() == FillapixCellType.UNKNOWN + && FillapixUtilities.isForcedWhite((FillapixBoard) node.getBoard(), cell)) { + cell.setCellType(FillapixCellType.WHITE); + fillapixBoard.addModifiedData(cell); + } + } + if (fillapixBoard.getModifiedData().isEmpty()) { + return null; + } else { + return fillapixBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/MirrorDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/MirrorDirectRule.java index 656cedb3f..e91931bd4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/MirrorDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/MirrorDirectRule.java @@ -1,103 +1,107 @@ -package edu.rpi.legup.puzzle.fillapix.rules; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.CaseRule; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.fillapix.FillapixBoard; -import edu.rpi.legup.puzzle.fillapix.FillapixCell; -import edu.rpi.legup.puzzle.fillapix.FillapixCellType; -import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; - -public class MirrorDirectRule extends DirectRule { - public MirrorDirectRule() { - super("FPIX-BASC-0003", - "Mirror", - "Two adjacent clues with the same value must have the same number of black squares in their unshared regions", - "edu/rpi/legup/images/fillapix/rules/Mirror.png"); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - FillapixBoard board = (FillapixBoard) transition.getBoard(); - FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard().copy(); - FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); - FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); - - // cell has to have been empty before - if (parentCell.getType() != FillapixCellType.UNKNOWN) { - return super.getInvalidUseOfRuleMessage(); - } - - // parentBoard cannot have any contradictions - if (FillapixUtilities.checkBoardForContradiction(parentBoard)) { - return super.getInvalidUseOfRuleMessage(); - } - - // find all cells adjacent to cell that are numbered - ArrayList adjCells = FillapixUtilities.getAdjacentCells(parentBoard, parentCell); - ArrayList adjNums = new ArrayList(); - for (int i=0; i < adjCells.size(); i++) { - if ((adjCells.get(i)).getNumber() >= 0 && adjCells.get(i).getNumber() < 10) { - adjNums.add(adjCells.get(i)); - } - } - // the numbered cells must be next to another numbered cell of the same value - Iterator itr = adjNums.iterator(); - while (itr.hasNext()) { - FillapixCell adjNum = itr.next(); - adjCells = FillapixUtilities.getAdjacentCells(parentBoard, adjNum); - boolean found = false; - for (FillapixCell adjCell : adjCells) { - if (adjCell.getNumber() == adjNum.getNumber() && adjCell.getIndex() != adjNum.getIndex()) { - found = true; - } - } - if (!found) { - itr.remove(); - } - } - - // change the color of the parentCell, and check if there exists a valid board - if (cell.getType() == FillapixCellType.BLACK) { - parentCell.setCellType(FillapixCellType.WHITE); - } - else { - parentCell.setCellType(FillapixCellType.BLACK); - } - parentBoard.addModifiedData(parentCell); - CaseRule completeClue = new SatisfyClueCaseRule(); - List caseBoards; - for (FillapixCell adjNum : adjNums) { - caseBoards = completeClue.getCases(parentBoard, adjNum); - boolean found = true; - for (Board b : caseBoards) { - if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) { - found = false; - } - } - if (found) { - return null; - } - } - - return super.getInvalidUseOfRuleMessage(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} \ No newline at end of file +package edu.rpi.legup.puzzle.fillapix.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.fillapix.FillapixBoard; +import edu.rpi.legup.puzzle.fillapix.FillapixCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; +import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class MirrorDirectRule extends DirectRule { + public MirrorDirectRule() { + super( + "FPIX-BASC-0003", + "Mirror", + "Two adjacent clues with the same value must have the same number of black squares" + + " in their unshared regions", + "edu/rpi/legup/images/fillapix/rules/Mirror.png"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + FillapixBoard board = (FillapixBoard) transition.getBoard(); + FillapixBoard parentBoard = + (FillapixBoard) transition.getParents().get(0).getBoard().copy(); + FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); + FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); + + // cell has to have been empty before + if (parentCell.getType() != FillapixCellType.UNKNOWN) { + return super.getInvalidUseOfRuleMessage(); + } + + // parentBoard cannot have any contradictions + if (FillapixUtilities.checkBoardForContradiction(parentBoard)) { + return super.getInvalidUseOfRuleMessage(); + } + + // find all cells adjacent to cell that are numbered + ArrayList adjCells = + FillapixUtilities.getAdjacentCells(parentBoard, parentCell); + ArrayList adjNums = new ArrayList(); + for (int i = 0; i < adjCells.size(); i++) { + if ((adjCells.get(i)).getNumber() >= 0 && adjCells.get(i).getNumber() < 10) { + adjNums.add(adjCells.get(i)); + } + } + // the numbered cells must be next to another numbered cell of the same value + Iterator itr = adjNums.iterator(); + while (itr.hasNext()) { + FillapixCell adjNum = itr.next(); + adjCells = FillapixUtilities.getAdjacentCells(parentBoard, adjNum); + boolean found = false; + for (FillapixCell adjCell : adjCells) { + if (adjCell.getNumber() == adjNum.getNumber() + && adjCell.getIndex() != adjNum.getIndex()) { + found = true; + } + } + if (!found) { + itr.remove(); + } + } + + // change the color of the parentCell, and check if there exists a valid board + if (cell.getType() == FillapixCellType.BLACK) { + parentCell.setCellType(FillapixCellType.WHITE); + } else { + parentCell.setCellType(FillapixCellType.BLACK); + } + parentBoard.addModifiedData(parentCell); + CaseRule completeClue = new SatisfyClueCaseRule(); + List caseBoards; + for (FillapixCell adjNum : adjNums) { + caseBoards = completeClue.getCases(parentBoard, adjNum); + boolean found = true; + for (Board b : caseBoards) { + if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) { + found = false; + } + } + if (found) { + return null; + } + } + + return super.getInvalidUseOfRuleMessage(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/NonTouchingSharedDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/NonTouchingSharedDirectRule.java index fe94dbcb4..71a85a95b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/NonTouchingSharedDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/NonTouchingSharedDirectRule.java @@ -1,99 +1,103 @@ -package edu.rpi.legup.puzzle.fillapix.rules; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.CaseRule; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.fillapix.FillapixBoard; -import edu.rpi.legup.puzzle.fillapix.FillapixCell; -import edu.rpi.legup.puzzle.fillapix.FillapixCellType; -import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; - -public class NonTouchingSharedDirectRule extends DirectRule { - public NonTouchingSharedDirectRule() { - super("FPIX-BASC-0005", - "NonTouching Shared", - "Clues with shared cells have the same difference in black cells in their unshared regions as the difference in their numbers", - "edu/rpi/legup/images/fillapix/rules/TouchingSides.png"); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - FillapixBoard board = (FillapixBoard) transition.getBoard(); - FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard().copy(); - FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); - FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); - - // cell has to have been empty before - if (parentCell.getType() != FillapixCellType.UNKNOWN) { - return super.getInvalidUseOfRuleMessage(); - } - - // parentBoard cannot have any contradictions - if (FillapixUtilities.checkBoardForContradiction(parentBoard)) { - return super.getInvalidUseOfRuleMessage(); - } - - // get all adjCells that have a number - ArrayList adjCells = FillapixUtilities.getAdjacentCells(parentBoard, parentCell); - adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10); - /* remove any number cell that does not have another number cell not - * touching, but sharing cells */ - Iterator itr = adjCells.iterator(); - while (itr.hasNext()) { - ArrayList sharingCells = FillapixUtilities.getCellsAtDistance(parentBoard, parentCell, 1); - boolean found = false; - for (FillapixCell sharingCell : sharingCells) { - if (sharingCell.getNumber() >= 0 && sharingCell.getNumber() < 10) { - found = true; - } - } - if (!found) { - itr.remove(); - } - } - - // change the cell to the opposite color - if (cell.getType() == FillapixCellType.BLACK) { - parentCell.setCellType(FillapixCellType.WHITE); - } - else { - parentCell.setCellType(FillapixCellType.BLACK); - } - // check for some contradiction in all cases - parentBoard.addModifiedData(parentCell); - CaseRule completeClue = new SatisfyClueCaseRule(); - List caseBoards; - for (FillapixCell adjCell : adjCells) { - caseBoards = completeClue.getCases(parentBoard, adjCell); - boolean found = true; - for (Board b : caseBoards) { - if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) { - found = false; - } - } - if (found) { - return null; - } - } - - return super.getInvalidUseOfRuleMessage(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} \ No newline at end of file +package edu.rpi.legup.puzzle.fillapix.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.fillapix.FillapixBoard; +import edu.rpi.legup.puzzle.fillapix.FillapixCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; +import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class NonTouchingSharedDirectRule extends DirectRule { + public NonTouchingSharedDirectRule() { + super( + "FPIX-BASC-0005", + "NonTouching Shared", + "Clues with shared cells have the same difference in black cells in their unshared" + + " regions as the difference in their numbers", + "edu/rpi/legup/images/fillapix/rules/TouchingSides.png"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + FillapixBoard board = (FillapixBoard) transition.getBoard(); + FillapixBoard parentBoard = + (FillapixBoard) transition.getParents().get(0).getBoard().copy(); + FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); + FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); + + // cell has to have been empty before + if (parentCell.getType() != FillapixCellType.UNKNOWN) { + return super.getInvalidUseOfRuleMessage(); + } + + // parentBoard cannot have any contradictions + if (FillapixUtilities.checkBoardForContradiction(parentBoard)) { + return super.getInvalidUseOfRuleMessage(); + } + + // get all adjCells that have a number + ArrayList adjCells = + FillapixUtilities.getAdjacentCells(parentBoard, parentCell); + adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10); + /* remove any number cell that does not have another number cell not + * touching, but sharing cells */ + Iterator itr = adjCells.iterator(); + while (itr.hasNext()) { + ArrayList sharingCells = + FillapixUtilities.getCellsAtDistance(parentBoard, parentCell, 1); + boolean found = false; + for (FillapixCell sharingCell : sharingCells) { + if (sharingCell.getNumber() >= 0 && sharingCell.getNumber() < 10) { + found = true; + } + } + if (!found) { + itr.remove(); + } + } + + // change the cell to the opposite color + if (cell.getType() == FillapixCellType.BLACK) { + parentCell.setCellType(FillapixCellType.WHITE); + } else { + parentCell.setCellType(FillapixCellType.BLACK); + } + // check for some contradiction in all cases + parentBoard.addModifiedData(parentCell); + CaseRule completeClue = new SatisfyClueCaseRule(); + List caseBoards; + for (FillapixCell adjCell : adjCells) { + caseBoards = completeClue.getCases(parentBoard, adjCell); + boolean found = true; + for (Board b : caseBoards) { + if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) { + found = false; + } + } + if (found) { + return null; + } + } + + return super.getInvalidUseOfRuleMessage(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java index 4520add31..f8bb2d4f5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/SatisfyClueCaseRule.java @@ -1,12 +1,5 @@ package edu.rpi.legup.puzzle.fillapix.rules; -import java.awt.Point; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; - import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; @@ -17,13 +10,20 @@ import edu.rpi.legup.puzzle.fillapix.FillapixCell; import edu.rpi.legup.puzzle.fillapix.FillapixCellType; import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; +import java.awt.Point; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; public class SatisfyClueCaseRule extends CaseRule { public SatisfyClueCaseRule() { - super("FPIX-CASE-0002", - "Satisfy Clue", - "Each clue must touch that number of squares.", - "edu/rpi/legup/images/fillapix/cases/SatisfyClue.png"); + super( + "FPIX-CASE-0002", + "Satisfy Clue", + "Each clue must touch that number of squares.", + "edu/rpi/legup/images/fillapix/cases/SatisfyClue.png"); } @Override @@ -33,7 +33,9 @@ public CaseBoard getCaseBoard(Board board) { fillapixBoard.setModifiable(false); for (PuzzleElement data : fillapixBoard.getPuzzleElements()) { FillapixCell cell = (FillapixCell) data; - if (cell.getNumber() >= 0 && cell.getNumber() <= 9 && FillapixUtilities.hasEmptyAdjacent(fillapixBoard, cell)) { + if (cell.getNumber() >= 0 + && cell.getNumber() <= 9 + && FillapixUtilities.hasEmptyAdjacent(fillapixBoard, cell)) { caseBoard.addPickableElement(data); } } @@ -43,6 +45,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList(); + if (puzzleElement == null) { + return cases; + } // get value of cell FillapixBoard fillapixBoard = (FillapixBoard) board.copy(); @@ -70,26 +75,25 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { if (cellNumBlack > cellMaxBlack || cellNumEmpty == 0) { return cases; } - + // generate all cases as boolean expressions ArrayList combinations; combinations = FillapixUtilities.getCombinations(cellMaxBlack - cellNumBlack, cellNumEmpty); - for (int i=0; i < combinations.size(); i++) { + for (int i = 0; i < combinations.size(); i++) { Board case_ = board.copy(); - for (int j=0; j < combinations.get(i).length; j++) { + for (int j = 0; j < combinations.get(i).length; j++) { cell = (FillapixCell) case_.getPuzzleElement(emptyCells.get(j)); if (combinations.get(i)[j]) { cell.setCellType(FillapixCellType.BLACK); - } - else { + } else { cell.setCellType(FillapixCellType.WHITE); } case_.addModifiedData(cell); } cases.add(case_); } - + return cases; } @@ -99,26 +103,24 @@ public String checkRuleRaw(TreeTransition transition) { List childTransitions = parent.getChildren(); /* - * In order for the transition to be valid, it can only be applied to + * In order for the transition to be valid, it can only be applied to * one cell, thus: * * there must be modified cells * * all modified cells must share at least one common adjacent * cell * * all modified cells must fit within a 3X3 square - * * the center of one of the possible squaress must be a cell + * * the center of one of the possible squaress must be a cell * with a number * * that cells possible combinations must match the transitions * If all the above is verified, then the transition is valid */ - /* ensure there are modified cells */ Set modCells = transition.getBoard().getModifiedData(); if (modCells.size() <= 0) { return super.getInvalidUseOfRuleMessage(); } - /* ensure modified cells occur within a 3X3 square */ int minVertLoc = Integer.MAX_VALUE, maxVertLoc = Integer.MIN_VALUE; int minHorzLoc = Integer.MAX_VALUE, maxHorzLoc = Integer.MIN_VALUE; @@ -141,14 +143,16 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } - - /* get the center of all possible 3X3 squares, + /* get the center of all possible 3X3 squares, * and collect all that have numbers */ FillapixBoard board = (FillapixBoard) transition.getParents().get(0).getBoard(); Set possibleCenters = new TreeSet(); - possibleCenters.addAll(FillapixUtilities.getAdjacentCells(board, (FillapixCell) modCells.iterator().next())); + possibleCenters.addAll( + FillapixUtilities.getAdjacentCells( + board, (FillapixCell) modCells.iterator().next())); for (PuzzleElement modCell : modCells) { - possibleCenters.retainAll((FillapixUtilities.getAdjacentCells(board, (FillapixCell) modCell))); + possibleCenters.retainAll( + (FillapixUtilities.getAdjacentCells(board, (FillapixCell) modCell))); } // removing all elements without a valid number possibleCenters.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10); @@ -156,7 +160,6 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } - /* Now go through the remaining centers, and check if their combinations * match the transitions */ for (FillapixCell possibleCenter : possibleCenters) { @@ -176,7 +179,8 @@ public String checkRuleRaw(TreeTransition transition) { continue; } - ArrayList combinations = FillapixUtilities.getCombinations(maxBlack - numBlack, numEmpty); + ArrayList combinations = + FillapixUtilities.getCombinations(maxBlack - numBlack, numEmpty); if (combinations.size() != childTransitions.size()) { // not this center because combinations do not match transitions continue; @@ -192,11 +196,10 @@ public String checkRuleRaw(TreeTransition transition) { } boolean[] translatedModCells = new boolean[transModCells.size()]; - for (int i=0; i < transModCells.size(); i++) { + for (int i = 0; i < transModCells.size(); i++) { if (transModCells.get(i).getType() == FillapixCellType.BLACK) { translatedModCells[i] = true; - } - else { + } else { translatedModCells[i] = false; } } @@ -226,9 +229,8 @@ public String checkRuleRaw(TreeTransition transition) { return super.getInvalidUseOfRuleMessage(); } - @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { return null; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooFewBlackCellsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooFewBlackCellsContradictionRule.java index c37050978..df5954d63 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooFewBlackCellsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooFewBlackCellsContradictionRule.java @@ -7,25 +7,26 @@ import edu.rpi.legup.puzzle.fillapix.FillapixCell; import edu.rpi.legup.puzzle.fillapix.FillapixCellType; import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; - import java.util.ArrayList; public class TooFewBlackCellsContradictionRule extends ContradictionRule { public TooFewBlackCellsContradictionRule() { - super("FPIX-CONT-0001", + super( + "FPIX-CONT-0001", "Too Few Black Cells", "There may not be fewer black cells than the number.", "edu/rpi/legup/images/fillapix/contradictions/TooFewBlackCells.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooManyBlackCellsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooManyBlackCellsContradictionRule.java index 68395ce7f..38b47c972 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooManyBlackCellsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TooManyBlackCellsContradictionRule.java @@ -7,25 +7,26 @@ import edu.rpi.legup.puzzle.fillapix.FillapixCell; import edu.rpi.legup.puzzle.fillapix.FillapixCellType; import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; - import java.util.ArrayList; public class TooManyBlackCellsContradictionRule extends ContradictionRule { public TooManyBlackCellsContradictionRule() { - super("FPIX-CONT-0002", + super( + "FPIX-CONT-0002", "Too Many Black Cells", "There may not be more black cells than the number", "edu/rpi/legup/images/fillapix/contradictions/TooManyBlackCells.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -45,8 +46,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } if (numBlack > cellNum) { return null; - } - + } + return super.getNoContradictionMessage(); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingCornersDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingCornersDirectRule.java index 6f4be7842..72e2def47 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingCornersDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingCornersDirectRule.java @@ -1,108 +1,113 @@ -package edu.rpi.legup.puzzle.fillapix.rules; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.CaseRule; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.fillapix.FillapixBoard; -import edu.rpi.legup.puzzle.fillapix.FillapixCell; -import edu.rpi.legup.puzzle.fillapix.FillapixCellType; -import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; - -public class TouchingCornersDirectRule extends DirectRule { - public TouchingCornersDirectRule() { - super("FPIX-BASC-0005", - "Touching Corners", - "Clues with touching corners have the same difference in black cells in their unshared regions as the difference in their numbers", - "edu/rpi/legup/images/fillapix/rules/TouchingCorners.png"); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - FillapixBoard board = (FillapixBoard) transition.getBoard(); - FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard().copy(); - FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); - FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); - - // cell has to have been empty before - if (parentCell.getType() != FillapixCellType.UNKNOWN) { - return super.getInvalidUseOfRuleMessage(); - } - - // parentBoard cannot have any contradictions - if (FillapixUtilities.checkBoardForContradiction(parentBoard)) { - return super.getInvalidUseOfRuleMessage(); - } - - // get all adjCells that have a number - ArrayList adjCells = FillapixUtilities.getAdjacentCells(parentBoard, parentCell); - adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10); - /* remove any number cell that does not have another number cell diagonally - * adjacent to it on the opposite side of the modified cell */ - Iterator itr = adjCells.iterator(); - while (itr.hasNext()) { - FillapixCell adjCell = itr.next(); - - boolean found = false; - ArrayList adjAdjCells = FillapixUtilities.getAdjacentCells(parentBoard, adjCell); - for (FillapixCell adjAdjCell : adjAdjCells) { - if (adjAdjCell.getLocation().x != adjCell.getLocation().x && - adjAdjCell.getLocation().y != adjCell.getLocation().y && - adjAdjCell.getNumber() >= 0 && adjAdjCell.getNumber() < 10 && - adjAdjCell.getIndex() != parentCell.getIndex()) { - // adjAdjCell is diagonally adjacent to adjCell && it has a - // number && it is not parentCell - found = true; - } - } - - // does not qualify for this rule - if (!found) { - itr.remove(); - } - } - - // change the cell to the opposite color - if (cell.getType() == FillapixCellType.BLACK) { - parentCell.setCellType(FillapixCellType.WHITE); - } - else { - parentCell.setCellType(FillapixCellType.BLACK); - } - // check for some contradiction in all cases - parentBoard.addModifiedData(parentCell); - CaseRule completeClue = new SatisfyClueCaseRule(); - List caseBoards; - for (FillapixCell adjCell : adjCells) { - caseBoards = completeClue.getCases(parentBoard, adjCell); - boolean found = true; - for (Board b : caseBoards) { - if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) { - found = false; - } - } - if (found) { - return null; - } - } - - return super.getInvalidUseOfRuleMessage(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} \ No newline at end of file +package edu.rpi.legup.puzzle.fillapix.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.fillapix.FillapixBoard; +import edu.rpi.legup.puzzle.fillapix.FillapixCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; +import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class TouchingCornersDirectRule extends DirectRule { + public TouchingCornersDirectRule() { + super( + "FPIX-BASC-0005", + "Touching Corners", + "Clues with touching corners have the same difference in black cells in their" + + " unshared regions as the difference in their numbers", + "edu/rpi/legup/images/fillapix/rules/TouchingCorners.png"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + FillapixBoard board = (FillapixBoard) transition.getBoard(); + FillapixBoard parentBoard = + (FillapixBoard) transition.getParents().get(0).getBoard().copy(); + FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); + FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); + + // cell has to have been empty before + if (parentCell.getType() != FillapixCellType.UNKNOWN) { + return super.getInvalidUseOfRuleMessage(); + } + + // parentBoard cannot have any contradictions + if (FillapixUtilities.checkBoardForContradiction(parentBoard)) { + return super.getInvalidUseOfRuleMessage(); + } + + // get all adjCells that have a number + ArrayList adjCells = + FillapixUtilities.getAdjacentCells(parentBoard, parentCell); + adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10); + /* remove any number cell that does not have another number cell diagonally + * adjacent to it on the opposite side of the modified cell */ + Iterator itr = adjCells.iterator(); + while (itr.hasNext()) { + FillapixCell adjCell = itr.next(); + + boolean found = false; + ArrayList adjAdjCells = + FillapixUtilities.getAdjacentCells(parentBoard, adjCell); + for (FillapixCell adjAdjCell : adjAdjCells) { + if (adjAdjCell.getLocation().x != adjCell.getLocation().x + && adjAdjCell.getLocation().y != adjCell.getLocation().y + && adjAdjCell.getNumber() >= 0 + && adjAdjCell.getNumber() < 10 + && adjAdjCell.getIndex() != parentCell.getIndex()) { + // adjAdjCell is diagonally adjacent to adjCell && it has a + // number && it is not parentCell + found = true; + } + } + + // does not qualify for this rule + if (!found) { + itr.remove(); + } + } + + // change the cell to the opposite color + if (cell.getType() == FillapixCellType.BLACK) { + parentCell.setCellType(FillapixCellType.WHITE); + } else { + parentCell.setCellType(FillapixCellType.BLACK); + } + // check for some contradiction in all cases + parentBoard.addModifiedData(parentCell); + CaseRule completeClue = new SatisfyClueCaseRule(); + List caseBoards; + for (FillapixCell adjCell : adjCells) { + caseBoards = completeClue.getCases(parentBoard, adjCell); + boolean found = true; + for (Board b : caseBoards) { + if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) { + found = false; + } + } + if (found) { + return null; + } + } + + return super.getInvalidUseOfRuleMessage(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingSidesDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingSidesDirectRule.java index bd6dd0169..281dd5392 100644 --- a/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingSidesDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/fillapix/rules/TouchingSidesDirectRule.java @@ -1,115 +1,126 @@ -package edu.rpi.legup.puzzle.fillapix.rules; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.CaseRule; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.fillapix.FillapixBoard; -import edu.rpi.legup.puzzle.fillapix.FillapixCell; -import edu.rpi.legup.puzzle.fillapix.FillapixCellType; -import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; - -public class TouchingSidesDirectRule extends DirectRule { - public TouchingSidesDirectRule() { - super("FPIX-BASC-0004", - "Touching Sides", - "Clues with touching sides have the same difference in black cells in their unshared regions as the difference in their numbers", - "edu/rpi/legup/images/fillapix/rules/TouchingSides.png"); - } - - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - FillapixBoard board = (FillapixBoard) transition.getBoard(); - FillapixBoard parentBoard = (FillapixBoard) transition.getParents().get(0).getBoard().copy(); - FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); - FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); - - // cell has to have been empty before - if (parentCell.getType() != FillapixCellType.UNKNOWN) { - return super.getInvalidUseOfRuleMessage(); - } - - // parentBoard cannot have any contradictions - if (FillapixUtilities.checkBoardForContradiction(parentBoard)) { - return super.getInvalidUseOfRuleMessage(); - } - - // get all adjCells that have a number - ArrayList adjCells = FillapixUtilities.getAdjacentCells(parentBoard, parentCell); - adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10); - /* remove any number cell that does not have another number cell adjacent - * to it on the opposite side of the modified cell */ - Iterator itr = adjCells.iterator(); - while (itr.hasNext()) { - // calculate x and y offset of adjCell from cell - FillapixCell adjCell = itr.next(); - int xOffset = adjCell.getLocation().x - cell.getLocation().x; - int yOffset = adjCell.getLocation().y - cell.getLocation().y; - - boolean found = false; - // check vertically for numbered cell in opposite direction of cell - if (adjCell.getLocation().x + xOffset >= 0 && adjCell.getLocation().x < parentBoard.getWidth()) { - int adjNum = parentBoard.getCell(adjCell.getLocation().x + xOffset, adjCell.getLocation().y).getNumber(); - if (adjNum >= 0 && adjNum < 10) { - found = true; - } - } - // check horizontally for numbered cell in opposite direction of cell - if (adjCell.getLocation().y + yOffset >= 0 && adjCell.getLocation().y < parentBoard.getHeight()) { - int adjNum = parentBoard.getCell(adjCell.getLocation().x, adjCell.getLocation().y + yOffset).getNumber(); - if (adjNum >= 0 && adjNum < 10) { - found = true; - } - } - - // if no horizontally or vertically adjacent cell on opposite side of 'cell' has number, - // then adjCell is not valid, so should be removed - if (!found) { - itr.remove(); - } - } - - // change the cell to the opposite color - if (cell.getType() == FillapixCellType.BLACK) { - parentCell.setCellType(FillapixCellType.WHITE); - } - else { - parentCell.setCellType(FillapixCellType.BLACK); - } - // check for some contradiction in all cases - parentBoard.addModifiedData(parentCell); - CaseRule completeClue = new SatisfyClueCaseRule(); - List caseBoards; - for (FillapixCell adjCell : adjCells) { - caseBoards = completeClue.getCases(parentBoard, adjCell); - boolean found = true; - for (Board b : caseBoards) { - if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) { - found = false; - } - } - if (found) { - return null; - } - } - - return super.getInvalidUseOfRuleMessage(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} \ No newline at end of file +package edu.rpi.legup.puzzle.fillapix.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.fillapix.FillapixBoard; +import edu.rpi.legup.puzzle.fillapix.FillapixCell; +import edu.rpi.legup.puzzle.fillapix.FillapixCellType; +import edu.rpi.legup.puzzle.fillapix.FillapixUtilities; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class TouchingSidesDirectRule extends DirectRule { + public TouchingSidesDirectRule() { + super( + "FPIX-BASC-0004", + "Touching Sides", + "Clues with touching sides have the same difference in black cells in their" + + " unshared regions as the difference in their numbers", + "edu/rpi/legup/images/fillapix/rules/TouchingSides.png"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + FillapixBoard board = (FillapixBoard) transition.getBoard(); + FillapixBoard parentBoard = + (FillapixBoard) transition.getParents().get(0).getBoard().copy(); + FillapixCell cell = (FillapixCell) board.getPuzzleElement(puzzleElement); + FillapixCell parentCell = (FillapixCell) parentBoard.getPuzzleElement(puzzleElement); + + // cell has to have been empty before + if (parentCell.getType() != FillapixCellType.UNKNOWN) { + return super.getInvalidUseOfRuleMessage(); + } + + // parentBoard cannot have any contradictions + if (FillapixUtilities.checkBoardForContradiction(parentBoard)) { + return super.getInvalidUseOfRuleMessage(); + } + + // get all adjCells that have a number + ArrayList adjCells = + FillapixUtilities.getAdjacentCells(parentBoard, parentCell); + adjCells.removeIf(x -> x.getNumber() < 0 || x.getNumber() >= 10); + /* remove any number cell that does not have another number cell adjacent + * to it on the opposite side of the modified cell */ + Iterator itr = adjCells.iterator(); + while (itr.hasNext()) { + // calculate x and y offset of adjCell from cell + FillapixCell adjCell = itr.next(); + int xOffset = adjCell.getLocation().x - cell.getLocation().x; + int yOffset = adjCell.getLocation().y - cell.getLocation().y; + + boolean found = false; + // check vertically for numbered cell in opposite direction of cell + if (adjCell.getLocation().x + xOffset >= 0 + && adjCell.getLocation().x < parentBoard.getWidth()) { + int adjNum = + parentBoard + .getCell(adjCell.getLocation().x + xOffset, adjCell.getLocation().y) + .getNumber(); + if (adjNum >= 0 && adjNum < 10) { + found = true; + } + } + // check horizontally for numbered cell in opposite direction of cell + if (adjCell.getLocation().y + yOffset >= 0 + && adjCell.getLocation().y < parentBoard.getHeight()) { + int adjNum = + parentBoard + .getCell(adjCell.getLocation().x, adjCell.getLocation().y + yOffset) + .getNumber(); + if (adjNum >= 0 && adjNum < 10) { + found = true; + } + } + + // if no horizontally or vertically adjacent cell on opposite side of 'cell' has number, + // then adjCell is not valid, so should be removed + if (!found) { + itr.remove(); + } + } + + // change the cell to the opposite color + if (cell.getType() == FillapixCellType.BLACK) { + parentCell.setCellType(FillapixCellType.WHITE); + } else { + parentCell.setCellType(FillapixCellType.BLACK); + } + // check for some contradiction in all cases + parentBoard.addModifiedData(parentCell); + CaseRule completeClue = new SatisfyClueCaseRule(); + List caseBoards; + for (FillapixCell adjCell : adjCells) { + caseBoards = completeClue.getCases(parentBoard, adjCell); + boolean found = true; + for (Board b : caseBoards) { + if (!FillapixUtilities.checkBoardForContradiction((FillapixBoard) b)) { + found = false; + } + } + if (found) { + return null; + } + } + + return super.getInvalidUseOfRuleMessage(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/Heyawake.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/Heyawake.java index fc52a6fff..afe3dd652 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/Heyawake.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/Heyawake.java @@ -16,9 +16,7 @@ public Heyawake() { this.importer = new HeyawakeImporter(this); } - /** - * Initializes the view. Called by the invoker of the class - */ + /** Initializes the view. Called by the invoker of the class */ @Override public void initializeView() { boardView = new HeyawakeView((HeyawakeBoard) currentBoard); @@ -39,8 +37,8 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for HeyAwake * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for HeyAwake, false otherwise */ public boolean isValidDimensions(int rows, int columns) { @@ -65,7 +63,5 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { - - } + public void onBoardChange(Board board) {} } diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeBoard.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeBoard.java index 2f15213ec..cedb3a91b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeBoard.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.*; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeCell.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeCell.java index ce8c73424..480e2e39b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeCell.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.heyawake; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; public class HeyawakeCell extends GridCell { diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeController.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeController.java index 2bad91933..2d081d7da 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeController.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeController.java @@ -2,5 +2,4 @@ import edu.rpi.legup.controller.ElementController; -public class HeyawakeController extends ElementController { -} +public class HeyawakeController extends ElementController {} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeElementView.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeElementView.java index 5efec44ff..d30159856 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.heyawake; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class HeyawakeElementView extends GridElementView { @@ -39,7 +38,8 @@ public void drawElement(Graphics2D graphics2D) { FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = String.valueOf(puzzleElement.getData()); int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeExporter.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeExporter.java index 344a0be92..4470d77be 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeExporter.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import org.w3c.dom.Document; public class HeyawakeExporter extends PuzzleExporter { @@ -16,8 +15,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { HeyawakeBoard board; if (puzzle.getTree() != null) { board = (HeyawakeBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (HeyawakeBoard) puzzle.getBoardView().getBoard(); } @@ -29,7 +27,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { HeyawakeCell cell = (HeyawakeCell) puzzleElement; if (cell.getData() != -2) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeFactory.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeFactory.java index 96fc20e6f..8ecf24135 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeFactory.java @@ -4,17 +4,16 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class HeyawakeFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid @@ -23,7 +22,8 @@ public class HeyawakeFactory extends ElementFactory { public HeyawakeCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("Heyawake Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "Heyawake Factory: unknown puzzleElement puzzleElement"); } HeyawakeBoard heyawakeBoard = (HeyawakeBoard) board; @@ -36,7 +36,8 @@ public HeyawakeCell importCell(Node node, Board board) throws InvalidFileFormatE int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); int regionIndex = Integer.valueOf(attributeList.getNamedItem("region").getNodeValue()); if (x >= width || y >= height) { - throw new InvalidFileFormatException("Heyawake Factory: cell location out of bounds"); + throw new InvalidFileFormatException( + "Heyawake Factory: cell location out of bounds"); } if (value < -4 || value > 4) { throw new InvalidFileFormatException("Heyawake Factory: cell unknown value"); @@ -46,11 +47,10 @@ public HeyawakeCell importCell(Node node, Board board) throws InvalidFileFormatE cell.setIndex(y * height + x); heyawakeBoard.getRegions(); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Heyawake Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Heyawake Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("Heyawake Factory: could not find attribute(s)"); } } @@ -58,7 +58,7 @@ public HeyawakeCell importCell(Node node, Board board) throws InvalidFileFormatE /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeImporter.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeImporter.java index 7527c717f..6bbabd54d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeImporter.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class HeyawakeImporter extends PuzzleImporter { public HeyawakeImporter(Heyawake heyawake) { @@ -27,14 +26,12 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException if board can not be created */ @Override - public void initializeBoard(int rows, int columns) { - - } + public void initializeBoard(int rows, int columns) {} /** * Creates the board for building @@ -46,11 +43,13 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("Heyawake Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "Heyawake Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("Heyawake Importer: no puzzleElement found for board"); + throw new InvalidFileFormatException( + "Heyawake Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); NodeList elementDataList = dataElement.getElementsByTagName("cell"); @@ -59,9 +58,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { if (!boardElement.getAttribute("size").isEmpty()) { int size = Integer.valueOf(boardElement.getAttribute("size")); heyawakeBoard = new HeyawakeBoard(size); - } - else { - if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { int width = Integer.valueOf(boardElement.getAttribute("width")); int height = Integer.valueOf(boardElement.getAttribute("height")); heyawakeBoard = new HeyawakeBoard(width, height); @@ -76,7 +75,10 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int height = heyawakeBoard.getHeight(); for (int i = 0; i < elementDataList.getLength(); i++) { - HeyawakeCell cell = (HeyawakeCell) puzzle.getFactory().importCell(elementDataList.item(i), heyawakeBoard); + HeyawakeCell cell = + (HeyawakeCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), heyawakeBoard); Point loc = cell.getLocation(); if (cell.getData() != -2) { cell.setModifiable(false); @@ -96,9 +98,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } puzzle.setCurrentBoard(heyawakeBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Heyawake Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Heyawake Importer: unknown value where integer expected"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeView.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeView.java index 00506df0f..fba5f0eb7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeView.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/HeyawakeView.java @@ -4,7 +4,6 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.ui.boardview.ElementView; import edu.rpi.legup.ui.boardview.GridBoardView; - import java.awt.*; import java.awt.geom.Area; import java.util.HashMap; @@ -25,14 +24,14 @@ public HeyawakeView(HeyawakeBoard board) { HeyawakeElementView elementView = new HeyawakeElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); elementViews.add(elementView); int regionIndex = cell.getRegionIndex(); if (regionsBoundaries.get(regionIndex) == null) { regionsBoundaries.put(regionIndex, new Area(elementView.getBounds())); - } - else { + } else { regionsBoundaries.get(regionIndex).add(new Area(elementView.getBounds())); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/AdjacentBlacksContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/AdjacentBlacksContradictionRule.java index d2eceb7a1..88d293f5e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/AdjacentBlacksContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/AdjacentBlacksContradictionRule.java @@ -7,18 +7,21 @@ public class AdjacentBlacksContradictionRule extends ContradictionRule { public AdjacentBlacksContradictionRule() { - super("HEYA-CONT-0001", "Adjacent Blacks", + super( + "HEYA-CONT-0001", + "Adjacent Blacks", "", "edu/rpi/legup/images/heyawake/contradictions/adjacentBlacks.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BlackOrWhiteCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BlackOrWhiteCaseRule.java index 0e7552dd2..251be46ee 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BlackOrWhiteCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BlackOrWhiteCaseRule.java @@ -5,21 +5,21 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.List; public class BlackOrWhiteCaseRule extends CaseRule { public BlackOrWhiteCaseRule() { - super("HEYA-CASE-0001", + super( + "HEYA-CASE-0001", "Black or White", "", "edu/rpi/legup/images/heyawake/cases/BlackOrWhite.png"); } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -30,13 +30,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. This method is the one that should overridden in child classes. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. This method is the one that should overridden in child + * classes. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -44,7 +45,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Gets the case board that indicates where this case rule can be applied on the given {@link Board}. + * Gets the case board that indicates where this case rule can be applied on the given {@link + * Board}. * * @param board board to find locations where this case rule can be applied * @return a case board @@ -55,9 +57,10 @@ public CaseBoard getCaseBoard(Board board) { } /** - * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on this case rule. + * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on + * this case rule. * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BlackPathDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BlackPathDirectRule.java index 474bdccdd..1fc3d0776 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BlackPathDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BlackPathDirectRule.java @@ -1,7 +1,7 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -public class BlackPathDirectRule { - public BlackPathDirectRule() { - throw new RuntimeException("This rule has not been implemented"); - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +public class BlackPathDirectRule { + public BlackPathDirectRule() { + throw new RuntimeException("This rule has not been implemented"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BottleNeckDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BottleNeckDirectRule.java index f2e7fef5c..41d950378 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BottleNeckDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/BottleNeckDirectRule.java @@ -1,7 +1,7 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -public class BottleNeckDirectRule { - public BottleNeckDirectRule() { - throw new RuntimeException("This rule has not been implemented"); - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +public class BottleNeckDirectRule { + public BottleNeckDirectRule() { + throw new RuntimeException("This rule has not been implemented"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/FillRoomBlackDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/FillRoomBlackDirectRule.java index 828739160..aee1ae4bf 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/FillRoomBlackDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/FillRoomBlackDirectRule.java @@ -1,43 +1,45 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class FillRoomBlackDirectRule extends DirectRule { - - public FillRoomBlackDirectRule() { - super("HEYA-BASC-0003", - "Fill Room Black", - "", - "edu/rpi/legup/images/heyawake/rules/FillRoomBlack.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class FillRoomBlackDirectRule extends DirectRule { + + public FillRoomBlackDirectRule() { + super( + "HEYA-BASC-0003", + "Fill Room Black", + "", + "edu/rpi/legup/images/heyawake/rules/FillRoomBlack.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/FillRoomWhiteDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/FillRoomWhiteDirectRule.java index 6b1a11c29..c4609b239 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/FillRoomWhiteDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/FillRoomWhiteDirectRule.java @@ -1,43 +1,45 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class FillRoomWhiteDirectRule extends DirectRule { - - public FillRoomWhiteDirectRule() { - super("HEYA-BASC-0004", - "Fill Room White", - "", - "edu/rpi/legup/images/heyawake/rules/FillRoomWhite.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class FillRoomWhiteDirectRule extends DirectRule { + + public FillRoomWhiteDirectRule() { + super( + "HEYA-BASC-0004", + "Fill Room White", + "", + "edu/rpi/legup/images/heyawake/rules/FillRoomWhite.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/OneRowDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/OneRowDirectRule.java index 3e8c07a4d..8b6f21564 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/OneRowDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/OneRowDirectRule.java @@ -1,7 +1,7 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -public class OneRowDirectRule { - public OneRowDirectRule() { - throw new RuntimeException("This rule has not been implemented"); - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +public class OneRowDirectRule { + public OneRowDirectRule() { + throw new RuntimeException("This rule has not been implemented"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/PreventWhiteLineDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/PreventWhiteLineDirectRule.java index 0efd90694..f5d4e78b7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/PreventWhiteLineDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/PreventWhiteLineDirectRule.java @@ -1,7 +1,7 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -public class PreventWhiteLineDirectRule { - public PreventWhiteLineDirectRule() { - throw new RuntimeException("This rule has not been implemented"); - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +public class PreventWhiteLineDirectRule { + public PreventWhiteLineDirectRule() { + throw new RuntimeException("This rule has not been implemented"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/RoomTooEmptyContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/RoomTooEmptyContradictionRule.java index 0e0beaeb2..762b435a2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/RoomTooEmptyContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/RoomTooEmptyContradictionRule.java @@ -7,19 +7,21 @@ public class RoomTooEmptyContradictionRule extends ContradictionRule { public RoomTooEmptyContradictionRule() { - super("HEYA-CONT-0002", + super( + "HEYA-CONT-0002", "Room too Empty", "", "edu/rpi/legup/images/heyawake/contradictions/RoomTooEmpty.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/RoomTooFullContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/RoomTooFullContradictionRule.java index 1de746cb2..643f75f13 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/RoomTooFullContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/RoomTooFullContradictionRule.java @@ -7,19 +7,21 @@ public class RoomTooFullContradictionRule extends ContradictionRule { public RoomTooFullContradictionRule() { - super("HEYA-CONT-0003", + super( + "HEYA-CONT-0003", "Room too Full", "", "edu/rpi/legup/images/heyawake/contradictions/RoomTooFull.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/ThreeByThreeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/ThreeByThreeDirectRule.java index 6dee3fc83..cf2c241e3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/ThreeByThreeDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/ThreeByThreeDirectRule.java @@ -1,7 +1,7 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -public class ThreeByThreeDirectRule { - public ThreeByThreeDirectRule() { - throw new RuntimeException("This rule has not been implemented"); - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +public class ThreeByThreeDirectRule { + public ThreeByThreeDirectRule() { + throw new RuntimeException("This rule has not been implemented"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/TwoInCornerDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/TwoInCornerDirectRule.java index 8e2776fc7..83f1ca72f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/TwoInCornerDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/TwoInCornerDirectRule.java @@ -1,7 +1,7 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -public class TwoInCornerDirectRule { - public TwoInCornerDirectRule() { - throw new RuntimeException("This rule has not been implemented"); - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +public class TwoInCornerDirectRule { + public TwoInCornerDirectRule() { + throw new RuntimeException("This rule has not been implemented"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteAreaContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteAreaContradictionRule.java index a287d9c78..c0987d4f9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteAreaContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteAreaContradictionRule.java @@ -7,19 +7,21 @@ public class WhiteAreaContradictionRule extends ContradictionRule { public WhiteAreaContradictionRule() { - super("HEYA-CONT-0004", + super( + "HEYA-CONT-0004", "White Area", "", "edu/rpi/legup/images/heyawake/contradictions/WhiteArea.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteAroundBlackDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteAroundBlackDirectRule.java index 21a698d41..2e3bc1812 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteAroundBlackDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteAroundBlackDirectRule.java @@ -1,43 +1,45 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class WhiteAroundBlackDirectRule extends DirectRule { - - public WhiteAroundBlackDirectRule() { - super("HEYA-BASC-0009", - "White Around Black", - "", - "edu/rpi/legup/images/heyawake/rules/WhiteAroundBlack.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class WhiteAroundBlackDirectRule extends DirectRule { + + public WhiteAroundBlackDirectRule() { + super( + "HEYA-BASC-0009", + "White Around Black", + "", + "edu/rpi/legup/images/heyawake/rules/WhiteAroundBlack.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteEscapeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteEscapeDirectRule.java index 231d353e6..f151ec12a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteEscapeDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteEscapeDirectRule.java @@ -1,7 +1,7 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -public class WhiteEscapeDirectRule { - public WhiteEscapeDirectRule() { - throw new RuntimeException("This rule has not been implemented"); - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +public class WhiteEscapeDirectRule { + public WhiteEscapeDirectRule() { + throw new RuntimeException("This rule has not been implemented"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteLineContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteLineContradictionRule.java index 835bce98c..b695b8206 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteLineContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/WhiteLineContradictionRule.java @@ -7,20 +7,21 @@ public class WhiteLineContradictionRule extends ContradictionRule { public WhiteLineContradictionRule() { - super("HEYA-CONT-0005", + super( + "HEYA-CONT-0005", "White Line", "", "edu/rpi/legup/images/heyawake/contradictions/WhiteLine.png"); - } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/ZigZagWhiteDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/ZigZagWhiteDirectRule.java index 22a76b9a9..9df735b0b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/ZigZagWhiteDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/heyawake/rules/ZigZagWhiteDirectRule.java @@ -1,7 +1,7 @@ -package edu.rpi.legup.puzzle.heyawake.rules; - -public class ZigZagWhiteDirectRule { - public ZigZagWhiteDirectRule() { - throw new RuntimeException("This rule has not been implemented"); - } -} +package edu.rpi.legup.puzzle.heyawake.rules; + +public class ZigZagWhiteDirectRule { + public ZigZagWhiteDirectRule() { + throw new RuntimeException("This rule has not been implemented"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java index 6a67d28ca..a73806cd7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUp.java @@ -19,9 +19,7 @@ public LightUp() { this.factory = new LightUpCellFactory(); } - /** - * Initializes the game board. Called by the invoker of the class - */ + /** Initializes the game board. Called by the invoker of the class */ @Override public void initializeView() { boardView = new LightUpView((LightUpBoard) currentBoard); @@ -44,12 +42,12 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Light Up * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Light Up, false otherwise */ public boolean isValidDimensions(int rows, int columns) { - return rows > 0 && columns > 0; + return rows >= 0 && columns >= 0; } /** @@ -71,7 +69,9 @@ public boolean isBoardComplete(Board board) { } for (PuzzleElement data : lightUpBoard.getPuzzleElements()) { LightUpCell cell = (LightUpCell) data; - if ((cell.getType() == LightUpCellType.UNKNOWN || cell.getType() == LightUpCellType.EMPTY) && !cell.isLite()) { + if ((cell.getType() == LightUpCellType.UNKNOWN + || cell.getType() == LightUpCellType.EMPTY) + && !cell.isLite()) { return false; } } @@ -84,7 +84,5 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { - - } + public void onBoardChange(Board board) {} } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java index b15f49919..21084b8c7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpBoard.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.*; import java.util.HashSet; import java.util.Set; @@ -17,7 +16,8 @@ public LightUpBoard(int size) { } /** - * Sets cells in board to lite depending on whether there is a bulb cell in the current row or column + * Sets cells in board to lite depending on whether there is a bulb cell in the current row or + * column */ public void fillWithLight() { for (int y = 0; y < this.dimension.height; y++) { @@ -33,28 +33,32 @@ public void fillWithLight() { cell.setLite(true); for (int i = x + 1; i < this.dimension.width; i++) { LightUpCell c = getCell(i, y); - if (c.getType() == LightUpCellType.NUMBER || c.getType() == LightUpCellType.BLACK) { + if (c.getType() == LightUpCellType.NUMBER + || c.getType() == LightUpCellType.BLACK) { break; } c.setLite(true); } for (int i = x - 1; i >= 0; i--) { LightUpCell c = getCell(i, y); - if (c.getType() == LightUpCellType.NUMBER || c.getType() == LightUpCellType.BLACK) { + if (c.getType() == LightUpCellType.NUMBER + || c.getType() == LightUpCellType.BLACK) { break; } c.setLite(true); } for (int i = y + 1; i < this.dimension.height; i++) { LightUpCell c = getCell(x, i); - if (c.getType() == LightUpCellType.NUMBER || c.getType() == LightUpCellType.BLACK) { + if (c.getType() == LightUpCellType.NUMBER + || c.getType() == LightUpCellType.BLACK) { break; } c.setLite(true); } for (int i = y - 1; i >= 0; i--) { LightUpCell c = getCell(x, i); - if (c.getType() == LightUpCellType.NUMBER || c.getType() == LightUpCellType.BLACK) { + if (c.getType() == LightUpCellType.NUMBER + || c.getType() == LightUpCellType.BLACK) { break; } c.setLite(true); @@ -130,12 +134,12 @@ public int getNumAdjLite(LightUpCell cell) { } /** - * Gets the number of adjacent cells that are placable + * Gets the number of adjacent cells that are placeable * * @param cell specified cell - * @return number of adjacent cells that are placable + * @return number of adjacent cells that are placeable */ - public int getNumPlacble(LightUpCell cell) { + public int getNumPlaceable(LightUpCell cell) { int num = 0; Set adjCells = getAdj(cell); for (LightUpCell c : adjCells) { diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java index 36e5a5088..6d890e67b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCell.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; import java.awt.event.MouseEvent; @@ -17,30 +16,28 @@ public LightUpCell(int valueInt, Point location) { @Override public void setType(Element e, MouseEvent m) { switch (e.getElementID()) { - case "LTUP-PLAC-0001": + case "LTUP-ELEM-0002": this.data = -4; break; - case "LTUP-UNPL-0002": + case "LTUP-ELEM-0001": this.data = -1; break; - case "LTUP-UNPL-0003": + case "LTUP-ELEM-0004": this.data = -2; break; - case "LTUP-UNPL-0001": - switch (m.getButton()){ + case "LTUP-ELEM-0003": + switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data < 0 || this.data > 3) { this.data = 0; - } - else { + } else { this.data = this.data + 1; } break; case MouseEvent.BUTTON3: if (this.data > 0) { this.data = this.data - 1; - } - else { + } else { this.data = 4; } break; diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellController.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellController.java index 9c94b24f7..d4049897d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellController.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellController.java @@ -2,7 +2,6 @@ import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.event.MouseEvent; public class LightUpCellController extends ElementController { @@ -11,32 +10,31 @@ public void changeCell(MouseEvent e, PuzzleElement data) { LightUpCell cell = (LightUpCell) data; if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { - this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); - } - else { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { if (cell.getData() == -2) { data.setData(-4); - } - else { + } else { if (cell.getData() == -4) { data.setData(-3); - } - else { + } else { data.setData(-2); } } } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() == -4) { data.setData(-2); - } - else { + } else { if (cell.getData() == -2) { data.setData(-3); - } - else { + } else { data.setData(-4); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellFactory.java index 4914facfa..384aa2b74 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellFactory.java @@ -4,17 +4,16 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class LightUpCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid @@ -23,7 +22,8 @@ public class LightUpCellFactory extends ElementFactory { public LightUpCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("lightup Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "lightup Factory: unknown puzzleElement puzzleElement"); } LightUpBoard lightUpBoard = (LightUpBoard) board; @@ -35,7 +35,8 @@ public LightUpCell importCell(Node node, Board board) throws InvalidFileFormatEx int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); if (x >= width || y >= height) { - throw new InvalidFileFormatException("lightup Factory: cell location out of bounds"); + throw new InvalidFileFormatException( + "lightup Factory: cell location out of bounds"); } if (value < -4 || value > 4) { throw new InvalidFileFormatException("lightup Factory: cell unknown value"); @@ -44,11 +45,10 @@ public LightUpCell importCell(Node node, Board board) throws InvalidFileFormatEx LightUpCell cell = new LightUpCell(value, new Point(x, y)); cell.setIndex(y * height + x); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("lightup Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "lightup Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("lightup Factory: could not find attribute(s)"); } } @@ -56,7 +56,7 @@ public LightUpCell importCell(Node node, Board board) throws InvalidFileFormatEx /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellType.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellType.java index b0825910d..8472be7a6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellType.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpCellType.java @@ -1,7 +1,11 @@ package edu.rpi.legup.puzzle.lightup; public enum LightUpCellType { - BULB(-4), EMPTY(-3), UNKNOWN(-2), BLACK(-1), NUMBER(0); + BULB(-4), + EMPTY(-3), + UNKNOWN(-2), + BLACK(-1), + NUMBER(0); public int value; diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpElementView.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpElementView.java index 7f35d46a6..1b00b007d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.lightup; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class LightUpElementView extends GridElementView { @@ -40,37 +39,45 @@ public void drawElement(Graphics2D graphics2D) { FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = String.valueOf(puzzleElement.getData()); int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - } - else { + } else { if (type == LightUpCellType.BLACK) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(BLACK_COLOR); graphics2D.fillRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == LightUpCellType.EMPTY) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(cell.isLite() ? LITE : WHITE_COLOR); graphics2D.fillRect(location.x, location.y, size.width, size.height); graphics2D.setColor(BLACK_COLOR); - graphics2D.fillRect(location.x + size.width * 7 / 16, location.y + size.height * 7 / 16, size.width / 8, size.height / 8); + graphics2D.fillRect( + location.x + size.width * 7 / 16, + location.y + size.height * 7 / 16, + size.width / 8, + size.height / 8); graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == LightUpCellType.UNKNOWN) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(cell.isLite() ? LITE : Color.LIGHT_GRAY); graphics2D.fillRect(location.x, location.y, size.width, size.height); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == LightUpCellType.BULB) { graphics2D.setColor(Color.LIGHT_GRAY); graphics2D.fillRect(location.x, location.y, size.width, size.height); - graphics2D.drawImage(LightUpView.lightImage, location.x, location.y, size.width, size.height, LITE, null); + graphics2D.drawImage( + LightUpView.lightImage, + location.x, + location.y, + size.width, + size.height, + LITE, + null); graphics2D.setColor(BLACK_COLOR); graphics2D.drawRect(location.x, location.y, size.width, size.height); } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpExporter.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpExporter.java index 89024ad6c..0e8987020 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpExporter.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import org.w3c.dom.Document; public class LightUpExporter extends PuzzleExporter { @@ -16,8 +15,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { LightUpBoard board; if (puzzle.getTree() != null) { board = (LightUpBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (LightUpBoard) puzzle.getBoardView().getBoard(); } @@ -29,7 +27,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { LightUpCell cell = (LightUpCell) puzzleElement; if (cell.getData() != -2) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpImporter.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpImporter.java index 7ef24ca69..336b063f6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpImporter.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class LightUpImporter extends PuzzleImporter { public LightUpImporter(LightUp lightUp) { super(lightUp); @@ -26,7 +25,7 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException if board can not be created */ @@ -57,11 +56,13 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("lightup Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "lightup Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("lightup Importer: no puzzleElement found for board"); + throw new InvalidFileFormatException( + "lightup Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); NodeList elementDataList = dataElement.getElementsByTagName("cell"); @@ -70,9 +71,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { if (!boardElement.getAttribute("size").isEmpty()) { int size = Integer.valueOf(boardElement.getAttribute("size")); lightUpBoard = new LightUpBoard(size); - } - else { - if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { int width = Integer.valueOf(boardElement.getAttribute("width")); int height = Integer.valueOf(boardElement.getAttribute("height")); lightUpBoard = new LightUpBoard(width, height); @@ -87,7 +88,10 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int height = lightUpBoard.getHeight(); for (int i = 0; i < elementDataList.getLength(); i++) { - LightUpCell cell = (LightUpCell) puzzle.getFactory().importCell(elementDataList.item(i), lightUpBoard); + LightUpCell cell = + (LightUpCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), lightUpBoard); Point loc = cell.getLocation(); if (cell.getData() != -2) { cell.setModifiable(false); @@ -107,9 +111,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } puzzle.setCurrentBoard(lightUpBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("lightup Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "lightup Importer: unknown value where integer expected"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpView.java b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpView.java index 0fd57e705..ebce6a682 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpView.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/LightUpView.java @@ -7,23 +7,24 @@ import edu.rpi.legup.ui.boardview.DataSelectionView; import edu.rpi.legup.ui.boardview.GridBoardView; import edu.rpi.legup.ui.boardview.SelectionItemView; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.imageio.ImageIO; -import javax.swing.*; import java.awt.*; import java.io.IOException; +import javax.imageio.ImageIO; +import javax.swing.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class LightUpView extends GridBoardView { - private final static Logger LOGGER = LogManager.getLogger(LightUpView.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(LightUpView.class.getName()); static Image lightImage; static { try { - lightImage = ImageIO.read(ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/lightup/light.png")); - } - catch (IOException e) { + lightImage = + ImageIO.read( + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/lightup/light.png")); + } catch (IOException e) { LOGGER.error("Failed to open TreeTent images"); } } @@ -37,7 +38,8 @@ public LightUpView(LightUpBoard board) { LightUpElementView elementView = new LightUpElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); elementViews.add(elementView); } } @@ -50,14 +52,15 @@ public LightUpView(LightUpBoard board) { @Override public void onTreeElementChanged(TreeElement treeElement) { super.onTreeElementChanged(treeElement); - LightUpBoard lightUpBoard = board instanceof CaseBoard ? (LightUpBoard) ((CaseBoard) board).getBaseBoard() : (LightUpBoard) board; + LightUpBoard lightUpBoard = + board instanceof CaseBoard + ? (LightUpBoard) ((CaseBoard) board).getBaseBoard() + : (LightUpBoard) board; lightUpBoard.fillWithLight(); repaint(); } - /** - * Returns a DataSelectionView popup menu - */ + /** Returns a DataSelectionView popup menu */ public DataSelectionView getSelectionPopupMenu() { DataSelectionView selectionView = new DataSelectionView(elementController); GridLayout layout = new GridLayout(3, 1); @@ -69,7 +72,9 @@ public DataSelectionView getSelectionPopupMenu() { LightUpElementView element1 = new LightUpElementView(new LightUpCell(-2, null)); element1.setSize(iconSize); element1.setLocation(loc); - SelectionItemView item1 = new SelectionItemView(element1.getPuzzleElement(), new ImageIcon(element1.getImage())); + SelectionItemView item1 = + new SelectionItemView( + element1.getPuzzleElement(), new ImageIcon(element1.getImage())); item1.addActionListener(elementController); item1.setHorizontalTextPosition(SwingConstants.CENTER); selectionView.add(item1); @@ -77,7 +82,9 @@ public DataSelectionView getSelectionPopupMenu() { LightUpElementView element2 = new LightUpElementView(new LightUpCell(-4, null)); element2.setSize(iconSize); element2.setLocation(loc); - SelectionItemView item2 = new SelectionItemView(element2.getPuzzleElement(), new ImageIcon(element2.getImage())); + SelectionItemView item2 = + new SelectionItemView( + element2.getPuzzleElement(), new ImageIcon(element2.getImage())); item2.addActionListener(elementController); item2.setHorizontalTextPosition(SwingConstants.CENTER); selectionView.add(item2); @@ -85,7 +92,9 @@ public DataSelectionView getSelectionPopupMenu() { LightUpElementView element3 = new LightUpElementView(new LightUpCell(-3, null)); element3.setSize(iconSize); element3.setLocation(loc); - SelectionItemView item3 = new SelectionItemView(element3.getPuzzleElement(), new ImageIcon(element3.getImage())); + SelectionItemView item3 = + new SelectionItemView( + element3.getPuzzleElement(), new ImageIcon(element3.getImage())); item3.addActionListener(elementController); item3.setHorizontalTextPosition(SwingConstants.CENTER); selectionView.add(item3); diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java index d3e8cf506..eed3795d7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BlackTile.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class BlackTile extends NonPlaceableElement { +public class BlackTile extends PlaceableElement { public BlackTile() { - super("LTUP-UNPL-0002", "Black Tile", "The black tile", "edu/rpi/legup/images/lightup/black.gif"); + super( + "LTUP-ELEM-0001", + "Black Tile", + "The black tile", + "edu/rpi/legup/images/lightup/black.gif"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java index 5fc4a334f..61ebac3d0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/BulbTile.java @@ -4,6 +4,10 @@ public class BulbTile extends PlaceableElement { public BulbTile() { - super("LTUP-PLAC-0001", "Bulb Tile", "The bulb tile", "edu/rpi/legup/images/lightup/light.png"); + super( + "LTUP-ELEM-0002", + "Bulb Tile", + "The bulb tile", + "edu/rpi/legup/images/lightup/light.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java index e96a969e5..26f9be46c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/NumberTile.java @@ -1,18 +1,26 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { int object_number; // Follow the default format and resolves the NoSuchMethod error public NumberTile() { - super("LTUP-UNPL-0001", "Number Tile", "The number tile", "edu/rpi/legup/images/lightup/1.gif"); + super( + "LTUP-ELEM-0003", + "Number Tile", + "The number tile", + "edu/rpi/legup/images/lightup/1.gif"); } public NumberTile(int num) { - super("LTUP-UNPL-0001", "Number Tile", "The number tile", "edu/rpi/legup/images/lightup/" + num + ".gif"); + super( + "LTUP-ELEM-0003", + "Number Tile", + "The number tile", + "edu/rpi/legup/images/lightup/" + num + ".gif"); if (num > 3 || num < 1) num = 1; object_number = num; } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java index 6839e70de..a724be600 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/UnknownTile.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.lightup.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { - super("LTUP-UNPL-0003", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/lightup/UnknownTile.png"); + super( + "LTUP-ELEM-0004", + "Unknown Tile", + "A blank tile", + "edu/rpi/legup/images/lightup/UnknownTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt new file mode 100644 index 000000000..93c97de1c --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/elements/lightup_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +LTUP-ELEM-0001 : BlackTile +LTUP-ELEM-0002 : BulbTile +LTUP-ELEM-0003 : NumberTile +LTUP-ELEM-0004 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/BulbsInPathContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/BulbsInPathContradictionRule.java index 2804e6eab..90652888c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/BulbsInPathContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/BulbsInPathContradictionRule.java @@ -6,24 +6,26 @@ import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; - import java.awt.*; public class BulbsInPathContradictionRule extends ContradictionRule { public BulbsInPathContradictionRule() { - super("LTUP-CONT-0001", "Bulbs In Path", + super( + "LTUP-CONT-0001", + "Bulbs In Path", "A bulb cannot be placed in another bulb's path.", "edu/rpi/legup/images/lightup/contradictions/BulbsInPath.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -38,8 +40,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { LightUpCell c = lightUpBoard.getCell(i, location.y); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else { + } else { if (c.getType() == LightUpCellType.BULB) { return null; } @@ -49,8 +50,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { LightUpCell c = lightUpBoard.getCell(i, location.y); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else { + } else { if (c.getType() == LightUpCellType.BULB) { return null; } @@ -60,8 +60,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { LightUpCell c = lightUpBoard.getCell(location.x, i); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else { + } else { if (c.getType() == LightUpCellType.BULB) { return null; } @@ -71,8 +70,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { LightUpCell c = lightUpBoard.getCell(location.x, i); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else { + } else { if (c.getType() == LightUpCellType.BULB) { return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/CannotLightACellContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/CannotLightACellContradictionRule.java index 011bf1c0a..0ed88636c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/CannotLightACellContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/CannotLightACellContradictionRule.java @@ -6,24 +6,26 @@ import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; - import java.awt.*; public class CannotLightACellContradictionRule extends ContradictionRule { public CannotLightACellContradictionRule() { - super("LTUP-CONT-0002", "Cannot Light A Cell", + super( + "LTUP-CONT-0002", + "Cannot Light A Cell", "All cells must be able to be lit.", "edu/rpi/legup/images/lightup/contradictions/CannotLightACell.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -42,8 +44,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { LightUpCell c = lightUpBoard.getCell(i, location.y); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else { + } else { if (c.getType() == LightUpCellType.UNKNOWN && !c.isLite()) { hor_count += 1; } @@ -53,8 +54,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { LightUpCell c = lightUpBoard.getCell(i, location.y); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else { + } else { if (c.getType() == LightUpCellType.UNKNOWN && !c.isLite()) { hor_count += 1; } @@ -64,8 +64,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { LightUpCell c = lightUpBoard.getCell(location.x, i); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else { + } else { if (c.getType() == LightUpCellType.UNKNOWN && !c.isLite()) { ver_count += 1; } @@ -75,8 +74,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { LightUpCell c = lightUpBoard.getCell(location.x, i); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else { + } else { if (c.getType() == LightUpCellType.UNKNOWN && !c.isLite()) { ver_count += 1; } @@ -88,4 +86,4 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } return super.getNoContradictionMessage(); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/EmptyCellinLightDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/EmptyCellinLightDirectRule.java index a40ede284..269ef0ad5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/EmptyCellinLightDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/EmptyCellinLightDirectRule.java @@ -1,64 +1,68 @@ -package edu.rpi.legup.puzzle.lightup.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import edu.rpi.legup.puzzle.lightup.LightUpCell; -import edu.rpi.legup.puzzle.lightup.LightUpCellType; - -public class EmptyCellinLightDirectRule extends DirectRule { - - public EmptyCellinLightDirectRule() { - super("LTUP-BASC-0002", "Empty Cells in Light", - "Cells in light must be empty.", - "edu/rpi/legup/images/lightup/rules/EmptyCellInLight.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - LightUpBoard initialBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); - initialBoard.fillWithLight(); - LightUpCell initCell = (LightUpCell) initialBoard.getPuzzleElement(puzzleElement); - LightUpCell finalCell = (LightUpCell) transition.getBoard().getPuzzleElement(puzzleElement); - if (finalCell.getType() == LightUpCellType.EMPTY && initCell.getType() == LightUpCellType.UNKNOWN && initCell.isLite()) { - return null; - } - return super.getInvalidUseOfRuleMessage() + ": Cell is not forced to be empty"; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); - for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { - LightUpCell cell = (LightUpCell) element; - if (cell.getType() == LightUpCellType.UNKNOWN && cell.isLite()) { - cell.setData(LightUpCellType.EMPTY.value); - lightUpBoard.addModifiedData(cell); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.lightup.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; +import edu.rpi.legup.puzzle.lightup.LightUpCell; +import edu.rpi.legup.puzzle.lightup.LightUpCellType; + +public class EmptyCellinLightDirectRule extends DirectRule { + + public EmptyCellinLightDirectRule() { + super( + "LTUP-BASC-0002", + "Empty Cells in Light", + "Cells in light must be empty.", + "edu/rpi/legup/images/lightup/rules/EmptyCellInLight.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + LightUpBoard initialBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); + initialBoard.fillWithLight(); + LightUpCell initCell = (LightUpCell) initialBoard.getPuzzleElement(puzzleElement); + LightUpCell finalCell = (LightUpCell) transition.getBoard().getPuzzleElement(puzzleElement); + if (finalCell.getType() == LightUpCellType.EMPTY + && initCell.getType() == LightUpCellType.UNKNOWN + && initCell.isLite()) { + return null; + } + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced to be empty"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); + for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { + LightUpCell cell = (LightUpCell) element; + if (cell.getType() == LightUpCellType.UNKNOWN && cell.isLite()) { + cell.setData(LightUpCellType.EMPTY.value); + lightUpBoard.addModifiedData(cell); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/EmptyCornersDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/EmptyCornersDirectRule.java index 04c493f08..702c116c1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/EmptyCornersDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/EmptyCornersDirectRule.java @@ -1,115 +1,117 @@ -package edu.rpi.legup.puzzle.lightup.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import edu.rpi.legup.puzzle.lightup.LightUpCell; -import edu.rpi.legup.puzzle.lightup.LightUpCellType; - -import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -public class EmptyCornersDirectRule extends DirectRule { - - public EmptyCornersDirectRule() { - super("LTUP-BASC-0003", "Empty Corners", - "Cells on the corners of a number must be empty if placing bulbs would prevent the number from being satisfied.", - "edu/rpi/legup/images/lightup/rules/EmptyCorners.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - LightUpBoard initialBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); - LightUpCell cell = (LightUpCell) initialBoard.getPuzzleElement(puzzleElement); - LightUpBoard finalBoard = (LightUpBoard) transition.getBoard(); - LightUpCell finalCell = (LightUpCell) finalBoard.getPuzzleElement(puzzleElement); - - if (!(cell.getType() == LightUpCellType.UNKNOWN && finalCell.getType() == LightUpCellType.EMPTY)) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be an empty cell"; - } - - Point loc = finalCell.getLocation(); - List numberedCells = new ArrayList<>(); - LightUpCell upperRight = finalBoard.getCell(loc.x + 1, loc.y - 1); - if (upperRight != null && upperRight.getType() == LightUpCellType.NUMBER) { - numberedCells.add(upperRight); - } - LightUpCell upperLeft = finalBoard.getCell(loc.x - 1, loc.y - 1); - if (upperLeft != null && upperLeft.getType() == LightUpCellType.NUMBER) { - numberedCells.add(upperLeft); - } - LightUpCell lowerRight = finalBoard.getCell(loc.x + 1, loc.y + 1); - if (lowerRight != null && lowerRight.getType() == LightUpCellType.NUMBER) { - numberedCells.add(lowerRight); - } - LightUpCell lowerLeft = finalBoard.getCell(loc.x - 1, loc.y + 1); - if (lowerLeft != null && lowerLeft.getType() == LightUpCellType.NUMBER) { - numberedCells.add(lowerLeft); - } - if (numberedCells.isEmpty()) { - return super.getInvalidUseOfRuleMessage() + ": This cell must diagonal to a numbered cell"; - } - - TooFewBulbsContradictionRule tooFew = new TooFewBulbsContradictionRule(); - LightUpBoard bulbCaseBoard = finalBoard.copy(); - LightUpCell bulbCaseCell = (LightUpCell) bulbCaseBoard.getPuzzleElement(puzzleElement); - bulbCaseCell.setData(LightUpCellType.BULB.value); - bulbCaseBoard.fillWithLight(); - - boolean createsContra = false; - for (LightUpCell c : numberedCells) { - createsContra |= tooFew.checkContradictionAt(bulbCaseBoard, c) == null; - } - if (createsContra) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be empty"; - } - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); - LightUpBoard lightUpBoardCopy = (LightUpBoard) node.getBoard().copy(); - TreeTransition transition = new TreeTransition(node, lightUpBoardCopy); - for (PuzzleElement element : lightUpBoardCopy.getPuzzleElements()) { - LightUpCell cell = (LightUpCell) element; - int temp = cell.getData(); - cell.setData(LightUpCellType.EMPTY.value); - if (checkRuleRawAt(transition, cell) == null) { - LightUpCell modCell = (LightUpCell) lightUpBoard.getPuzzleElement(cell); - modCell.setData(LightUpCellType.EMPTY.value); - lightUpBoard.addModifiedData(modCell); - } - else { - cell.setData(temp); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.lightup.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; +import edu.rpi.legup.puzzle.lightup.LightUpCell; +import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class EmptyCornersDirectRule extends DirectRule { + + public EmptyCornersDirectRule() { + super( + "LTUP-BASC-0003", + "Empty Corners", + "Cells on the corners of a number must be empty if placing bulbs would prevent the" + + " number from being satisfied.", + "edu/rpi/legup/images/lightup/rules/EmptyCorners.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + LightUpBoard initialBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); + LightUpCell cell = (LightUpCell) initialBoard.getPuzzleElement(puzzleElement); + LightUpBoard finalBoard = (LightUpBoard) transition.getBoard(); + LightUpCell finalCell = (LightUpCell) finalBoard.getPuzzleElement(puzzleElement); + + if (!(cell.getType() == LightUpCellType.UNKNOWN + && finalCell.getType() == LightUpCellType.EMPTY)) { + return super.getInvalidUseOfRuleMessage() + ": This cell must be an empty cell"; + } + + Point loc = finalCell.getLocation(); + List numberedCells = new ArrayList<>(); + LightUpCell upperRight = finalBoard.getCell(loc.x + 1, loc.y - 1); + if (upperRight != null && upperRight.getType() == LightUpCellType.NUMBER) { + numberedCells.add(upperRight); + } + LightUpCell upperLeft = finalBoard.getCell(loc.x - 1, loc.y - 1); + if (upperLeft != null && upperLeft.getType() == LightUpCellType.NUMBER) { + numberedCells.add(upperLeft); + } + LightUpCell lowerRight = finalBoard.getCell(loc.x + 1, loc.y + 1); + if (lowerRight != null && lowerRight.getType() == LightUpCellType.NUMBER) { + numberedCells.add(lowerRight); + } + LightUpCell lowerLeft = finalBoard.getCell(loc.x - 1, loc.y + 1); + if (lowerLeft != null && lowerLeft.getType() == LightUpCellType.NUMBER) { + numberedCells.add(lowerLeft); + } + if (numberedCells.isEmpty()) { + return super.getInvalidUseOfRuleMessage() + + ": This cell must diagonal to a numbered cell"; + } + + TooFewBulbsContradictionRule tooFew = new TooFewBulbsContradictionRule(); + LightUpBoard bulbCaseBoard = finalBoard.copy(); + LightUpCell bulbCaseCell = (LightUpCell) bulbCaseBoard.getPuzzleElement(puzzleElement); + bulbCaseCell.setData(LightUpCellType.BULB.value); + bulbCaseBoard.fillWithLight(); + + boolean createsContra = false; + for (LightUpCell c : numberedCells) { + createsContra |= tooFew.checkContradictionAt(bulbCaseBoard, c) == null; + } + if (createsContra) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be empty"; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); + LightUpBoard lightUpBoardCopy = (LightUpBoard) node.getBoard().copy(); + TreeTransition transition = new TreeTransition(node, lightUpBoardCopy); + for (PuzzleElement element : lightUpBoardCopy.getPuzzleElements()) { + LightUpCell cell = (LightUpCell) element; + int temp = cell.getData(); + cell.setData(LightUpCellType.EMPTY.value); + if (checkRuleRawAt(transition, cell) == null) { + LightUpCell modCell = (LightUpCell) lightUpBoard.getPuzzleElement(cell); + modCell.setData(LightUpCellType.EMPTY.value); + lightUpBoard.addModifiedData(modCell); + } else { + cell.setData(temp); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/FinishWithBulbsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/FinishWithBulbsDirectRule.java index cdea7880f..3f884d459 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/FinishWithBulbsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/FinishWithBulbsDirectRule.java @@ -1,107 +1,110 @@ -package edu.rpi.legup.puzzle.lightup.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import edu.rpi.legup.puzzle.lightup.LightUpCell; -import edu.rpi.legup.puzzle.lightup.LightUpCellType; - -import java.util.Set; - -public class FinishWithBulbsDirectRule extends DirectRule { - - public FinishWithBulbsDirectRule() { - super("LTUP-BASC-0004", "Finish with Bulbs", - "The remaining unknowns around a block must be bulbs to satisfy the number.", - "edu/rpi/legup/images/lightup/rules/FinishWithBulbs.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - LightUpBoard initialBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); - LightUpCell initCell = (LightUpCell) initialBoard.getPuzzleElement(puzzleElement); - LightUpBoard finalBoard = (LightUpBoard) transition.getBoard(); - LightUpCell finalCell = (LightUpCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(initCell.getType() == LightUpCellType.UNKNOWN && finalCell.getType() == LightUpCellType.BULB)) { - return super.getInvalidUseOfRuleMessage() + ": Modified cells must be bulbs"; - } - - Set adjCells = finalBoard.getAdj(finalCell); - adjCells.removeIf(cell -> cell.getType() != LightUpCellType.NUMBER); - if (adjCells.isEmpty()) { - return super.getInvalidUseOfRuleMessage() + ": This cell is not adjacent to a numbered cell"; - } - - LightUpBoard emptyCase = initialBoard.copy(); - emptyCase.getPuzzleElement(finalCell).setData(LightUpCellType.EMPTY.value); - TooFewBulbsContradictionRule tooFew = new TooFewBulbsContradictionRule(); - for (LightUpCell c : adjCells) { - if (tooFew.checkContradictionAt(emptyCase, c) == null) { - return null; - } - } - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be a bulb"; - } - - /** - * Determines whether the specified cell is forced to be a bulb or not - * - * @param board the entire board - * @param cell specified cell - * @return whether cell is forced to be a bulb or not - */ - private boolean isForced(LightUpBoard board, LightUpCell cell) { - Set adjCells = board.getAdj(cell); - adjCells.removeIf(c -> c.getType() != LightUpCellType.NUMBER); - if (adjCells.isEmpty()) { - return false; - } - - LightUpBoard emptyCase = board.copy(); - emptyCase.getPuzzleElement(cell).setData(LightUpCellType.EMPTY.value); - TooFewBulbsContradictionRule tooFew = new TooFewBulbsContradictionRule(); - for (LightUpCell c : adjCells) { - if (tooFew.checkContradictionAt(emptyCase, c) == null) { - return true; - } - } - return false; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - LightUpBoard initialBoard = (LightUpBoard) node.getBoard(); - LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); - for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { - LightUpCell cell = (LightUpCell) element; - if (cell.getType() == LightUpCellType.UNKNOWN && isForced(initialBoard, cell)) { - cell.setData(LightUpCellType.BULB.value); - lightUpBoard.addModifiedData(cell); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.lightup.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; +import edu.rpi.legup.puzzle.lightup.LightUpCell; +import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import java.util.Set; + +public class FinishWithBulbsDirectRule extends DirectRule { + + public FinishWithBulbsDirectRule() { + super( + "LTUP-BASC-0004", + "Finish with Bulbs", + "The remaining unknowns around a block must be bulbs to satisfy the number.", + "edu/rpi/legup/images/lightup/rules/FinishWithBulbs.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + LightUpBoard initialBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); + LightUpCell initCell = (LightUpCell) initialBoard.getPuzzleElement(puzzleElement); + LightUpBoard finalBoard = (LightUpBoard) transition.getBoard(); + LightUpCell finalCell = (LightUpCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(initCell.getType() == LightUpCellType.UNKNOWN + && finalCell.getType() == LightUpCellType.BULB)) { + return super.getInvalidUseOfRuleMessage() + ": Modified cells must be bulbs"; + } + + Set adjCells = finalBoard.getAdj(finalCell); + adjCells.removeIf(cell -> cell.getType() != LightUpCellType.NUMBER); + if (adjCells.isEmpty()) { + return super.getInvalidUseOfRuleMessage() + + ": This cell is not adjacent to a numbered cell"; + } + + LightUpBoard emptyCase = initialBoard.copy(); + emptyCase.getPuzzleElement(finalCell).setData(LightUpCellType.EMPTY.value); + TooFewBulbsContradictionRule tooFew = new TooFewBulbsContradictionRule(); + for (LightUpCell c : adjCells) { + if (tooFew.checkContradictionAt(emptyCase, c) == null) { + return null; + } + } + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be a bulb"; + } + + /** + * Determines whether the specified cell is forced to be a bulb or not + * + * @param board the entire board + * @param cell specified cell + * @return whether cell is forced to be a bulb or not + */ + private boolean isForced(LightUpBoard board, LightUpCell cell) { + Set adjCells = board.getAdj(cell); + adjCells.removeIf(c -> c.getType() != LightUpCellType.NUMBER); + if (adjCells.isEmpty()) { + return false; + } + + LightUpBoard emptyCase = board.copy(); + emptyCase.getPuzzleElement(cell).setData(LightUpCellType.EMPTY.value); + TooFewBulbsContradictionRule tooFew = new TooFewBulbsContradictionRule(); + for (LightUpCell c : adjCells) { + if (tooFew.checkContradictionAt(emptyCase, c) == null) { + return true; + } + } + return false; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + LightUpBoard initialBoard = (LightUpBoard) node.getBoard(); + LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); + for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { + LightUpCell cell = (LightUpCell) element; + if (cell.getType() == LightUpCellType.UNKNOWN && isForced(initialBoard, cell)) { + cell.setData(LightUpCellType.BULB.value); + lightUpBoard.addModifiedData(cell); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/FinishWithEmptyDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/FinishWithEmptyDirectRule.java index f7433150c..678ee67a2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/FinishWithEmptyDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/FinishWithEmptyDirectRule.java @@ -1,118 +1,122 @@ -package edu.rpi.legup.puzzle.lightup.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import edu.rpi.legup.puzzle.lightup.LightUpCell; -import edu.rpi.legup.puzzle.lightup.LightUpCellType; - -import java.awt.*; - -public class FinishWithEmptyDirectRule extends DirectRule { - - public FinishWithEmptyDirectRule() { - super("LTUP-BASC-0005", "Finish with Empty", - "The remaining unknowns around a block must be empty if the number is satisfied.", - "edu/rpi/legup/images/lightup/rules/FinishWithEmpty.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - LightUpBoard initialBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); - LightUpBoard finalBoard = (LightUpBoard) transition.getBoard(); - LightUpCell cell = (LightUpCell) finalBoard.getPuzzleElement(puzzleElement); - if (cell.getType() != LightUpCellType.EMPTY) { - return super.getInvalidUseOfRuleMessage() + ": Modified cells must be empty"; - } - - if (isForced(initialBoard, cell.getLocation())) { - return null; - } - return super.getInvalidUseOfRuleMessage() + ": Empty is not forced"; - } - - /** - * Checks whether a certain cell is forced to not be a bulb - * - * @param board specified board - * @param location location of cell to check - * @return boolean value based on whether a certain cell has an adjacent cell that has the required amount of adjacent bulbs - */ - private boolean isForced(LightUpBoard board, Point location) { - return isForcedEmpty(board, new Point(location.x + 1, location.y)) || - isForcedEmpty(board, new Point(location.x, location.y + 1)) || - isForcedEmpty(board, new Point(location.x - 1, location.y)) || - isForcedEmpty(board, new Point(location.x, location.y - 1)); - } - - /** - * Checks whether a certain cell has the required amount of adjacent bulbs - * - * @param board specified board - * @param loc location of cell to check - * @return boolean value based on whether a certain cell has the required amount of adjacent bulbs - */ - private boolean isForcedEmpty(LightUpBoard board, Point loc) { - LightUpCell cell = board.getCell(loc.x, loc.y); - if (cell == null || cell.getType() != LightUpCellType.NUMBER) { - return false; - } - - int bulbs = 0; - int bulbsNeeded = cell.getData(); - cell = board.getCell(loc.x + 1, loc.y); - if (cell != null && cell.getType() == LightUpCellType.BULB) { - bulbs++; - } - cell = board.getCell(loc.x, loc.y + 1); - if (cell != null && cell.getType() == LightUpCellType.BULB) { - bulbs++; - } - cell = board.getCell(loc.x - 1, loc.y); - if (cell != null && cell.getType() == LightUpCellType.BULB) { - bulbs++; - } - cell = board.getCell(loc.x, loc.y - 1); - if (cell != null && cell.getType() == LightUpCellType.BULB) { - bulbs++; - } - return bulbs == bulbsNeeded; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - LightUpBoard initialBoard = (LightUpBoard) node.getBoard(); - LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); - for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { - LightUpCell cell = (LightUpCell) element; - if (cell.getType() == LightUpCellType.UNKNOWN && isForced(initialBoard, cell.getLocation())) { - cell.setData(LightUpCellType.EMPTY.value); - lightUpBoard.addModifiedData(cell); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.lightup.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; +import edu.rpi.legup.puzzle.lightup.LightUpCell; +import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import java.awt.*; + +public class FinishWithEmptyDirectRule extends DirectRule { + + public FinishWithEmptyDirectRule() { + super( + "LTUP-BASC-0005", + "Finish with Empty", + "The remaining unknowns around a block must be empty if the number is satisfied.", + "edu/rpi/legup/images/lightup/rules/FinishWithEmpty.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + LightUpBoard initialBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); + LightUpBoard finalBoard = (LightUpBoard) transition.getBoard(); + LightUpCell cell = (LightUpCell) finalBoard.getPuzzleElement(puzzleElement); + if (cell.getType() != LightUpCellType.EMPTY) { + return super.getInvalidUseOfRuleMessage() + ": Modified cells must be empty"; + } + + if (isForced(initialBoard, cell.getLocation())) { + return null; + } + return super.getInvalidUseOfRuleMessage() + ": Empty is not forced"; + } + + /** + * Checks whether a certain cell is forced to not be a bulb + * + * @param board specified board + * @param location location of cell to check + * @return boolean value based on whether a certain cell has an adjacent cell that has the + * required amount of adjacent bulbs + */ + private boolean isForced(LightUpBoard board, Point location) { + return isForcedEmpty(board, new Point(location.x + 1, location.y)) + || isForcedEmpty(board, new Point(location.x, location.y + 1)) + || isForcedEmpty(board, new Point(location.x - 1, location.y)) + || isForcedEmpty(board, new Point(location.x, location.y - 1)); + } + + /** + * Checks whether a certain cell has the required amount of adjacent bulbs + * + * @param board specified board + * @param loc location of cell to check + * @return boolean value based on whether a certain cell has the required amount of adjacent + * bulbs + */ + private boolean isForcedEmpty(LightUpBoard board, Point loc) { + LightUpCell cell = board.getCell(loc.x, loc.y); + if (cell == null || cell.getType() != LightUpCellType.NUMBER) { + return false; + } + + int bulbs = 0; + int bulbsNeeded = cell.getData(); + cell = board.getCell(loc.x + 1, loc.y); + if (cell != null && cell.getType() == LightUpCellType.BULB) { + bulbs++; + } + cell = board.getCell(loc.x, loc.y + 1); + if (cell != null && cell.getType() == LightUpCellType.BULB) { + bulbs++; + } + cell = board.getCell(loc.x - 1, loc.y); + if (cell != null && cell.getType() == LightUpCellType.BULB) { + bulbs++; + } + cell = board.getCell(loc.x, loc.y - 1); + if (cell != null && cell.getType() == LightUpCellType.BULB) { + bulbs++; + } + return bulbs == bulbsNeeded; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + LightUpBoard initialBoard = (LightUpBoard) node.getBoard(); + LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); + for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { + LightUpCell cell = (LightUpCell) element; + if (cell.getType() == LightUpCellType.UNKNOWN + && isForced(initialBoard, cell.getLocation())) { + cell.setData(LightUpCellType.EMPTY.value); + lightUpBoard.addModifiedData(cell); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java index 410c30e9c..53efb6587 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/LightOrEmptyCaseRule.java @@ -8,14 +8,15 @@ import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; - import java.util.ArrayList; import java.util.List; public class LightOrEmptyCaseRule extends CaseRule { public LightOrEmptyCaseRule() { - super("LTUP-CASE-0001", "Light or Empty", + super( + "LTUP-CASE-0001", + "Light or Empty", "Each blank cell is either a light or empty.", "edu/rpi/legup/images/lightup/cases/LightOrEmpty.png"); } @@ -36,13 +37,17 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement puzzleElement to determine the possible cases for * @return a list of elements the specified could be */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(-4); @@ -73,33 +78,37 @@ public String checkRuleRaw(TreeTransition transition) { TreeTransition case1 = childTransitions.get(0); TreeTransition case2 = childTransitions.get(1); - if (case1.getBoard().getModifiedData().size() != 1 || - case2.getBoard().getModifiedData().size() != 1) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case"; + if (case1.getBoard().getModifiedData().size() != 1 + || case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case"; } LightUpCell mod1 = (LightUpCell) case1.getBoard().getModifiedData().iterator().next(); LightUpCell mod2 = (LightUpCell) case2.getBoard().getModifiedData().iterator().next(); if (!mod1.getLocation().equals(mod2.getLocation())) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case"; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case"; } - if (!((mod1.getType() == LightUpCellType.EMPTY && mod2.getType() == LightUpCellType.BULB) || - (mod2.getType() == LightUpCellType.EMPTY && mod1.getType() == LightUpCellType.BULB))) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must an empty cell and a bulb cell"; + if (!((mod1.getType() == LightUpCellType.EMPTY && mod2.getType() == LightUpCellType.BULB) + || (mod2.getType() == LightUpCellType.EMPTY + && mod1.getType() == LightUpCellType.BULB))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must an empty cell and a bulb cell"; } return null; } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/MustLightDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/MustLightDirectRule.java index f0f943401..bf1843728 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/MustLightDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/MustLightDirectRule.java @@ -1,149 +1,153 @@ -package edu.rpi.legup.puzzle.lightup.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import edu.rpi.legup.puzzle.lightup.LightUpCell; -import edu.rpi.legup.puzzle.lightup.LightUpCellType; - -import java.awt.*; - -public class MustLightDirectRule extends DirectRule { - - public MustLightDirectRule() { - super("LTUP-BASC-0006", "Must Light", - "A cell must be a bulb if it is the only cell to be able to light another.", - "edu/rpi/legup/images/lightup/rules/MustLight.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - LightUpBoard parentBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); - LightUpBoard finalBoard = (LightUpBoard) transition.getBoard(); - LightUpCell parentCell = (LightUpCell) parentBoard.getPuzzleElement(puzzleElement); - LightUpCell finalCell = (LightUpCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(parentCell.getType() == LightUpCellType.UNKNOWN && !parentCell.isLite() && finalCell.getType() == LightUpCellType.BULB)) { - return super.getInvalidUseOfRuleMessage() + ": Modified cells must be bulbs"; - } - - finalBoard.fillWithLight(); - boolean isForced = isForcedBulb(parentBoard, parentCell.getLocation()); - finalCell.setData(LightUpCellType.BULB.value); - finalBoard.fillWithLight(); - - if (isForced) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell can be lit by another cell"; - } - } - - private boolean isForcedBulb(LightUpBoard board, Point loc) { - CannotLightACellContradictionRule cannotLite = new CannotLightACellContradictionRule(); - LightUpBoard modifiedBoard = board.copy(); - LightUpCell modifiedCell = modifiedBoard.getCell(loc.x, loc.y); - modifiedCell.setData(LightUpCellType.EMPTY.value); - //Check if this cell itself (the one with the bulb) has no other lighting option - if ((modifiedCell.getType() == LightUpCellType.EMPTY || modifiedCell.getType() == LightUpCellType.UNKNOWN) && - !modifiedCell.isLite() && cannotLite.checkContradictionAt(modifiedBoard, modifiedCell) == null) { - return true; - } - //Look right - for (int i = loc.x + 1; i < modifiedBoard.getWidth(); i++) { - LightUpCell c = modifiedBoard.getCell(i, loc.y); - if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { - break; - } - else { - if (c.getType() == LightUpCellType.EMPTY && - !c.isLite() && cannotLite.checkContradictionAt(modifiedBoard, c) == null) { - return true; - } - } - } - //Look left - for (int i = loc.x - 1; i >= 0; i--) { - LightUpCell c = modifiedBoard.getCell(i, loc.y); - if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { - break; - } - else { - if (c.getType() == LightUpCellType.EMPTY && - !c.isLite() && cannotLite.checkContradictionAt(modifiedBoard, c) == null) { - return true; - } - } - } - //Look down - for (int i = loc.y + 1; i < modifiedBoard.getHeight(); i++) { - LightUpCell c = modifiedBoard.getCell(loc.x, i); - if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { - break; - } - else { - if (c.getType() == LightUpCellType.EMPTY && - !c.isLite() && cannotLite.checkContradictionAt(modifiedBoard, c) == null) { - return true; - } - } - } - //Look up - for (int i = loc.y - 1; i >= 0; i--) { - LightUpCell c = modifiedBoard.getCell(loc.x, i); - if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { - break; - } - else { - if (c.getType() == LightUpCellType.EMPTY && - !c.isLite() && cannotLite.checkContradictionAt(modifiedBoard, c) == null) { - return true; - } - } - } - return false; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - LightUpBoard initialBoard = (LightUpBoard) node.getBoard(); - LightUpBoard tempBoard = (LightUpBoard) node.getBoard().copy(); - LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); - for (PuzzleElement element : tempBoard.getPuzzleElements()) { - LightUpCell cell = (LightUpCell) element; - if (cell.getType() == LightUpCellType.UNKNOWN && !cell.isLite()) { - cell.setData(LightUpCellType.EMPTY.value); - if (isForcedBulb(initialBoard, cell.getLocation())) { - LightUpCell modCell = (LightUpCell) lightUpBoard.getPuzzleElement(cell); - modCell.setData(LightUpCellType.BULB.value); - lightUpBoard.addModifiedData(modCell); - } - cell.setData(LightUpCellType.UNKNOWN.value); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.lightup.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; +import edu.rpi.legup.puzzle.lightup.LightUpCell; +import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import java.awt.*; + +public class MustLightDirectRule extends DirectRule { + + public MustLightDirectRule() { + super( + "LTUP-BASC-0006", + "Must Light", + "A cell must be a bulb if it is the only cell to be able to light another.", + "edu/rpi/legup/images/lightup/rules/MustLight.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + LightUpBoard parentBoard = (LightUpBoard) transition.getParents().get(0).getBoard(); + LightUpBoard finalBoard = (LightUpBoard) transition.getBoard(); + LightUpCell parentCell = (LightUpCell) parentBoard.getPuzzleElement(puzzleElement); + LightUpCell finalCell = (LightUpCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(parentCell.getType() == LightUpCellType.UNKNOWN + && !parentCell.isLite() + && finalCell.getType() == LightUpCellType.BULB)) { + return super.getInvalidUseOfRuleMessage() + ": Modified cells must be bulbs"; + } + + finalBoard.fillWithLight(); + boolean isForced = isForcedBulb(parentBoard, parentCell.getLocation()); + finalCell.setData(LightUpCellType.BULB.value); + finalBoard.fillWithLight(); + + if (isForced) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell can be lit by another cell"; + } + } + + private boolean isForcedBulb(LightUpBoard board, Point loc) { + CannotLightACellContradictionRule cannotLite = new CannotLightACellContradictionRule(); + LightUpBoard modifiedBoard = board.copy(); + LightUpCell modifiedCell = modifiedBoard.getCell(loc.x, loc.y); + modifiedCell.setData(LightUpCellType.EMPTY.value); + // Check if this cell itself (the one with the bulb) has no other lighting option + if ((modifiedCell.getType() == LightUpCellType.EMPTY + || modifiedCell.getType() == LightUpCellType.UNKNOWN) + && !modifiedCell.isLite() + && cannotLite.checkContradictionAt(modifiedBoard, modifiedCell) == null) { + return true; + } + // Look right + for (int i = loc.x + 1; i < modifiedBoard.getWidth(); i++) { + LightUpCell c = modifiedBoard.getCell(i, loc.y); + if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { + break; + } else { + if (c.getType() == LightUpCellType.EMPTY + && !c.isLite() + && cannotLite.checkContradictionAt(modifiedBoard, c) == null) { + return true; + } + } + } + // Look left + for (int i = loc.x - 1; i >= 0; i--) { + LightUpCell c = modifiedBoard.getCell(i, loc.y); + if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { + break; + } else { + if (c.getType() == LightUpCellType.EMPTY + && !c.isLite() + && cannotLite.checkContradictionAt(modifiedBoard, c) == null) { + return true; + } + } + } + // Look down + for (int i = loc.y + 1; i < modifiedBoard.getHeight(); i++) { + LightUpCell c = modifiedBoard.getCell(loc.x, i); + if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { + break; + } else { + if (c.getType() == LightUpCellType.EMPTY + && !c.isLite() + && cannotLite.checkContradictionAt(modifiedBoard, c) == null) { + return true; + } + } + } + // Look up + for (int i = loc.y - 1; i >= 0; i--) { + LightUpCell c = modifiedBoard.getCell(loc.x, i); + if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { + break; + } else { + if (c.getType() == LightUpCellType.EMPTY + && !c.isLite() + && cannotLite.checkContradictionAt(modifiedBoard, c) == null) { + return true; + } + } + } + return false; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + LightUpBoard initialBoard = (LightUpBoard) node.getBoard(); + LightUpBoard tempBoard = (LightUpBoard) node.getBoard().copy(); + LightUpBoard lightUpBoard = (LightUpBoard) node.getBoard().copy(); + for (PuzzleElement element : tempBoard.getPuzzleElements()) { + LightUpCell cell = (LightUpCell) element; + if (cell.getType() == LightUpCellType.UNKNOWN && !cell.isLite()) { + cell.setData(LightUpCellType.EMPTY.value); + if (isForcedBulb(initialBoard, cell.getLocation())) { + LightUpCell modCell = (LightUpCell) lightUpBoard.getPuzzleElement(cell); + modCell.setData(LightUpCellType.BULB.value); + lightUpBoard.addModifiedData(modCell); + } + cell.setData(LightUpCellType.UNKNOWN.value); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java index cf7b70ccd..f73a34b2d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/SatisfyNumberCaseRule.java @@ -9,7 +9,6 @@ import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; - import java.awt.*; import java.util.ArrayList; import java.util.Iterator; @@ -19,7 +18,9 @@ public class SatisfyNumberCaseRule extends CaseRule { public SatisfyNumberCaseRule() { - super("LTUP-CASE-0002", "Satisfy Number", + super( + "LTUP-CASE-0002", + "Satisfy Number", "The different ways a blocks number can be satisfied.", "edu/rpi/legup/images/lightup/cases/SatisfyNumber.png"); } @@ -40,12 +41,17 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement puzzleElement to determine the possible cases for * @return a list of elements the specified could be */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + LightUpBoard lightUpBoard = (LightUpBoard) board; LightUpCell cell = (LightUpCell) puzzleElement; Point loc = cell.getLocation(); @@ -58,8 +64,7 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { if (checkCell != null) { if (checkCell.getType() == LightUpCellType.UNKNOWN && !checkCell.isLite()) { openSpots.add(checkCell); - } - else { + } else { if (checkCell.getType() == LightUpCellType.BULB) { numNeeded--; } @@ -69,8 +74,7 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { if (checkCell != null) { if (checkCell.getType() == LightUpCellType.UNKNOWN && !checkCell.isLite()) { openSpots.add(checkCell); - } - else { + } else { if (checkCell.getType() == LightUpCellType.BULB) { numNeeded--; } @@ -80,8 +84,7 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { if (checkCell != null) { if (checkCell.getType() == LightUpCellType.UNKNOWN && !checkCell.isLite()) { openSpots.add(checkCell); - } - else { + } else { if (checkCell.getType() == LightUpCellType.BULB) { numNeeded--; } @@ -91,15 +94,13 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { if (checkCell != null) { if (checkCell.getType() == LightUpCellType.UNKNOWN && !checkCell.isLite()) { openSpots.add(checkCell); - } - else { + } else { if (checkCell.getType() == LightUpCellType.BULB) { numNeeded--; } } } - ArrayList cases = new ArrayList<>(); if (numNeeded == 0) { return cases; } @@ -109,7 +110,11 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { return cases; } - private void generateCases(final LightUpBoard board, final int num, List openSpots, List cases) { + private void generateCases( + final LightUpBoard board, + final int num, + List openSpots, + List cases) { if (num > openSpots.size()) { return; } @@ -128,7 +133,13 @@ private void generateCases(final LightUpBoard board, final int num, List openSpots, List cases, LightUpBoard curBoard, int index) { + private void generateCases( + final LightUpBoard board, + final int num, + List openSpots, + List cases, + LightUpBoard curBoard, + int index) { if (num <= curBoard.getModifiedData().size()) { cases.add(curBoard); return; @@ -181,8 +192,28 @@ public String checkRuleRaw(TreeTransition transition) { for (LightUpCell c : spots) { ArrayList cases = getCases(parent.getBoard(), c); - // We will allow case rules to have only one option - if (cases.size() == childTransitions.size() && cases.size() >= 1) { + // Note: we will allow case rules to have only one option + + // Some error checking to make sure that weird stuff doesn't happen + // if this case rule is incorrectly used to justify changes on the + // puzzle board + if (cases.size() == childTransitions.size() && cases.size() == 1) { + TreeTransition childTransition = childTransitions.get(0); + + // If there is only 1 case, then this case rule should function no + // differently than the Finish With Bulbs Direct Rule + FinishWithBulbsDirectRule finishWithBulbs = new FinishWithBulbsDirectRule(); + childTransition.setRule(finishWithBulbs); + boolean isCorrect = childTransition.isCorrect(); + + // Changes the transition back to this case rule + childTransition.setRule(this); + + if (isCorrect) { + return null; + } + return super.getInvalidUseOfRuleMessage(); + } else if (cases.size() == childTransitions.size() && cases.size() > 1) { boolean foundSpot = true; for (TreeTransition childTrans : childTransitions) { LightUpBoard actCase = (LightUpBoard) childTrans.getBoard(); @@ -197,8 +228,9 @@ public String checkRuleRaw(TreeTransition transition) { boolean foundCell = false; for (PuzzleElement posEle : posCase.getModifiedData()) { LightUpCell posCell = (LightUpCell) posEle; - if (actCell.getType() == posCell.getType() && - actCell.getLocation().equals(posCell.getLocation())) { + if (actCell.getType() == posCell.getType() + && actCell.getLocation() + .equals(posCell.getLocation())) { foundCell = true; break; } @@ -228,13 +260,13 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -245,7 +277,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem * Gets all cells in the TreeTransition board that are adjacent to all modified cells * * @param transition TreeTransition object - * @return list of cells that are adjacent to all modified cells, returns null if the number of modified cells is =0 || >4 + * @return list of cells that are adjacent to all modified cells, returns null if the number of + * modified cells is =0 || >4 */ private List getPossibleSpots(TreeTransition transition) { LightUpBoard board = (LightUpBoard) transition.getBoard(); @@ -254,8 +287,7 @@ private List getPossibleSpots(TreeTransition transition) { int size = modCells.size(); if (size == 0 || size > 4) { return null; - } - else { + } else { Iterator it = modCells.iterator(); List spots = getAdjacentCells(board, (LightUpCell) it.next()); @@ -289,33 +321,32 @@ private List getAdjacentCells(LightUpBoard board, LightUpCell cell) } /** - * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid - * Overridden by case rules dependent on more than just the modified data + * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be + * valid Overridden by case rules dependent on more than just the modified data * - * @param board board state at application + * @param board board state at application * @param puzzleElement selected puzzleElement - * @return List of puzzle elements (typically cells) this application of the case rule depends upon. - * Defaults to any element modified by any case + * @return List of puzzle elements (typically cells) this application of the case rule depends + * upon. Defaults to any element modified by any case */ @Override public List dependentElements(Board board, PuzzleElement puzzleElement) { List elements = new ArrayList<>(); LightUpBoard puzzleBoard = (LightUpBoard) board; - LightUpCell point = (LightUpCell)puzzleBoard.getPuzzleElement(puzzleElement); + LightUpCell point = (LightUpCell) puzzleBoard.getPuzzleElement(puzzleElement); - List cells = getAdjacentCells(puzzleBoard,point); + List cells = getAdjacentCells(puzzleBoard, point); for (LightUpCell cell : cells) { - //add cells that can light adjacents from any direction + // add cells that can light adjacents from any direction Point location = cell.getLocation(); for (int i = location.x; i < puzzleBoard.getWidth(); i++) { System.out.println(i); LightUpCell c = puzzleBoard.getCell(i, location.y); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else if (!elements.contains(board.getPuzzleElement(c))) { + } else if (!elements.contains(board.getPuzzleElement(c))) { elements.add(board.getPuzzleElement(c)); } } @@ -323,8 +354,7 @@ else if (!elements.contains(board.getPuzzleElement(c))) { LightUpCell c = puzzleBoard.getCell(i, location.y); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else if (!elements.contains(board.getPuzzleElement(c))) { + } else if (!elements.contains(board.getPuzzleElement(c))) { elements.add(board.getPuzzleElement(c)); } } @@ -332,8 +362,7 @@ else if (!elements.contains(board.getPuzzleElement(c))) { LightUpCell c = puzzleBoard.getCell(location.x, i); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else if (!elements.contains(board.getPuzzleElement(c))) { + } else if (!elements.contains(board.getPuzzleElement(c))) { elements.add(board.getPuzzleElement(c)); } } @@ -341,8 +370,7 @@ else if (!elements.contains(board.getPuzzleElement(c))) { LightUpCell c = puzzleBoard.getCell(location.x, i); if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) { break; - } - else if (!elements.contains(board.getPuzzleElement(c))) { + } else if (!elements.contains(board.getPuzzleElement(c))) { elements.add(board.getPuzzleElement(c)); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java index f36c4ca57..de1f85edc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooFewBulbsContradictionRule.java @@ -6,24 +6,26 @@ import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; - import java.awt.*; public class TooFewBulbsContradictionRule extends ContradictionRule { public TooFewBulbsContradictionRule() { - super("LTUP-CONT-0003", "Too Few Bulbs", + super( + "LTUP-CONT-0003", + "Too Few Bulbs", "There cannot be less bulbs around a block than its number states.", "edu/rpi/legup/images/lightup/contradictions/TooFewBulbs.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -34,7 +36,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } int bulbs = lightUpBoard.getNumAdj(cell, LightUpCellType.BULB); - int placeable = lightUpBoard.getNumPlacble(cell); + int placeable = lightUpBoard.getNumPlaceable(cell); if (bulbs + placeable < cell.getData()) { return null; diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooManyBulbsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooManyBulbsContradictionRule.java index ffe7ca4d1..64cd4adcb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooManyBulbsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/TooManyBulbsContradictionRule.java @@ -6,24 +6,26 @@ import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; - import java.awt.*; public class TooManyBulbsContradictionRule extends ContradictionRule { public TooManyBulbsContradictionRule() { - super("LTUP-CONT-0004", "Too Many Bulbs", + super( + "LTUP-CONT-0004", + "Too Many Bulbs", "There cannot be more bulbs around a block than its number states.", "edu/rpi/legup/images/lightup/contradictions/TooManyBulbs.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/EditLineCommand.java b/src/main/java/edu/rpi/legup/puzzle/masyu/EditLineCommand.java index 827be37ff..9986a1eda 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/EditLineCommand.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/EditLineCommand.java @@ -1,5 +1,7 @@ package edu.rpi.legup.puzzle.masyu; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.history.PuzzleCommand; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.gameboard.Board; @@ -12,11 +14,8 @@ import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.boardview.ElementView; import edu.rpi.legup.ui.proofeditorui.treeview.*; - import java.awt.event.MouseEvent; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - public class EditLineCommand extends PuzzleCommand { private TreeTransition transition; private PuzzleElement oldData; @@ -29,7 +28,11 @@ public class EditLineCommand extends PuzzleCommand { private TreeTransitionView transitionView; - public EditLineCommand(ElementView elementView, TreeElementView selectedView, MouseEvent event, MasyuLine line) { + public EditLineCommand( + ElementView elementView, + TreeElementView selectedView, + MouseEvent event, + MasyuLine line) { this.elementView = elementView; this.selectedView = selectedView; this.event = event; @@ -38,9 +41,7 @@ public EditLineCommand(ElementView elementView, TreeElementView selectedView, Mo this.transition = null; } - /** - * Executes a command - */ + /** Executes a command */ @Override public void executeCommand() { Tree tree = getInstance().getTree(); @@ -61,18 +62,19 @@ public void executeCommand() { } treeNode.getChildren().add(transition); - puzzle.notifyTreeListeners((ITreeListener listener) -> listener.onTreeElementAdded(transition)); + puzzle.notifyTreeListeners( + (ITreeListener listener) -> listener.onTreeElementAdded(transition)); transitionView = (TreeTransitionView) treeView.getElementView(transition); selection.newSelection(transitionView); - puzzle.notifyTreeListeners((ITreeListener listener) -> listener.onTreeSelectionChanged(selection)); + puzzle.notifyTreeListeners( + (ITreeListener listener) -> listener.onTreeSelectionChanged(selection)); getInstance().getLegupUI().repaintTree(); board = (MasyuBoard) transition.getBoard(); getInstance().getPuzzleModule().setCurrentBoard(board); oldData = newData.copy(); - } - else { + } else { transitionView = (TreeTransitionView) selectedView; transition = transitionView.getTreeElement(); } @@ -100,13 +102,14 @@ public void executeCommand() { System.out.println("delete"); board.getModifiedData().remove(dup_line); board.getLines().remove(dup_line); -// puzzle.notifyBoardListeners((IBoardListener listener) -> listener.onTreeElementChanged(editBoard)); - } - else { + // puzzle.notifyBoardListeners((IBoardListener listener) -> + // listener.onTreeElementChanged(editBoard)); + } else { System.out.println("adding"); board.getModifiedData().add(newData); board.getLines().add((MasyuLine) newData); -// puzzle.notifyBoardListeners((IBoardListener listener) -> listener.onTreeElementChanged(editBoard)); + // puzzle.notifyBoardListeners((IBoardListener listener) -> + // listener.onTreeElementChanged(editBoard)); } transition.propagateChange(newData); @@ -116,15 +119,14 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { Board board = selectedView.getTreeElement().getBoard(); if (!board.isModifiable()) { return "Board is not modifiable"; - } - else { + } else { if (!board.getPuzzleElement(elementView.getPuzzleElement()).isModifiable()) { return "Data is not modifiable"; } @@ -132,9 +134,7 @@ public String getErrorString() { return null; } - /** - * Undoes an command - */ + /** Undoes an command */ @Override public void undoCommand() { Tree tree = getInstance().getTree(); @@ -156,17 +156,16 @@ public void undoCommand() { getInstance().getPuzzleModule().setCurrentBoard(treeNode.getBoard()); } - Board prevBoard = null;// transition.getParentNode().getBoard(); + Board prevBoard = null; // transition.getParentNode().getBoard(); newData.setData(oldData.getData()); board.notifyChange(newData); - //System.err.println(newData.getData() + " : " + oldData.getData()); + // System.err.println(newData.getData() + " : " + oldData.getData()); if (prevBoard.getPuzzleElement(elementView.getPuzzleElement()).equalsData(newData)) { board.removeModifiedData(newData); - } - else { + } else { board.addModifiedData(newData); } transition.propagateChange(newData); diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/Masyu.java b/src/main/java/edu/rpi/legup/puzzle/masyu/Masyu.java index b339630e9..1ab74d56b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/Masyu.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/Masyu.java @@ -14,12 +14,9 @@ public Masyu() { this.exporter = new MasyuExporter(this); this.factory = new MasyuCellFactory(); - } - /** - * Initializes the game board. Called by the invoker of the class - */ + /** Initializes the game board. Called by the invoker of the class */ @Override public void initializeView() { boardView = new MasyuView((MasyuBoard) currentBoard); @@ -40,8 +37,8 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Masyu * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Masyu, false otherwise */ public boolean isValidDimensions(int rows, int columns) { @@ -66,7 +63,5 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { - - } + public void onBoardChange(Board board) {} } diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuBoard.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuBoard.java index 96183bcfe..f347ff4c4 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuBoard.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.util.ArrayList; import java.util.List; @@ -36,8 +35,7 @@ public void setLines(List lines) { public void notifyChange(PuzzleElement puzzleElement) { if (puzzleElement instanceof MasyuLine) { lines.add((MasyuLine) puzzleElement); - } - else { + } else { super.notifyChange(puzzleElement); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCell.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCell.java index af32dbfb6..af0811c55 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCell.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.masyu; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; public class MasyuCell extends GridCell { diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCellFactory.java index 5278e0036..50e3c4cc0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCellFactory.java @@ -4,17 +4,16 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class MasyuCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid @@ -23,7 +22,8 @@ public class MasyuCellFactory extends ElementFactory { public MasyuCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("Masyu Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "Masyu Factory: unknown puzzleElement puzzleElement"); } MasyuBoard masyuBoard = (MasyuBoard) board; @@ -44,11 +44,10 @@ public MasyuCell importCell(Node node, Board board) throws InvalidFileFormatExce MasyuCell cell = new MasyuCell(MasyuType.convertToMasyuType(value), new Point(x, y)); cell.setIndex(y * height + x); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Masyu Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Masyu Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("Masyu Factory: could not find attribute(s)"); } } @@ -56,7 +55,7 @@ public MasyuCell importCell(Node node, Board board) throws InvalidFileFormatExce /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuController.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuController.java index 02328c691..202c43a1e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuController.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuController.java @@ -1,18 +1,17 @@ package edu.rpi.legup.puzzle.masyu; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.ui.boardview.BoardView; - import java.awt.*; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - public class MasyuController extends ElementController { private MasyuElementView mousePressedCell; @@ -52,19 +51,25 @@ public void mouseDragged(MouseEvent e) { if (Math.abs(p1.x - p2.x) == 1 ^ Math.abs(p1.y - p2.y) == 1) { masyuLine.add(elementView); - MasyuLine newLine = new MasyuLine(mousePressedCell.getPuzzleElement(), mouseDraggedCell.getPuzzleElement()); + MasyuLine newLine = + new MasyuLine( + mousePressedCell.getPuzzleElement(), + mouseDraggedCell.getPuzzleElement()); puzzle.notifyBoardListeners(listener -> listener.onBoardDataChanged(newLine)); } - } - else { + } else { if (mouseDraggedCell != elementView) { Point p1 = mouseDraggedCell.getPuzzleElement().getLocation(); Point p2 = elementView.getPuzzleElement().getLocation(); if (Math.abs(p1.x - p2.x) == 1 ^ Math.abs(p1.y - p2.y) == 1) { masyuLine.add(elementView); - MasyuLine newLine = new MasyuLine(mouseDraggedCell.getPuzzleElement(), elementView.getPuzzleElement()); - puzzle.notifyBoardListeners(listener -> listener.onBoardDataChanged(newLine)); + MasyuLine newLine = + new MasyuLine( + mouseDraggedCell.getPuzzleElement(), + elementView.getPuzzleElement()); + puzzle.notifyBoardListeners( + listener -> listener.onBoardDataChanged(newLine)); } mouseDraggedCell = elementView; } @@ -83,7 +88,7 @@ public void mouseReleased(MouseEvent e) { /** * Alters the cells as they are being dragged over or clicked * - * @param e Mouse event being used + * @param e Mouse event being used * @param data Data of selected cell */ @Override @@ -94,8 +99,7 @@ public void changeCell(MouseEvent e, PuzzleElement data) { } if (cell.getData() == MasyuType.UNKNOWN) { data.setData(3); - } - else { + } else { data.setData(0); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuElementView.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuElementView.java index b2f1f8902..942e1ffd2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.masyu; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class MasyuElementView extends GridElementView { @@ -24,8 +23,7 @@ public void drawElement(Graphics2D graphics2D) { graphics2D.fillRect(location.x, location.y, size.width, size.height); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == MasyuType.BLACK) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(Color.LIGHT_GRAY); @@ -34,8 +32,7 @@ public void drawElement(Graphics2D graphics2D) { graphics2D.fillOval(location.x + 5, location.y + 5, 20, 20); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == MasyuType.WHITE) { graphics2D.setStroke(new BasicStroke(2)); graphics2D.setColor(Color.LIGHT_GRAY); diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuExporter.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuExporter.java index e5fb071b4..0c692193a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuExporter.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import org.w3c.dom.Document; public class MasyuExporter extends PuzzleExporter { @@ -16,8 +15,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { MasyuBoard board; if (puzzle.getTree() != null) { board = (MasyuBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (MasyuBoard) puzzle.getBoardView().getBoard(); } @@ -28,7 +26,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); for (PuzzleElement puzzleElement : board.getPuzzleElements()) { MasyuCell cell = (MasyuCell) puzzleElement; - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuImporter.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuImporter.java index 3e0d328c4..2170da3ee 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuImporter.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class MasyuImporter extends PuzzleImporter { public MasyuImporter(Masyu masyu) { super(masyu); @@ -26,14 +25,12 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException if board can not be created */ @Override - public void initializeBoard(int rows, int columns) { - - } + public void initializeBoard(int rows, int columns) {} /** * Creates the board for building @@ -45,11 +42,13 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("Masyu Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "Masyu Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("Masyu Importer: no puzzleElement found for board"); + throw new InvalidFileFormatException( + "Masyu Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); NodeList elementDataList = dataElement.getElementsByTagName("cell"); @@ -58,9 +57,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { if (!boardElement.getAttribute("size").isEmpty()) { int size = Integer.valueOf(boardElement.getAttribute("size")); masyuBoard = new MasyuBoard(size); - } - else { - if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { int width = Integer.valueOf(boardElement.getAttribute("width")); int height = Integer.valueOf(boardElement.getAttribute("height")); masyuBoard = new MasyuBoard(width, height); @@ -75,7 +74,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int height = masyuBoard.getHeight(); for (int i = 0; i < elementDataList.getLength(); i++) { - MasyuCell cell = (MasyuCell) puzzle.getFactory().importCell(elementDataList.item(i), masyuBoard); + MasyuCell cell = + (MasyuCell) + puzzle.getFactory().importCell(elementDataList.item(i), masyuBoard); Point loc = cell.getLocation(); if (cell.getData() != MasyuType.UNKNOWN) { cell.setModifiable(false); @@ -95,9 +96,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } puzzle.setCurrentBoard(masyuBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Masyu Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Masyu Importer: unknown value where integer expected"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuLine.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuLine.java index d8c3240c7..eda51c839 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuLine.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuLine.java @@ -25,8 +25,10 @@ public void setC2(MasyuCell c2) { } public boolean compare(MasyuLine line) { - return ((line.getC1().getLocation().equals(data.getKey().getLocation()) && line.getC2().getLocation().equals(data.getValue().getLocation())) || - (line.getC1().getLocation().equals(data.getValue().getLocation()) && line.getC2().getLocation().equals(data.getKey().getLocation()))); + return ((line.getC1().getLocation().equals(data.getKey().getLocation()) + && line.getC2().getLocation().equals(data.getValue().getLocation())) + || (line.getC1().getLocation().equals(data.getValue().getLocation()) + && line.getC2().getLocation().equals(data.getKey().getLocation()))); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuLineView.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuLineView.java index d527ca414..c967f4865 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuLineView.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuLineView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.masyu; import edu.rpi.legup.ui.boardview.ElementView; - import java.awt.*; public class MasyuLineView extends ElementView { diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuType.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuType.java index 264350a95..4029d259d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuType.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuType.java @@ -1,9 +1,10 @@ package edu.rpi.legup.puzzle.masyu; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - public enum MasyuType { - UNKNOWN, BLACK, WHITE, LINE; + UNKNOWN, + BLACK, + WHITE, + LINE; public static MasyuType convertToMasyuType(int num) { switch (num) { @@ -18,4 +19,3 @@ public static MasyuType convertToMasyuType(int num) { } } } - diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuView.java b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuView.java index ac60dbe66..e962a6ebf 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuView.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuView.java @@ -3,7 +3,6 @@ import edu.rpi.legup.controller.BoardController; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.ui.boardview.GridBoardView; - import java.awt.*; import java.util.ArrayList; import java.util.List; @@ -20,7 +19,8 @@ public MasyuView(MasyuBoard board) { MasyuElementView elementView = new MasyuElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); elementViews.add(elementView); } lineViews = new ArrayList<>(); @@ -33,7 +33,8 @@ public MasyuView(MasyuBoard board) { @Override public void drawBoard(Graphics2D graphics2D) { - graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); super.drawBoard(graphics2D); lineViews.forEach(masyuLineView -> masyuLineView.draw(graphics2D)); } diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BadLoopingContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BadLoopingContradictionRule.java index 0da4dffe2..1681446cd 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BadLoopingContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BadLoopingContradictionRule.java @@ -7,18 +7,21 @@ public class BadLoopingContradictionRule extends ContradictionRule { public BadLoopingContradictionRule() { - super("MASY-CONT-0001", "Bad Looping", + super( + "MASY-CONT-0001", + "Bad Looping", "", "edu/rpi/legup/images/masyu/ContradictionBadLooping.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackContradictionRule.java index b4d32a46a..c219eeaa3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackContradictionRule.java @@ -7,18 +7,17 @@ public class BlackContradictionRule extends ContradictionRule { public BlackContradictionRule() { - super("MASY-CONT-0002", "Black", - "", - "edu/rpi/legup/images/masyu/ContradictionBlack.png"); + super("MASY-CONT-0002", "Black", "", "edu/rpi/legup/images/masyu/ContradictionBlack.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackEdgeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackEdgeDirectRule.java index b35dceaa7..665a74204 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackEdgeDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackEdgeDirectRule.java @@ -1,42 +1,41 @@ -package edu.rpi.legup.puzzle.masyu.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class BlackEdgeDirectRule extends DirectRule { - - public BlackEdgeDirectRule() { - super("MASY-BASC-0001", "Black Edge", - "", - "edu/rpi/legup/images/masyu/RuleBlackEdge.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.masyu.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class BlackEdgeDirectRule extends DirectRule { + + public BlackEdgeDirectRule() { + super("MASY-BASC-0001", "Black Edge", "", "edu/rpi/legup/images/masyu/RuleBlackEdge.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackSplitCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackSplitCaseRule.java index 3db89ef58..c7e3ff500 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackSplitCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlackSplitCaseRule.java @@ -5,20 +5,17 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.List; public class BlackSplitCaseRule extends CaseRule { public BlackSplitCaseRule() { - super("MASY-CASE-0001", "Black Split", - "", - "edu/rpi/legup/images/masyu/CaseBlackSplit.png"); + super("MASY-CASE-0001", "Black Split", "", "edu/rpi/legup/images/masyu/CaseBlackSplit.png"); } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -29,13 +26,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. This method is the one that should overridden in child classes. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. This method is the one that should overridden in child + * classes. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -43,7 +41,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Gets the case board that indicates where this case rule can be applied on the given {@link Board}. + * Gets the case board that indicates where this case rule can be applied on the given {@link + * Board}. * * @param board board to find locations where this case rule can be applied * @return a case board @@ -54,9 +53,10 @@ public CaseBoard getCaseBoard(Board board) { } /** - * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on this case rule. + * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on + * this case rule. * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlockedBlackDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlockedBlackDirectRule.java index 4364d016c..5c284eb45 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlockedBlackDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/BlockedBlackDirectRule.java @@ -1,42 +1,45 @@ -package edu.rpi.legup.puzzle.masyu.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class BlockedBlackDirectRule extends DirectRule { - - public BlockedBlackDirectRule() { - super("MASY-BASC-0002", "Blocked Black", - "", - "edu/rpi/legup/images/masyu/RuleBlockedBlack.gif"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.masyu.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class BlockedBlackDirectRule extends DirectRule { + + public BlockedBlackDirectRule() { + super( + "MASY-BASC-0002", + "Blocked Black", + "", + "edu/rpi/legup/images/masyu/RuleBlockedBlack.gif"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/ConnectedCellsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/ConnectedCellsDirectRule.java index 49949ecec..6aee8ba5f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/ConnectedCellsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/ConnectedCellsDirectRule.java @@ -1,42 +1,45 @@ -package edu.rpi.legup.puzzle.masyu.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class ConnectedCellsDirectRule extends DirectRule { - - public ConnectedCellsDirectRule() { - super("MASY-BASC-0003", "Connected Cells", - "", - "edu/rpi/legup/images/masyu/RuleConnectedCells.gif"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.masyu.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class ConnectedCellsDirectRule extends DirectRule { + + public ConnectedCellsDirectRule() { + super( + "MASY-BASC-0003", + "Connected Cells", + "", + "edu/rpi/legup/images/masyu/RuleConnectedCells.gif"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/FinishPathDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/FinishPathDirectRule.java index e04301ce2..27b39bc04 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/FinishPathDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/FinishPathDirectRule.java @@ -1,42 +1,45 @@ -package edu.rpi.legup.puzzle.masyu.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class FinishPathDirectRule extends DirectRule { - - public FinishPathDirectRule() { - super("MASY-BASC-0004", "Finished Path", - "", - "edu/rpi/legup/images/masyu/RuleFinishPath.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.masyu.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class FinishPathDirectRule extends DirectRule { + + public FinishPathDirectRule() { + super( + "MASY-BASC-0004", + "Finished Path", + "", + "edu/rpi/legup/images/masyu/RuleFinishPath.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NearWhiteDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NearWhiteDirectRule.java index 7cf707d0d..6a565bc82 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NearWhiteDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NearWhiteDirectRule.java @@ -1,42 +1,41 @@ -package edu.rpi.legup.puzzle.masyu.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class NearWhiteDirectRule extends DirectRule { - - public NearWhiteDirectRule() { - super("MASY-BASC-0005", "Near White", - "", - "edu/rpi/legup/images/masyu/RuleNearWhite.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.masyu.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class NearWhiteDirectRule extends DirectRule { + + public NearWhiteDirectRule() { + super("MASY-BASC-0005", "Near White", "", "edu/rpi/legup/images/masyu/RuleNearWhite.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NoOptionsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NoOptionsContradictionRule.java index 19da790aa..c41999b9c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NoOptionsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NoOptionsContradictionRule.java @@ -7,18 +7,21 @@ public class NoOptionsContradictionRule extends ContradictionRule { public NoOptionsContradictionRule() { - super("MASY-CONT-0003", "No Options", + super( + "MASY-CONT-0003", + "No Options", "", "edu/rpi/legup/images/masyu/ContradictionNoOptions.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NormalSplitCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NormalSplitCaseRule.java index ab47adc1b..382ac6466 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NormalSplitCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/NormalSplitCaseRule.java @@ -5,20 +5,21 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.List; public class NormalSplitCaseRule extends CaseRule { public NormalSplitCaseRule() { - super("MASY-CASE-0002", "Normal Split", + super( + "MASY-CASE-0002", + "Normal Split", "", "edu/rpi/legup/images/masyu/CaseNormalSplit.png"); } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -29,13 +30,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. This method is the one that should overridden in child classes. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. This method is the one that should overridden in child + * classes. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -43,7 +45,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Gets the case board that indicates where this case rule can be applied on the given {@link Board}. + * Gets the case board that indicates where this case rule can be applied on the given {@link + * Board}. * * @param board board to find locations where this case rule can be applied * @return a case board @@ -54,9 +57,10 @@ public CaseBoard getCaseBoard(Board board) { } /** - * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on this case rule. + * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on + * this case rule. * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/OnlyOneChoiceDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/OnlyOneChoiceDirectRule.java index b0311e741..bc7353e5d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/OnlyOneChoiceDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/OnlyOneChoiceDirectRule.java @@ -1,42 +1,45 @@ -package edu.rpi.legup.puzzle.masyu.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class OnlyOneChoiceDirectRule extends DirectRule { - - public OnlyOneChoiceDirectRule() { - super("MASY-BASC-0006", "Only One Choice", - "", - "edu/rpi/legup/images/masyu/RuleOnlyOneChoice.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.masyu.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class OnlyOneChoiceDirectRule extends DirectRule { + + public OnlyOneChoiceDirectRule() { + super( + "MASY-BASC-0006", + "Only One Choice", + "", + "edu/rpi/legup/images/masyu/RuleOnlyOneChoice.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/OnlyTwoContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/OnlyTwoContradictionRule.java index ab587a0ec..ee71ee2bc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/OnlyTwoContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/OnlyTwoContradictionRule.java @@ -7,18 +7,21 @@ public class OnlyTwoContradictionRule extends ContradictionRule { public OnlyTwoContradictionRule() { - super("MASY-CONT-0004", "Only Two", + super( + "MASY-CONT-0004", + "Only Two", "", "edu/rpi/legup/images/masyu/ContradictionOnly2.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteContradictionRule.java index 091c2b039..efc523b8d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteContradictionRule.java @@ -7,18 +7,17 @@ public class WhiteContradictionRule extends ContradictionRule { public WhiteContradictionRule() { - super("MASY-CONT-0005", "White", - "", - "edu/rpi/legup/images/masyu/ContradictionWhite.png"); + super("MASY-CONT-0005", "White", "", "edu/rpi/legup/images/masyu/ContradictionWhite.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteEdgeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteEdgeDirectRule.java index bd894e1d4..4d2982d00 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteEdgeDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteEdgeDirectRule.java @@ -1,41 +1,40 @@ -package edu.rpi.legup.puzzle.masyu.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; - -public class WhiteEdgeDirectRule extends DirectRule { - public WhiteEdgeDirectRule() { - super("MASY-BASC-0007", "White Edge", - "", - "edu/rpi/legup/images/masyu/RuleWhiteEdge.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * This method is the one that should overridden in child classes - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.masyu.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class WhiteEdgeDirectRule extends DirectRule { + public WhiteEdgeDirectRule() { + super("MASY-BASC-0007", "White Edge", "", "edu/rpi/legup/images/masyu/RuleWhiteEdge.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule This method is the one that should overridden in child + * classes + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteSplitCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteSplitCaseRule.java index e45fde0a1..d50ddacfa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteSplitCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/masyu/rules/WhiteSplitCaseRule.java @@ -5,20 +5,17 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; - import java.util.List; public class WhiteSplitCaseRule extends CaseRule { public WhiteSplitCaseRule() { - super("MASY-CASE-0003", "White Split", - "", - "edu/rpi/legup/images/masyu/CaseWhiteSplit.png"); + super("MASY-CASE-0003", "White Split", "", "edu/rpi/legup/images/masyu/CaseWhiteSplit.png"); } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -29,13 +26,14 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node at the specific puzzleElement index using - * this rule. This method is the one that should overridden in child classes. + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule. This method is the one that should overridden in child + * classes. * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -43,7 +41,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Gets the case board that indicates where this case rule can be applied on the given {@link Board}. + * Gets the case board that indicates where this case rule can be applied on the given {@link + * Board}. * * @param board board to find locations where this case rule can be applied * @return a case board @@ -54,9 +53,10 @@ public CaseBoard getCaseBoard(Board board) { } /** - * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on this case rule. + * Gets the possible cases for this {@link Board} at a specific {@link PuzzleElement} based on + * this case rule. * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java new file mode 100644 index 000000000..ed8066f39 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/Minesweeper.java @@ -0,0 +1,64 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class Minesweeper extends Puzzle { + + public static final String NAME = "Minesweeper"; + + public Minesweeper() { + this.name = NAME; + this.importer = new MinesweeperImporter(this); + this.exporter = new MinesweeperExporter(this); + this.factory = MinesweeperCellFactory.INSTANCE; + } + + @Override + @Contract(pure = false) + public void initializeView() { + this.boardView = new MinesweeperView((MinesweeperBoard) this.currentBoard); + this.boardView.setBoard(this.currentBoard); + addBoardListener(boardView); + } + + @Override + @Contract("_ -> null") + public @Nullable Board generatePuzzle(int difficulty) { + return null; + } + + @Override + @Contract(pure = true) + public boolean isBoardComplete(@NotNull Board board) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + + for (ContradictionRule rule : contradictionRules) { + if (rule.checkContradiction(minesweeperBoard) == null) { + return false; + } + } + for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) data; + if (cell.getData().equals(MinesweeperTileData.empty())) { + return false; + } + } + return true; + } + + @Override + @Contract(pure = true) + public void onBoardChange(@NotNull Board board) {} + + @Override + @Contract(pure = true) + public boolean isValidDimensions(int rows, int columns) { + return rows >= 1 && columns >= 1; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java new file mode 100644 index 000000000..bef317ab5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperBoard.java @@ -0,0 +1,36 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.gameboard.GridBoard; + +public class MinesweeperBoard extends GridBoard { + + public MinesweeperBoard(int width, int height) { + super(width, height); + } + + public MinesweeperBoard(int size) { + super(size); + } + + @Override + public MinesweeperCell getCell(int x, int y) { + return (MinesweeperCell) super.getCell(x, y); + } + + /** + * Performs a deep copy of the Board + * + * @return a new copy of the board that is independent of this one + */ + @Override + public MinesweeperBoard copy() { + MinesweeperBoard newMinesweeperBoard = + new MinesweeperBoard(this.dimension.width, this.dimension.height); + for (int x = 0; x < this.dimension.width; x++) { + for (int y = 0; y < this.dimension.height; y++) { + newMinesweeperBoard.setCell(x, y, getCell(x, y).copy()); + } + } + return newMinesweeperBoard; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java new file mode 100644 index 000000000..325e42b7b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCell.java @@ -0,0 +1,73 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.elements.Element; +import edu.rpi.legup.model.gameboard.GridCell; +import java.awt.*; +import java.awt.event.MouseEvent; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public class MinesweeperCell extends GridCell { + + public MinesweeperCell(@NotNull MinesweeperTileData value, @NotNull Point location) { + super(value, location); + } + + public @NotNull MinesweeperTileType getTileType() { + return super.data.type(); + } + + public @NotNull int getTileNumber() { + return super.data.data(); + } + + @Override + @Contract(pure = false) + /** Sets this cell's data to the value specified by {@link Element#getElementID()} */ + public void setType(@NotNull Element element, @NotNull MouseEvent event) { + switch (element.getElementID()) { + case MinesweeperElementIdentifiers.BOMB -> { + this.data = MinesweeperTileData.bomb(); + break; + } + case MinesweeperElementIdentifiers.FLAG -> { + final int currentData = super.data.data(); + switch (event.getButton()) { + case MouseEvent.BUTTON1 -> { + if (currentData >= 8) { + this.data = MinesweeperTileData.empty(); + return; + } + this.data = MinesweeperTileData.flag(currentData + 1); + return; + } + case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> { + if (currentData <= 0) { + this.data = MinesweeperTileData.empty(); + return; + } + this.data = MinesweeperTileData.flag(currentData - 1); + return; + } + } + } + default -> { + this.data = MinesweeperTileData.empty(); + } + } + } + + public void setCellType(MinesweeperTileData type) { + this.data = type; + } + + @Override + @Contract(pure = true) + public @NotNull MinesweeperCell copy() { + MinesweeperCell copy = new MinesweeperCell(data, (Point) location.clone()); + copy.setIndex(index); + copy.setModifiable(isModifiable); + copy.setGiven(isGiven); + return copy; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java new file mode 100644 index 000000000..5fe6096a9 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperCellFactory.java @@ -0,0 +1,101 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.ElementFactory; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public class MinesweeperCellFactory extends ElementFactory { + + /** The key of the data used in {@link NamedNodeMap} */ + private static final String DATA_ATTRIBUTE = "data"; + + /** The key of the x position used in {@link NamedNodeMap} */ + private static final String X_ATTRIBUTE = "x"; + + /** The key of the y position used in {@link NamedNodeMap} */ + private static final String Y_ATTRIBUTE = "y"; + + private MinesweeperCellFactory() {} + + public static final MinesweeperCellFactory INSTANCE = new MinesweeperCellFactory(); + + /** + * @param node node that represents the puzzleElement + * @param board Board to use to verify the newly created {@link MinesweeperCell} is valid + * @return a new {@link MinesweeperCell} + * @throws InvalidFileFormatException If the node name is not "cell" + * @throws NumberFormatException If the {@link #X_ATTRIBUTE} or {@link #Y_ATTRIBUTE} is not a + * number + * @throws NullPointerException If one of {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE} or + * {@link #Y_ATTRIBUTE} does not exist. + */ + @Override + @Contract(pure = false) + public @NotNull PuzzleElement importCell( + @NotNull Node node, @NotNull Board board) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("cell")) { + throw new InvalidFileFormatException( + "Minesweeper Factory: unknown puzzleElement puzzleElement"); + } + + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + final int width = minesweeperBoard.getWidth(); + final int height = minesweeperBoard.getHeight(); + + final NamedNodeMap attributeList = node.getAttributes(); + final int value = + Integer.parseInt(attributeList.getNamedItem(DATA_ATTRIBUTE).getNodeValue()); + final int x = Integer.parseInt(attributeList.getNamedItem(X_ATTRIBUTE).getNodeValue()); + final int y = Integer.parseInt(attributeList.getNamedItem(Y_ATTRIBUTE).getNodeValue()); + if (x >= width || y >= height) { + throw new InvalidFileFormatException( + "Minesweeper Factory: cell location out of bounds"); + } + if (value < -2) { + throw new InvalidFileFormatException("Minesweeper Factory: cell unknown value"); + } + final MinesweeperCell cell = + new MinesweeperCell(MinesweeperTileData.fromData(value), new Point(x, y)); + cell.setIndex(y * height + x); + return cell; + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Minesweeper Factory: unknown value where integer expected"); + } catch (NullPointerException e) { + throw new InvalidFileFormatException( + "Minesweeper Factory: could not find attribute(s)"); + } + } + + /** + * @param document Document used to create the element + * @param puzzleElement PuzzleElement cell + * @return a {@link Element} that contains the {@link #DATA_ATTRIBUTE}, {@link #X_ATTRIBUTE}, + * and {@link #Y_ATTRIBUTE} + */ + @Override + @Contract(pure = false) + public @NotNull Element exportCell( + @NotNull Document document, + @SuppressWarnings("rawtypes") @NotNull PuzzleElement puzzleElement) { + org.w3c.dom.Element cellElement = document.createElement("cell"); + + MinesweeperCell cell = (MinesweeperCell) puzzleElement; + Point loc = cell.getLocation(); + + cellElement.setAttribute(DATA_ATTRIBUTE, String.valueOf(cell.getData())); + cellElement.setAttribute(X_ATTRIBUTE, String.valueOf(loc.x)); + cellElement.setAttribute(Y_ATTRIBUTE, String.valueOf(loc.y)); + + return cellElement; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java new file mode 100644 index 000000000..aaf061704 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperController.java @@ -0,0 +1,57 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.controller.ElementController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import java.awt.event.MouseEvent; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public class MinesweeperController extends ElementController { + + /** + * If the button clicked was button 1, then {@link MinesweeperTileData#fromData(int)} is called + * with a value of {@code current.data() + 1}. If the button clicked was button 2 or 3, then + * {@link MinesweeperTileData#fromData(int)} is called with a value of {@code currentData() - 1} + * Otherwise {@link MinesweeperTileData#empty()} is returned. + * + * @param event The user's click data + * @param current The current data at the cell they clicked on + * @return A different cell data depending on what the current data is + */ + @Contract(pure = true) + public static @NotNull MinesweeperTileData getNewCellDataOnClick( + @NotNull MouseEvent event, @NotNull MinesweeperTileData current) { + final int numberData = current.data(); + return switch (event.getButton()) { + case MouseEvent.BUTTON1 -> MinesweeperTileData.fromData(numberData + 1); + case MouseEvent.BUTTON2, MouseEvent.BUTTON3 -> + MinesweeperTileData.fromData(numberData - 1); + default -> MinesweeperTileData.empty(); + }; + } + + /** + * @see #getNewCellDataOnClick(MouseEvent, MinesweeperTileData) + * @param event The user's click data + * @param data The current data at the cell they clicked on + */ + @Override + @SuppressWarnings("unchecked") + @Contract(pure = false) + public void changeCell( + @NotNull MouseEvent event, @SuppressWarnings("rawtypes") @NotNull PuzzleElement data) { + final MinesweeperCell cell = (MinesweeperCell) data; + if (event.isControlDown()) { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + event.getX(), + this.boardView.getCanvas().getY() + event.getY()); + return; + } + + final MinesweeperTileData newData = getNewCellDataOnClick(event, cell.getData()); + data.setData(newData); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java new file mode 100644 index 000000000..77e490f7e --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementIdentifiers.java @@ -0,0 +1,16 @@ +package edu.rpi.legup.puzzle.minesweeper; + +public class MinesweeperElementIdentifiers { + + /** ID for unset Minesweeper elements */ + public static final String UNSET = "MINESWEEPER-UNSET"; + + /** ID for bomb Minesweeper elements */ + public static final String BOMB = "MINESWEEPER-BOMB"; + + /** ID for empty Minesweeper elements */ + public static final String EMPTY = "MINESWEEPER-EMPTY"; + + /** ID for flag Minesweeper elements */ + public static final String FLAG = "MINESWEEPER-FLAG"; +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java new file mode 100644 index 000000000..1bfc0d698 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperElementView.java @@ -0,0 +1,83 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.ui.boardview.GridElementView; +import java.awt.*; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public class MinesweeperElementView extends GridElementView { + + private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); + private static final Color FONT_COLOR = Color.BLACK; + + public MinesweeperElementView(@NotNull MinesweeperCell cell) { + super(cell); + } + + @Override + public @NotNull MinesweeperCell getPuzzleElement() { + return (MinesweeperCell) super.getPuzzleElement(); + } + + @Override + @SuppressWarnings("Duplicates") + @Contract(pure = true) + public void drawElement(@NotNull Graphics2D graphics2D) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + final MinesweeperTileType type = cell.getTileType(); + if (type == MinesweeperTileType.FLAG) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.WHITE); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + final FontMetrics metrics = graphics2D.getFontMetrics(FONT); + final String value = String.valueOf(((MinesweeperCell) puzzleElement).getData().data()); + final int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; + final int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + graphics2D.drawString(value, xText, yText); + return; + } + if (type == MinesweeperTileType.UNSET) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.DARK_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + return; + } + if (type == MinesweeperTileType.EMPTY) { + graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.drawImage( + MinesweeperView.EMPTY_IMAGE, + location.x, + location.y, + size.width, + size.height, + Color.GRAY, + null); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + } + if (type == MinesweeperTileType.BOMB) { + graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.drawImage( + MinesweeperView.BOMB_IMAGE, + location.x, + location.y, + size.width, + size.height, + Color.GRAY, + null); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java new file mode 100644 index 000000000..8ae9c5a9a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperExporter.java @@ -0,0 +1,44 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.PuzzleExporter; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class MinesweeperExporter extends PuzzleExporter { + + public MinesweeperExporter(@NotNull Puzzle puzzle) { + super(puzzle); + } + + @Override + @Contract(pure = true) + protected @NotNull Element createBoardElement(@NotNull Document newDocument) { + MinesweeperBoard board; + if (puzzle.getTree() != null) { + board = (MinesweeperBoard) puzzle.getTree().getRootNode().getBoard(); + } else { + board = (MinesweeperBoard) puzzle.getBoardView().getBoard(); + } + + final org.w3c.dom.Element boardElement = newDocument.createElement("board"); + boardElement.setAttribute("width", String.valueOf(board.getWidth())); + boardElement.setAttribute("height", String.valueOf(board.getHeight())); + + final org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + if (!MinesweeperTileData.unset().equals(cell.getData())) { + final org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); + cellsElement.appendChild(cellElement); + } + } + + boardElement.appendChild(cellsElement); + return boardElement; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java new file mode 100644 index 000000000..419a69247 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperImporter.java @@ -0,0 +1,128 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.model.PuzzleImporter; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class MinesweeperImporter extends PuzzleImporter { + + public MinesweeperImporter(@NotNull Minesweeper minesweeper) { + super(minesweeper); + } + + @Override + @Contract(pure = true, value = "-> true") + public boolean acceptsRowsAndColumnsInput() { + return true; + } + + @Override + @Contract(pure = true, value = "-> false") + public boolean acceptsTextInput() { + return false; + } + + @Override + @Contract(pure = false) + public void initializeBoard(int rows, int columns) { + MinesweeperBoard minesweeperBoard = new MinesweeperBoard(columns, rows); + + for (int y = 0; y < rows; y++) { + for (int x = 0; x < columns; x++) { + MinesweeperCell cell = + new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); + cell.setIndex(y * columns + x); + cell.setModifiable(true); + minesweeperBoard.setCell(x, y, cell); + } + } + puzzle.setCurrentBoard(minesweeperBoard); + } + + @Override + @Contract(pure = false) + public void initializeBoard(@NotNull Node node) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("board")) { + throw new InvalidFileFormatException( + "Minesweeper Importer: cannot find board puzzleElement"); + } + final Element boardElement = (Element) node; + if (boardElement.getElementsByTagName("cells").getLength() == 0) { + throw new InvalidFileFormatException( + "Minesweeper Importer: no puzzleElement found for board"); + } + final Element dataElement = + (Element) boardElement.getElementsByTagName("cells").item(0); + final NodeList elementDataList = dataElement.getElementsByTagName("cell"); + + final MinesweeperBoard minesweeperBoard = getMinesweeperBoard(boardElement); + + final int width = minesweeperBoard.getWidth(); + final int height = minesweeperBoard.getHeight(); + + for (int i = 0; i < elementDataList.getLength(); i++) { + final MinesweeperCell cell = + (MinesweeperCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), minesweeperBoard); + final Point loc = cell.getLocation(); + if (MinesweeperTileData.unset().equals(cell.getData())) { + cell.setModifiable(false); + cell.setGiven(true); + } + minesweeperBoard.setCell(loc.x, loc.y, cell); + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (minesweeperBoard.getCell(x, y) == null) { + final MinesweeperCell cell = + new MinesweeperCell(MinesweeperTileData.unset(), new Point(x, y)); + cell.setIndex(y * height + x); + cell.setModifiable(true); + minesweeperBoard.setCell(x, y, cell); + } + } + } + puzzle.setCurrentBoard(minesweeperBoard); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Minesweeper Importer: unknown value where integer expected"); + } + } + + @Contract(pure = true) + private static @NotNull MinesweeperBoard getMinesweeperBoard(@NotNull Element boardElement) + throws InvalidFileFormatException { + MinesweeperBoard minesweeperBoard = null; + if (!boardElement.getAttribute("size").isEmpty()) { + final int size = Integer.parseInt(boardElement.getAttribute("size")); + minesweeperBoard = new MinesweeperBoard(size); + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { + final int width = Integer.parseInt(boardElement.getAttribute("width")); + final int height = Integer.parseInt(boardElement.getAttribute("height")); + minesweeperBoard = new MinesweeperBoard(width, height); + } + } + + if (minesweeperBoard == null) { + throw new InvalidFileFormatException("Minesweeper Importer: invalid board dimensions"); + } + return minesweeperBoard; + } + + @Override + @Contract(value = "_ -> fail", pure = false) + public void initializeBoard(@NotNull String[] statements) + throws UnsupportedOperationException, IllegalArgumentException { + throw new UnsupportedOperationException("Minesweeper does not support text input."); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java new file mode 100644 index 000000000..5296cf057 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileData.java @@ -0,0 +1,107 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import java.util.Objects; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public record MinesweeperTileData(MinesweeperTileType type, int data) { + + public static final int UNSET_DATA = -2; + public static final int BOMB_DATA = -1; + public static final int EMPTY_DATA = 0; + + /** + * Always has a type of {@link MinesweeperTileType#UNSET}, and a data value of {@value + * UNSET_DATA} + */ + private static final MinesweeperTileData UNSET = + new MinesweeperTileData(MinesweeperTileType.UNSET, UNSET_DATA); + + /** + * Always has a type of {@link MinesweeperTileType#BOMB}, and a data value of {@value BOMB_DATA} + */ + private static final MinesweeperTileData BOMB = + new MinesweeperTileData(MinesweeperTileType.BOMB, BOMB_DATA); + + /** + * Always has a type of {@link MinesweeperTileType#EMPTY}, and a data value of {@value + * EMPTY_DATA} + */ + private static final MinesweeperTileData EMPTY = + new MinesweeperTileData(MinesweeperTileType.EMPTY, EMPTY_DATA); + + /** + * @param count how many bombs are near the flag + * @return a new {@link MinesweeperTileData} with a {@link MinesweeperTileData#type} of {@link + * MinesweeperTileType#FLAG} and a {@link MinesweeperTileData#data} of {@code count} + */ + @Contract(pure = true) + public static @NotNull MinesweeperTileData flag(int count) { + return new MinesweeperTileData(MinesweeperTileType.FLAG, count); + } + + /** + * @param data Determines what type of {@link MinesweeperTileData} to return. + * @return If {@code data} is one of {@link MinesweeperTileData#UNSET_DATA}, {@link + * MinesweeperTileData#BOMB_DATA}, or {@link MinesweeperTileData#EMPTY_DATA}, it will return + * that data. If {@code data} is less than any of the values, or greater than 8, it will + * return {@link MinesweeperTileData#UNSET_DATA}. Otherwise, it returns {@link + * MinesweeperTileData#flag(int)} and passes {@code data} as the parameter. + */ + @Contract(pure = true) + public static @NotNull MinesweeperTileData fromData(int data) { + return switch (data) { + case UNSET_DATA -> unset(); + case BOMB_DATA -> bomb(); + case EMPTY_DATA -> empty(); + default -> { + if (data <= -2 || data > 8) { + yield unset(); + } + yield flag(data); + } + }; + } + + public static @NotNull MinesweeperTileData unset() { + return UNSET; + } + + public static @NotNull MinesweeperTileData bomb() { + return BOMB; + } + + public static @NotNull MinesweeperTileData empty() { + return EMPTY; + } + + public boolean isUnset() { + return this.data == UNSET_DATA; + } + + public boolean isBomb() { + return this.data == BOMB_DATA; + } + + public boolean isEmpty() { + return this.data == EMPTY_DATA; + } + + public boolean isFlag() { + return this.data > 0 && this.data <= 8; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MinesweeperTileData that = (MinesweeperTileData) o; + return data == that.data && type == that.type; + } + + @Override + public int hashCode() { + return Objects.hash(type, data); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java new file mode 100644 index 000000000..a682da5e5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperTileType.java @@ -0,0 +1,14 @@ +package edu.rpi.legup.puzzle.minesweeper; + +public enum MinesweeperTileType { + + /** A cell with nothing */ + UNSET, + + /** Represents a cell with no bombs in it */ + EMPTY, + /** A flag has values 1-8 representing how many bombs are touching it */ + FLAG, + /** A bomb tile that should be marked by nearby flags */ + BOMB +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java new file mode 100644 index 000000000..d38460ac8 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperUtilities.java @@ -0,0 +1,170 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.puzzle.minesweeper.rules.LessBombsThanFlagContradictionRule; +import java.awt.*; +import java.util.*; +import java.util.Objects; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public final class MinesweeperUtilities { + + private static final int SURROUNDING_CELL_MIN_INDEX = 0; + private static final int SURROUNDING_CELL_MAX_INDEX = 9; + + public static Stream getSurroundingCells( + MinesweeperBoard board, MinesweeperCell cell) { + final Point loc = cell.getLocation(); + final int height = board.getHeight(); + final int width = board.getWidth(); + final int x = (int) loc.getX(); + final int y = (int) loc.getY(); + // IntStream of 0-9 to represent 2D matrix of surrounding elements, + // this maps from 0,0 to 2,2 so everything needs to be shifted + // left 1 and up 1 to become + // -1,1 to 1,1 + // and 5 is skipped because we want to ignore 1,1 + return IntStream.range(SURROUNDING_CELL_MIN_INDEX, SURROUNDING_CELL_MAX_INDEX) + // skip 0,0 element + .filter(i -> i != (SURROUNDING_CELL_MAX_INDEX - SURROUNDING_CELL_MIN_INDEX) / 2) + .mapToObj( + index -> { + final int newX = index / 3 - 1 + x; + final int newY = index % 3 - 1 + y; + // only keep valid locations + if (newX < 0 || newY < 0 || newX >= width || newY >= height) { + return null; + } + return board.getCell(newX, newY); + }) + .filter(Objects::nonNull); + } + + public static int countSurroundingType( + MinesweeperBoard board, MinesweeperCell cell, MinesweeperTileType type) { + final Stream stream = + getSurroundingCells(board, cell).map(MinesweeperCell::getData); + return (int) + (switch (type) { + case UNSET -> stream.filter(MinesweeperTileData::isUnset); + case BOMB -> stream.filter(MinesweeperTileData::isBomb); + case EMPTY -> stream.filter(MinesweeperTileData::isEmpty); + case FLAG -> stream.filter(MinesweeperTileData::isFlag); + }) + .count(); + } + + public static int countSurroundingBombs(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.BOMB); + } + + public static int countSurroundingUnset(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.UNSET); + } + + public static int countSurroundingEmpty(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.EMPTY); + } + + public static int countSurroundingFlags(MinesweeperBoard board, MinesweeperCell cell) { + return countSurroundingType(board, cell, MinesweeperTileType.FLAG); + } + + /** + * @return how many bombs are left that need to be placed around {@code cell} which must be a + * flag + */ + public int countNeededBombsFromFlag(MinesweeperBoard board, MinesweeperCell cell) { + if (!cell.getData().isFlag()) { + throw new IllegalArgumentException("Bombs are only needed surrounding flags"); + } + return cell.getData().data() - countSurroundingBombs(board, cell); + } + + public static boolean hasEmptyAdjacent(MinesweeperBoard board, MinesweeperCell cell) { + ArrayList adjCells = getAdjacentCells(board, cell); + for (MinesweeperCell adjCell : adjCells) { + if (adjCell.getTileType() == MinesweeperTileType.UNSET) { + return true; + } + } + return false; + } + + public static ArrayList getAdjacentCells( + MinesweeperBoard board, MinesweeperCell cell) { + ArrayList adjCells = new ArrayList(); + Point cellLoc = cell.getLocation(); + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (cellLoc.getX() + i < 0 + || cellLoc.y + j < 0 + || cellLoc.x + i >= board.getWidth() + || cellLoc.y + j >= board.getHeight()) { + continue; + } + MinesweeperCell adjCell = + (MinesweeperCell) board.getCell(cellLoc.x + i, cellLoc.y + j); + if (adjCell == null || adjCell == cell) { + continue; + } + adjCells.add(adjCell); + } + } + return adjCells; + } + + public static ArrayList getCombinations(int chosenNumItems, int totalNumItems) { + ArrayList combinations = new ArrayList(); + + // calculate all combinations + boolean[] array = new boolean[totalNumItems]; + recurseCombinations(combinations, 0, chosenNumItems, 0, totalNumItems, array); + + return combinations; + } + + private static void recurseCombinations( + ArrayList result, + int curIndex, + int maxBlack, + int numBlack, + int len, + boolean[] workingArray) { + if (curIndex == len) { + // complete, but not valid solution + if (numBlack != maxBlack) { + return; + } + // complete and valid solution + result.add(workingArray.clone()); + return; + } + // there is no chance of completing the required number of solutions, so quit + if (len - curIndex < maxBlack - numBlack) { + return; + } + + if (numBlack < maxBlack) { + workingArray[curIndex] = true; + recurseCombinations(result, curIndex + 1, maxBlack, numBlack + 1, len, workingArray); + } + workingArray[curIndex] = false; + recurseCombinations(result, curIndex + 1, maxBlack, numBlack, len, workingArray); + } + + public static boolean isForcedBomb(MinesweeperBoard board, MinesweeperCell cell) { + + LessBombsThanFlagContradictionRule tooManyBombs = new LessBombsThanFlagContradictionRule(); + MinesweeperBoard emptyCaseBoard = board.copy(); + MinesweeperCell emptyCell = (MinesweeperCell) emptyCaseBoard.getPuzzleElement(cell); + emptyCell.setCellType(MinesweeperTileData.empty()); + ArrayList adjCells = getAdjacentCells(emptyCaseBoard, emptyCell); + for (MinesweeperCell adjCell : adjCells) { + if (tooManyBombs.checkContradictionAt(emptyCaseBoard, adjCell) == null) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java new file mode 100644 index 000000000..e8ab8dfcb --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/MinesweeperView.java @@ -0,0 +1,65 @@ +package edu.rpi.legup.puzzle.minesweeper; + +import edu.rpi.legup.controller.BoardController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.ui.boardview.GridBoardView; +import java.awt.*; +import java.io.IOException; +import java.util.Objects; +import javax.imageio.ImageIO; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +public class MinesweeperView extends GridBoardView { + + private static final Logger LOGGER = LogManager.getLogger(MinesweeperView.class.getName()); + public static final Image BOMB_IMAGE; + + public static final Image EMPTY_IMAGE; + + static { + Image tempBombImage = null; + try { + tempBombImage = + ImageIO.read( + Objects.requireNonNull( + ClassLoader.getSystemClassLoader() + .getResource( + "edu/rpi/legup/images/minesweeper/tiles/Bomb.png"))); + } catch (IOException e) { + LOGGER.error("Failed to open Minesweeper images"); + } + BOMB_IMAGE = tempBombImage; + } + + static { + Image tempEmptyImage = null; + try { + tempEmptyImage = + ImageIO.read( + Objects.requireNonNull( + ClassLoader.getSystemClassLoader() + .getResource( + "edu/rpi/legup/images/minesweeper/tiles/Empty.png"))); + } catch (IOException e) { + LOGGER.error("Failed to open Minesweeper images"); + } + EMPTY_IMAGE = tempEmptyImage; + } + + public MinesweeperView(@NotNull MinesweeperBoard board) { + super(new BoardController(), new MinesweeperController(), board.getDimension()); + + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + final MinesweeperCell cell = (MinesweeperCell) puzzleElement; + final Point loc = cell.getLocation(); + final MinesweeperElementView elementView = new MinesweeperElementView(cell); + elementView.setIndex(cell.getIndex()); + elementView.setSize(elementSize); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(elementView); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java new file mode 100644 index 000000000..cd5577eeb --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/BombTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class BombTile extends PlaceableElement { + public BombTile() { + super( + "MINE-UNPL-0001", + "Bomb", + "A bomb", + "edu/rpi/legup/images/minesweeper/tiles/Bomb.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java new file mode 100644 index 000000000..7149bfa6a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/EmptyTile.java @@ -0,0 +1,14 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class EmptyTile extends PlaceableElement { + + public EmptyTile() { + super( + "MINE-PLAC-0002", + "Empty", + "An empty tile", + "edu/rpi/legup/images/minesweeper/tiles/Empty.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java new file mode 100644 index 000000000..0bbca81f9 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/FlagTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class FlagTile extends PlaceableElement { + public FlagTile() { + super( + "MINE-PLAC-0001", + "Flag", + "The flag", + "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java new file mode 100644 index 000000000..6cfc34c8d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/UnsetTile.java @@ -0,0 +1,14 @@ +package edu.rpi.legup.puzzle.minesweeper.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class UnsetTile extends PlaceableElement { + + public UnsetTile() { + super( + "MINE-UNPL-0002", + "Unset", + "An unset tile", + "edu/rpi/legup/images/minesweeper/tiles/Unset.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt new file mode 100644 index 000000000..08ce23f59 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/elements/minesweeper_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +MINE-UNPL-0001 : BombTile +MINE-PLAC-0001 : FlagTile +MINE-PLAC-0002 : EmptyTile +MINE-UNPL-0002 : UnsetTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java new file mode 100644 index 000000000..a1ef97928 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/BombOrFilledCaseRule.java @@ -0,0 +1,93 @@ +package edu.rpi.legup.puzzle.minesweeper.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileData; +import java.util.ArrayList; +import java.util.List; + +public class BombOrFilledCaseRule extends CaseRule { + + public BombOrFilledCaseRule() { + super( + "MINE-CASE-0001", + "Bomb Or Filled", + "A cell can either be a bomb or filled.\n", + "edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg"); + } + + @Override + public CaseBoard getCaseBoard(Board board) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(minesweeperBoard, this); + minesweeperBoard.setModifiable(false); + for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { + MinesweeperCell cell = (MinesweeperCell) data; + if (cell.getData().isUnset()) { + caseBoard.addPickableElement(data); + } + } + return caseBoard; + } + + @Override + public List getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + + Board case1 = board.copy(); + MinesweeperCell cell1 = (MinesweeperCell) case1.getPuzzleElement(puzzleElement); + cell1.setData(MinesweeperTileData.bomb()); + case1.addModifiedData(cell1); + cases.add(case1); + + Board case2 = board.copy(); + MinesweeperCell cell2 = (MinesweeperCell) case2.getPuzzleElement(puzzleElement); + cell2.setData(MinesweeperTileData.empty()); + case2.addModifiedData(cell2); + cases.add(case2); + return cases; + } + + @Override + public String checkRuleRaw(TreeTransition transition) { + List childTransitions = transition.getParents().get(0).getChildren(); + if (childTransitions.size() != 2) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must have 2 children."; + } + + TreeTransition case1 = childTransitions.get(0); + TreeTransition case2 = childTransitions.get(1); + if (case1.getBoard().getModifiedData().size() != 1 + || case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; + } + + MinesweeperCell mod1 = + (MinesweeperCell) case1.getBoard().getModifiedData().iterator().next(); + MinesweeperCell mod2 = + (MinesweeperCell) case2.getBoard().getModifiedData().iterator().next(); + if (!mod1.getLocation().equals(mod2.getLocation())) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; + } + + if (!((mod1.getData().isBomb() && mod2.getData().isEmpty()) + || (mod2.getData().isBomb() && mod1.getData().isEmpty()))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must an empty cell and a bomb cell."; + } + + return null; + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java new file mode 100644 index 000000000..e85008d23 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/FinishWithBombsDirectRule.java @@ -0,0 +1,64 @@ +package edu.rpi.legup.puzzle.minesweeper.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.minesweeper.*; + +public class FinishWithBombsDirectRule extends DirectRule { + public FinishWithBombsDirectRule() { + super( + "MINE-BASC-0001", + "Finish with Bombs", + "The remaining unknowns around a flag must be bombs to satisfy the number", + "edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg"); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + MinesweeperBoard board = (MinesweeperBoard) transition.getBoard(); + MinesweeperBoard parentBoard = (MinesweeperBoard) transition.getParents().get(0).getBoard(); + MinesweeperCell cell = (MinesweeperCell) board.getPuzzleElement(puzzleElement); + MinesweeperCell parentCell = (MinesweeperCell) parentBoard.getPuzzleElement(puzzleElement); + + if (!(parentCell.getTileType() == MinesweeperTileType.UNSET + && cell.getTileType() == MinesweeperTileType.BOMB)) { + return super.getInvalidUseOfRuleMessage() + + ": This cell must be black to be applicable with this rule."; + } + + if (MinesweeperUtilities.isForcedBomb(parentBoard, cell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be black"; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) node.getBoard().copy(); + for (PuzzleElement element : minesweeperBoard.getPuzzleElements()) { + MinesweeperCell cell = (MinesweeperCell) element; + if (cell.getTileType() == MinesweeperTileType.UNSET + && MinesweeperUtilities.isForcedBomb( + (MinesweeperBoard) node.getBoard(), cell)) { + cell.setCellType(MinesweeperTileData.bomb()); + minesweeperBoard.addModifiedData(cell); + } + } + if (minesweeperBoard.getModifiedData().isEmpty()) { + return null; + } else { + return minesweeperBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java new file mode 100644 index 000000000..c9919343f --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/LessBombsThanFlagContradictionRule.java @@ -0,0 +1,50 @@ +package edu.rpi.legup.puzzle.minesweeper.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.minesweeper.*; +import java.util.ArrayList; + +public class LessBombsThanFlagContradictionRule extends ContradictionRule { + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Contradiction must be a region"; + + public LessBombsThanFlagContradictionRule() { + super( + "MINE-CONT-0000", + "Less Bombs Than Flag", + "There can not be less then the number of Bombs around a flag then the specified number\n", + "edu/rpi/legup/images/nurikabe/contradictions/NoNumber.png"); + } + + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + MinesweeperCell cell = (MinesweeperCell) minesweeperBoard.getPuzzleElement(puzzleElement); + + int cellNum = cell.getTileNumber(); + if (cellNum <= 0 || cellNum >= 9) { + return super.getNoContradictionMessage(); + } + int numEmpty = 0; + int numAdj = 0; + ArrayList adjCells = + MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + for (MinesweeperCell adjCell : adjCells) { + numAdj++; + if (adjCell.getTileType() == MinesweeperTileType.EMPTY && adjCell != cell) { + numEmpty++; + } + } + System.out.println(numEmpty); + System.out.println(numAdj); + System.out.println(cellNum); + if (numEmpty > (numAdj - cellNum)) { + return null; + } + + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java new file mode 100644 index 000000000..ecfdbad66 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/MoreBombsThanFlagContradictionRule.java @@ -0,0 +1,54 @@ +package edu.rpi.legup.puzzle.minesweeper.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperTileType; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities; +import java.util.ArrayList; + +public class MoreBombsThanFlagContradictionRule extends ContradictionRule { + + public MoreBombsThanFlagContradictionRule() { + super( + "MINE-CONT-0001", + "More Bombs Than Flag", + "There can not be more Bombs around a flag than the specified number\n", + "edu/rpi/legup/images/minesweeper/contradictions/Bomb_Surplus.jpg"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board; + MinesweeperCell cell = (MinesweeperCell) minesweeperBoard.getPuzzleElement(puzzleElement); + + int cellNum = cell.getTileNumber(); + if (cellNum < 0 || cellNum >= 10) { + return super.getNoContradictionMessage(); + } + int numBlack = 0; + ArrayList adjCells = + MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + for (MinesweeperCell adjCell : adjCells) { + if (adjCell.getTileType() == MinesweeperTileType.BOMB) { + numBlack++; + } + } + if (numBlack > cellNum) { + return null; + } + + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java new file mode 100644 index 000000000..a59369b7a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/minesweeper/rules/SatisfyFlagCaseRule.java @@ -0,0 +1,231 @@ +package edu.rpi.legup.puzzle.minesweeper.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.minesweeper.*; +import java.awt.*; +import java.util.*; +import java.util.List; + +public class SatisfyFlagCaseRule extends CaseRule { + public SatisfyFlagCaseRule() { + super( + "MINE-CASE-0002", + "Satisfy Flag", + "Create a different path for each valid way to mark bombs and filled cells around a flag", + "edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png"); + } + + @Override + public CaseBoard getCaseBoard(Board board) { + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(minesweeperBoard, this); + minesweeperBoard.setModifiable(false); + for (PuzzleElement data : minesweeperBoard.getPuzzleElements()) { + MinesweeperCell cell = (MinesweeperCell) data; + if (cell.getTileNumber() > 0 + && cell.getTileNumber() <= 8 + && MinesweeperUtilities.hasEmptyAdjacent(minesweeperBoard, cell)) { + caseBoard.addPickableElement(data); + } + } + return caseBoard; + } + + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList(); + + // get value of cell + MinesweeperBoard minesweeperBoard = (MinesweeperBoard) board.copy(); + MinesweeperCell cell = (MinesweeperCell) minesweeperBoard.getPuzzleElement(puzzleElement); + int cellMaxBlack = cell.getTileNumber(); + if (cellMaxBlack <= 0 || cellMaxBlack > 8) { // cell is not valid cell + return null; + } + + // find number of black & unset squares + int cellNumBomb = 0; + int cellNumUnset = 0; + ArrayList unsetCells = new ArrayList(); + ArrayList adjCells = + MinesweeperUtilities.getAdjacentCells(minesweeperBoard, cell); + for (MinesweeperCell adjCell : adjCells) { + if (adjCell.getTileType() == MinesweeperTileType.BOMB) { + cellNumBomb++; + } + if (adjCell.getTileType() == MinesweeperTileType.UNSET) { + cellNumUnset++; + unsetCells.add(adjCell); + } + } + // no cases if no empty or if too many black already + if (cellNumBomb >= cellMaxBlack || cellNumUnset == 0) { + return cases; + } + + // generate all cases as boolean expressions + ArrayList combinations; + combinations = + MinesweeperUtilities.getCombinations(cellMaxBlack - cellNumBomb, cellNumUnset); + + for (int i = 0; i < combinations.size(); i++) { + Board case_ = board.copy(); + for (int j = 0; j < combinations.get(i).length; j++) { + cell = (MinesweeperCell) case_.getPuzzleElement(unsetCells.get(j)); + if (combinations.get(i)[j]) { + cell.setCellType(MinesweeperTileData.bomb()); + } else { + cell.setCellType(MinesweeperTileData.empty()); + } + case_.addModifiedData(cell); + } + cases.add(case_); + } + + return cases; + } + + @Override + public String checkRuleRaw(TreeTransition transition) { + TreeNode parent = transition.getParents().get(0); + List childTransitions = parent.getChildren(); + + /* + * In order for the transition to be valid, it can only be applied to + * one cell, thus: + * * there must be modified cells + * * all modified cells must share at least one common adjacent + * cell + * * all modified cells must fit within a 3X3 square + * * the center of one of the possible squares must be a cell + * with a number + * * that cells possible combinations must match the transitions + * If all the above is verified, then the transition is valid + */ + + /* ensure there are modified cells */ + Set modCells = transition.getBoard().getModifiedData(); + if (modCells.size() <= 0) { + return super.getInvalidUseOfRuleMessage(); + } + + /* ensure modified cells occur within a 3X3 square */ + int minVertLoc = Integer.MAX_VALUE, maxVertLoc = Integer.MIN_VALUE; + int minHorzLoc = Integer.MAX_VALUE, maxHorzLoc = Integer.MIN_VALUE; + for (PuzzleElement modCell : modCells) { + Point loc = ((MinesweeperCell) modCell).getLocation(); + if (loc.x < minHorzLoc) { + minHorzLoc = loc.x; + } + if (loc.x > maxHorzLoc) { + maxHorzLoc = loc.x; + } + if (loc.y < minVertLoc) { + minVertLoc = loc.y; + } + if (loc.y > maxVertLoc) { + maxVertLoc = loc.y; + } + } + if (maxVertLoc - minVertLoc > 3 || maxHorzLoc - minHorzLoc > 3) { + return super.getInvalidUseOfRuleMessage(); + } + + /* get the center of all possible 3X3 squares, + * and collect all that have numbers */ + MinesweeperBoard board = (MinesweeperBoard) transition.getParents().get(0).getBoard(); + ArrayList possibleCenters = new ArrayList(); + for (PuzzleElement modCell : modCells) { + ArrayList adjacentCells = + MinesweeperUtilities.getAdjacentCells(board, (MinesweeperCell) modCell); + for (MinesweeperCell cell : adjacentCells) { + possibleCenters.add(cell); + } + } + + // removing all elements without a valid number + possibleCenters.removeIf(x -> x.getTileNumber() <= 0 || x.getTileNumber() >= 9); + if (possibleCenters.isEmpty()) { + return super.getInvalidUseOfRuleMessage(); + } + + /* Now go through the remaining centers, and check if their combinations + * match the transitions */ + for (MinesweeperCell possibleCenter : possibleCenters) { + int numBlack = 0; + int numEmpty = 0; + int maxBlack = possibleCenter.getTileNumber(); + for (MinesweeperCell adjCell : + MinesweeperUtilities.getAdjacentCells(board, possibleCenter)) { + if (adjCell.getTileType() == MinesweeperTileType.BOMB) { + numBlack++; + } + if (adjCell.getTileType() == MinesweeperTileType.UNSET) { + numEmpty++; + } + } + if (numEmpty <= 0 || numBlack > maxBlack) { + // this cell has no cases (no empty) or is already broken (too many black) + continue; + } + + ArrayList combinations = + MinesweeperUtilities.getCombinations(maxBlack - numBlack, numEmpty); + if (combinations.size() != childTransitions.size()) { + // not this center because combinations do not match transitions + continue; + } + boolean quitEarly = false; + for (TreeTransition trans : childTransitions) { + /* convert the transition board into boolean format, so that it + * can be compared to the combinations */ + MinesweeperBoard transBoard = (MinesweeperBoard) trans.getBoard(); + ArrayList transModCells = new ArrayList(); + for (PuzzleElement modCell : modCells) { + transModCells.add((MinesweeperCell) transBoard.getPuzzleElement(modCell)); + } + + boolean[] translatedModCells = new boolean[transModCells.size()]; + for (int i = 0; i < transModCells.size(); i++) { + if (transModCells.get(i).getTileType() == MinesweeperTileType.BOMB) { + translatedModCells[i] = true; + } else { + translatedModCells[i] = false; + } + } + + // try to find the above state in the combinations, remove if found + boolean removed = false; + for (boolean[] combination : combinations) { + if (Arrays.equals(combination, translatedModCells)) { + combinations.remove(combination); + removed = true; + break; + } + } + // if combination not found, no need to check further, just quit + if (!removed) { + quitEarly = true; + break; + } + } + + /* we found a center that is valid */ + if (combinations.isEmpty() && !quitEarly) { + return null; + } + } + + return super.getInvalidUseOfRuleMessage(); + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/Nurikabe.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/Nurikabe.java index 2edbcb039..8366d905f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/Nurikabe.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/Nurikabe.java @@ -17,9 +17,7 @@ public Nurikabe() { this.factory = new NurikabeCellFactory(); } - /** - * Initializes the game board. Called by the invoker of the class - */ + /** Initializes the game board. Called by the invoker of the class */ @Override public void initializeView() { boardView = new NurikabeView((NurikabeBoard) currentBoard); @@ -42,8 +40,8 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Nurikabe * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Nurikabe, false otherwise */ public boolean isValidDimensions(int rows, int columns) { @@ -80,7 +78,5 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { - - } + public void onBoardChange(Board board) {} } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeBoard.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeBoard.java index d5b83d1e8..1f80611e8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeBoard.java @@ -1,6 +1,5 @@ package edu.rpi.legup.puzzle.nurikabe; -import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; @@ -15,8 +14,11 @@ public NurikabeBoard(int size) { @Override public NurikabeCell getCell(int x, int y) { - if (y * dimension.width + x >= puzzleElements.size() || x >= dimension.width || - y >= dimension.height || x < 0 || y < 0) { + if (y * dimension.width + x >= puzzleElements.size() + || x >= dimension.width + || y >= dimension.height + || x < 0 + || y < 0) { return null; } return (NurikabeCell) super.getCell(x, y); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java index f84a3c9f1..1e0e85ed8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCell.java @@ -1,8 +1,7 @@ package edu.rpi.legup.puzzle.nurikabe; -import edu.rpi.legup.model.gameboard.GridCell; import edu.rpi.legup.model.elements.Element; - +import edu.rpi.legup.model.gameboard.GridCell; import java.awt.*; import java.awt.event.MouseEvent; @@ -11,7 +10,7 @@ public class NurikabeCell extends GridCell { /** * NurikabeCell Constructor - creates a NurikabeCell from the specified value and location * - * @param value value of the NurikabeCell + * @param value value of the NurikabeCell * @param location position of the NurikabeCell */ public NurikabeCell(int value, Point location) { @@ -46,28 +45,26 @@ public NurikabeType getType() { */ @Override public void setType(Element e, MouseEvent m) { - switch (e.getElementID()){ - case "NURI-PLAC-0001": + switch (e.getElementID()) { + case "NURI-ELEM-0001": this.data = -1; break; - case "NURI-PLAC-0002": + case "NURI-ELEM-0004": this.data = 0; break; - case "NURI-UNPL-0001": - switch (m.getButton()){ + case "NURI-ELEM-0002": + switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data <= 0 || this.data > 8) { this.data = 1; - } - else { + } else { this.data = this.data + 1; } break; case MouseEvent.BUTTON3: if (this.data > 1) { this.data = this.data - 1; - } - else { + } else { this.data = 9; } break; @@ -92,4 +89,4 @@ public NurikabeCell copy() { copy.setGiven(isGiven); return copy; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCellFactory.java index b754f3e46..7241608ac 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeCellFactory.java @@ -4,17 +4,16 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class NurikabeCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid @@ -23,7 +22,8 @@ public class NurikabeCellFactory extends ElementFactory { public NurikabeCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("nurikabe Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "nurikabe Factory: unknown puzzleElement puzzleElement"); } NurikabeBoard nurikabeBoard = (NurikabeBoard) board; @@ -35,7 +35,8 @@ public NurikabeCell importCell(Node node, Board board) throws InvalidFileFormatE int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); if (x >= width || y >= height) { - throw new InvalidFileFormatException("nurikabe Factory: cell location out of bounds"); + throw new InvalidFileFormatException( + "nurikabe Factory: cell location out of bounds"); } if (value < -2) { throw new InvalidFileFormatException("nurikabe Factory: cell unknown value"); @@ -44,11 +45,10 @@ public NurikabeCell importCell(Node node, Board board) throws InvalidFileFormatE NurikabeCell cell = new NurikabeCell(value, new Point(x, y)); cell.setIndex(y * height + x); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("nurikabe Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "nurikabe Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("nurikabe Factory: could not find attribute(s)"); } } @@ -56,7 +56,7 @@ public NurikabeCell importCell(Node node, Board board) throws InvalidFileFormatE /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java index c115498a8..f2fad0d50 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeController.java @@ -2,42 +2,50 @@ import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.event.MouseEvent; public class NurikabeController extends ElementController { + /** + * Handles cell state changes in the nurikabe puzzle when a mouse event occurs + * If the left mouse button is clicked: + * - If the control key is held down, shows a context menu at the mouse position + * - Otherwise, toggles the cell data state between 0, -1, and -2 in a cyclic manner + * If the right mouse button is clicked, the cell data state is also toggled between -2, -1, and 0 + * + * @param e MouseEvent triggered by the user interaction + * @param data PuzzleElement representing the cell being modified + */ @Override public void changeCell(MouseEvent e, PuzzleElement data) { NurikabeCell cell = (NurikabeCell) data; if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { - this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); - } - else { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { if (cell.getData() == -2) { data.setData(0); - } - else { + } else { if (cell.getData() == 0) { data.setData(-1); - } - else { + } else { data.setData(-2); } } } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() == -2) { data.setData(-1); - } - else { + } else { if (cell.getData() == 0) { data.setData(-2); - } - else { + } else { data.setData(0); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeElementView.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeElementView.java index f122a7a5b..116b727d2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.nurikabe; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class NurikabeElementView extends GridElementView { @@ -40,24 +39,22 @@ public void drawElement(Graphics2D graphics2D) { FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = String.valueOf(puzzleElement.getData()); int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); - } - else { + } else { if (type == NurikabeType.BLACK) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(Color.BLACK); graphics2D.fillRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == NurikabeType.WHITE) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(Color.WHITE); graphics2D.fillRect(location.x, location.y, size.width, size.height); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == NurikabeType.UNKNOWN) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(Color.LIGHT_GRAY); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java index 095642a6e..e01821639 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeExporter.java @@ -10,13 +10,19 @@ public NurikabeExporter(Nurikabe nurikabe) { super(nurikabe); } + /** + * Generates an XML element for the nurikabe puzzle board, including its dimensions and the + * state of each cell. Nurikabe cells that are not empty are included in the XML. + * + * @param newDocument The XML document to which the board element belongs. + * @return The XML element representing the board. + */ @Override protected org.w3c.dom.Element createBoardElement(Document newDocument) { NurikabeBoard board; if (puzzle.getTree() != null) { board = (NurikabeBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (NurikabeBoard) puzzle.getBoardView().getBoard(); } @@ -28,7 +34,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { NurikabeCell cell = (NurikabeCell) puzzleElement; if (cell.getData() != -2) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeImporter.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeImporter.java index 2cbcc9ad0..ec4ed3ac1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeImporter.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class NurikabeImporter extends PuzzleImporter { public NurikabeImporter(Nurikabe nurikabe) { super(nurikabe); @@ -26,7 +25,7 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException if board can not be created */ @@ -36,7 +35,8 @@ public void initializeBoard(int rows, int columns) { for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { - NurikabeCell cell = new NurikabeCell(NurikabeType.UNKNOWN.toValue(), new Point(x, y)); + NurikabeCell cell = + new NurikabeCell(NurikabeType.UNKNOWN.toValue(), new Point(x, y)); cell.setIndex(y * columns + x); cell.setModifiable(true); nurikabeBoard.setCell(x, y, cell); @@ -55,11 +55,13 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("nurikabe Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "nurikabe Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("nurikabe Importer: no puzzleElement found for board"); + throw new InvalidFileFormatException( + "nurikabe Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); NodeList elementDataList = dataElement.getElementsByTagName("cell"); @@ -68,9 +70,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { if (!boardElement.getAttribute("size").isEmpty()) { int size = Integer.valueOf(boardElement.getAttribute("size")); nurikabeBoard = new NurikabeBoard(size); - } - else { - if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { int width = Integer.valueOf(boardElement.getAttribute("width")); int height = Integer.valueOf(boardElement.getAttribute("height")); nurikabeBoard = new NurikabeBoard(width, height); @@ -85,7 +87,10 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int height = nurikabeBoard.getHeight(); for (int i = 0; i < elementDataList.getLength(); i++) { - NurikabeCell cell = (NurikabeCell) puzzle.getFactory().importCell(elementDataList.item(i), nurikabeBoard); + NurikabeCell cell = + (NurikabeCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), nurikabeBoard); Point loc = cell.getLocation(); if (cell.getData() != NurikabeType.UNKNOWN.toValue()) { cell.setModifiable(false); @@ -97,7 +102,8 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (nurikabeBoard.getCell(x, y) == null) { - NurikabeCell cell = new NurikabeCell(NurikabeType.UNKNOWN.toValue(), new Point(x, y)); + NurikabeCell cell = + new NurikabeCell(NurikabeType.UNKNOWN.toValue(), new Point(x, y)); cell.setIndex(y * height + x); cell.setModifiable(true); nurikabeBoard.setCell(x, y, cell); @@ -105,9 +111,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } puzzle.setCurrentBoard(nurikabeBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("nurikabe Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "nurikabe Importer: unknown value where integer expected"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeType.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeType.java index 1dbab645d..8acf9fc02 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeType.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeType.java @@ -1,7 +1,10 @@ package edu.rpi.legup.puzzle.nurikabe; public enum NurikabeType { - UNKNOWN, BLACK, WHITE, NUMBER; + UNKNOWN, + BLACK, + WHITE, + NUMBER; public int toValue() { return this.ordinal() - 2; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeUtilities.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeUtilities.java index 024cf6bb2..71ffa08e5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeUtilities.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeUtilities.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.utility.DisjointSets; - import java.awt.*; import java.util.HashMap; import java.util.HashSet; @@ -50,18 +49,18 @@ public static DisjointSets getNurikabeRegions(NurikabeBoard board) NurikabeCell rightCell = board.getCell(x + 1, y); NurikabeCell downCell = board.getCell(x, y + 1); - if (cell.getType() == NurikabeType.NUMBER || - cell.getType() == NurikabeType.WHITE) { - if (rightCell != null && (rightCell.getType() == NurikabeType.NUMBER || - rightCell.getType() == NurikabeType.WHITE)) { + if (cell.getType() == NurikabeType.NUMBER || cell.getType() == NurikabeType.WHITE) { + if (rightCell != null + && (rightCell.getType() == NurikabeType.NUMBER + || rightCell.getType() == NurikabeType.WHITE)) { regions.union(cell, rightCell); } - if (downCell != null && (downCell.getType() == NurikabeType.NUMBER || - downCell.getType() == NurikabeType.WHITE)) { + if (downCell != null + && (downCell.getType() == NurikabeType.NUMBER + || downCell.getType() == NurikabeType.WHITE)) { regions.union(cell, downCell); } - } - else { + } else { if (cell.getType() == NurikabeType.BLACK) { if (rightCell != null && rightCell.getType() == NurikabeType.BLACK) { regions.union(cell, rightCell); @@ -69,8 +68,7 @@ public static DisjointSets getNurikabeRegions(NurikabeBoard board) if (downCell != null && downCell.getType() == NurikabeType.BLACK) { regions.union(cell, downCell); } - } - else { + } else { if (cell.getType() == NurikabeType.UNKNOWN) { if (rightCell != null && rightCell.getType() == NurikabeType.UNKNOWN) { regions.union(cell, rightCell); @@ -110,13 +108,16 @@ public static DisjointSets getPossibleBlackRegions(NurikabeBoard b NurikabeCell cell = board.getCell(x, y); NurikabeCell rightCell = board.getCell(x + 1, y); NurikabeCell downCell = board.getCell(x, y + 1); - if (cell.getType() == NurikabeType.BLACK || cell.getType() == NurikabeType.UNKNOWN) { - if (rightCell != null && (rightCell.getType() == NurikabeType.BLACK || - rightCell.getType() == NurikabeType.UNKNOWN)) { + if (cell.getType() == NurikabeType.BLACK + || cell.getType() == NurikabeType.UNKNOWN) { + if (rightCell != null + && (rightCell.getType() == NurikabeType.BLACK + || rightCell.getType() == NurikabeType.UNKNOWN)) { blackRegions.union(cell, rightCell); } - if (downCell != null && (downCell.getType() == NurikabeType.BLACK || - downCell.getType() == NurikabeType.UNKNOWN)) { + if (downCell != null + && (downCell.getType() == NurikabeType.BLACK + || downCell.getType() == NurikabeType.UNKNOWN)) { blackRegions.union(cell, downCell); } } @@ -139,7 +140,9 @@ public static DisjointSets getPossibleWhiteRegions(NurikabeBoard b DisjointSets whiteRegions = new DisjointSets<>(); for (PuzzleElement data : board.getPuzzleElements()) { NurikabeCell cell = (NurikabeCell) data; - if (cell.getType() == NurikabeType.WHITE || cell.getType() == NurikabeType.NUMBER || cell.getType() == NurikabeType.UNKNOWN) { + if (cell.getType() == NurikabeType.WHITE + || cell.getType() == NurikabeType.NUMBER + || cell.getType() == NurikabeType.UNKNOWN) { whiteRegions.createSet(cell); } } @@ -149,14 +152,19 @@ public static DisjointSets getPossibleWhiteRegions(NurikabeBoard b NurikabeCell cell = board.getCell(x, y); NurikabeCell rightCell = board.getCell(x + 1, y); NurikabeCell downCell = board.getCell(x, y + 1); - if (cell.getType() == NurikabeType.WHITE || cell.getType() == NurikabeType.NUMBER || - cell.getType() == NurikabeType.UNKNOWN) { - if (rightCell != null && (rightCell.getType() == NurikabeType.WHITE || - rightCell.getType() == NurikabeType.NUMBER || rightCell.getType() == NurikabeType.UNKNOWN)) { + if (cell.getType() == NurikabeType.WHITE + || cell.getType() == NurikabeType.NUMBER + || cell.getType() == NurikabeType.UNKNOWN) { + if (rightCell != null + && (rightCell.getType() == NurikabeType.WHITE + || rightCell.getType() == NurikabeType.NUMBER + || rightCell.getType() == NurikabeType.UNKNOWN)) { whiteRegions.union(cell, rightCell); } - if (downCell != null && (downCell.getType() == NurikabeType.WHITE || - downCell.getType() == NurikabeType.NUMBER || downCell.getType() == NurikabeType.UNKNOWN)) { + if (downCell != null + && (downCell.getType() == NurikabeType.WHITE + || downCell.getType() == NurikabeType.NUMBER + || downCell.getType() == NurikabeType.UNKNOWN)) { whiteRegions.union(cell, downCell); } } @@ -166,9 +174,8 @@ public static DisjointSets getPossibleWhiteRegions(NurikabeBoard b } /** - * Makes a map where the keys are white/numbered cells - * and the values are the amount of cells that need - * to be added to the region + * Makes a map where the keys are white/numbered cells and the values are the amount of cells + * that need to be added to the region * * @param board nurikabe board * @return a map of cell keys to integer values @@ -181,7 +188,7 @@ public static HashMap getWhiteRegionMap(NurikabeBoard boa // Final mapping of cell to size HashMap whiteRegionMap = new HashMap<>(); for (NurikabeCell center : numberedCells) { - //BFS for each center to find the size of the region + // BFS for each center to find the size of the region int size = 1; // Mark all the vertices as not visited(By default // set as false) @@ -224,8 +231,7 @@ public static HashMap getWhiteRegionMap(NurikabeBoard boa // If a adjacent has not been visited, then mark it // visited and enqueue it for (NurikabeCell n : adj) { - if (!visited.getOrDefault(n, false) - && n.getType() == NurikabeType.WHITE) { + if (!visited.getOrDefault(n, false) && n.getType() == NurikabeType.WHITE) { connected.add(n); visited.put(n, true); queue.add(n); @@ -249,7 +255,8 @@ public static HashMap getWhiteRegionMap(NurikabeBoard boa * @param center nurikabe cell * @return a set of all white/numbered cells in the region */ - public static Set getSurroundedRegionOf(NurikabeBoard board, NurikabeCell center) { + public static Set getSurroundedRegionOf( + NurikabeBoard board, NurikabeCell center) { int width = board.getWidth(); int height = board.getHeight(); diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeView.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeView.java index cef287b92..0bac7e3e5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeView.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeView.java @@ -3,7 +3,6 @@ import edu.rpi.legup.controller.BoardController; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.ui.boardview.GridBoardView; - import java.awt.*; public class NurikabeView extends GridBoardView { @@ -17,7 +16,8 @@ public NurikabeView(NurikabeBoard board) { NurikabeElementView elementView = new NurikabeElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); elementViews.add(elementView); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java index 1609fbf99..a7972b9b2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/BlackTile.java @@ -4,6 +4,10 @@ public class BlackTile extends PlaceableElement { public BlackTile() { - super("NURI-PLAC-0001", "Black Tile", "The black tile", "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); + super( + "NURI-ELEM-0001", + "Black Tile", + "The black tile", + "edu/rpi/legup/images/nurikabe/tiles/BlackTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java index 0b1ee9656..2015d990b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/NumberTile.java @@ -1,12 +1,16 @@ package edu.rpi.legup.puzzle.nurikabe.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { private int object_num; public NumberTile() { - super("NURI-UNPL-0001", "Number Tile", "A numbered tile", "edu/rpi/legup/images/nurikabe/tiles/NumberTile.png"); + super( + "NURI-ELEM-0002", + "Number Tile", + "A numbered tile", + "edu/rpi/legup/images/nurikabe/tiles/NumberTile.png"); object_num = 0; } @@ -23,5 +27,4 @@ public int getTileNumber() { public void setTileNumber(int num) { object_num = num; } - } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java index 259e17e74..8a18c80cc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/UnknownTile.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.nurikabe.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { - super("NURI-UNPL-0002", "Unknown Tile", "A blank tile", "edu/rpi/legup/images/nurikabe/tiles/UnknownTile.png"); + super( + "NURI-ELEM-0003", + "Unknown Tile", + "A blank tile", + "edu/rpi/legup/images/nurikabe/tiles/UnknownTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java index 434e0663e..ae07c6d76 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/WhiteTile.java @@ -4,6 +4,10 @@ public class WhiteTile extends PlaceableElement { public WhiteTile() { - super("NURI-PLAC-0002", "White Tile", "The white tile", "edu/rpi/legup/images/nurikabe/tiles/WhiteTile.png"); + super( + "NURI-ELEM-0004", + "White Tile", + "The white tile", + "edu/rpi/legup/images/nurikabe/tiles/WhiteTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt new file mode 100644 index 000000000..667972fd6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/elements/nurikabe_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +NURI-ELEM-0001 : BlackTile +NURI-ELEM-0002 : NumberTile +NURI-ELEM-0003 : UnknownTile +NURI-ELEM-0004 : WhiteTile diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBetweenRegionsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBetweenRegionsDirectRule.java index bb527e4e2..7428ac204 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBetweenRegionsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBetweenRegionsDirectRule.java @@ -1,112 +1,122 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; -import edu.rpi.legup.utility.DisjointSets; - -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; - -public class BlackBetweenRegionsDirectRule extends DirectRule { - - public BlackBetweenRegionsDirectRule() { - super("NURI-BASC-0001", - "Black Between Regions", - "Any unknowns between two regions must be black.", - "edu/rpi/legup/images/nurikabe/rules/BetweenRegions.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - Set contras = new LinkedHashSet<>(); - contras.add(new MultipleNumbersContradictionRule()); - contras.add(new TooManySpacesContradictionRule()); - - NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); - NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); - - NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); - - if (cell.getType() != NurikabeType.BLACK) { - return super.getInvalidUseOfRuleMessage() + ": Only black cells are allowed for this rule!"; - } - - int x = cell.getLocation().x; - int y = cell.getLocation().y; - - DisjointSets regions = NurikabeUtilities.getNurikabeRegions(destBoardState); - Set adjacentWhiteRegions = new HashSet<>(); - NurikabeCell upCell = destBoardState.getCell(x, y - 1); - NurikabeCell rightCell = destBoardState.getCell(x + 1, y); - NurikabeCell downCell = destBoardState.getCell(x, y + 1); - NurikabeCell leftCell = destBoardState.getCell(x - 1, y); - - if (upCell != null && (upCell.getType() == NurikabeType.WHITE || upCell.getType() == NurikabeType.NUMBER)) { - NurikabeCell repCell = regions.find(upCell); - if (!adjacentWhiteRegions.contains(repCell)) { - adjacentWhiteRegions.add(repCell); - } - } - if (rightCell != null && (rightCell.getType() == NurikabeType.WHITE || rightCell.getType() == NurikabeType.NUMBER)) { - NurikabeCell repCell = regions.find(rightCell); - if (!adjacentWhiteRegions.contains(repCell)) { - adjacentWhiteRegions.add(repCell); - } - } - if (downCell != null && (downCell.getType() == NurikabeType.WHITE || downCell.getType() == NurikabeType.NUMBER)) { - NurikabeCell repCell = regions.find(downCell); - if (!adjacentWhiteRegions.contains(repCell)) { - adjacentWhiteRegions.add(repCell); - } - } - if (leftCell != null && (leftCell.getType() == NurikabeType.WHITE || leftCell.getType() == NurikabeType.NUMBER)) { - NurikabeCell repCell = regions.find(leftCell); - if (!adjacentWhiteRegions.contains(repCell)) { - adjacentWhiteRegions.add(repCell); - } - } - - if (adjacentWhiteRegions.size() < 2) { - return "The new black cell must separate two white regions for this rule!"; - } - - NurikabeBoard modified = origBoardState.copy(); - modified.getCell(x, y).setData(NurikabeType.WHITE.toValue()); - - for (ContradictionRule c : contras) { - if (c.checkContradiction(modified) == null) { - return null; - } - } - return "Does not follow from the rule"; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; +import edu.rpi.legup.utility.DisjointSets; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +public class BlackBetweenRegionsDirectRule extends DirectRule { + + public BlackBetweenRegionsDirectRule() { + super( + "NURI-BASC-0001", + "Black Between Regions", + "Any unknowns between two regions must be black.", + "edu/rpi/legup/images/nurikabe/rules/BetweenRegions.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + Set contras = new LinkedHashSet<>(); + contras.add(new MultipleNumbersContradictionRule()); + contras.add(new TooManySpacesContradictionRule()); + + NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); + NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); + + NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); + + if (cell.getType() != NurikabeType.BLACK) { + return super.getInvalidUseOfRuleMessage() + + ": Only black cells are allowed for this rule!"; + } + + int x = cell.getLocation().x; + int y = cell.getLocation().y; + + DisjointSets regions = NurikabeUtilities.getNurikabeRegions(destBoardState); + Set adjacentWhiteRegions = new HashSet<>(); + NurikabeCell upCell = destBoardState.getCell(x, y - 1); + NurikabeCell rightCell = destBoardState.getCell(x + 1, y); + NurikabeCell downCell = destBoardState.getCell(x, y + 1); + NurikabeCell leftCell = destBoardState.getCell(x - 1, y); + + if (upCell != null + && (upCell.getType() == NurikabeType.WHITE + || upCell.getType() == NurikabeType.NUMBER)) { + NurikabeCell repCell = regions.find(upCell); + if (!adjacentWhiteRegions.contains(repCell)) { + adjacentWhiteRegions.add(repCell); + } + } + if (rightCell != null + && (rightCell.getType() == NurikabeType.WHITE + || rightCell.getType() == NurikabeType.NUMBER)) { + NurikabeCell repCell = regions.find(rightCell); + if (!adjacentWhiteRegions.contains(repCell)) { + adjacentWhiteRegions.add(repCell); + } + } + if (downCell != null + && (downCell.getType() == NurikabeType.WHITE + || downCell.getType() == NurikabeType.NUMBER)) { + NurikabeCell repCell = regions.find(downCell); + if (!adjacentWhiteRegions.contains(repCell)) { + adjacentWhiteRegions.add(repCell); + } + } + if (leftCell != null + && (leftCell.getType() == NurikabeType.WHITE + || leftCell.getType() == NurikabeType.NUMBER)) { + NurikabeCell repCell = regions.find(leftCell); + if (!adjacentWhiteRegions.contains(repCell)) { + adjacentWhiteRegions.add(repCell); + } + } + + if (adjacentWhiteRegions.size() < 2) { + return "The new black cell must separate two white regions for this rule!"; + } + + NurikabeBoard modified = origBoardState.copy(); + modified.getCell(x, y).setData(NurikabeType.WHITE.toValue()); + + for (ContradictionRule c : contras) { + if (c.checkContradiction(modified) == null) { + return null; + } + } + return "Does not follow from the rule"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBottleNeckDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBottleNeckDirectRule.java index c4cf0d3fd..a8a94178b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBottleNeckDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBottleNeckDirectRule.java @@ -1,65 +1,69 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; - -public class BlackBottleNeckDirectRule extends DirectRule { - - public BlackBottleNeckDirectRule() { - super("NURI-BASC-0002", - "Black Bottle Neck", - "If there is only one path for a black to escape, then those unknowns must be black.", - "edu/rpi/legup/images/nurikabe/rules/OneUnknownBlack.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - ContradictionRule contraRule = new IsolateBlackContradictionRule(); - - NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); - NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); - - NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); - - if (cell.getType() != NurikabeType.BLACK) { - return super.getInvalidUseOfRuleMessage() + ": Only black cells are allowed for this rule!"; - } - NurikabeBoard modified = origBoardState.copy(); - NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); - modCell.setData(NurikabeType.WHITE.toValue()); - - if (contraRule.checkContradiction(modified) == null) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This is not the only way for black to escape!"; - } - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; + +public class BlackBottleNeckDirectRule extends DirectRule { + + public BlackBottleNeckDirectRule() { + super( + "NURI-BASC-0002", + "Black Bottle Neck", + "If there is only one path for a black to escape, then those unknowns must be" + + " black.", + "edu/rpi/legup/images/nurikabe/rules/OneUnknownBlack.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + ContradictionRule contraRule = new IsolateBlackContradictionRule(); + + NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); + NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); + + NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); + + if (cell.getType() != NurikabeType.BLACK) { + return super.getInvalidUseOfRuleMessage() + + ": Only black cells are allowed for this rule!"; + } + NurikabeBoard modified = origBoardState.copy(); + NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); + modCell.setData(NurikabeType.WHITE.toValue()); + + if (contraRule.checkContradiction(modified) == null) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + + ": This is not the only way for black to escape!"; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java index 641b76322..1c87d5cfa 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackOrWhiteCaseRule.java @@ -8,22 +8,23 @@ import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; import edu.rpi.legup.puzzle.nurikabe.NurikabeType; - import java.util.ArrayList; import java.util.List; public class BlackOrWhiteCaseRule extends CaseRule { public BlackOrWhiteCaseRule() { - super("NURI-CASE-0001", + super( + "NURI-CASE-0001", "Black or White", "Each blank cell is either black or white.", "edu/rpi/legup/images/nurikabe/cases/BlackOrWhite.png"); + this.MAX_CASES = 2; } /** - * Checks whether the {@link TreeTransition} logically follows from the parent node using this rule. This method is - * the one that should overridden in child classes. + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should be overridden in child classes. * * @param transition transition to check * @return null if the child node logically follow from the parent node, otherwise error message @@ -37,20 +38,24 @@ public String checkRuleRaw(TreeTransition transition) { TreeTransition case1 = childTransitions.get(0); TreeTransition case2 = childTransitions.get(1); - if (case1.getBoard().getModifiedData().size() != 1 || - case2.getBoard().getModifiedData().size() != 1) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case."; + if (case1.getBoard().getModifiedData().size() != 1 + || case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; } NurikabeCell mod1 = (NurikabeCell) case1.getBoard().getModifiedData().iterator().next(); NurikabeCell mod2 = (NurikabeCell) case2.getBoard().getModifiedData().iterator().next(); if (!mod1.getLocation().equals(mod2.getLocation())) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; } - if (!((mod1.getType() == NurikabeType.WHITE && mod2.getType() == NurikabeType.BLACK) || - (mod2.getType() == NurikabeType.WHITE && mod1.getType() == NurikabeType.BLACK))) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must an empty white and black cell."; + if (!((mod1.getType() == NurikabeType.WHITE && mod2.getType() == NurikabeType.BLACK) + || (mod2.getType() == NurikabeType.WHITE + && mod1.getType() == NurikabeType.BLACK))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must an empty white and black cell."; } return null; @@ -72,13 +77,17 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); data1.setData(NurikabeType.WHITE.toValue()); @@ -95,13 +104,13 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackSquareContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackSquareContradictionRule.java index 2dfb817e2..751c88881 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackSquareContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackSquareContradictionRule.java @@ -13,20 +13,21 @@ public class BlackSquareContradictionRule extends ContradictionRule { private final String INVALID_USE_MESSAGE = "Does not contain a contradiction at this index"; public BlackSquareContradictionRule() { - super("NURI-CONT-0001", + super( + "NURI-CONT-0001", "Black Square", "There cannot be a 2x2 square of black.", "edu/rpi/legup/images/nurikabe/contradictions/BlackSquare.png"); } - /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -39,12 +40,16 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } - for (int x = cell.getLocation().x - 1; x >= 0 && x < cell.getLocation().x + 1 && x < width - 1; x++) { - for (int y = cell.getLocation().y - 1; y >= 0 && y < cell.getLocation().y + 1 && y < height - 1; y++) { - if (nurikabeBoard.getCell(x, y).getType() == NurikabeType.BLACK && - nurikabeBoard.getCell(x + 1, y).getType() == NurikabeType.BLACK && - nurikabeBoard.getCell(x, y + 1).getType() == NurikabeType.BLACK && - nurikabeBoard.getCell(x + 1, y + 1).getType() == NurikabeType.BLACK) { + for (int x = cell.getLocation().x - 1; + x >= 0 && x < cell.getLocation().x + 1 && x < width - 1; + x++) { + for (int y = cell.getLocation().y - 1; + y >= 0 && y < cell.getLocation().y + 1 && y < height - 1; + y++) { + if (nurikabeBoard.getCell(x, y).getType() == NurikabeType.BLACK + && nurikabeBoard.getCell(x + 1, y).getType() == NurikabeType.BLACK + && nurikabeBoard.getCell(x, y + 1).getType() == NurikabeType.BLACK + && nurikabeBoard.getCell(x + 1, y + 1).getType() == NurikabeType.BLACK) { return null; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CannotReachCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CannotReachCellDirectRule.java index e86724ed9..f3d3ee8f2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CannotReachCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CannotReachCellDirectRule.java @@ -1,61 +1,64 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; - -public class CannotReachCellDirectRule extends DirectRule { - public CannotReachCellDirectRule() { - super("NURI-BASC-0008", - "Can't Reach Cell", - "A cell must be black if it cannot be reached by any white region", - "edu/rpi/legup/images/nurikabe/rules/Unreachable.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - ContradictionRule contraRule = new UnreachableWhiteCellContradictionRule(); - - NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); - NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); - if (cell.getType() != NurikabeType.BLACK) { - return super.getInvalidUseOfRuleMessage() + ": Only black cells are allowed for this rule!"; - } - - NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); - NurikabeBoard modified = origBoardState.copy(); - - NurikabeCell modifiedCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); - modifiedCell.setData(NurikabeType.WHITE.toValue()); - if (contraRule.checkContradictionAt(modified, modifiedCell) == null) { - return null; - } - return super.getInvalidUseOfRuleMessage() + ": Cell at this index can be reached"; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; + +public class CannotReachCellDirectRule extends DirectRule { + public CannotReachCellDirectRule() { + super( + "NURI-BASC-0008", + "Can't Reach Cell", + "A cell must be black if it cannot be reached by any white region", + "edu/rpi/legup/images/nurikabe/rules/Unreachable.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + ContradictionRule contraRule = new UnreachableWhiteCellContradictionRule(); + + NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); + NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); + if (cell.getType() != NurikabeType.BLACK) { + return super.getInvalidUseOfRuleMessage() + + ": Only black cells are allowed for this rule!"; + } + + NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); + NurikabeBoard modified = origBoardState.copy(); + + NurikabeCell modifiedCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); + modifiedCell.setData(NurikabeType.WHITE.toValue()); + if (contraRule.checkContradictionAt(modified, modifiedCell) == null) { + return null; + } + return super.getInvalidUseOfRuleMessage() + ": Cell at this index can be reached"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CornerBlackDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CornerBlackDirectRule.java index 55316fcbb..84ec45e99 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CornerBlackDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CornerBlackDirectRule.java @@ -1,108 +1,133 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -import edu.rpi.legup.utility.ConnectedRegions; - -import java.awt.*; -import java.util.Set; - -public class CornerBlackDirectRule extends DirectRule { - - public CornerBlackDirectRule() { - super("NURI-BASC-0003", - "Corners Black", - "If there is only one white square connected to unknowns and one more white is needed then the angles of that white square are black", - "edu/rpi/legup/images/nurikabe/rules/CornerBlack.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - NurikabeCell cell = (NurikabeCell) board.getPuzzleElement(puzzleElement); - if (cell.getType() != NurikabeType.BLACK) { - return "Only black cells are allowed for this rule!"; - } - - ContradictionRule tooFewContra = new TooFewSpacesContradictionRule(); - Point cellLocation = cell.getLocation(); - // 1. Find the coordinates of the white space (should be a corner of cell) - for (int i = -1; i < 2; i += 2) { - for (int j = -1; j < 2; j += 2) { - // If the corner does not exist, skip the corner - if (!(cellLocation.x + i >= 0 && cellLocation.x + i < board.getWidth() && cellLocation.y + j >= 0 && cellLocation.y + j < board.getHeight())) { - continue; - } - - NurikabeCell corner = board.getCell(cellLocation.x + i, cellLocation.y + j); - NurikabeType cornerType = corner.getType(); - if (cornerType == NurikabeType.WHITE || cornerType == NurikabeType.NUMBER) { - Point cornerLocation = corner.getLocation(); - // 2. Check if the intersecting adjacent spaces of the white space and the black corner are empty - if (board.getCell(cornerLocation.x, cellLocation.y).getType() == NurikabeType.UNKNOWN && board.getCell(cellLocation.x, cornerLocation.y).getType() == NurikabeType.UNKNOWN) { - // System.out.println("Went inside if statement"); - NurikabeBoard modified = board.copy(); - modified.getCell(cornerLocation.x, cellLocation.y).setData(NurikabeType.BLACK.toValue()); - modified.getCell(cellLocation.x, cornerLocation.y).setData(NurikabeType.BLACK.toValue()); - boolean containsContradiction = tooFewContra.checkContradiction(modified) == null; - if (containsContradiction) { - // 3. Check if the connected region is 1 under what is needed - Set region = ConnectedRegions.getRegionAroundPoint(cornerLocation, NurikabeType.BLACK.toValue(), modified.getIntArray(), modified.getWidth(), modified.getHeight()); - int regionNumber = 0; - // System.out.println("Region set size: " + region.size()); - for (Point p : region) { - NurikabeCell pCell = modified.getCell(p.x, p.y); - if (pCell.getType() == NurikabeType.NUMBER) { - if (regionNumber == 0) { - regionNumber = pCell.getData(); - } - else { - return "There is a MultipleNumbers Contradiction on the board."; - } - } - } - // If the region size is 0, there is a possibility that there was only 1 cell in the white - // region, and that white cell was a NurikabeType.NUMBER cell - if (regionNumber == 0 && corner.getType() == NurikabeType.NUMBER && corner.getData() == 2) { - return null; - } - // If the region size is not 0, make sure the regionNumber and the region size match (need - // to add 1 to account for the cell that was surrounded - if (regionNumber != 0 && region.size() + 1 == regionNumber) { - return null; - } - } - } - } - } - } - return "This is not a valid use of the corner black rule!"; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +import edu.rpi.legup.utility.ConnectedRegions; +import java.awt.*; +import java.util.Set; + +public class CornerBlackDirectRule extends DirectRule { + + public CornerBlackDirectRule() { + super( + "NURI-BASC-0003", + "Corners Black", + "If there is only one white square connected to unknowns and one more white is" + + " needed then the angles of that white square are black", + "edu/rpi/legup/images/nurikabe/rules/CornerBlack.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + NurikabeBoard board = (NurikabeBoard) transition.getBoard(); + NurikabeCell cell = (NurikabeCell) board.getPuzzleElement(puzzleElement); + if (cell.getType() != NurikabeType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + + ContradictionRule tooFewContra = new TooFewSpacesContradictionRule(); + Point cellLocation = cell.getLocation(); + // 1. Find the coordinates of the white space (should be a corner of cell) + for (int i = -1; i < 2; i += 2) { + for (int j = -1; j < 2; j += 2) { + // If the corner does not exist, skip the corner + if (!(cellLocation.x + i >= 0 + && cellLocation.x + i < board.getWidth() + && cellLocation.y + j >= 0 + && cellLocation.y + j < board.getHeight())) { + continue; + } + + NurikabeCell corner = board.getCell(cellLocation.x + i, cellLocation.y + j); + NurikabeType cornerType = corner.getType(); + if (cornerType == NurikabeType.WHITE || cornerType == NurikabeType.NUMBER) { + Point cornerLocation = corner.getLocation(); + // 2. Check if the intersecting adjacent spaces of the white space and the black + // corner + // are empty + if (board.getCell(cornerLocation.x, cellLocation.y).getType() + == NurikabeType.UNKNOWN + && board.getCell(cellLocation.x, cornerLocation.y).getType() + == NurikabeType.UNKNOWN) { + // System.out.println("Went inside if statement"); + NurikabeBoard modified = board.copy(); + modified.getCell(cornerLocation.x, cellLocation.y) + .setData(NurikabeType.BLACK.toValue()); + modified.getCell(cellLocation.x, cornerLocation.y) + .setData(NurikabeType.BLACK.toValue()); + boolean containsContradiction = + tooFewContra.checkContradiction(modified) == null; + if (containsContradiction) { + // 3. Check if the connected region is 1 under what is needed + Set region = + ConnectedRegions.getRegionAroundPoint( + cornerLocation, + NurikabeType.BLACK.toValue(), + modified.getIntArray(), + modified.getWidth(), + modified.getHeight()); + int regionNumber = 0; + // System.out.println("Region set size: " + region.size()); + for (Point p : region) { + NurikabeCell pCell = modified.getCell(p.x, p.y); + if (pCell.getType() == NurikabeType.NUMBER) { + if (regionNumber == 0) { + regionNumber = pCell.getData(); + } else { + return "There is a MultipleNumbers Contradiction on the" + + " board."; + } + } + } + // If the region size is 0, there is a possibility that there was only 1 + // cell in the + // white + // region, and that white cell was a NurikabeType.NUMBER cell + if (regionNumber == 0 + && corner.getType() == NurikabeType.NUMBER + && corner.getData() == 2) { + return null; + } + // If the region size is not 0, make sure the regionNumber and the + // region size match + // (need + // to add 1 to account for the cell that was surrounded + if (regionNumber != 0 && region.size() + 1 == regionNumber) { + return null; + } + } + } + } + } + } + return "This is not a valid use of the corner black rule!"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FillinBlackDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FillinBlackDirectRule.java index aab389e4a..7c4629f65 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FillinBlackDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FillinBlackDirectRule.java @@ -1,60 +1,62 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; - -public class FillinBlackDirectRule extends DirectRule { - - public FillinBlackDirectRule() { - super("NURI-BASC-0004", - "Fill In Black", - "If there an unknown region surrounded by black, it must be black.", - "edu/rpi/legup/images/nurikabe/rules/FillInBlack.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - NurikabeBoard origBoard = (NurikabeBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new NoNumberContradictionRule(); - - NurikabeCell cell = (NurikabeCell) board.getPuzzleElement(puzzleElement); - - if (cell.getType() != NurikabeType.BLACK) { - return "Only black cells are allowed for this rule!"; - } - NurikabeBoard modified = origBoard.copy(); - modified.getPuzzleElement(puzzleElement).setData(NurikabeType.WHITE.toValue()); - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { - return "Black cells must be placed in a region of black cells!"; - } - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; + +public class FillinBlackDirectRule extends DirectRule { + + public FillinBlackDirectRule() { + super( + "NURI-BASC-0004", + "Fill In Black", + "If there an unknown region surrounded by black, it must be black.", + "edu/rpi/legup/images/nurikabe/rules/FillInBlack.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + NurikabeBoard board = (NurikabeBoard) transition.getBoard(); + NurikabeBoard origBoard = (NurikabeBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new NoNumberContradictionRule(); + + NurikabeCell cell = (NurikabeCell) board.getPuzzleElement(puzzleElement); + + if (cell.getType() != NurikabeType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + NurikabeBoard modified = origBoard.copy(); + modified.getPuzzleElement(puzzleElement).setData(NurikabeType.WHITE.toValue()); + if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + return "Black cells must be placed in a region of black cells!"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FillinWhiteDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FillinWhiteDirectRule.java index 4f57602d5..05bb2f046 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FillinWhiteDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FillinWhiteDirectRule.java @@ -1,60 +1,62 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; - -public class FillinWhiteDirectRule extends DirectRule { - - public FillinWhiteDirectRule() { - super("NURI-BASC-0005", - "Fill In White", - "If there an unknown region surrounded by white, it must be white.", - "edu/rpi/legup/images/nurikabe/rules/FillInWhite.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - NurikabeBoard origBoard = (NurikabeBoard) transition.getParents().get(0).getBoard(); - ContradictionRule contraRule = new IsolateBlackContradictionRule(); - - NurikabeCell cell = (NurikabeCell) board.getPuzzleElement(puzzleElement); - - if (cell.getType() != NurikabeType.WHITE) { - return "Only white cells are allowed for this rule!"; - } - NurikabeBoard modified = origBoard.copy(); - modified.getPuzzleElement(puzzleElement).setData(NurikabeType.BLACK.toValue()); - if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { - return "white cells must be placed in a region of white cells!"; - } - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; + +public class FillinWhiteDirectRule extends DirectRule { + + public FillinWhiteDirectRule() { + super( + "NURI-BASC-0005", + "Fill In White", + "If there an unknown region surrounded by white, it must be white.", + "edu/rpi/legup/images/nurikabe/rules/FillInWhite.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + NurikabeBoard board = (NurikabeBoard) transition.getBoard(); + NurikabeBoard origBoard = (NurikabeBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new IsolateBlackContradictionRule(); + + NurikabeCell cell = (NurikabeCell) board.getPuzzleElement(puzzleElement); + + if (cell.getType() != NurikabeType.WHITE) { + return "Only white cells are allowed for this rule!"; + } + NurikabeBoard modified = origBoard.copy(); + modified.getPuzzleElement(puzzleElement).setData(NurikabeType.BLACK.toValue()); + if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + return "white cells must be placed in a region of white cells!"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java new file mode 100644 index 000000000..dd8943cdb --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/FinishRoomCaseRule.java @@ -0,0 +1,263 @@ +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; +import edu.rpi.legup.utility.DisjointSets; +import java.awt.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class FinishRoomCaseRule extends CaseRule { + private int legitCases = 0; // placeholder for amount of cases originally generated in case user tries to delete + private Set uniqueCases; // stores the unique case hashes + // cases + + public FinishRoomCaseRule() { + super( + "NURI-CASE-0002", + "Finish Room", + "Room can be finished in up to nine ways", + "edu/rpi/legup/images/nurikabe/cases/FinishRoom.png"); + this.MAX_CASES = 9; + this.MIN_CASES = 1; + this.uniqueCases = new HashSet<>(); + } + + /** + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should have overridden in child classes. + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); + List childTransitions = transition.getParents().get(0).getChildren(); + if (childTransitions.size() > MAX_CASES) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 9 or less children."; + } + if (childTransitions.size() < MIN_CASES) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 or more children."; + } + if (childTransitions.size() != legitCases) { + return super.getInvalidUseOfRuleMessage() + + ": Cases can not be removed from the branch."; + } // stops user from deleting 1 or more generated cases and still having path show as green + Set locations = new HashSet<>(); + for (TreeTransition t1 : childTransitions) { + locations.add( + ((NurikabeCell) t1.getBoard().getModifiedData().iterator().next()) + .getLocation()); // loop see if matches + if (t1.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; + } + for (Point loc : locations) { + for (Point loc2 : locations) { + if (!(loc.equals(loc2)) && (loc.x == loc2.x) && (loc.y == loc2.y)) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must alter a different cell for each case."; + } + } + } + } + + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + NurikabeBoard nurikabeBoard = (NurikabeBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(nurikabeBoard, this); + DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nurikabeBoard); + nurikabeBoard.setModifiable(false); + + for (PuzzleElement element : nurikabeBoard.getPuzzleElements()) { // loops all puzzle elements + if (((NurikabeCell) element).getType() == NurikabeType.NUMBER) { // if the tile is a white number block + Set disRow = regions.getSet(((NurikabeCell) element)); // store the row of the white region + boolean only = true; // placeholder boolean of if the element being tested is the only number block in the room or not + + for (NurikabeCell d : disRow) { // loops through tiles in the room + // if found another number tile and it's data is different from the element we're working with + if ((d.getType() == NurikabeType.NUMBER) + && !(d.getData().equals(((NurikabeCell) element).getData()))) { + only = false; + } + } + // if size of region is 1 less than the number block and the number block is only number block in the region + if (disRow.size() < ((NurikabeCell) element).getData() && only) { + caseBoard.addPickableElement(element); // add that room as a pickable element + } + } + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); // makes array list of cases + if (puzzleElement == null) { + return cases; + } + + NurikabeBoard nuriBoard = (NurikabeBoard) board.copy(); // nurikabe board to edit + NurikabeCell numberCell = nuriBoard.getCell( + ((NurikabeCell) puzzleElement).getLocation().x, + ((NurikabeCell) puzzleElement).getLocation().y + ); // number cell whose room we want to fill + + Point origPoint = new Point(numberCell.getLocation().x, numberCell.getLocation().y); + int filledRoomSize = numberCell.getData(); // size of room we want afterward + + Point left = new Point(-1, 0); + Point right = new Point(1, 0); + Point bot = new Point(0, -1); + Point top = new Point(0, 1); + Set directions = new HashSet<>(); + directions.add(left); + directions.add(right); + directions.add(top); + directions.add(bot); + + Set checkedPoints = new HashSet<>(); // add all into checked points and continue at start of loop if inside + DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // gathers regions + Set numberCellRegion = regions.getSet(numberCell); // set of white spaces + + for (NurikabeCell d : numberCellRegion) { // loops through white spaces + generateCases(nuriBoard, d, filledRoomSize, directions, checkedPoints, cases, origPoint); + } + + legitCases = cases.size(); + return cases; + } + + /** + * Recursively generates possible cases for filling a room with white cells based on the current + * board state and specified parameters. + * + * @param nuriBoard the current Nurikabe board state + * @param currentCell the current cell being evaluated + * @param filledRoomSize the target size for the room being filled + * @param directions the set of possible directions to expand the room + * @param checkedPoints the set of points already evaluated to avoid redundancy + * @param cases the list of valid board cases generated + * @param origPoint the original point of the number cell initiating the room filling + */ + private void generateCases(NurikabeBoard nuriBoard, NurikabeCell currentCell, int filledRoomSize, + Set directions, Set checkedPoints, ArrayList cases, Point origPoint) { + for (Point direction : directions) { + Point newPoint = new Point( + currentCell.getLocation().x + direction.x, + currentCell.getLocation().y + direction.y + ); + + if (newPoint.x < 0 || newPoint.y < 0 || + newPoint.x >= nuriBoard.getWidth() || newPoint.y >= nuriBoard.getHeight()) { + continue; // out of bounds + } + + NurikabeCell newCell = nuriBoard.getCell(newPoint.x, newPoint.y); + if (checkedPoints.contains(newPoint)) { + continue; // already checked + } + + if (newCell.getType() == NurikabeType.UNKNOWN) { + newCell.setData(NurikabeType.WHITE.toValue()); // changes adjacent cell color to white + newCell.setModifiable(false); + checkedPoints.add(newPoint); + + DisjointSets regions = NurikabeUtilities.getNurikabeRegions(nuriBoard); // update regions variable + Set newRoomSet = regions.getSet(newCell); // gets set of cells in room with new white cell added + + if (!touchesDifferentRoom(nuriBoard, newCell, filledRoomSize, directions, origPoint)) { + if (newRoomSet.size() == filledRoomSize) { // if adding white fills the room to exact size of + // number block and doesn't connect with another room + Board caseBoard = nuriBoard.copy(); + // check if case for board already exists + boolean unique = true; + for (Board board : cases) { + if (caseBoard.equalsBoard(board)) { + unique = false; + break; + } + } + if (unique) { + caseBoard.addModifiedData(newCell); + cases.add(caseBoard); + } + } else if (newRoomSet.size() < filledRoomSize) { + generateCases(nuriBoard, newCell, filledRoomSize, directions, checkedPoints, cases, origPoint); + } + } + newCell.setData(NurikabeType.UNKNOWN.toValue()); + newCell.setModifiable(true); + checkedPoints.remove(newPoint); + } + } + } + + /** + * Determines if a given cell touches a different room by checking adjacent cells in specified directions. + * + * @param board the current Nurikabe board state + * @param cell the cell being evaluated + * @param origRoomSize the size of the original room being filled + * @param directions the set of possible directions to check around the cell + * @param origPoint the original point of the number cell initiating the room filling + * @return true if the cell touches a different room, false otherwise + */ + private boolean touchesDifferentRoom(NurikabeBoard board, NurikabeCell cell, int origRoomSize, Set directions, Point origPoint) { + for (Point direction : directions) { + Point adjacentPoint = new Point( + cell.getLocation().x + direction.x, + cell.getLocation().y + direction.y + ); + + if (adjacentPoint.x >= 0 && adjacentPoint.y >= 0 && + adjacentPoint.x < board.getWidth() && adjacentPoint.y < board.getHeight()) { // check if out of bounds + NurikabeCell adjacentCell = board.getCell(adjacentPoint.x, adjacentPoint.y); + // check if the adjacent cell is a number cell + if (adjacentCell.getType() == NurikabeType.NUMBER) { + // check if it's different from the original number cell + if (origRoomSize != adjacentCell.getData() || (adjacentPoint.x != origPoint.x || adjacentPoint.y != origPoint.y)) { + return true; + } + } + } + } + return false; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/IsolateBlackContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/IsolateBlackContradictionRule.java index c7331330b..f26f0c3fe 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/IsolateBlackContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/IsolateBlackContradictionRule.java @@ -8,30 +8,30 @@ import edu.rpi.legup.puzzle.nurikabe.NurikabeType; import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; import edu.rpi.legup.utility.DisjointSets; - import java.util.Set; public class IsolateBlackContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Contradiction applied incorrectly. No isolated Blacks."; + private final String NO_CONTRADICTION_MESSAGE = + "Contradiction applied incorrectly. No isolated Blacks."; private final String INVALID_USE_MESSAGE = "Contradiction must be a black cell"; public IsolateBlackContradictionRule() { - super("NURI-CONT-0003", + super( + "NURI-CONT-0003", "Isolated Black", "There must still be a possibility to connect every Black cell", "edu/rpi/legup/images/nurikabe/contradictions/BlackArea.png"); } /** - * Checks whether the transition has a contradiction at the specific - * {@link PuzzleElement} index using this rule. + * Checks whether the transition has a contradiction at the specific {@link PuzzleElement} index + * using this rule. * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement - * @return null if the transition contains a - * contradiction at the specified {@link PuzzleElement}, - * otherwise return a no contradiction message. + * @return null if the transition contains a contradiction at the specified {@link + * PuzzleElement}, otherwise return a no contradiction message. */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -41,15 +41,15 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } - DisjointSets blackRegions = NurikabeUtilities.getPossibleBlackRegions(nurikabeBoard); + DisjointSets blackRegions = + NurikabeUtilities.getPossibleBlackRegions(nurikabeBoard); boolean oneRegion = false; for (Set region : blackRegions.getAllSets()) { for (NurikabeCell c : region) { if (c.getType() == NurikabeType.BLACK) { if (oneRegion) { return null; - } - else { + } else { oneRegion = true; break; } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/MultipleNumbersContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/MultipleNumbersContradictionRule.java index e83204b99..1925a68ec 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/MultipleNumbersContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/MultipleNumbersContradictionRule.java @@ -8,28 +8,30 @@ import edu.rpi.legup.puzzle.nurikabe.NurikabeType; import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; import edu.rpi.legup.utility.DisjointSets; - import java.util.Set; public class MultipleNumbersContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Contradiction must be a numbered cell"; public MultipleNumbersContradictionRule() { - super("NURI-CONT-0004", + super( + "NURI-CONT-0004", "Multiple Numbers", "All white regions cannot have more than one number.", "edu/rpi/legup/images/nurikabe/contradictions/MultipleNumbers.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/NoNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/NoNumberContradictionRule.java index c2752da7a..6c69136b2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/NoNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/NoNumberContradictionRule.java @@ -7,31 +7,31 @@ import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; import edu.rpi.legup.puzzle.nurikabe.NurikabeType; import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; -import edu.rpi.legup.utility.DisjointSets; - import java.util.Set; -import java.util.List; public class NoNumberContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Contradiction must be a white cell"; private final String NOT_SURROUNDED_BY_BLACK_MESSAGE = "Must be surrounded by black cells"; public NoNumberContradictionRule() { - super("NURI-CONT-0005", + super( + "NURI-CONT-0005", "No Number", "All enclosed white regions must have a number.", "edu/rpi/legup/images/nurikabe/contradictions/NoNumber.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/PreventBlackSquareDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/PreventBlackSquareDirectRule.java index 2502ee62f..106c22f7a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/PreventBlackSquareDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/PreventBlackSquareDirectRule.java @@ -1,66 +1,67 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; - -public class PreventBlackSquareDirectRule extends DirectRule { - - public PreventBlackSquareDirectRule() { - super("NURI-BASC-0006", - "Prevent Black Square", - "There cannot be a 2x2 square of black. (3 blacks = fill in last corner white)", - "edu/rpi/legup/images/nurikabe/rules/NoBlackSquare.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - ContradictionRule contraRule = new BlackSquareContradictionRule(); - - NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); - NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); - - NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); - - if (cell.getType() != NurikabeType.WHITE) { - return "Only white cells are allowed for this rule!"; - } - - NurikabeBoard modified = origBoardState.copy(); - NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); - modCell.setData(NurikabeType.BLACK.toValue()); - - if (contraRule.checkContradiction(modified) == null) { - return null; - } - else { - return "Does not contain a contradiction at this index"; - } - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; + +public class PreventBlackSquareDirectRule extends DirectRule { + + public PreventBlackSquareDirectRule() { + super( + "NURI-BASC-0006", + "Prevent Black Square", + "There cannot be a 2x2 square of black. (3 blacks = fill in last corner white)", + "edu/rpi/legup/images/nurikabe/rules/NoBlackSquare.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + ContradictionRule contraRule = new BlackSquareContradictionRule(); + + NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); + NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); + + NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); + + if (cell.getType() != NurikabeType.WHITE) { + return "Only white cells are allowed for this rule!"; + } + + NurikabeBoard modified = origBoardState.copy(); + NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); + modCell.setData(NurikabeType.BLACK.toValue()); + + if (contraRule.checkContradiction(modified) == null) { + return null; + } else { + return "Does not contain a contradiction at this index"; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/SurroundRegionDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/SurroundRegionDirectRule.java index d992fd22c..8e260cf42 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/SurroundRegionDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/SurroundRegionDirectRule.java @@ -1,95 +1,103 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; -import edu.rpi.legup.utility.DisjointSets; - -import java.util.Arrays; -import java.util.ArrayList; -import java.util.List; -import java.util.HashSet; -import java.util.Set; -import java.awt.*; - -public class SurroundRegionDirectRule extends DirectRule { - - public SurroundRegionDirectRule() { - super("NURI-BASC-0007", "Surround Region", - "Surround Region", - "edu/rpi/legup/images/nurikabe/rules/SurroundBlack.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - - NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); - NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); - - NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); - - if (cell.getType() != NurikabeType.BLACK) { - return "Only black cells are allowed for this rule!"; - } - - NurikabeBoard modified = origBoardState.copy(); - NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); - modCell.setData(NurikabeType.WHITE.toValue()); - - if(cell.getType() == NurikabeType.BLACK) { - DisjointSets regions = NurikabeUtilities.getNurikabeRegions(destBoardState); - Set adj = new HashSet<>(); //set to hold adjacent cells - Point loc = cell.getLocation(); //position of placed cell - List directions = Arrays.asList(new Point(-1, 0), new Point(1, 0), new Point(0, -1), new Point(0, 1)); - for(Point direction : directions) { - NurikabeCell curr = destBoardState.getCell(loc.x + direction.x, loc.y + direction.y); - if(curr != null) { - if(curr.getType() == NurikabeType.WHITE || curr.getType() == NurikabeType.NUMBER) { - adj.add(curr); //adds cells to adj only if they are white or number blocks - } - } - } - List numberedCells = new ArrayList<>(); //number value of number cells - for (NurikabeCell c : adj) { //loops through adjacent cells - Set disRow = regions.getSet(c); //set of white spaces - for (NurikabeCell d : disRow) { //loops through white spaces - if (d.getType() == NurikabeType.NUMBER) { //if the white space is a number - numberedCells.add(d); //add that number to numberedCells - } - } - } - for (NurikabeCell number : numberedCells) { //loops through numberedCells - if (regions.getSet(number).size() == number.getData()) { //if that cells white area is the exact - return null; //size of the number of one of the number cells within that set - } - } - } - return "Does not follow from this rule at this index"; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; +import edu.rpi.legup.utility.DisjointSets; +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class SurroundRegionDirectRule extends DirectRule { + + public SurroundRegionDirectRule() { + super( + "NURI-BASC-0007", + "Surround Region", + "Surround Region", + "edu/rpi/legup/images/nurikabe/rules/SurroundBlack.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + + NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); + NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); + + NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); + + if (cell.getType() != NurikabeType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + + NurikabeBoard modified = origBoardState.copy(); + NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); + modCell.setData(NurikabeType.WHITE.toValue()); + + if (cell.getType() == NurikabeType.BLACK) { + DisjointSets regions = + NurikabeUtilities.getNurikabeRegions(destBoardState); + Set adj = new HashSet<>(); // set to hold adjacent cells + Point loc = cell.getLocation(); // position of placed cell + List directions = + Arrays.asList( + new Point(-1, 0), new Point(1, 0), new Point(0, -1), new Point(0, 1)); + for (Point direction : directions) { + NurikabeCell curr = + destBoardState.getCell(loc.x + direction.x, loc.y + direction.y); + if (curr != null) { + if (curr.getType() == NurikabeType.WHITE + || curr.getType() == NurikabeType.NUMBER) { + adj.add(curr); // adds cells to adj only if they are white or number blocks + } + } + } + List numberedCells = new ArrayList<>(); // number value of number cells + for (NurikabeCell c : adj) { // loops through adjacent cells + Set disRow = regions.getSet(c); // set of white spaces + for (NurikabeCell d : disRow) { // loops through white spaces + if (d.getType() == NurikabeType.NUMBER) { // if the white space is a number + numberedCells.add(d); // add that number to numberedCells + } + } + } + for (NurikabeCell number : numberedCells) { // loops through numberedCells + if (regions.getSet(number).size() + == number.getData()) { // if that cells white area is the exact + return null; // size of the number of one of the number cells within that set + } + } + } + return "Does not follow from this rule at this index"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/TooFewSpacesContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/TooFewSpacesContradictionRule.java index d01dd806c..e7995165b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/TooFewSpacesContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/TooFewSpacesContradictionRule.java @@ -8,28 +8,30 @@ import edu.rpi.legup.puzzle.nurikabe.NurikabeType; import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; import edu.rpi.legup.utility.DisjointSets; - import java.util.Set; public class TooFewSpacesContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Contradiction must be a white or a numbered cell"; public TooFewSpacesContradictionRule() { - super("NURI-CONT-0006", + super( + "NURI-CONT-0006", "Too Few Spaces", "A region cannot contain less spaces than its number.", "edu/rpi/legup/images/nurikabe/contradictions/TooFewSpaces.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -40,7 +42,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; } - DisjointSets regions = NurikabeUtilities.getPossibleWhiteRegions(nurikabeBoard); + DisjointSets regions = + NurikabeUtilities.getPossibleWhiteRegions(nurikabeBoard); Set whiteRegion = regions.getSet(cell); NurikabeCell numberedCell = null; for (NurikabeCell c : whiteRegion) { @@ -51,7 +54,9 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } if (numberedCell != null && whiteRegion.size() < numberedCell.getData()) { - // System.err.println("Cell Value: " + numberedCell.getData() + ", Loc: " + cell.getLocation() + ", region: " + whiteRegion.size()); + // System.err.println("Cell Value: " + numberedCell.getData() + ", Loc: " + + // cell.getLocation() + // + ", region: " + whiteRegion.size()); return null; } return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/TooManySpacesContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/TooManySpacesContradictionRule.java index e5aa9f18b..7bd0883ef 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/TooManySpacesContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/TooManySpacesContradictionRule.java @@ -8,29 +8,31 @@ import edu.rpi.legup.puzzle.nurikabe.NurikabeType; import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; import edu.rpi.legup.utility.DisjointSets; - import java.util.ArrayList; import java.util.Set; public class TooManySpacesContradictionRule extends ContradictionRule { - private final String NO_CONTRADICTION_MESSAGE = "Does not contain a contradiction at this index"; + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; private final String INVALID_USE_MESSAGE = "Contradiction must be a white or a numbered cell"; public TooManySpacesContradictionRule() { - super("NURI-CONT-0007", + super( + "NURI-CONT-0007", "Too Many Spaces", "A region cannot contain more spaces than its number.", "edu/rpi/legup/images/nurikabe/contradictions/TooManySpaces.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/UnreachableWhiteCellContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/UnreachableWhiteCellContradictionRule.java index ec16475f1..c578d317f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/UnreachableWhiteCellContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/UnreachableWhiteCellContradictionRule.java @@ -7,7 +7,6 @@ import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; import edu.rpi.legup.puzzle.nurikabe.NurikabeType; import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities; - import java.awt.*; import java.util.*; @@ -17,19 +16,21 @@ public class UnreachableWhiteCellContradictionRule extends ContradictionRule { private final String INVALID_USE_MESSAGE = "Does not contain a contradiction at this index"; public UnreachableWhiteCellContradictionRule() { - super("NURI-CONT-0002", + super( + "NURI-CONT-0002", "Unreachable White Cell", "A white cell must be able to reach a white region", "edu/rpi/legup/images/nurikabe/contradictions/CantReach.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -44,7 +45,8 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int width = nurikabeBoard.getWidth(); // Get regions - HashMap whiteRegionMap = NurikabeUtilities.getWhiteRegionMap(nurikabeBoard); + HashMap whiteRegionMap = + NurikabeUtilities.getWhiteRegionMap(nurikabeBoard); if (whiteRegionMap.containsKey(cell)) { return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; } @@ -83,15 +85,17 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { for (NurikabeCell n : adj) { int regionNeed = whiteRegionMap.getOrDefault(n, -1); if (pathLength <= regionNeed) { - return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + return super.getNoContradictionMessage() + + ": " + + this.NO_CONTRADICTION_MESSAGE; } } } for (NurikabeCell n : adj) { if (!visited.getOrDefault(n, false) - && (n.getType() == NurikabeType.UNKNOWN || - n.getType() == NurikabeType.WHITE)) { + && (n.getType() == NurikabeType.UNKNOWN + || n.getType() == NurikabeType.WHITE)) { visited.put(n, true); queue.add(n); } diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/WhiteBottleNeckDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/WhiteBottleNeckDirectRule.java index dd337858c..434e7ccde 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/WhiteBottleNeckDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/WhiteBottleNeckDirectRule.java @@ -1,69 +1,72 @@ -package edu.rpi.legup.puzzle.nurikabe.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; - -import java.util.LinkedHashSet; -import java.util.Set; - -public class WhiteBottleNeckDirectRule extends DirectRule { - - public WhiteBottleNeckDirectRule() { - super("NURI-BASC-0009", - "White Bottle Neck", - "If a region needs more whites and there is only one path for the region to expand, then those unknowns must be white.", "edu/rpi/legup/images/nurikabe/rules/OneUnknownWhite.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - Set contras = new LinkedHashSet<>(); - contras.add(new NoNumberContradictionRule()); - contras.add(new TooFewSpacesContradictionRule()); - - NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); - NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); - - NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); - - if (cell.getType() != NurikabeType.WHITE) { - return "Only white cells are allowed for this rule!"; - } - NurikabeBoard modified = origBoardState.copy(); - NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); - modCell.setData(NurikabeType.BLACK.toValue()); - - for (ContradictionRule contraRule : contras) { - if (contraRule.checkContradiction(modified) == null) { - return null; - } - } - return "This is not the only way for white to escape!"; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.nurikabe.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +import java.util.LinkedHashSet; +import java.util.Set; + +public class WhiteBottleNeckDirectRule extends DirectRule { + + public WhiteBottleNeckDirectRule() { + super( + "NURI-BASC-0009", + "White Bottle Neck", + "If a region needs more whites and there is only one path for the region to expand," + + " then those unknowns must be white.", + "edu/rpi/legup/images/nurikabe/rules/OneUnknownWhite.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + Set contras = new LinkedHashSet<>(); + contras.add(new NoNumberContradictionRule()); + contras.add(new TooFewSpacesContradictionRule()); + + NurikabeBoard destBoardState = (NurikabeBoard) transition.getBoard(); + NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard(); + + NurikabeCell cell = (NurikabeCell) destBoardState.getPuzzleElement(puzzleElement); + + if (cell.getType() != NurikabeType.WHITE) { + return "Only white cells are allowed for this rule!"; + } + NurikabeBoard modified = origBoardState.copy(); + NurikabeCell modCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement); + modCell.setData(NurikabeType.BLACK.toValue()); + + for (ContradictionRule contraRule : contras) { + if (contraRule.checkContradiction(modified) == null) { + return null; + } + } + return "This is not the only way for white to escape!"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/nurikabe_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/nurikabe_reference_sheet.txt index 6a6e6bc1f..596de7819 100644 --- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/nurikabe_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/nurikabe_reference_sheet.txt @@ -16,4 +16,5 @@ NURI-CONT-0005 : NoNumberContradictionRule NURI-CONT-0006 : TooFewSpacesContradictionRule NURI-CONT-0007 : TooManySpacesContradictionRule -NURI-CASE-0001 : BlackOrWhiteCaseRule \ No newline at end of file +NURI-CASE-0001 : BlackOrWhiteCaseRule +NURI-CASE-0002 : FinishRoomCaseRule \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTable.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTable.java index e8f9ffc0d..8b0b8e6d5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTable.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTable.java @@ -18,9 +18,7 @@ public ShortTruthTable() { this.factory = new ShortTruthTableCellFactory(); } - /** - * Initializes the game board. Called by the invoker of the class - */ + /** Initializes the game board. Called by the invoker of the class */ @Override public void initializeView() { ShortTruthTableBoard sttBoard = (ShortTruthTableBoard) currentBoard; @@ -44,8 +42,8 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Short Truth Table * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Short Truth Table, false otherwise */ public boolean isValidDimensions(int rows, int columns) { @@ -100,7 +98,6 @@ public boolean isBoardComplete(Board board) { } } return true; - } /** @@ -109,7 +106,5 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { - - } -} \ No newline at end of file + public void onBoardChange(Board board) {} +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableBoard.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableBoard.java index e5011182a..519a61974 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableBoard.java @@ -1,17 +1,12 @@ package edu.rpi.legup.puzzle.shorttruthtable; -import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - -import edu.rpi.legup.puzzle.lightup.LightUpCell; -import edu.rpi.legup.puzzle.shorttruthtable.*; - import java.awt.*; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.HashSet; public class ShortTruthTableBoard extends GridBoard { @@ -22,10 +17,8 @@ public ShortTruthTableBoard(int width, int height, ShortTruthTableStatement[] st super(width, height); this.statements = statements; - } - public Set getCellsWithSymbol(char symbol) { Set cells = new HashSet(); for (int x = 0; x < this.dimension.width; x++) { @@ -48,23 +41,23 @@ public ShortTruthTableCell getCell(int x, int y) { return (ShortTruthTableCell) super.getCell(x, y); } - @Override public ShortTruthTableBoard copy() { - //Copy the statements - ShortTruthTableStatement[] statementsCopy = new ShortTruthTableStatement[this.statements.length]; + // Copy the statements + ShortTruthTableStatement[] statementsCopy = + new ShortTruthTableStatement[this.statements.length]; for (int i = 0; i < statements.length; i++) { statementsCopy[i] = this.statements[i].copy(); } - //copy the board and set the cells - ShortTruthTableBoard boardCopy = new ShortTruthTableBoard(getWidth(), getHeight(), statementsCopy); + // copy the board and set the cells + ShortTruthTableBoard boardCopy = + new ShortTruthTableBoard(getWidth(), getHeight(), statementsCopy); for (int r = 0; r < this.dimension.height; r++) { for (int c = 0; c < this.dimension.width; c++) { if (r % 2 == 0 && c < statementsCopy[r / 2].getLength()) { boardCopy.setCell(c, r, statementsCopy[r / 2].getCell(c)); - } - else { + } else { boardCopy.setCell(c, r, getCell(c, r).copy()); } } @@ -76,14 +69,14 @@ public ShortTruthTableBoard copy() { System.out.println("original:\n" + this); System.out.println("copy:\n" + boardCopy); return boardCopy; - } public ShortTruthTableStatement[] getStatements() { return statements; } - public static List copyStatementList(List statements) { + public static List copyStatementList( + List statements) { List copy = new ArrayList(); for (int i = 0; i < statements.size(); i++) { copy.add(statements.get(i).copy()); @@ -91,13 +84,12 @@ public static List copyStatementList(List { - //The symbol on the cell + // The symbol on the cell private char symbol; - //This is a reference to the statement that contains this cell + // This is a reference to the statement that contains this cell private ShortTruthTableStatement statement; - //Constructors + // Constructors public ShortTruthTableCell(char symbol, ShortTruthTableCellType cellType, Point location) { super(cellType, location); this.symbol = symbol; } - /** * Constructs a new NOT_IN_PLAY Cell * @@ -33,8 +29,7 @@ public ShortTruthTableCell(Point location) { this(' ', ShortTruthTableCellType.NOT_IN_PLAY, location); } - - //Getters + // Getters public ShortTruthTableStatement getStatementReference() { return statement; @@ -65,12 +60,12 @@ public int getY() { return (int) location.getY(); } - public boolean isAssigned() { - return getType() == ShortTruthTableCellType.TRUE || getType() == ShortTruthTableCellType.FALSE; + return getType() == ShortTruthTableCellType.TRUE + || getType() == ShortTruthTableCellType.FALSE; } - //Setters + // Setters void setStatementReference(ShortTruthTableStatement statement) { this.statement = statement; @@ -86,7 +81,7 @@ public void setGiven(ShortTruthTableCellType type) { setGiven(true); } - //Modifiers + // Modifiers public void cycleTypeForward() { switch (data) { @@ -109,16 +104,14 @@ public void cycleTypeBackward() { cycleTypeForward(); } - - //TO STRING + // TO STRING @Override public String toString() { return String.format("STTCell: %c %2d %-11s %s", symbol, index, data, location.toString()); } - - //Copy function + // Copy function @Override public ShortTruthTableCell copy() { @@ -142,22 +135,22 @@ public void setType(Element e, MouseEvent m) { } // Red Element - if (e.getElementID().equals("STTT-PLAC-0002")) { + if (e.getElementID().equals("STTT-ELEM-0004")) { this.data = ShortTruthTableCellType.FALSE; } // Green Element else { - if (e.getElementID().equals("STTT-PLAC-0001")) { + if (e.getElementID().equals("STTT-ELEM-0002")) { this.data = ShortTruthTableCellType.TRUE; } // Unknown Element else { - if (e.getElementID().equals("STTT-PLAC-0003")) { + if (e.getElementID().equals("STTT-ELEM-0005")) { this.data = ShortTruthTableCellType.UNKNOWN; } // Argument Element else { - if (e.getElementID().equals("STTT-UNPL-0001")) { + if (e.getElementID().equals("STTT-ELEM-0001")) { // Prevents non-argument symbols from being changed if (!(this.symbol >= 'A' && this.symbol <= 'Z')) { return; @@ -168,8 +161,7 @@ public void setType(Element e, MouseEvent m) { if (this.symbol > 'Z') { this.symbol = 'A'; } - } - else { + } else { if (m.getButton() == MouseEvent.BUTTON3) { this.symbol -= 1; if (this.symbol < 'A') { @@ -180,41 +172,34 @@ public void setType(Element e, MouseEvent m) { } // And/Or Element else { - if (e.getElementID().equals("STTT-UNPL-0002")) { + if (e.getElementID().equals("STTT-ELEM-0003")) { if (m.getButton() == MouseEvent.BUTTON1) { if (this.symbol == '^') { this.symbol = '|'; - } - else { + } else { if (this.symbol == '|') { this.symbol = '>'; - } - else { + } else { if (this.symbol == '>') { this.symbol = '-'; - } - else { + } else { if (this.symbol == '-') { this.symbol = '^'; } } } } - } - else { + } else { if (m.getButton() == MouseEvent.BUTTON3) { if (this.symbol == '^') { this.symbol = '-'; - } - else { + } else { if (this.symbol == '|') { this.symbol = '^'; - } - else { + } else { if (this.symbol == '>') { this.symbol = '|'; - } - else { + } else { if (this.symbol == '-') { this.symbol = '>'; } @@ -229,4 +214,4 @@ public void setType(Element e, MouseEvent m) { } } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCellFactory.java index 99d626447..df74afdc9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCellFactory.java @@ -4,57 +4,58 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class ShortTruthTableCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid */ @Override - public ShortTruthTableCell importCell(Node node, Board board) throws InvalidFileFormatException { + public ShortTruthTableCell importCell(Node node, Board board) + throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("ShortTruthTable Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "ShortTruthTable Factory: unknown puzzleElement puzzleElement"); } ShortTruthTableBoard sttBoard = (ShortTruthTableBoard) board; - //get the attributes for the cell + // get the attributes for the cell NamedNodeMap attributeList = node.getAttributes(); int rowIndex = Integer.valueOf(attributeList.getNamedItem("row_index").getNodeValue()); - int charIndex = Integer.valueOf(attributeList.getNamedItem("char_index").getNodeValue()); + int charIndex = + Integer.valueOf(attributeList.getNamedItem("char_index").getNodeValue()); String cellType = attributeList.getNamedItem("type").getNodeValue(); - //modify the appropriate cell - ShortTruthTableCell cell = (ShortTruthTableCell) sttBoard.getCell(charIndex, rowIndex * 2); + // modify the appropriate cell + ShortTruthTableCell cell = + (ShortTruthTableCell) sttBoard.getCell(charIndex, rowIndex * 2); cell.setData(ShortTruthTableCellType.valueOf(cellType)); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("nurikabe Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "nurikabe Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("nurikabe Factory: could not find attribute(s)"); } - } /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCellType.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCellType.java index c997faf5f..d5a8292a2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCellType.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableCellType.java @@ -1,11 +1,14 @@ package edu.rpi.legup.puzzle.shorttruthtable; -import java.util.Map; import java.util.HashMap; +import java.util.Map; public enum ShortTruthTableCellType { - - FALSE(0), TRUE(1), UNKNOWN(-1), NOT_IN_PLAY(-2), PARENTHESIS(-3); + FALSE(0), + TRUE(1), + UNKNOWN(-1), + NOT_IN_PLAY(-2), + PARENTHESIS(-3); public int value; private static Map map = new HashMap<>(); @@ -37,7 +40,6 @@ public static char toChar(ShortTruthTableCellType type) { return ' '; } - /** * Returns true if this cell holds the value either TRUE or FALSE * @@ -47,7 +49,6 @@ public boolean isTrueOrFalse() { return value == 0 || value == 1; } - public ShortTruthTableCellType getNegation() { switch (value) { case 1: @@ -63,5 +64,4 @@ public static ShortTruthTableCellType getDefaultType(char c) { if (c == '(' || c == ')') return PARENTHESIS; return UNKNOWN; } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableController.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableController.java index bddde44a5..172867f5a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableController.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableController.java @@ -2,7 +2,6 @@ import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.event.MouseEvent; public class ShortTruthTableController extends ElementController { @@ -17,13 +16,16 @@ public void changeCell(MouseEvent e, PuzzleElement data) { if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { - this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); - } - else { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { cell.cycleTypeForward(); } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { cell.cycleTypeBackward(); } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableElementView.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableElementView.java index b787921ad..43e1d2299 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableElementView.java @@ -1,20 +1,19 @@ package edu.rpi.legup.puzzle.shorttruthtable; -import edu.rpi.legup.ui.boardview.GridElementView; import edu.rpi.legup.app.LegupPreferences; - +import edu.rpi.legup.ui.boardview.GridElementView; import java.awt.*; public class ShortTruthTableElementView extends GridElementView { - //Font + // Font private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); private static final Color FONT_COLOR = Color.BLACK; - //Square Colors - private static final Color TRUE_COLOR = new Color(0, 130, 0);//green + // Square Colors + private static final Color TRUE_COLOR = new Color(0, 130, 0); // green private static final Color TRUE_COLOR_COLORBLIND = new Color(0, 0, 255); - private static final Color FALSE_COLOR = new Color(200, 0, 0);//red + private static final Color FALSE_COLOR = new Color(200, 0, 0); // red private static final Color FALSE_COLOR_COLORBLIND = new Color(255, 0, 0); private static final Color UNKNOWN_COLOR = Color.WHITE; @@ -23,7 +22,6 @@ public ShortTruthTableElementView(ShortTruthTableCell cell) { super(cell); } - /** * Gets the PuzzleElement associated with this view * @@ -37,14 +35,14 @@ public ShortTruthTableCell getPuzzleElement() { @Override public void drawElement(Graphics2D graphics2D) { - //get information about the cell + // get information about the cell ShortTruthTableCell cell = (ShortTruthTableCell) puzzleElement; ShortTruthTableCellType type = cell.getData(); - //do not draw the cell if it is not in play + // do not draw the cell if it is not in play if (type == ShortTruthTableCellType.NOT_IN_PLAY) return; - //fill in background color of the cell + // fill in background color of the cell graphics2D.setStroke(new BasicStroke(1)); LegupPreferences prefs = LegupPreferences.getInstance(); switch (type) { @@ -68,15 +66,14 @@ public void drawElement(Graphics2D graphics2D) { } graphics2D.fillRect(location.x, location.y, size.width, size.height); - //Draw the symbol on the cell + // Draw the symbol on the cell graphics2D.setColor(FONT_COLOR); graphics2D.setFont(FONT); FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = String.valueOf(cell.getSymbol()); int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); - graphics2D.drawString(ShortTruthTableOperation.getLogicSymbol(cell.getSymbol()), xText, yText); - - + graphics2D.drawString( + ShortTruthTableOperation.getLogicSymbol(cell.getSymbol()), xText, yText); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableExporter.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableExporter.java index 9d6553c7c..0914c159a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableExporter.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; import org.w3c.dom.Document; public class ShortTruthTableExporter extends PuzzleExporter { @@ -16,8 +15,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { ShortTruthTableBoard board; if (puzzle.getTree() != null) { board = (ShortTruthTableBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (ShortTruthTableBoard) puzzle.getBoardView().getBoard(); } @@ -33,12 +31,12 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { dataElement.appendChild(statementElement); } - for (PuzzleElement puzzleElement : board.getPuzzleElements()) { ShortTruthTableCell cell = board.getCellFromElement(puzzleElement); if (!cell.getType().isTrueOrFalse()) continue; - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); dataElement.appendChild(cellElement); } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableImporter.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableImporter.java index 84d04fb45..396668380 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableImporter.java @@ -2,16 +2,15 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import javax.swing.*; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; class ShortTruthTableImporter extends PuzzleImporter { @@ -19,9 +18,9 @@ public ShortTruthTableImporter(ShortTruthTable stt) { super(stt); } - /** - * Parse a string into all the cells, the y position of the statement is passed so the y position can be set + * Parse a string into all the cells, the y position of the statement is passed so the y + * position can be set * * @param statement * @param y @@ -29,83 +28,90 @@ public ShortTruthTableImporter(ShortTruthTable stt) { */ private List getCells(String statement, int y) { List cells = new ArrayList(); - //go through each char in the statement and make a cell for it + // go through each char in the statement and make a cell for it for (int i = 0; i < statement.length(); i++) { char c = statement.charAt(i); - ShortTruthTableCell cell = new ShortTruthTableCell(c, ShortTruthTableCellType.getDefaultType(c), new Point(i, y)); - //it is modifiable if the type is unknown + ShortTruthTableCell cell = + new ShortTruthTableCell( + c, ShortTruthTableCellType.getDefaultType(c), new Point(i, y)); + // it is modifiable if the type is unknown cell.setModifiable(cell.getType() == ShortTruthTableCellType.UNKNOWN); cells.add(cell); } return cells; } - /** - * Parses the statementData into all the cells (with symbols) and statements for the - * puzzle. All cells are set to UNKNWON, it their value is given, it will be set later - * in the import process. - *

- * Both allCells and statements act as returns, They should be passed as empty arrays + * Parses the statementData into all the cells (with symbols) and statements for the puzzle. All + * cells are set to UNKNWON, it their value is given, it will be set later in the import + * process. + * + *

Both allCells and statements act as returns, They should be passed as empty arrays * * @param statementData The data to be imported - * @param allCells returns all the cells as a jagged 2d array - * @param statements returns all the statements + * @param allCells returns all the cells as a jagged 2d array + * @param statements returns all the statements * @return the length, in chars, of the longest statement */ - private int parseAllStatementsAndCells(final NodeList statementData, - List> allCells, - List statements) throws InvalidFileFormatException { + private int parseAllStatementsAndCells( + final NodeList statementData, + List> allCells, + List statements) + throws InvalidFileFormatException { int maxStatementLength = 0; - //get a 2D arraylist of all the cells + // get a 2D arraylist of all the cells for (int i = 0; i < statementData.getLength(); i++) { - //Get the atributes from the statement i in the file + // Get the atributes from the statement i in the file NamedNodeMap attributeList = statementData.item(i).getAttributes(); String statementRep = attributeList.getNamedItem("representation").getNodeValue(); System.out.println("STATEMENT REP: " + statementRep); - System.out.println("ROW INDEX: " + attributeList.getNamedItem("row_index").getNodeValue()); - //parser time (on statementRep) - //if (!validGrammar(statementRep)) throw some error + System.out.println( + "ROW INDEX: " + attributeList.getNamedItem("row_index").getNodeValue()); + // parser time (on statementRep) + // if (!validGrammar(statementRep)) throw some error if (!validGrammar(statementRep)) { JOptionPane.showMessageDialog(null, "ERROR: Invalid file syntax"); - throw new InvalidFileFormatException("shorttruthtable importer: invalid sentence syntax"); + throw new InvalidFileFormatException( + "shorttruthtable importer: invalid sentence syntax"); } int rowIndex = Integer.valueOf(attributeList.getNamedItem("row_index").getNodeValue()); - //get the cells for the statement + // get the cells for the statement List rowOfCells = getCells(statementRep, rowIndex * 2); allCells.add(rowOfCells); statements.add(new ShortTruthTableStatement(statementRep, rowOfCells)); - //keep track of the length of the longest statement + // keep track of the length of the longest statement maxStatementLength = Math.max(maxStatementLength, statementRep.length()); - } return maxStatementLength; } - private int parseAllStatementsAndCells(String[] statementData, - List> allCells, - List statements) throws IllegalArgumentException { + private int parseAllStatementsAndCells( + String[] statementData, + List> allCells, + List statements) + throws IllegalArgumentException { int maxStatementLength = 0; for (int i = 0; i < statementData.length; i++) { if (!validGrammar(statementData[i])) { JOptionPane.showMessageDialog(null, "ERROR: Invalid file syntax"); - throw new IllegalArgumentException("shorttruthtable importer: invalid sentence syntax"); + throw new IllegalArgumentException( + "shorttruthtable importer: invalid sentence syntax"); } - //get the cells for the statement + // get the cells for the statement List rowOfCells = getCells(statementData[i], i * 2); allCells.add(rowOfCells); statements.add(new ShortTruthTableStatement(statementData[i], rowOfCells)); - //keep track of the length of the longest statement + // keep track of the length of the longest statement maxStatementLength = Math.max(maxStatementLength, statementData[i].length()); } @@ -115,7 +121,7 @@ private int parseAllStatementsAndCells(String[] statementData, protected boolean validGrammar(String sentence) { int open = 0; int close = 0; - char[] valid_characters = new char[]{'^', 'v', '!', '>', '-', '&', '|', '~', '$', '%'}; + char[] valid_characters = new char[] {'^', 'v', '!', '>', '-', '&', '|', '~', '$', '%'}; for (int i = 0; i < sentence.length(); i++) { char s = sentence.charAt(i); if (s == '(' || s == ')') { @@ -155,8 +161,7 @@ protected boolean validGrammar(String sentence) { } } } - } - else { + } else { if (i != sentence.length() - 1) { if (Character.isLetter(sentence.charAt(i + 1))) { System.out.println("Invalid next character"); @@ -170,75 +175,81 @@ protected boolean validGrammar(String sentence) { return open == close; } - private ShortTruthTableBoard generateBoard(List> allCells, - List statements, - int width) { + private ShortTruthTableBoard generateBoard( + List> allCells, + List statements, + int width) { - //calculate the height for the board + // calculate the height for the board int height = statements.size() * 2 - 1; - //instantiate the board with the correct width and height - ShortTruthTableBoard sttBoard = new ShortTruthTableBoard(width, height, - statements.toArray(new ShortTruthTableStatement[statements.size()])); + // instantiate the board with the correct width and height + ShortTruthTableBoard sttBoard = + new ShortTruthTableBoard( + width, + height, + statements.toArray(new ShortTruthTableStatement[statements.size()])); - //set the cells in the board. create not_in_play cells where needed + // set the cells in the board. create not_in_play cells where needed for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - //get the statement index for this row of the table + // get the statement index for this row of the table int statementIndex = y / 2; - //get the cell at this location; or create a not_in_play one if necessary + // get the cell at this location; or create a not_in_play one if necessary ShortTruthTableCell cell = null; - //for a cell to exist at (x, y), it must be a valid row and within the statement length + // for a cell to exist at (x, y), it must be a valid row and within the statement + // length if (y % 2 == 0 && x < statements.get(statementIndex).getLength()) { cell = allCells.get(statementIndex).get(x); - System.out.println("Importer: check cell statement ref: " + cell.getStatementReference()); - } - else { - //if it is not a valid cell space, add a NOT_IN_PLAY cell - cell = new ShortTruthTableCell(' ', ShortTruthTableCellType.NOT_IN_PLAY, new Point(x, y)); + System.out.println( + "Importer: check cell statement ref: " + cell.getStatementReference()); + } else { + // if it is not a valid cell space, add a NOT_IN_PLAY cell + cell = + new ShortTruthTableCell( + ' ', ShortTruthTableCellType.NOT_IN_PLAY, new Point(x, y)); cell.setModifiable(false); } - //add the cell to the table + // add the cell to the table cell.setIndex(y * width + x); sttBoard.setCell(x, y, cell); } } return sttBoard; - } + private void setGivenCells( + ShortTruthTableBoard sttBoard, + Element dataElement, + NodeList cellData, + List statements) + throws InvalidFileFormatException { - private void setGivenCells(ShortTruthTableBoard sttBoard, - Element dataElement, - NodeList cellData, - List statements) throws InvalidFileFormatException { - - - //if it is normal, set all predicates to true and the conclusion to false + // if it is normal, set all predicates to true and the conclusion to false if (dataElement.getAttribute("normal").equalsIgnoreCase("true")) { - //set all predicates to true (all but the last one) + // set all predicates to true (all but the last one) for (int i = 0; i < statements.size() - 1; i++) { statements.get(i).getCell().setGiven(ShortTruthTableCellType.TRUE); } - //set the conclusion to false (the last one) + // set the conclusion to false (the last one) statements.get(statements.size() - 1).getCell().setGiven(ShortTruthTableCellType.FALSE); } - //set the given cell values + // set the given cell values for (int i = 0; i < cellData.getLength(); i++) { - //set the value with the factory importer - ShortTruthTableCell cell = (ShortTruthTableCell) puzzle.getFactory().importCell(cellData.item(i), sttBoard); - //set the modifiable and given flags + // set the value with the factory importer + ShortTruthTableCell cell = + (ShortTruthTableCell) + puzzle.getFactory().importCell(cellData.item(i), sttBoard); + // set the modifiable and given flags cell.setModifiable(false); cell.setGiven(true); } - - } @Override @@ -254,16 +265,14 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException */ @Override - public void initializeBoard(int rows, int columns) { - - } + public void initializeBoard(int rows, int columns) {} - //STATEMENT IMPORTER + // STATEMENT IMPORTER /** * Creates the board for building @@ -276,41 +285,42 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { try { - //Check File formatting + // Check File formatting if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("short truth table Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "short truth table Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("data").getLength() == 0) { - throw new InvalidFileFormatException("short truth table Importer: no statements found for board"); + throw new InvalidFileFormatException( + "short truth table Importer: no statements found for board"); } - - //get all the cells in a 2D arraylist + // get all the cells in a 2D arraylist List> allCells = new ArrayList>(); - //store the statement data structors + // store the statement data structors List statements = new ArrayList(); - //get the elements from the file + // get the elements from the file Element dataElement = (Element) boardElement.getElementsByTagName("data").item(0); NodeList statementData = dataElement.getElementsByTagName("statement"); NodeList cellData = dataElement.getElementsByTagName("cell"); + // Parse the data + int maxStatementLength = + parseAllStatementsAndCells(statementData, allCells, statements); - //Parse the data - int maxStatementLength = parseAllStatementsAndCells(statementData, allCells, statements); - - //generate the board + // generate the board ShortTruthTableBoard sttBoard = generateBoard(allCells, statements, maxStatementLength); - //set the given cell values + // set the given cell values setGivenCells(sttBoard, dataElement, cellData, statements); puzzle.setCurrentBoard(sttBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("short truth table Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "short truth table Importer: unknown value where integer expected"); } } @@ -321,7 +331,8 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { * @throws UnsupportedOperationException * @throws IllegalArgumentException */ - public void initializeBoard(String[] statementInput) throws UnsupportedOperationException, IllegalArgumentException { + public void initializeBoard(String[] statementInput) + throws UnsupportedOperationException, IllegalArgumentException { List statementsList = new LinkedList<>(); for (String s : statementInput) { if (s.strip().length() > 0) { @@ -331,7 +342,8 @@ public void initializeBoard(String[] statementInput) throws UnsupportedOperation String[] statementData = statementsList.toArray(new String[statementsList.size()]); if (statementData.length == 0) { - throw new IllegalArgumentException("short truth table Importer: no statements found for board"); + throw new IllegalArgumentException( + "short truth table Importer: no statements found for board"); } // Store all cells and statements diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableOperation.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableOperation.java index bc713d407..8284474da 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableOperation.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableOperation.java @@ -1,57 +1,48 @@ -package edu.rpi.legup.puzzle.shorttruthtable; - -import java.util.Collections; -import java.util.Map; -import java.util.TreeMap; - -public class ShortTruthTableOperation { - - public static final char AND = '^'; - public static final char OR = '|'; - public static final char NOT = '~'; - public static final char CONDITIONAL = '>'; - public static final char BICONDITIONAL = '-'; - - private ShortTruthTableOperation() { - } - - public static String getLogicSymbol(char c) { - switch (c) { - case AND: - return "\u2227"; - case OR: - return "\u2228"; - case NOT: - return "\u00AC"; - case CONDITIONAL: - return "\u2192"; - case BICONDITIONAL: - return "\u2194"; - } - return "" + c; - } - - public static String getRuleName(char operation) { - switch (operation) { - case AND: - return "And"; - case OR: - return "Or"; - case NOT: - return "Not"; - case CONDITIONAL: - return "Conditional"; - case BICONDITIONAL: - return "Biconditional"; - } - return null; - } - - public static boolean isOperation(char c) { - return c == AND || - c == OR || - c == NOT || - c == CONDITIONAL || - c == BICONDITIONAL; - } -} +package edu.rpi.legup.puzzle.shorttruthtable; + +public class ShortTruthTableOperation { + + public static final char AND = '^'; + public static final char OR = '|'; + public static final char NOT = '~'; + public static final char CONDITIONAL = '>'; + public static final char BICONDITIONAL = '-'; + + private ShortTruthTableOperation() {} + + public static String getLogicSymbol(char c) { + switch (c) { + case AND: + return "\u2227"; + case OR: + return "\u2228"; + case NOT: + return "\u00AC"; + case CONDITIONAL: + return "\u2192"; + case BICONDITIONAL: + return "\u2194"; + } + return "" + c; + } + + public static String getRuleName(char operation) { + switch (operation) { + case AND: + return "And"; + case OR: + return "Or"; + case NOT: + return "Not"; + case CONDITIONAL: + return "Conditional"; + case BICONDITIONAL: + return "Biconditional"; + } + return null; + } + + public static boolean isOperation(char c) { + return c == AND || c == OR || c == NOT || c == CONDITIONAL || c == BICONDITIONAL; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableStatement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableStatement.java index e40a10cf0..2059e3ca5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableStatement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableStatement.java @@ -1,149 +1,143 @@ package edu.rpi.legup.puzzle.shorttruthtable; - import edu.rpi.legup.model.gameboard.PuzzleElement; - -import java.util.Set; -import java.util.HashSet; import java.awt.Point; -import java.util.List; import java.util.ArrayList; - +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class ShortTruthTableStatement extends PuzzleElement { - //the cell that this statement holds + // the cell that this statement holds private final ShortTruthTableCell cell; - //child nodes of the tree + // child nodes of the tree private final ShortTruthTableStatement parentStatement; private final ShortTruthTableStatement leftStatement; private final ShortTruthTableStatement rightStatement; - //the representation string for this statement + // the representation string for this statement private final String stringRep; private final List cells; - - //constructor for root statement, sets parent to null + // constructor for root statement, sets parent to null public ShortTruthTableStatement(String statement, List cells) { this(statement, null, cells); } - //recursive constructor; constructs child statement nodes if necessary - private ShortTruthTableStatement(String statement, ShortTruthTableStatement parent, List cells) { + // recursive constructor; constructs child statement nodes if necessary + private ShortTruthTableStatement( + String statement, ShortTruthTableStatement parent, List cells) { this.parentStatement = parent; - //set the string rep to the statement (include parens in case this is a sub statement) + // set the string rep to the statement (include parens in case this is a sub statement) this.stringRep = statement; this.cells = new ArrayList(cells); - //remove the parens for parsing the statement + // remove the parens for parsing the statement statement = removeParens(statement); removeParens(cells); - //get the index of the char that this statement represents + // get the index of the char that this statement represents int index = parse(statement); - //construct the cell for this node in the tree + // construct the cell for this node in the tree cell = cells.get(index); - //give the cell a reference back to this statement + // give the cell a reference back to this statement cell.setStatementReference(this); - //get the strings on either side of this char in the string rep + // get the strings on either side of this char in the string rep String left = statement.substring(0, index); String right = statement.substring(index + 1); - List leftCells = new ArrayList(cells.subList(0, index)); - List rightCells = new ArrayList(cells.subList(index + 1, cells.size())); + List leftCells = + new ArrayList(cells.subList(0, index)); + List rightCells = + new ArrayList(cells.subList(index + 1, cells.size())); - //construct sub-statements if necessary + // construct sub-statements if necessary if (left.length() > 0) { leftStatement = new ShortTruthTableStatement(left, this, leftCells); - } - else { + } else { leftStatement = null; } if (right.length() > 0) { rightStatement = new ShortTruthTableStatement(right, this, rightCells); - } - else { + } else { rightStatement = null; } - } - - //parsing for the constructor + // parsing for the constructor static String removeParens(String statement) { if (statement.charAt(0) != '(') { return statement; } - //if the statement does start with a paren, check that it matches with the last paren + // if the statement does start with a paren, check that it matches with the last paren int openParenCount = 1; int i = 1; while (i < statement.length() - 1) { char c = statement.charAt(i); if (c == '(') { openParenCount++; - } - else { + } else { if (c == ')') openParenCount--; } - //if the first paren has been closed, and it is not the end of the string, - //then there is no whole statement parens to remove + // if the first paren has been closed, and it is not the end of the string, + // then there is no whole statement parens to remove if (openParenCount == 0 && i != statement.length() - 1) { return statement; } i++; } - //if the while loop made it through the entire statement, there are parens around the whole thing + // if the while loop made it through the entire statement, there are parens around the whole + // thing return statement.substring(1, statement.length() - 1); - } int parse(String statement) { - - //Split by and, or, CONDITIONAL, or biconditional - //keep track of the parens, it must be equal to zero to split + // Split by and, or, CONDITIONAL, or biconditional + // keep track of the parens, it must be equal to zero to split int openParenCount = 0; - //index for stepping through the string + // index for stepping through the string int i = 0; - //step through each char in the statement + // step through each char in the statement while (i < statement.length()) { - //get the char + // get the char char c = statement.charAt(i); - //keep track of the open parens + // keep track of the open parens if (c == '(') { openParenCount++; - } - else { + } else { if (c == ')') { openParenCount--; } - //if the char is an operator, and there are no open parens, split the statement here + // if the char is an operator, and there are no open parens, split the statement + // here else { - if (openParenCount == 0 && ShortTruthTableOperation.isOperation(c) && c != ShortTruthTableOperation.NOT) { + if (openParenCount == 0 + && ShortTruthTableOperation.isOperation(c) + && c != ShortTruthTableOperation.NOT) { return i; } } } - //increment the index + // increment the index i++; } - //if it made it through the while loop: - //this is an atomic statement or a negation - //either way, the important char is the first character in the string + // if it made it through the while loop: + // this is an atomic statement or a negation + // either way, the important char is the first character in the string return 0; - } static void removeParens(List cells) { @@ -152,20 +146,19 @@ static void removeParens(List cells) { return; } - //if the statement does start with a paren, check that it matches with the last paren + // if the statement does start with a paren, check that it matches with the last paren int openParenCount = 1; int i = 1; while (i < cells.size() - 1) { char c = cells.get(i).getSymbol(); if (c == '(') { openParenCount++; - } - else { + } else { if (c == ')') openParenCount--; } - //if the first paren has been closed, and it is not the end of the string, - //then there is no whole statement parens to remove + // if the first paren has been closed, and it is not the end of the string, + // then there is no whole statement parens to remove if (openParenCount == 0 && i != cells.size() - 1) { return; } @@ -173,15 +166,13 @@ static void removeParens(List cells) { i++; } - //if the while loop made it through the entire statement, there are parens around the whole thing + // if the while loop made it through the entire statement, there are parens around the whole + // thing cells.remove(cells.size() - 1); cells.remove(0); - } - - //Getters - + // Getters public ShortTruthTableCell getCell() { return cell; @@ -220,15 +211,15 @@ public int getLength() { return stringRep.length(); } - public ShortTruthTableCell getCell(int i) { return cells.get(i); } + // Getters (recursive) - //Getters (recursive) - - //returns all cells in this statement with the symbol 'symbol'; runs recursively on both sides of the tree + // returns all cells in this statement with the symbol 'symbol'; runs recursively on both sides + // of + // the tree public Set getCellsWithSymbol(char symbol) { Set set = new HashSet(getLength()); if (cell.getSymbol() == symbol) set.add(cell); @@ -238,38 +229,37 @@ public Set getCellsWithSymbol(char symbol) { } /** - * Returns an array of three elements where [0] is the left - * statement type, [1] is this statement type, and [2] is the - * right statement type. null means either the statement doesn't + * Returns an array of three elements where [0] is the left statement type, [1] is this + * statement type, and [2] is the right statement type. null means either the statement doesn't * exist or is an unknown value. * * @return the assigned values to this statement and its sub-statements */ public ShortTruthTableCellType[] getCellTypePattern() { - //get this type and the right type, they will always be used + // get this type and the right type, they will always be used ShortTruthTableCellType type = this.cell.getType(); System.out.println("Right statement: " + rightStatement.getCell()); ShortTruthTableCellType rightType = this.rightStatement.getCell().getType(); System.out.println("Right type: " + rightType); - //if this is a not statement, there is no left side + // if this is a not statement, there is no left side if (cell.getSymbol() == ShortTruthTableOperation.NOT) { - return new ShortTruthTableCellType[]{null, type, rightType}; + return new ShortTruthTableCellType[] {null, type, rightType}; } - //if it is any other operation, get the left side too and return it + // if it is any other operation, get the left side too and return it ShortTruthTableCellType leftType = this.leftStatement.getCell().getType(); - return new ShortTruthTableCellType[]{leftType, type, rightType}; + return new ShortTruthTableCellType[] {leftType, type, rightType}; } - //Setters + // Setters private void setCellLocations(int rowIndex, int offset) { - //set the location of this cell + // set the location of this cell int xLoc = offset; if (leftStatement != null) { xLoc += leftStatement.getLength(); } cell.setLocation(new Point(xLoc, rowIndex)); - //recurse on both sides of the tree + // recurse on both sides of the tree if (leftStatement != null) { leftStatement.setCellLocations(rowIndex, offset); } @@ -282,32 +272,29 @@ public void setCellLocations(int rowIndex) { setCellLocations(rowIndex, 0); } - public ShortTruthTableStatement copy() { - //copy all the cells + // copy all the cells List cellsCopy = new ArrayList<>(); for (ShortTruthTableCell c : cells) { cellsCopy.add(c.copy()); } - //make a copy of the statement with all the copied cells - //return the new statement + // make a copy of the statement with all the copied cells + // return the new statement return new ShortTruthTableStatement(stringRep, cellsCopy); } public ShortTruthTableStatement replace(int column, ShortTruthTableCell cell) { - //copy all the cells (replacing one) + // copy all the cells (replacing one) List cellsCopy = new ArrayList<>(); for (ShortTruthTableCell c : cells) { if (c.getX() == column) { cellsCopy.add(cell); - } - else { + } else { cellsCopy.add(c); } } - //make a copy of the statement with all the copied cells - //return the new statement + // make a copy of the statement with all the copied cells + // return the new statement return new ShortTruthTableStatement(stringRep, cellsCopy); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableView.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableView.java index 64e9fda75..15becf443 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableView.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/ShortTruthTableView.java @@ -3,7 +3,6 @@ import edu.rpi.legup.controller.BoardController; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.ui.boardview.GridBoardView; - import java.awt.*; public class ShortTruthTableView extends GridBoardView { @@ -13,12 +12,13 @@ public ShortTruthTableView(ShortTruthTableBoard board) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { ShortTruthTableCell cell = (ShortTruthTableCell) puzzleElement; -// System.out.println("STTView :"+cell); + // System.out.println("STTView :"+cell); Point loc = cell.getLocation(); ShortTruthTableElementView elementView = new ShortTruthTableElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); elementViews.add(elementView); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java index 9f238a9bf..912fd2672 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/ArgumentElement.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.shorttruthtable.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class ArgumentElement extends NonPlaceableElement { +public class ArgumentElement extends PlaceableElement { public ArgumentElement() { - super("STTT-UNPL-0001", "Argument Element", "Argument of logic statement element", "edu/rpi/legup/images/shorttruthtable/tiles/LetterTile.png"); + super( + "STTT-ELEM-0001", + "Argument Element", + "Argument of logic statement element", + "edu/rpi/legup/images/shorttruthtable/tiles/LetterTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java index 605f6a207..56221fef3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/GreenElement.java @@ -4,6 +4,10 @@ public class GreenElement extends PlaceableElement { public GreenElement() { - super("STTT-PLAC-0001", "Green Element", "A green tile to set certain tiles to true", "edu/rpi/legup/images/shorttruthtable/tiles/GreenTile.png"); + super( + "STTT-ELEM-0002", + "Green Element", + "A green tile to set certain tiles to true", + "edu/rpi/legup/images/shorttruthtable/tiles/GreenTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java index b2adfddef..b82ebc2cb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/LogicSymbolElement.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.shorttruthtable.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class LogicSymbolElement extends NonPlaceableElement { +public class LogicSymbolElement extends PlaceableElement { public LogicSymbolElement() { - super("STTT-UNPL-0002", "Logic Symbol Element", "Logic symbol element", "edu/rpi/legup/images/shorttruthtable/tiles/ConditionalBiconditionalTile.png"); + super( + "STTT-ELEM-0003", + "Logic Symbol Element", + "Logic symbol element", + "edu/rpi/legup/images/shorttruthtable/tiles/ConditionalBiconditionalTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java index ecc7d5a02..2114e62ec 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/RedElement.java @@ -4,6 +4,10 @@ public class RedElement extends PlaceableElement { public RedElement() { - super("STTT-PLAC-0002", "Red Element", "A red tile to set certain tiles to false", "edu/rpi/legup/images/shorttruthtable/tiles/RedTile.png"); + super( + "STTT-ELEM-0004", + "Red Element", + "A red tile to set certain tiles to false", + "edu/rpi/legup/images/shorttruthtable/tiles/RedTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java index 9a9ab8b84..52b54f202 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/UnknownElement.java @@ -4,6 +4,10 @@ public class UnknownElement extends PlaceableElement { public UnknownElement() { - super("STTT-PLAC-0003", "Unknown Element", "A blank tile", "edu/rpi/legup/images/shorttruthtable/tiles/UnknownTile.png"); + super( + "STTT-ELEM-0005", + "Unknown Element", + "A blank tile", + "edu/rpi/legup/images/shorttruthtable/tiles/UnknownTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet index 471631553..c5421169f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/elements/shorttruthtable_elements_reference_sheet @@ -1,6 +1,5 @@ -STTT-UNPL-0001 : ArgumentElement -STTT-UNPL-0002 : ConditionalBiconditionalElement - -STTT-PLAC-0001 : GreenElement -STTT-PLAC-0002 : RedElement -STTT-PLAC-0003 : UnknownElement \ No newline at end of file +STTT-ELEM-0001 : ArgumentElement +STTT-ELEM-0002 : GreenElement +STTT-ELEM-0003 : LogicSymbolElement +STTT-ELEM-0004 : RedElement +STTT-ELEM-0005 : UnknownElement \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRuleAtomic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRuleAtomic.java index 4b40c833d..38048b5b0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRuleAtomic.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRuleAtomic.java @@ -5,12 +5,12 @@ public class DirectRuleAtomic extends DirectRule_Generic { public DirectRuleAtomic() { - super("STTT-BASC-0001", "Atomic Rule", + super( + "STTT-BASC-0001", + "Atomic Rule", "All identical atoms have the same T/F value", "Atomic", new ContradictionRuleAtomic(), - false - ); + false); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRule_Generic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRule_Generic.java index e1ac78b8c..470ba7c29 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRule_Generic.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/DirectRule_Generic.java @@ -2,21 +2,30 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.model.rules.DirectRule; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; - import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; -import edu.rpi.legup.model.rules.ContradictionRule; public abstract class DirectRule_Generic extends DirectRule { final ContradictionRule CORRESPONDING_CONTRADICTION_RULE; final boolean ELIMINATION_RULE; - public DirectRule_Generic(String ruleID, String ruleName, String description, String imageName, ContradictionRule contraRule, boolean eliminationRule) { - super(ruleID, ruleName, description, "edu/rpi/legup/images/shorttruthtable/ruleimages/basic/" + imageName + ".png"); + public DirectRule_Generic( + String ruleID, + String ruleName, + String description, + String imageName, + ContradictionRule contraRule, + boolean eliminationRule) { + super( + ruleID, + ruleName, + description, + "edu/rpi/legup/images/shorttruthtable/ruleimages/basic/" + imageName + ".png"); this.CORRESPONDING_CONTRADICTION_RULE = contraRule; this.ELIMINATION_RULE = eliminationRule; } @@ -26,17 +35,23 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement element) { if (element == null) return super.getInvalidUseOfRuleMessage() + ": Must have painted cell"; // Check that the puzzle element is not unknown - ShortTruthTableBoard parentBoard = (ShortTruthTableBoard) transition.getParents().get(0).getBoard(); + ShortTruthTableBoard parentBoard = + (ShortTruthTableBoard) transition.getParents().get(0).getBoard(); ShortTruthTableBoard finalBoard = (ShortTruthTableBoard) transition.getBoard(); - ShortTruthTableCell parentCell = (ShortTruthTableCell) parentBoard.getPuzzleElement(element); + ShortTruthTableCell parentCell = + (ShortTruthTableCell) parentBoard.getPuzzleElement(element); ShortTruthTableCell finalCell = (ShortTruthTableCell) finalBoard.getPuzzleElement(element); if (!finalCell.isAssigned()) { - return super.getInvalidUseOfRuleMessage() + ": Only assigned cells are allowed for basic rules"; + return super.getInvalidUseOfRuleMessage() + + ": Only assigned cells are allowed for basic rules"; } - // Strategy: Negate the modified cell and check if there is a contradiction. If there is one, then the - // original statement must be true. If there isn't one, then the original statement must be false. + // Strategy: Negate the modified cell and check if there is a contradiction. If there is + // one, + // then the + // original statement must be true. If there isn't one, then the original statement must be + // false. ShortTruthTableBoard modifiedBoard = parentBoard.copy(); @@ -47,13 +62,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement element) { ShortTruthTableCell checkCell = this.ELIMINATION_RULE - ? (ShortTruthTableCell) modifiedBoard.getCell(parentCell.getX(), parentCell.getY()) + ? (ShortTruthTableCell) + modifiedBoard.getCell(parentCell.getX(), parentCell.getY()) : (ShortTruthTableCell) modifiedBoard.getPuzzleElement(element); checkCell.setType(finalCell.getType().getNegation()); - String contradictionMessage = CORRESPONDING_CONTRADICTION_RULE.checkContradictionAt(modifiedBoard, checkElement); - if (contradictionMessage == null) { // A contradiction exists in the modified statement; this is good! + String contradictionMessage = + CORRESPONDING_CONTRADICTION_RULE.checkContradictionAt(modifiedBoard, checkElement); + if (contradictionMessage + == null) { // A contradiction exists in the modified statement; this is good! return null; } @@ -61,7 +79,8 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement element) { } /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. * * @param node short truth table board used to create default transition board * @return default board or null if this rule cannot be applied to this tree node diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleAndElimination.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleAndElimination.java index 63e3c8dd9..6f48784a3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleAndElimination.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleAndElimination.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleAnd; - -public class DirectRuleAndElimination extends DirectRule_GenericElimination { - - public DirectRuleAndElimination() { - super("STTT-BASC-0002", "And", new ContradictionRuleAnd()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleAnd; + +public class DirectRuleAndElimination extends DirectRule_GenericElimination { + + public DirectRuleAndElimination() { + super("STTT-BASC-0002", "And", new ContradictionRuleAnd()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleBiconditionalElimination.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleBiconditionalElimination.java index 7f7336a4c..168877ca6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleBiconditionalElimination.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleBiconditionalElimination.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleBiconditional; - -public class DirectRuleBiconditionalElimination extends DirectRule_GenericElimination { - - public DirectRuleBiconditionalElimination() { - super("STTT-BASC-0003", "Biconditional", new ContradictionRuleBiconditional()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleBiconditional; + +public class DirectRuleBiconditionalElimination extends DirectRule_GenericElimination { + + public DirectRuleBiconditionalElimination() { + super("STTT-BASC-0003", "Biconditional", new ContradictionRuleBiconditional()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleConditionalElimination.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleConditionalElimination.java index 8f15be021..4a287b195 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleConditionalElimination.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleConditionalElimination.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleConditional; - -public class DirectRuleConditionalElimination extends DirectRule_GenericElimination { - - public DirectRuleConditionalElimination() { - super("STTT-BASC-0004", "Conditional", new ContradictionRuleConditional()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleConditional; + +public class DirectRuleConditionalElimination extends DirectRule_GenericElimination { + + public DirectRuleConditionalElimination() { + super("STTT-BASC-0004", "Conditional", new ContradictionRuleConditional()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleNotElimination.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleNotElimination.java index a2f08635c..5acff5837 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleNotElimination.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleNotElimination.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleNot; - -public class DirectRuleNotElimination extends DirectRule_GenericElimination { - - public DirectRuleNotElimination() { - super("STTT-BASC-0005", "Not", new ContradictionRuleNot()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleNot; + +public class DirectRuleNotElimination extends DirectRule_GenericElimination { + + public DirectRuleNotElimination() { + super("STTT-BASC-0005", "Not", new ContradictionRuleNot()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleOrElimination.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleOrElimination.java index eca1848bd..fba43762a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleOrElimination.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRuleOrElimination.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleOr; - -public class DirectRuleOrElimination extends DirectRule_GenericElimination { - - public DirectRuleOrElimination() { - super("STTT-BASC-0006", "Or", new ContradictionRuleOr()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleOr; + +public class DirectRuleOrElimination extends DirectRule_GenericElimination { + + public DirectRuleOrElimination() { + super("STTT-BASC-0006", "Or", new ContradictionRuleOr()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRule_GenericElimination.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRule_GenericElimination.java index 49dc43510..1f85e5b79 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRule_GenericElimination.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/elimination/DirectRule_GenericElimination.java @@ -1,18 +1,19 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.DirectRule_Generic; -import edu.rpi.legup.model.rules.ContradictionRule; - -public abstract class DirectRule_GenericElimination extends DirectRule_Generic { - - public DirectRule_GenericElimination(String ruleID, String ruleName, ContradictionRule contradictionRule) { - - super(ruleID, ruleName + " Elimination", - ruleName + " statements must have a valid pattern", - "elimination/" + ruleName, - contradictionRule, - true - ); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.elimination; + +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.DirectRule_Generic; + +public abstract class DirectRule_GenericElimination extends DirectRule_Generic { + + public DirectRule_GenericElimination( + String ruleID, String ruleName, ContradictionRule contradictionRule) { + + super( + ruleID, + ruleName + " Elimination", + ruleName + " statements must have a valid pattern", + "elimination/" + ruleName, + contradictionRule, + true); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleAndIntroduction.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleAndIntroduction.java index 0ca2a7dcf..667b97a0f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleAndIntroduction.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleAndIntroduction.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleAnd; - -public class DirectRuleAndIntroduction extends DirectRule_GenericIntroduction { - - public DirectRuleAndIntroduction() { - super("STTT-BASC-0007", "And", new ContradictionRuleAnd()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleAnd; + +public class DirectRuleAndIntroduction extends DirectRule_GenericIntroduction { + + public DirectRuleAndIntroduction() { + super("STTT-BASC-0007", "And", new ContradictionRuleAnd()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleBiconditionalIntroduction.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleBiconditionalIntroduction.java index b72d5299c..c2dfeebba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleBiconditionalIntroduction.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleBiconditionalIntroduction.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleBiconditional; - -public class DirectRuleBiconditionalIntroduction extends DirectRule_GenericIntroduction { - - public DirectRuleBiconditionalIntroduction() { - super("STTT-BASC-0008", "Biconditional", new ContradictionRuleBiconditional()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleBiconditional; + +public class DirectRuleBiconditionalIntroduction extends DirectRule_GenericIntroduction { + + public DirectRuleBiconditionalIntroduction() { + super("STTT-BASC-0008", "Biconditional", new ContradictionRuleBiconditional()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleConditionalIntroduction.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleConditionalIntroduction.java index 0e27d267c..728d7f244 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleConditionalIntroduction.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleConditionalIntroduction.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleConditional; - -public class DirectRuleConditionalIntroduction extends DirectRule_GenericIntroduction { - - public DirectRuleConditionalIntroduction() { - super("STTT-BASC-0009", "Conditional", new ContradictionRuleConditional()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleConditional; + +public class DirectRuleConditionalIntroduction extends DirectRule_GenericIntroduction { + + public DirectRuleConditionalIntroduction() { + super("STTT-BASC-0009", "Conditional", new ContradictionRuleConditional()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleNotIntroduction.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleNotIntroduction.java index 980a132fe..80b963a56 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleNotIntroduction.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleNotIntroduction.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleNot; - -public class DirectRuleNotIntroduction extends DirectRule_GenericIntroduction { - - public DirectRuleNotIntroduction() { - super("STTT-BASC-0010", "Not", new ContradictionRuleNot()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleNot; + +public class DirectRuleNotIntroduction extends DirectRule_GenericIntroduction { + + public DirectRuleNotIntroduction() { + super("STTT-BASC-0010", "Not", new ContradictionRuleNot()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleOrIntroduction.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleOrIntroduction.java index 0fd7108bd..66a569655 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleOrIntroduction.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRuleOrIntroduction.java @@ -1,11 +1,10 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleOr; - -public class DirectRuleOrIntroduction extends DirectRule_GenericIntroduction { - - public DirectRuleOrIntroduction() { - super("STTT-BASC-0011", "Or", new ContradictionRuleOr()); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; + +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleOr; + +public class DirectRuleOrIntroduction extends DirectRule_GenericIntroduction { + + public DirectRuleOrIntroduction() { + super("STTT-BASC-0011", "Or", new ContradictionRuleOr()); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRule_GenericIntroduction.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRule_GenericIntroduction.java index 123165d7a..8469ff0b9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRule_GenericIntroduction.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/basic/introduction/DirectRule_GenericIntroduction.java @@ -1,18 +1,19 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; - -import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.DirectRule_Generic; -import edu.rpi.legup.model.rules.ContradictionRule; - -public abstract class DirectRule_GenericIntroduction extends DirectRule_Generic { - - protected DirectRule_GenericIntroduction(String ruleID, String ruleName, ContradictionRule contradictionRule) { - - super(ruleID, ruleName + " Introduction", - ruleName + " statements must have a valid pattern", - "introduction/" + ruleName, - contradictionRule, - false - ); - } - -} \ No newline at end of file +package edu.rpi.legup.puzzle.shorttruthtable.rules.basic.introduction; + +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.shorttruthtable.rules.basic.DirectRule_Generic; + +public abstract class DirectRule_GenericIntroduction extends DirectRule_Generic { + + protected DirectRule_GenericIntroduction( + String ruleID, String ruleName, ContradictionRule contradictionRule) { + + super( + ruleID, + ruleName + " Introduction", + ruleName + " statements must have a valid pattern", + "introduction/" + ruleName, + contradictionRule, + false); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAnd.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAnd.java index 12fac9c4c..9b589f14e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAnd.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAnd.java @@ -1,23 +1,17 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; - -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; - -public class CaseRuleAnd extends CaseRule_GenericStatement { - - public CaseRuleAnd() { - super("STTT-CASE-0001", ShortTruthTableOperation.AND, - "And", - trueCases, - falseCases); - } - - private static final ShortTruthTableCellType[][] trueCases = { - {T, T} - }; - private static final ShortTruthTableCellType[][] falseCases = { - {F, U}, - {U, F} - }; - -} +package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; + +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; + +public class CaseRuleAnd extends CaseRule_GenericStatement { + + public CaseRuleAnd() { + super("STTT-CASE-0001", ShortTruthTableOperation.AND, "And", trueCases, falseCases); + } + + private static final ShortTruthTableCellType[][] trueCases = {{T, T}}; + private static final ShortTruthTableCellType[][] falseCases = { + {F, U}, + {U, F} + }; +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java index f168499cc..22b49fd77 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleAtomic.java @@ -3,21 +3,18 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; - import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; - - import java.util.ArrayList; -import java.util.List; public class CaseRuleAtomic extends CaseRule_Generic { public CaseRuleAtomic() { - super("STTT-CASE-0002", "Atomic", + super( + "STTT-CASE-0002", + "Atomic", "True or False", "Each unknown cell must either be true or false"); } @@ -39,7 +36,7 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ @@ -47,6 +44,9 @@ public CaseBoard getCaseBoard(Board board) { @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } Board case1 = board.copy(); PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleBiconditional.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleBiconditional.java index 85c6f5447..1bb5f0332 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleBiconditional.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleBiconditional.java @@ -1,24 +1,25 @@ package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; public class CaseRuleBiconditional extends CaseRule_GenericStatement { public CaseRuleBiconditional() { - super("STTT-CASE-0003", ShortTruthTableOperation.BICONDITIONAL, + super( + "STTT-CASE-0003", + ShortTruthTableOperation.BICONDITIONAL, "Biconditional", trueCases, falseCases); } private static final ShortTruthTableCellType[][] trueCases = { - {T, T}, - {F, F} + {T, T}, + {F, F} }; private static final ShortTruthTableCellType[][] falseCases = { - {T, F}, - {F, T} + {T, F}, + {F, T} }; - } diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleConditional.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleConditional.java index a9fee2b4e..397341f0e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleConditional.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleConditional.java @@ -1,23 +1,24 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; - -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; - -public class CaseRuleConditional extends CaseRule_GenericStatement { - - public CaseRuleConditional() { - super("STTT-CASE-0004", ShortTruthTableOperation.CONDITIONAL, - "Conditional", - trueCases, - falseCases); - } - - private static final ShortTruthTableCellType[][] trueCases = { - {U, T}, - {F, U} - }; - private static final ShortTruthTableCellType[][] falseCases = { - {T, F}, - }; - -} +package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; + +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; + +public class CaseRuleConditional extends CaseRule_GenericStatement { + + public CaseRuleConditional() { + super( + "STTT-CASE-0004", + ShortTruthTableOperation.CONDITIONAL, + "Conditional", + trueCases, + falseCases); + } + + private static final ShortTruthTableCellType[][] trueCases = { + {U, T}, + {F, U} + }; + private static final ShortTruthTableCellType[][] falseCases = { + {T, F}, + }; +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleOr.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleOr.java index 82f814cc8..36f4e6f87 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleOr.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRuleOr.java @@ -1,23 +1,19 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; - -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; - -public class CaseRuleOr extends CaseRule_GenericStatement { - - public CaseRuleOr() { - super("STTT-CASE-0005", ShortTruthTableOperation.OR, - "Or", - trueCases, - falseCases); - } - - private static final ShortTruthTableCellType[][] trueCases = { - {T, U}, - {U, T} - }; - private static final ShortTruthTableCellType[][] falseCases = { - {F, F}, - }; - -} +package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; + +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; + +public class CaseRuleOr extends CaseRule_GenericStatement { + + public CaseRuleOr() { + super("STTT-CASE-0005", ShortTruthTableOperation.OR, "Or", trueCases, falseCases); + } + + private static final ShortTruthTableCellType[][] trueCases = { + {T, U}, + {U, T} + }; + private static final ShortTruthTableCellType[][] falseCases = { + {F, F}, + }; +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_Generic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_Generic.java index 46163c2a3..5885f98f8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_Generic.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_Generic.java @@ -1,71 +1,63 @@ -package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.CaseBoard; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.CaseRule; -import edu.rpi.legup.model.tree.TreeTransition; - -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; - - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.swing.JOptionPane; - -import com.google.firebase.database.core.utilities.Tree; - -public abstract class CaseRule_Generic extends CaseRule { - - public CaseRule_Generic(String ruleID, String ruleName, String title, String description) { - super(ruleID, title, description, "edu/rpi/legup/images/shorttruthtable/ruleimages/case/" + ruleName + ".png"); - } - - - /** - * Checks whether the transition logically follows from the parent node using this rule - * - * @param transition transition to check - * @return null if the child node logically follow from the parent node, otherwise error message - */ - @Override - public String checkRuleRaw(TreeTransition transition) { - // Validate that two children are generated - List childTransitions = transition.getParents().get(0).getChildren(); - if (childTransitions.size() == 0) { - return "ERROR: This case rule must spawn at least 1 child."; - } - - // // Validate that the modified cells are of type UNKNOWN, TRUE, or FALSE - // List cases = Arrays.asList(childTransitions.get(0), childTransitions.get(1)); - // for (TreeTransition c : cases) { - // ShortTruthTableCell mod1 = (ShortTruthTableCell)c.getBoard().getModifiedData().iterator().next(); - // ShortTruthTableCell mod2 = (ShortTruthTableCell)c.getBoard().getModifiedData().iterator().next(); - // if (!(mod1.getType() == ShortTruthTableCellType.TRUE || mod1.getType() == ShortTruthTableCellType.FALSE || mod1.getType() == ShortTruthTableCellType.UNKNOWN) && - // (mod2.getType() == ShortTruthTableCellType.TRUE || mod2.getType() == ShortTruthTableCellType.FALSE || mod2.getType() == ShortTruthTableCellType.UNKNOWN)) { - // return "ERROR: This case rule must be an unknown, true, or false cell."; - // } - // } - return null; - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return checkRuleRaw(transition); - } -} +package edu.rpi.legup.puzzle.shorttruthtable.rules.caserule; + +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import java.util.List; + +public abstract class CaseRule_Generic extends CaseRule { + + public CaseRule_Generic(String ruleID, String ruleName, String title, String description) { + super( + ruleID, + title, + description, + "edu/rpi/legup/images/shorttruthtable/ruleimages/case/" + ruleName + ".png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + // Validate that two children are generated + List childTransitions = transition.getParents().get(0).getChildren(); + if (childTransitions.size() == 0) { + return "ERROR: This case rule must spawn at least 1 child."; + } + + // // Validate that the modified cells are of type UNKNOWN, TRUE, or FALSE + // List cases = Arrays.asList(childTransitions.get(0), + // childTransitions.get(1)); + // for (TreeTransition c : cases) { + // ShortTruthTableCell mod1 = + // (ShortTruthTableCell)c.getBoard().getModifiedData().iterator().next(); + // ShortTruthTableCell mod2 = + // (ShortTruthTableCell)c.getBoard().getModifiedData().iterator().next(); + // if (!(mod1.getType() == ShortTruthTableCellType.TRUE || mod1.getType() == + // ShortTruthTableCellType.FALSE || mod1.getType() == ShortTruthTableCellType.UNKNOWN) && + // (mod2.getType() == ShortTruthTableCellType.TRUE || mod2.getType() == + // ShortTruthTableCellType.FALSE || mod2.getType() == ShortTruthTableCellType.UNKNOWN)) { + // return "ERROR: This case rule must be an unknown, true, or false cell."; + // } + // } + return null; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return checkRuleRaw(transition); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java index 0e25586a8..8aeb51a46 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/caserule/CaseRule_GenericStatement.java @@ -3,22 +3,25 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableStatement; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; - -import java.util.List; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableStatement; import java.util.ArrayList; +import java.util.List; public abstract class CaseRule_GenericStatement extends CaseRule_Generic { - public CaseRule_GenericStatement(String ruleID, char operation, String title, - ShortTruthTableCellType[][] trueCases, - ShortTruthTableCellType[][] falseCases) { - super(ruleID, ShortTruthTableOperation.getRuleName(operation), + public CaseRule_GenericStatement( + String ruleID, + char operation, + String title, + ShortTruthTableCellType[][] trueCases, + ShortTruthTableCellType[][] falseCases) { + super( + ruleID, + ShortTruthTableOperation.getRuleName(operation), title + " case", "A known " + title.toUpperCase() + " statement can have multiple forms"); @@ -40,25 +43,33 @@ public CaseRule_GenericStatement(String ruleID, char operation, String title, // Adds all elements that can be selected for this caserule @Override public CaseBoard getCaseBoard(Board board) { - //copy the board and add all elements that can be selected + // copy the board and add all elements that can be selected ShortTruthTableBoard sttBoard = (ShortTruthTableBoard) board.copy(); sttBoard.setModifiable(false); CaseBoard caseBoard = new CaseBoard(sttBoard, this); - //add all elements that can be selected for the case rule statement + // add all elements that can be selected for the case rule statement for (PuzzleElement element : sttBoard.getPuzzleElements()) { - //get the cell object + // get the cell object ShortTruthTableCell cell = sttBoard.getCellFromElement(element); - //the cell must match the symbol + // the cell must match the symbol if (cell.getSymbol() != this.operation) continue; - //the statement must be assigned with unassigned sub-statements + // the statement must be assigned with unassigned sub-statements if (!cell.getType().isTrueOrFalse()) continue; - if (cell.getStatementReference().getRightStatement().getCell().getType().isTrueOrFalse()) continue; - if (this.operation != ShortTruthTableOperation.NOT && - cell.getStatementReference().getRightStatement().getCell().getType().isTrueOrFalse()) { + if (cell.getStatementReference() + .getRightStatement() + .getCell() + .getType() + .isTrueOrFalse()) continue; + if (this.operation != ShortTruthTableOperation.NOT + && cell.getStatementReference() + .getRightStatement() + .getCell() + .getType() + .isTrueOrFalse()) { continue; } - //if the element has passed all the checks, it can be selected + // if the element has passed all the checks, it can be selected caseBoard.addPickableElement(element); } return caseBoard; @@ -67,13 +78,18 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ @SuppressWarnings("unchecked") @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + + if (puzzleElement == null) { + return new ArrayList(); + } + ShortTruthTableBoard sttBoard = ((ShortTruthTableBoard) board); ShortTruthTableCell cell = sttBoard.getCellFromElement(puzzleElement); @@ -86,12 +102,16 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { /** * Collects a list of boards for each possible outcome of case-rule application + * * @param board current board state * @param puzzleElement case rule operator * @param possibilities list of possibilities for operator state * @return ArrayList of Boards */ - private ArrayList getCasesFromCell(ShortTruthTableBoard board, PuzzleElement puzzleElement, ShortTruthTableCellType[][] possibilities) { + private ArrayList getCasesFromCell( + ShortTruthTableBoard board, + PuzzleElement puzzleElement, + ShortTruthTableCellType[][] possibilities) { // Create branch case for each possibility ArrayList cases = new ArrayList<>(); for (int i = 0; i < possibilities.length; i++) { @@ -116,19 +136,19 @@ private ArrayList getCasesFromCell(ShortTruthTableBoard board, PuzzleElem } return cases; } - - /** - * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid - * Overridden by case rules dependent on more than just the modified data + + /** + * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be + * valid Overridden by case rules dependent on more than just the modified data * - * @param board board state at application + * @param board board state at application * @param puzzleElement selected puzzleElement - * @return List of puzzle elements (typically cells) this application of the case rule depends upon. - * Defaults to any element modified by any case + * @return List of puzzle elements (typically cells) this application of the case rule depends + * upon. Defaults to any element modified by any case */ @Override public List dependentElements(Board board, PuzzleElement puzzleElement) { - List elements = super.dependentElements(board,puzzleElement); + List elements = super.dependentElements(board, puzzleElement); elements.add(board.getPuzzleElement(puzzleElement)); diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleAnd.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleAnd.java index aa0da52c3..595dd0cb2 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleAnd.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleAnd.java @@ -1,22 +1,22 @@ package edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; public class ContradictionRuleAnd extends ContradictionRule_GenericStatement { public ContradictionRuleAnd() { - super("STTT-CONT-0001", "Contradicting And", + super( + "STTT-CONT-0001", + "Contradicting And", "An AND statement must have a contradicting pattern", "edu/rpi/legup/images/shorttruthtable/ruleimages/contradiction/And.png", ShortTruthTableOperation.AND, - new ShortTruthTableCellType[][]{ - {n, T, F}, - {F, T, n}, - // {F, T, F}, - {T, F, T}, - } - ); + new ShortTruthTableCellType[][] { + {n, T, F}, + {F, T, n}, + // {F, T, F}, + {T, F, T}, + }); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleAtomic.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleAtomic.java index 2d1efb945..879b7c9a5 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleAtomic.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleAtomic.java @@ -1,36 +1,31 @@ package edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction; - import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.ContradictionRule; - import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableStatement; - -import java.util.Set; import java.util.Iterator; - +import java.util.Set; public class ContradictionRuleAtomic extends ContradictionRule { - public ContradictionRuleAtomic() { - super("STTT-CONT-0002", "Contradicting Variable", + super( + "STTT-CONT-0002", + "Contradicting Variable", "A single variable can not be both True and False", "edu/rpi/legup/images/shorttruthtable/ruleimages/contradiction/Atomic.png"); } - @Override public String checkContradictionAt(Board puzzleBoard, PuzzleElement puzzleElement) { - //cast the board toa shortTruthTableBoard + // cast the board toa shortTruthTableBoard ShortTruthTableBoard board = (ShortTruthTableBoard) puzzleBoard; - //get the cell that contradicts another cell in the board + // get the cell that contradicts another cell in the board ShortTruthTableCell cell = (ShortTruthTableCell) board.getPuzzleElement(puzzleElement); if (!cell.isVariable()) { @@ -40,26 +35,25 @@ public String checkContradictionAt(Board puzzleBoard, PuzzleElement puzzleElemen ShortTruthTableCellType cellType = cell.getType(); if (!cellType.isTrueOrFalse()) { - return "Can only check for a contradiction against a cell that is assigned a value of True or False"; + return "Can only check for a contradiction against a cell that is assigned a value of" + + " True or False"; } - //get all the cells with the same value + // get all the cells with the same value Set varCells = board.getCellsWithSymbol(cell.getSymbol()); - //check if there are any contradictions + // check if there are any contradictions Iterator itr = varCells.iterator(); while (itr.hasNext()) { ShortTruthTableCell checkCell = itr.next(); ShortTruthTableCellType checkCellType = checkCell.getType(); - //if there is an assigned contradiction, return null + // if there is an assigned contradiction, return null if (checkCellType.isTrueOrFalse() && checkCellType != cellType) { return null; } } - //if it made it through the while loop, thene there is no contradiction + // if it made it through the while loop, thene there is no contradiction return "There is no contradiction for the variable " + cell.getSymbol(); - } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleBiconditional.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleBiconditional.java index bf215358a..bae07acce 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleBiconditional.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleBiconditional.java @@ -1,22 +1,22 @@ package edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; public class ContradictionRuleBiconditional extends ContradictionRule_GenericStatement { public ContradictionRuleBiconditional() { - super("STTT-CONT-0003", "Contradicting Biconditional", + super( + "STTT-CONT-0003", + "Contradicting Biconditional", "A Biconditional statement must have a contradicting pattern", "edu/rpi/legup/images/shorttruthtable/ruleimages/contradiction/Biconditional.png", ShortTruthTableOperation.BICONDITIONAL, - new ShortTruthTableCellType[][]{ - {T, T, F}, - {F, T, T}, - {T, F, T}, - {F, F, F} - } - ); + new ShortTruthTableCellType[][] { + {T, T, F}, + {F, T, T}, + {T, F, T}, + {F, F, F} + }); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleConditional.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleConditional.java index caa65afa4..e3a51a00e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleConditional.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleConditional.java @@ -1,21 +1,21 @@ package edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; public class ContradictionRuleConditional extends ContradictionRule_GenericStatement { public ContradictionRuleConditional() { - super("STTT-CONT-0004", "Contradicting Conditional", + super( + "STTT-CONT-0004", + "Contradicting Conditional", "A Conditional statement must have a contradicting pattern", "edu/rpi/legup/images/shorttruthtable/ruleimages/contradiction/Conditional.png", ShortTruthTableOperation.CONDITIONAL, - new ShortTruthTableCellType[][]{ - {n, F, T}, - {F, F, n}, - {T, T, F} - } - ); + new ShortTruthTableCellType[][] { + {n, F, T}, + {F, F, n}, + {T, T, F} + }); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleNot.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleNot.java index 4be059a06..4e20485bc 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleNot.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleNot.java @@ -1,20 +1,20 @@ package edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; public class ContradictionRuleNot extends ContradictionRule_GenericStatement { public ContradictionRuleNot() { - super("STTT-CONT-0005", "Contradicting Negation", + super( + "STTT-CONT-0005", + "Contradicting Negation", "A negation and its following statement can not have the same truth value", "edu/rpi/legup/images/shorttruthtable/ruleimages/contradiction/Not.png", ShortTruthTableOperation.NOT, - new ShortTruthTableCellType[][]{ - {n, T, T}, - {n, F, F} - } - ); + new ShortTruthTableCellType[][] { + {n, T, T}, + {n, F, F} + }); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleOr.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleOr.java index 46fee2a44..2ab197dad 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleOr.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRuleOr.java @@ -1,21 +1,21 @@ package edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction; -import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableOperation; public class ContradictionRuleOr extends ContradictionRule_GenericStatement { public ContradictionRuleOr() { - super("STTT-CONT-0006", "Contradicting Or", + super( + "STTT-CONT-0006", + "Contradicting Or", "An OR statement must have a contradicting pattern", "edu/rpi/legup/images/shorttruthtable/ruleimages/contradiction/Or.png", ShortTruthTableOperation.OR, - new ShortTruthTableCellType[][]{ - {n, F, T}, - {T, F, n}, - {F, T, F} - } - ); + new ShortTruthTableCellType[][] { + {n, F, T}, + {T, F, n}, + {F, T, F} + }); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRule_GenericStatement.java b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRule_GenericStatement.java index 4554e5100..87b1ba628 100644 --- a/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRule_GenericStatement.java +++ b/src/main/java/edu/rpi/legup/puzzle/shorttruthtable/rules/contradiction/ContradictionRule_GenericStatement.java @@ -1,31 +1,36 @@ package edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction; - import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.ContradictionRule; - import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableStatement; - public abstract class ContradictionRule_GenericStatement extends ContradictionRule { private final char operationSymbol; private final ShortTruthTableCellType[][] contradictionPatterns; - final static ShortTruthTableCellType T = ShortTruthTableCellType.TRUE; - final static ShortTruthTableCellType F = ShortTruthTableCellType.FALSE; - final static ShortTruthTableCellType n = null; - - private final String NOT_RIGHT_OPERATOR_ERROR_MESSAGE = "This cell does not contain the correct operation"; - private final String NOT_TRUE_FALSE_ERROR_MESSAGE = "Can only check for a contradiction on a cell that is assigned a value of True or False"; - - public ContradictionRule_GenericStatement(String ruleID, String ruleName, String description, String imageName, - char operationSymbol, ShortTruthTableCellType[][] contradictionPatterns) { + static final ShortTruthTableCellType T = ShortTruthTableCellType.TRUE; + static final ShortTruthTableCellType F = ShortTruthTableCellType.FALSE; + static final ShortTruthTableCellType n = null; + + private final String NOT_RIGHT_OPERATOR_ERROR_MESSAGE = + "This cell does not contain the correct operation"; + private final String NOT_TRUE_FALSE_ERROR_MESSAGE = + "Can only check for a contradiction on a cell that is assigned a value of True or" + + " False"; + + public ContradictionRule_GenericStatement( + String ruleID, + String ruleName, + String description, + String imageName, + char operationSymbol, + ShortTruthTableCellType[][] contradictionPatterns) { super(ruleID, ruleName, description, imageName); this.operationSymbol = operationSymbol; this.contradictionPatterns = contradictionPatterns; @@ -42,7 +47,9 @@ public String checkContradictionAt(Board puzzleBoard, PuzzleElement operatorPuzz ShortTruthTableStatement statement = cell.getStatementReference(); if (cell.getSymbol() != this.operationSymbol) { - return super.getInvalidUseOfRuleMessage() + ": " + this.NOT_RIGHT_OPERATOR_ERROR_MESSAGE; + return super.getInvalidUseOfRuleMessage() + + ": " + + this.NOT_RIGHT_OPERATOR_ERROR_MESSAGE; } // check that the initial statement is assigned @@ -63,13 +70,14 @@ public String checkContradictionAt(Board puzzleBoard, PuzzleElement operatorPuzz if (pattern[i] == null) { continue; } - //if it is not null, it must match the test pattern + // if it is not null, it must match the test pattern if (pattern[i] != testPattern[i]) { matches = false; break; } } - // if testPattern matches one of the valid contradiction patterns, the contradiction is correct + // if testPattern matches one of the valid contradiction patterns, the contradiction is + // correct if (matches) { return null; } @@ -77,4 +85,4 @@ public String checkContradictionAt(Board puzzleBoard, PuzzleElement operatorPuzz return super.getNoContradictionMessage(); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java index f87462978..44f416cef 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java @@ -18,9 +18,7 @@ public Skyscrapers() { this.factory = new SkyscrapersCellFactory(); } - /** - * Initializes the game board. Called by the invoker of the class - */ + /** Initializes the game board. Called by the invoker of the class */ @Override public void initializeView() { boardView = new SkyscrapersView((SkyscrapersBoard) currentBoard); @@ -43,12 +41,12 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Skyscrapers * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Skyscrapers, false otherwise */ public boolean isValidDimensions(int rows, int columns) { - return rows >= 4 && rows == columns; + return rows >= 3 && rows == columns; } /** @@ -82,7 +80,5 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { - - } + public void onBoardChange(Board board) {} } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java index 5834ab7ac..0fc133786 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java @@ -3,7 +3,6 @@ import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.*; import java.awt.event.MouseEvent; import java.util.ArrayList; @@ -11,15 +10,14 @@ public class SkyscrapersBoard extends GridBoard { - private ArrayList eastClues; - //EAST clues + // EAST clues private ArrayList southClues; - //SOUTH clues + // SOUTH clues private ArrayList westClues; - //WEST clues + // WEST clues private ArrayList northClues; - //NORTH clues + // NORTH clues private boolean viewFlag = false; private boolean dupeFlag = false; @@ -40,10 +38,9 @@ public SkyscrapersBoard(int size) { } } - /** - * @return eastClues a list of the eastern clues ordered from loc.y = 0 to max - */ + * @return eastClues a list of the eastern clues ordered from loc.y = 0 to max + */ public ArrayList getEastClues() { return eastClues; } @@ -103,7 +100,6 @@ public PuzzleElement getPuzzleElement(PuzzleElement element) { return super.getPuzzleElement(element); } - /** * Gets the cells of a certain type directly adjacent to a given cell * @@ -176,8 +172,7 @@ public List getRowCol(int index, SkyscrapersType type, boolean SkyscrapersCell cell; if (isRow) { cell = getCell(i, index); - } - else { + } else { cell = getCell(index, i); } @@ -188,16 +183,13 @@ public List getRowCol(int index, SkyscrapersType type, boolean return list; } - /** - * Prints a semblance of the board to console (helps in debugging) - */ + /** Prints a semblance of the board to console (helps in debugging) */ public void printBoard() { for (int i = 0; i < this.dimension.height; i++) { for (SkyscrapersCell cell : this.getRowCol(i, SkyscrapersType.ANY, true)) { if (cell.getType() == SkyscrapersType.Number) { System.out.print(cell.getData() + " "); - } - else { + } else { System.out.print(0 + " "); } } @@ -206,46 +198,40 @@ public void printBoard() { } /** - * * @param x position of cell * @param y position of cell * @param e Element to be placed (null if nothing selected) - * @param m MouseEvent - * Increases clue values if in editor mode. Currently allows for - * presetting tile values, though they will not be saved. + * @param m MouseEvent Increases clue values if in editor mode. Currently allows for presetting + * tile values, though they will not be saved. */ @Override public void setCell(int x, int y, Element e, MouseEvent m) { SkyscrapersClue clue = this.getClue(x, y); if (e == null) return; if (clue != null) { - if (!e.getElementID().equals("SKYS-UNPL-0003")) + if (!e.getElementID().equals("SKYS-ELEM-0001")) { return; + } if (m.getButton() == MouseEvent.BUTTON1) { if (clue.getData() < dimension.height) { clue.setData(clue.getData() + 1); + } else { + clue.setData(1); } - else { - clue.setData(0); - } - } - else { - if (clue.getData() > 0) { + } else { + if (clue.getData() > 1) { clue.setData(clue.getData() - 1); - } - else { + } else { clue.setData(dimension.height); } } - } - else { + } else { super.setCell(x - 1, y - 1, e, m); } } /** - * * @param x position of element on boardView * @param y position of element on boardView * @return The clue at the given position @@ -253,16 +239,13 @@ public void setCell(int x, int y, Element e, MouseEvent m) { public SkyscrapersClue getClue(int x, int y) { int viewIndex = getSize() + 1; if (x == 0 && y > 0 && y < viewIndex) { - return westClues.get(y-1); - } - else if (x == viewIndex && y > 0 && y < viewIndex) { - return eastClues.get(y-1); - } - else if (y == 0 && x > 0 && x < viewIndex) { - return northClues.get(x-1); - } - else if (y == viewIndex && x > 0 && x < viewIndex) { - return southClues.get(x-1); + return westClues.get(y - 1); + } else if (x == viewIndex && y > 0 && y < viewIndex) { + return eastClues.get(y - 1); + } else if (y == 0 && x > 0 && x < viewIndex) { + return northClues.get(x - 1); + } else if (y == viewIndex && x > 0 && x < viewIndex) { + return southClues.get(x - 1); } return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java index 409555b83..9e7283b20 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCell.java @@ -1,13 +1,12 @@ package edu.rpi.legup.puzzle.skyscrapers; +import static edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType.convertToSkyType; + import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; import java.awt.event.MouseEvent; -import static edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType.convertToSkyType; - public class SkyscrapersCell extends GridCell { private int max; @@ -17,7 +16,7 @@ public SkyscrapersCell(Integer value, Point location, int size) { } public SkyscrapersType getType() { - switch (convertToSkyType(data)){ + switch (convertToSkyType(data)) { case UNKNOWN: return SkyscrapersType.UNKNOWN; default: @@ -27,25 +26,23 @@ public SkyscrapersType getType() { @Override public void setType(Element e, MouseEvent m) { - switch (e.getElementID()){ - case "SKYS-UNPL-0001": + switch (e.getElementID()) { + case "SKYS-ELEM-0002": this.data = 0; break; - case "SKYS-UNPL-0002": - switch (m.getButton()){ + case "SKYS-ELEM-0001": + switch (m.getButton()) { case MouseEvent.BUTTON1: if (this.data <= 0 || this.data >= this.max) { this.data = 1; - } - else { + } else { this.data = this.data + 1; } break; case MouseEvent.BUTTON3: if (this.data > 1) { this.data = this.data - 1; - } - else { + } else { this.data = this.max; } break; @@ -54,7 +51,6 @@ public void setType(Element e, MouseEvent m) { } } - public int getMax() { return max; } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCellFactory.java index 5f6de7369..03572b816 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersCellFactory.java @@ -4,17 +4,16 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class SkyscrapersCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if input is invalid @@ -23,7 +22,8 @@ public class SkyscrapersCellFactory extends ElementFactory { public PuzzleElement importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("Skyscrapers Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "Skyscrapers Factory: unknown puzzleElement puzzleElement"); } SkyscrapersBoard skyscrapersBoard = (SkyscrapersBoard) board; @@ -34,7 +34,8 @@ public PuzzleElement importCell(Node node, Board board) throws InvalidFileFormat int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); if (x >= size || y >= size) { - throw new InvalidFileFormatException("Skyscrapers Factory: cell location out of bounds"); + throw new InvalidFileFormatException( + "Skyscrapers Factory: cell location out of bounds"); } if (value < 0 || value > size) { throw new InvalidFileFormatException("Skyscrapers Factory: cell unknown value"); @@ -44,19 +45,19 @@ public PuzzleElement importCell(Node node, Board board) throws InvalidFileFormat cell.setIndex(y * size + x); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Skyscrapers Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { - throw new InvalidFileFormatException("Skyscrapers Factory: could not find attribute(s)"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Skyscrapers Factory: unknown value where integer expected"); + } catch (NullPointerException e) { + throw new InvalidFileFormatException( + "Skyscrapers Factory: could not find attribute(s)"); } } /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClue.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClue.java index 1e7b1b45e..7b8bf635b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClue.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClue.java @@ -9,7 +9,7 @@ public class SkyscrapersClue extends PuzzleElement { public SkyscrapersClue(int value, int clueIndex, SkyscrapersType type) { super(value); this.index = -2; - this.clueIndex = clueIndex;//index in list + this.clueIndex = clueIndex; // index in list this.type = type; this.setModifiable(false); } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java index 649f85f4e..0e6345ff1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.skyscrapers; import edu.rpi.legup.ui.boardview.ElementView; - import java.awt.*; public class SkyscrapersClueView extends ElementView { @@ -26,11 +25,11 @@ public SkyscrapersClue getPuzzleElement() { @Override public void draw(Graphics2D graphics2D) { drawElement(graphics2D); + if (this.isHover()) { + drawHover(graphics2D); + } if (this.isShowCasePicker() && this.isCaseRulePickable()) { drawCase(graphics2D); - if (this.isHover()) { - drawHover(graphics2D); - } } } @@ -55,6 +54,19 @@ public void drawElement(Graphics2D graphics2D) { int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + + // REPRESENT NO CLUE AS EMPTY STRING INSTEAD OF 0, SOLVING PUZZLES WITH NO CLUE IS CURRENTLY NOT WORKING + // IF YOU ARE IMPLEMENTING NO CLUE FUNCTIONALITY, UNCOMMENT BELOW CODE AND DELETE OTHER IF STATEMENT, + // ADDITIONALLY, GO TO SkyscrapersBoard AND EDIT LINES 220 AND 223 SO YOU CAN CYCLE FOR NO CLUE + // IN THE SKYSCRAPERS PUZZLE EDITOR +// if (value.equals("0")) { +// value = ""; +// } + if (value.equals("0")) { + value = "1"; + clue.setData(1); + } + graphics2D.drawString(value, xText, yText); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersController.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersController.java index 8e338a351..f78774e35 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersController.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersController.java @@ -2,7 +2,6 @@ import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.event.MouseEvent; public class SkyscrapersController extends ElementController { @@ -18,18 +17,15 @@ public void changeCell(MouseEvent e, PuzzleElement element) { if (cell.getData() < cell.getMax()) { int num = cell.getData() + 1; cell.setData(num); - } - else { + } else { cell.setData(SkyscrapersType.UNKNOWN.toValue()); } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() > 0) { int num = cell.getData() - 1; cell.setData(num); - } - else { + } else { cell.setData(cell.getMax()); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersElementView.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersElementView.java index 9884b4a3c..2f33017c3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.skyscrapers; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class SkyscrapersElementView extends GridElementView { @@ -30,7 +29,8 @@ public void drawElement(Graphics2D graphics2D) { FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = String.valueOf(val); int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(value, xText, yText); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersExporter.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersExporter.java index aee97bbd0..75d2bd04f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersExporter.java @@ -1,6 +1,7 @@ package edu.rpi.legup.puzzle.skyscrapers; import edu.rpi.legup.model.PuzzleExporter; +import edu.rpi.legup.model.gameboard.PuzzleElement; import org.w3c.dom.Document; public class SkyscrapersExporter extends PuzzleExporter { @@ -14,34 +15,53 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { SkyscrapersBoard board; if (puzzle.getTree() != null) { board = (SkyscrapersBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (SkyscrapersBoard) puzzle.getBoardView().getBoard(); } org.w3c.dom.Element boardElement = newDocument.createElement("board"); boardElement.setAttribute("size", String.valueOf(board.getWidth())); + org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + SkyscrapersCell cell = (SkyscrapersCell) puzzleElement; + if (cell.getData() != 0) { + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); + cellsElement.appendChild(cellElement); + } + } + boardElement.appendChild(cellsElement); + org.w3c.dom.Element axisEast = newDocument.createElement("axis"); axisEast.setAttribute("side", "east"); - for (int i=0; i northClues; private ArrayList eastClues; @@ -34,7 +33,8 @@ public SkyscrapersView(SkyscrapersBoard board) { SkyscrapersElementView elementView = new SkyscrapersElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point((loc.x + 1) * elementSize.width, (loc.y + 1) * elementSize.height)); + elementView.setLocation( + new Point((loc.x + 1) * elementSize.width, (loc.y + 1) * elementSize.height)); elementViews.add(elementView); } @@ -44,7 +44,10 @@ public SkyscrapersView(SkyscrapersBoard board) { row.setSize(elementSize); SkyscrapersClueView clue = new SkyscrapersClueView(board.getEastClues().get(i)); - clue.setLocation(new Point((gridSize.height + 1) * elementSize.height, (i + 1) * elementSize.height)); + clue.setLocation( + new Point( + (gridSize.height + 1) * elementSize.height, + (i + 1) * elementSize.height)); clue.setSize(elementSize); westClues.add(row); @@ -57,7 +60,9 @@ public SkyscrapersView(SkyscrapersBoard board) { col.setSize(elementSize); SkyscrapersClueView clue = new SkyscrapersClueView(board.getSouthClues().get(i)); - clue.setLocation(new Point((i + 1) * elementSize.width, (gridSize.width + 1) * elementSize.width)); + clue.setLocation( + new Point( + (i + 1) * elementSize.width, (gridSize.width + 1) * elementSize.width)); clue.setSize(elementSize); northClues.add(col); @@ -66,15 +71,18 @@ public SkyscrapersView(SkyscrapersBoard board) { } /** - * Gets the ElementView from the location specified or - * null if one does not exists at that location + * Gets the ElementView from the location specified or null if one does not exists at that + * location * * @param point location on the viewport * @return ElementView at the specified location */ @Override public ElementView getElement(Point point) { - Point scaledPoint = new Point((int) Math.round(point.x / getScale()), (int) Math.round(point.y / getScale())); + Point scaledPoint = + new Point( + (int) Math.round(point.x / getScale()), + (int) Math.round(point.y / getScale())); for (ElementView element : elementViews) { if (element.isWithinBounds(scaledPoint)) { return element; @@ -131,10 +139,10 @@ public void setBoard(Board board) { if (board instanceof CaseBoard) { setCasePickable(); - } - else { + } else { for (ElementView elementView : elementViews) { - elementView.setPuzzleElement(board.getPuzzleElement(elementView.getPuzzleElement())); + elementView.setPuzzleElement( + board.getPuzzleElement(elementView.getPuzzleElement())); elementView.setShowCasePicker(false); } for (SkyscrapersClueView clueView : northClues) { @@ -155,7 +163,8 @@ protected void setCasePickable() { Board baseBoard = caseBoard.getBaseBoard(); for (ElementView elementView : elementViews) { - PuzzleElement puzzleElement = baseBoard.getPuzzleElement(elementView.getPuzzleElement()); + PuzzleElement puzzleElement = + baseBoard.getPuzzleElement(elementView.getPuzzleElement()); elementView.setPuzzleElement(puzzleElement); elementView.setShowCasePicker(true); elementView.setCaseRulePickable(caseBoard.isPickable(puzzleElement, null)); diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java index 8f78fb1cf..f60e5fe8b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/NumberTile.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.skyscrapers.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class NumberTile extends NonPlaceableElement { +public class NumberTile extends PlaceableElement { public NumberTile() { - super("SKYS-UNPL-0002", "Number Tile", "A numbered tile", "edu/rpi/legup/images/skyscrapers/tiles/ClueTile.png"); + super( + "SKYS-ELEM-0001", + "Number Tile", + "A numbered tile", + "edu/rpi/legup/images/skyscrapers/tiles/ClueTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java index 3559dc332..07f6a1238 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/UnknownTile.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.skyscrapers.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { - super("SKYS-UNPL-0001", "Unknown", "A blank tile", "edu/rpi/legup/images/skyscrapers/tiles/UnknownTile.png"); + super( + "SKYS-ELEM-0002", + "Unknown", + "A blank tile", + "edu/rpi/legup/images/skyscrapers/tiles/UnknownTile.png"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt index 604e1824e..14e76a29d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/elements/skyscrapers_elements_reference_sheet.txt @@ -1,3 +1,2 @@ -SKYS-UNPL-0001: Unknown Tile -SKYS-UNPL-0002: Number Tile -SKYS-UNPL-0003: Clue "Tile" \ No newline at end of file +SKYS-ELEM-0001: NumberTile +SKYS-ELEM-0002: UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java index 01527294a..b48962c41 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java @@ -6,18 +6,16 @@ import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.skyscrapers.*; -import org.apache.commons.lang3.ObjectUtils; - -import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.List; -import java.util.Set; -import java.util.TreeSet; +import javax.swing.*; public class CellForNumberCaseRule extends CaseRule { public CellForNumberCaseRule() { - super("SKYS-CASE-0002", "Cell For Number", + super( + "SKYS-CASE-0002", + "Cell For Number", "A number (1-n) must appear in any given row/column", "edu/rpi/legup/images/skyscrapers/cases/CellForNumber.png"); } @@ -30,15 +28,15 @@ public CaseBoard getCaseBoard(Board board) { currentBoard.setModifiable(false); CaseBoard caseBoard = new CaseBoard(currentBoard, this); for (SkyscrapersClue data : currentBoard.getWestClues()) { - //System.out.println(data.getType()); + // System.out.println(data.getType()); caseBoard.addPickableElement(data); } for (SkyscrapersClue data : currentBoard.getNorthClues()) { - //System.out.println(data.getType()); + // System.out.println(data.getType()); caseBoard.addPickableElement(data); } - //selects integer before checking Command.canExecute for use in Command.getErrorString + // selects integer before checking Command.canExecute for use in Command.getErrorString int size = ((SkyscrapersBoard) board).getWidth(); Object[] possibleValues = new Object[size]; for (int i = 0; i < size; i++) { @@ -46,12 +44,16 @@ public CaseBoard getCaseBoard(Board board) { } Object selectedValue; do { - selectedValue = JOptionPane.showInputDialog(null, - "Pick the number to be added", "Cell For Number", - JOptionPane.INFORMATION_MESSAGE, null, - possibleValues, possibleValues[0]); - } - while (selectedValue == null); + selectedValue = + JOptionPane.showInputDialog( + null, + "Pick the number to be added", + "Cell For Number", + JOptionPane.INFORMATION_MESSAGE, + null, + possibleValues, + possibleValues[0]); + } while (selectedValue == null); selectedNumber = (Integer) selectedValue; return caseBoard; @@ -59,32 +61,38 @@ public CaseBoard getCaseBoard(Board board) { public ArrayList getCasesFor(Board board, PuzzleElement puzzleElement, Integer number) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } SkyscrapersClue clue = (SkyscrapersClue) puzzleElement; SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; - List openCells = skyscrapersboard.getRowCol(clue.getClueIndex(), SkyscrapersType.UNKNOWN, clue.getType() == SkyscrapersType.CLUE_WEST); + List openCells = + skyscrapersboard.getRowCol( + clue.getClueIndex(), + SkyscrapersType.UNKNOWN, + clue.getType() == SkyscrapersType.CLUE_WEST); for (SkyscrapersCell cell : openCells) { SkyscrapersBoard newCase = skyscrapersboard.copy(); PuzzleElement newCell = newCase.getPuzzleElement(cell); newCell.setData(number); newCase.addModifiedData(newCell); - //if flags + // if flags boolean passed = true; if (skyscrapersboard.getDupeFlag()) { DuplicateNumberContradictionRule DupeRule = new DuplicateNumberContradictionRule(); passed = passed && DupeRule.checkContradictionAt(newCase, newCell) != null; } if (skyscrapersboard.getViewFlag()) { - PreemptiveVisibilityContradictionRule ViewRule = new PreemptiveVisibilityContradictionRule(); + PreemptiveVisibilityContradictionRule ViewRule = + new PreemptiveVisibilityContradictionRule(); passed = passed && ViewRule.checkContradictionAt(newCase, newCell) != null; } if (passed) { cases.add(newCase); } - - } return cases; } @@ -102,20 +110,33 @@ public String checkRuleRaw(TreeTransition transition) { return "This case rule must have at least one child."; } - if (childTransitions.size() != getCasesFor(oldBoard, oldBoard.getPuzzleElement(transition.getSelection()), (Integer) childTransitions.get(0).getBoard().getModifiedData().iterator().next().getData()).size()) { - //System.out.println("Wrong number of cases."); + if (childTransitions.size() + != getCasesFor( + oldBoard, + oldBoard.getPuzzleElement(transition.getSelection()), + (Integer) + childTransitions + .get(0) + .getBoard() + .getModifiedData() + .iterator() + .next() + .getData()) + .size()) { + // System.out.println("Wrong number of cases."); return "Wrong number of cases."; } for (TreeTransition newTree : childTransitions) { SkyscrapersBoard newBoard = (SkyscrapersBoard) newTree.getBoard(); if (newBoard.getModifiedData().size() != 1) { - //System.out.println("Only one cell should be modified."); + // System.out.println("Only one cell should be modified."); return "Only one cell should be modified."; } - SkyscrapersCell newCell = (SkyscrapersCell) newBoard.getModifiedData().iterator().next(); + SkyscrapersCell newCell = + (SkyscrapersCell) newBoard.getModifiedData().iterator().next(); if (newCell.getType() != SkyscrapersType.Number) { - //System.out.println("Changed value should be a number."); + // System.out.println("Changed value should be a number."); return "Changed value should be a number."; } } @@ -128,37 +149,45 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid - * Overridden by case rules dependent on more than just the modified data + * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be + * valid Overridden by case rules dependent on more than just the modified data * - * @param board board state at application + * @param board board state at application * @param puzzleElement selected puzzleElement - * @return List of puzzle elements (typically cells) this application of the case rule depends upon. - * Defaults to any element modified by any case + * @return List of puzzle elements (typically cells) this application of the case rule depends + * upon. Defaults to any element modified by any case */ @Override public List dependentElements(Board board, PuzzleElement puzzleElement) { List elements = new ArrayList<>(); SkyscrapersBoard puzzleBoard = (SkyscrapersBoard) board; - SkyscrapersClue clue = (SkyscrapersClue)puzzleBoard.getPuzzleElement(puzzleElement); + SkyscrapersClue clue = (SkyscrapersClue) puzzleBoard.getPuzzleElement(puzzleElement); // check each point in modified row/col - List data = puzzleBoard.getRowCol(clue.getClueIndex(),SkyscrapersType.ANY,clue.getType() == SkyscrapersType.CLUE_WEST); + List data = + puzzleBoard.getRowCol( + clue.getClueIndex(), + SkyscrapersType.ANY, + clue.getType() == SkyscrapersType.CLUE_WEST); for (SkyscrapersCell point : data) { List cells = new ArrayList<>(List.of(point)); // if dependent on row/col - if ((puzzleBoard.getDupeFlag() || puzzleBoard.getViewFlag()) && point.getType() == SkyscrapersType.UNKNOWN) { + if ((puzzleBoard.getDupeFlag() || puzzleBoard.getViewFlag()) + && point.getType() == SkyscrapersType.UNKNOWN) { // get perpendicular row/col intersecting this point int index; if (clue.getType() == SkyscrapersType.CLUE_WEST) { index = point.getLocation().x; - } - else { + } else { index = point.getLocation().y; } - cells.addAll(puzzleBoard.getRowCol(index,SkyscrapersType.ANY,clue.getType() != SkyscrapersType.CLUE_WEST)); + cells.addAll( + puzzleBoard.getRowCol( + index, + SkyscrapersType.ANY, + clue.getType() != SkyscrapersType.CLUE_WEST)); } // add all to result diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/DuplicateNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/DuplicateNumberContradictionRule.java index db5357fbe..b13a62bc6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/DuplicateNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/DuplicateNumberContradictionRule.java @@ -6,7 +6,6 @@ import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - import java.awt.*; import java.util.HashSet; import java.util.Set; @@ -14,34 +13,39 @@ public class DuplicateNumberContradictionRule extends ContradictionRule { public DuplicateNumberContradictionRule() { - super("SKYS-CONT-0001", "Duplicate Number", + super( + "SKYS-CONT-0001", + "Duplicate Number", "Skyscrapers of same height cannot be placed in the same row or column.", "edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { - //TODO:? Refactor to count each row/col once rather than per cell (override checkContradiction) SkyscrapersCell cell = (SkyscrapersCell) puzzleElement; SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; Point loc = cell.getLocation(); Set candidates = new HashSet(); - //check row + // check row for (int i = 0; i < skyscrapersboard.getWidth(); i++) { SkyscrapersCell c = skyscrapersboard.getCell(i, loc.y); - if (i != loc.x && cell.getType() == SkyscrapersType.Number && c.getType() == SkyscrapersType.Number && c.getData() == cell.getData()) { - System.out.print(c.getData()); - System.out.println(cell.getData()); + if (i != loc.x + && cell.getType() == SkyscrapersType.Number + && c.getType() == SkyscrapersType.Number + && c.getData() == cell.getData()) { + // System.out.print(c.getData()); + // System.out.println(cell.getData()); return null; } } @@ -49,9 +53,12 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { // check column for (int i = 0; i < skyscrapersboard.getHeight(); i++) { SkyscrapersCell c = skyscrapersboard.getCell(loc.x, i); - if (i != loc.y && cell.getType() == SkyscrapersType.Number && c.getType() == SkyscrapersType.Number && c.getData() == cell.getData()) { - System.out.print(c.getData()); - System.out.println(cell.getData()); + if (i != loc.y + && cell.getType() == SkyscrapersType.Number + && c.getType() == SkyscrapersType.Number + && c.getData() == cell.getData()) { + // System.out.print(c.getData()); + // System.out.println(cell.getData()); return null; } } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/ExceedingVisibilityContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/ExceedingVisibilityContradictionRule.java index efa905ea2..742bdb253 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/ExceedingVisibilityContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/ExceedingVisibilityContradictionRule.java @@ -6,28 +6,28 @@ import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - import java.awt.*; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; public class ExceedingVisibilityContradictionRule extends ContradictionRule { public ExceedingVisibilityContradictionRule() { - super("SKYS-CONT-0002", "Exceeding Visibility", + super( + "SKYS-CONT-0002", + "Exceeding Visibility", "More skyscrapers are visible than there should be.", "edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -35,22 +35,22 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; Point loc = cell.getLocation(); - //get borders + // get borders int west = skyscrapersboard.getWestClues().get(loc.y).getData(); int east = skyscrapersboard.getEastClues().get(loc.y).getData(); int north = skyscrapersboard.getNorthClues().get(loc.x).getData(); int south = skyscrapersboard.getSouthClues().get(loc.x).getData(); - //check row + // check row int max = 0; int count = 0; List row = skyscrapersboard.getRowCol(loc.y, SkyscrapersType.Number, true); if (row.size() == skyscrapersboard.getWidth()) { - //from west border + // from west border for (SkyscrapersCell c : row) { if (c.getData() > max) { - //System.out.print(c.getData()); - //System.out.println(cell.getData()); + // System.out.print(c.getData()); + // System.out.println(cell.getData()); max = c.getData(); count++; } @@ -61,12 +61,12 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { max = 0; count = 0; - //from east border + // from east border Collections.reverse(row); for (SkyscrapersCell c : row) { if (c.getData() > max) { - System.out.print(c.getData()); - //System.out.println(cell.getData()); + // System.out.print(c.getData()); + // System.out.println(cell.getData()); max = c.getData(); count++; } @@ -76,17 +76,18 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - //check column - List col = skyscrapersboard.getRowCol(loc.x, SkyscrapersType.Number, false); + // check column + List col = + skyscrapersboard.getRowCol(loc.x, SkyscrapersType.Number, false); if (col.size() == skyscrapersboard.getHeight()) { - //from north border + // from north border max = 0; count = 0; for (SkyscrapersCell c : col) { - System.out.println(c.getData()); + // System.out.println(c.getData()); if (c.getData() > max) { - //System.out.println(cell.getData()); + // System.out.println(cell.getData()); max = c.getData(); count++; } @@ -95,15 +96,15 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return null; } - //from south border + // from south border max = 0; count = 0; Collections.reverse(col); for (SkyscrapersCell c : col) { - System.out.println(c.getData()); + // System.out.println(c.getData()); if (c.getData() > max) { - //System.out.println(cell.getData()); + // System.out.println(cell.getData()); max = c.getData(); count++; } @@ -113,7 +114,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - //System.out.print("Does not contain a contradiction at this index"); + // System.out.print("Does not contain a contradiction at this index"); return super.getNoContradictionMessage(); } @@ -127,7 +128,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { public String checkContradiction(Board board) { SkyscrapersBoard skyscrapersBoard = (SkyscrapersBoard) board; for (int i = 0; i < skyscrapersBoard.getWidth(); i++) { - //checks the middle diagonal (checkContradictionAt checks row/col off each) + // checks the middle diagonal (checkContradictionAt checks row/col off each) String checkStr = checkContradictionAt(board, skyscrapersBoard.getCell(i, i)); if (checkStr == null) { return checkStr; @@ -135,5 +136,4 @@ public String checkContradiction(Board board) { } return "No instance of the contradiction " + this.ruleName + " here"; } - } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/InsufficientVisibilityContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/InsufficientVisibilityContradictionRule.java index afc1b1341..fa7c9074e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/InsufficientVisibilityContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/InsufficientVisibilityContradictionRule.java @@ -6,28 +6,28 @@ import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - import java.awt.*; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; public class InsufficientVisibilityContradictionRule extends ContradictionRule { public InsufficientVisibilityContradictionRule() { - super("SKYS-CONT-0003", "Insufficient Visibility", + super( + "SKYS-CONT-0003", + "Insufficient Visibility", "Less skyscrapers are visible than there should be.", "edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -35,22 +35,23 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; Point loc = cell.getLocation(); - //get borders + // get borders int west = skyscrapersboard.getWestClues().get(loc.y).getData(); int east = skyscrapersboard.getEastClues().get(loc.y).getData(); int north = skyscrapersboard.getNorthClues().get(loc.x).getData(); int south = skyscrapersboard.getSouthClues().get(loc.x).getData(); - //check row + // check row int max = 0; int count = 0; - java.util.List row = skyscrapersboard.getRowCol(loc.y, SkyscrapersType.Number, true); + java.util.List row = + skyscrapersboard.getRowCol(loc.y, SkyscrapersType.Number, true); if (row.size() == skyscrapersboard.getWidth()) { - //from west border + // from west border for (SkyscrapersCell c : row) { if (c.getData() > max) { - System.out.print(c.getData()); - //System.out.println(cell.getData()); + // System.out.print(c.getData()); + // System.out.println(cell.getData()); max = c.getData(); count++; } @@ -61,12 +62,12 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { max = 0; count = 0; - //from east border + // from east border Collections.reverse(row); for (SkyscrapersCell c : row) { if (c.getData() > max) { - System.out.print(c.getData()); - //System.out.println(cell.getData()); + // System.out.print(c.getData()); + // System.out.println(cell.getData()); max = c.getData(); count++; } @@ -76,17 +77,18 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - //check column - List col = skyscrapersboard.getRowCol(loc.x, SkyscrapersType.Number, false); + // check column + List col = + skyscrapersboard.getRowCol(loc.x, SkyscrapersType.Number, false); if (col.size() == skyscrapersboard.getHeight()) { - //from north border + // from north border max = 0; count = 0; for (SkyscrapersCell c : col) { - System.out.println(c.getData()); + // System.out.println(c.getData()); if (c.getData() > max) { - //System.out.println(cell.getData()); + // System.out.println(cell.getData()); max = c.getData(); count++; } @@ -95,15 +97,15 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { return null; } - //from south border + // from south border max = 0; count = 0; Collections.reverse(col); for (SkyscrapersCell c : col) { - System.out.println(c.getData()); + // System.out.println(c.getData()); if (c.getData() > max) { - //System.out.println(cell.getData()); + // System.out.println(cell.getData()); max = c.getData(); count++; } @@ -113,7 +115,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { } } - //System.out.print("Does not contain a contradiction at this index"); + // System.out.print("Does not contain a contradiction at this index"); return super.getNoContradictionMessage(); } @@ -127,7 +129,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { public String checkContradiction(Board board) { SkyscrapersBoard skyscrapersBoard = (SkyscrapersBoard) board; for (int i = 0; i < skyscrapersBoard.getWidth(); i++) { - //checks the middle diagonal (checkContradictionAt checks row/col off each) + // checks the middle diagonal (checkContradictionAt checks row/col off each) String checkStr = checkContradictionAt(board, skyscrapersBoard.getCell(i, i)); if (checkStr == null) { return checkStr; diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularCellDirectRule.java index 541075167..391448781 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularCellDirectRule.java @@ -1,115 +1,129 @@ -package edu.rpi.legup.puzzle.skyscrapers.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - -import java.util.ArrayList; - -public class LastSingularCellDirectRule extends DirectRule { - - public LastSingularCellDirectRule() { - super("SKYS-BASC-0002", "Last Non-Duplicate Cell", - "There is only one cell on this row/col for this number that does not create a duplicate contradiction", - "edu/rpi/legup/images/skyscrapers/rules/LastCell.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SkyscrapersBoard initialBoard = (SkyscrapersBoard) transition.getParents().get(0).getBoard(); - SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); - SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); - SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(initCell.getType() == SkyscrapersType.UNKNOWN && finalCell.getType() == SkyscrapersType.Number)) { - return super.getInvalidUseOfRuleMessage() + ": Modified cells must be number"; - } - - //set all rules used by case rule to false except for dupe, get all cases - boolean dupeTemp = initialBoard.getDupeFlag(); - boolean viewTemp = initialBoard.getViewFlag(); - initialBoard.setDupeFlag(true); - initialBoard.setViewFlag(false); - CellForNumberCaseRule caseRule = new CellForNumberCaseRule(); - ArrayList XCandidates = caseRule.getCasesFor(initialBoard, initialBoard.getWestClues().get(finalCell.getLocation().y), (Integer) finalCell.getData()); - ArrayList YCandidates = caseRule.getCasesFor(initialBoard, initialBoard.getNorthClues().get(finalCell.getLocation().x), (Integer) finalCell.getData()); - initialBoard.setDupeFlag(dupeTemp); - initialBoard.setViewFlag(viewTemp); - - System.out.println(XCandidates.size()); - System.out.println(YCandidates.size()); - - //return null if either pass, both messages otherwise - String xCheck = candidateCheck(XCandidates, puzzleElement, finalCell); - String yCheck = candidateCheck(YCandidates, puzzleElement, finalCell); - if (xCheck == null || yCheck == null) { - return null; - } - return super.getInvalidUseOfRuleMessage() + "\nRow" + xCheck + "\nCol" + yCheck; - } - - //helper to check if candidate list is valid - private String candidateCheck(ArrayList candidates, PuzzleElement puzzleElement, SkyscrapersCell finalCell) { - if (candidates.size() == 1) { - if (((SkyscrapersCell) candidates.get(0).getPuzzleElement(puzzleElement)).getType() == SkyscrapersType.Number) { - if (candidates.get(0).getPuzzleElement(puzzleElement).getData() == finalCell.getData()) { - return null; - } - return ": Wrong number in the cell."; - } - return ": No case for this cell."; - } - return ": This cell is not forced."; - } - - private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { - SkyscrapersBoard emptyCase = board.copy(); - emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); - DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); - if (duplicate.checkContradictionAt(emptyCase, cell) == null) { - System.out.println("no contradiction ln"); - return true; - } - return false; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); - SkyscrapersBoard lightUpBoard = (SkyscrapersBoard) node.getBoard().copy(); - System.out.println(lightUpBoard.getPuzzleElements().size()); - for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { - System.out.println("123"); - SkyscrapersCell cell = (SkyscrapersCell) element; - if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { - //cell.setData(SkyscrapersType.BULB.value); - lightUpBoard.addModifiedData(cell); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.skyscrapers.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; +import java.util.ArrayList; + +public class LastSingularCellDirectRule extends DirectRule { + + public LastSingularCellDirectRule() { + super( + "SKYS-BASC-0002", + "Last Cell for Number", + "There is only one cell on this row/col for this number that does not create a" + + " duplicate contradiction", + "edu/rpi/legup/images/skyscrapers/rules/LastCell.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + SkyscrapersBoard initialBoard = + (SkyscrapersBoard) transition.getParents().get(0).getBoard(); + SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); + SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(initCell.getType() == SkyscrapersType.UNKNOWN + && finalCell.getType() == SkyscrapersType.Number)) { + return super.getInvalidUseOfRuleMessage() + ": Modified cells must be number"; + } + + // set all rules used by case rule to false except for dupe, get all cases + boolean dupeTemp = initialBoard.getDupeFlag(); + boolean viewTemp = initialBoard.getViewFlag(); + initialBoard.setDupeFlag(true); + initialBoard.setViewFlag(false); + CellForNumberCaseRule caseRule = new CellForNumberCaseRule(); + ArrayList XCandidates = + caseRule.getCasesFor( + initialBoard, + initialBoard.getWestClues().get(finalCell.getLocation().y), + (Integer) finalCell.getData()); + ArrayList YCandidates = + caseRule.getCasesFor( + initialBoard, + initialBoard.getNorthClues().get(finalCell.getLocation().x), + (Integer) finalCell.getData()); + initialBoard.setDupeFlag(dupeTemp); + initialBoard.setViewFlag(viewTemp); + + // System.out.println(XCandidates.size()); + // System.out.println(YCandidates.size()); + + // return null if either pass, both messages otherwise + String xCheck = candidateCheck(XCandidates, puzzleElement, finalCell); + String yCheck = candidateCheck(YCandidates, puzzleElement, finalCell); + if (xCheck == null || yCheck == null) { + return null; + } + return super.getInvalidUseOfRuleMessage() + "\nRow" + xCheck + "\nCol" + yCheck; + } + + // helper to check if candidate list is valid + private String candidateCheck( + ArrayList candidates, PuzzleElement puzzleElement, SkyscrapersCell finalCell) { + if (candidates.size() == 1) { + if (((SkyscrapersCell) candidates.get(0).getPuzzleElement(puzzleElement)).getType() + == SkyscrapersType.Number) { + if (candidates.get(0).getPuzzleElement(puzzleElement).getData() + == finalCell.getData()) { + return null; + } + return ": Wrong number in the cell."; + } + return ": No case for this cell."; + } + return ": This cell is not forced."; + } + + private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { + SkyscrapersBoard emptyCase = board.copy(); + emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); + DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); + if (duplicate.checkContradictionAt(emptyCase, cell) == null) { + System.out.println("no contradiction ln"); + return true; + } + return false; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); + SkyscrapersBoard lightUpBoard = (SkyscrapersBoard) node.getBoard().copy(); + // System.out.println(lightUpBoard.getPuzzleElements().size()); + for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { + SkyscrapersCell cell = (SkyscrapersCell) element; + if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { + // cell.setData(SkyscrapersType.BULB.value); + lightUpBoard.addModifiedData(cell); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularNumberDirectRule.java index 934496827..fceee0cd1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularNumberDirectRule.java @@ -1,98 +1,103 @@ -package edu.rpi.legup.puzzle.skyscrapers.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - -import java.util.ArrayList; - -public class LastSingularNumberDirectRule extends DirectRule { - - public LastSingularNumberDirectRule() { - super("SKYS-BASC-0003", "Last Non-Duplicate Number", - "There is only one number for this cell that does not create a duplicate contradiction", - "edu/rpi/legup/images/skyscrapers/rules/LastNumber.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SkyscrapersBoard initialBoard = (SkyscrapersBoard) transition.getParents().get(0).getBoard(); - SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); - SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); - SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); - if (initCell.getType() != SkyscrapersType.UNKNOWN || finalCell.getType() != SkyscrapersType.Number) { - return super.getInvalidUseOfRuleMessage() + ": Modified cells must transition from unknown to number"; - } - - //set all rules used by case rule to false except for dupe, get all cases - boolean dupeTemp = initialBoard.getDupeFlag(); - boolean viewTemp = initialBoard.getViewFlag(); - initialBoard.setDupeFlag(true); - initialBoard.setViewFlag(false); - NumberForCellCaseRule caseRule = new NumberForCellCaseRule(); - ArrayList candidates = caseRule.getCases(initialBoard, puzzleElement); - initialBoard.setDupeFlag(dupeTemp); - initialBoard.setViewFlag(viewTemp); - - //check if given value is the only remaining value - if (candidates.size() == 1) { - if (candidates.get(0).getPuzzleElement(puzzleElement).getData() == finalCell.getData()) { - return null; - } - return super.getInvalidUseOfRuleMessage() + ": Wrong number in the cell."; - } - return super.getInvalidUseOfRuleMessage() + ":This cell is not forced."; - } - - private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { - SkyscrapersBoard emptyCase = board.copy(); - emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); - DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); - if (duplicate.checkContradictionAt(emptyCase, cell) == null) { - System.out.println("no contradiction ln"); - return true; - } - return false; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); - SkyscrapersBoard lightUpBoard = (SkyscrapersBoard) node.getBoard().copy(); - System.out.println(lightUpBoard.getPuzzleElements().size()); - for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { - System.out.println("123"); - SkyscrapersCell cell = (SkyscrapersCell) element; - if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { - //cell.setData(SkyscrapersType.BULB.value); - lightUpBoard.addModifiedData(cell); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.skyscrapers.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; +import java.util.ArrayList; + +public class LastSingularNumberDirectRule extends DirectRule { + + public LastSingularNumberDirectRule() { + super( + "SKYS-BASC-0003", + "Last Number for Cell", + "There is only one number for this cell that does not create a duplicate" + + " contradiction", + "edu/rpi/legup/images/skyscrapers/rules/LastNumber.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + SkyscrapersBoard initialBoard = + (SkyscrapersBoard) transition.getParents().get(0).getBoard(); + SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); + SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); + if (initCell.getType() != SkyscrapersType.UNKNOWN + || finalCell.getType() != SkyscrapersType.Number) { + return super.getInvalidUseOfRuleMessage() + + ": Modified cells must transition from unknown to number"; + } + + // set all rules used by case rule to false except for dupe, get all cases + boolean dupeTemp = initialBoard.getDupeFlag(); + boolean viewTemp = initialBoard.getViewFlag(); + initialBoard.setDupeFlag(true); + initialBoard.setViewFlag(false); + NumberForCellCaseRule caseRule = new NumberForCellCaseRule(); + ArrayList candidates = caseRule.getCases(initialBoard, puzzleElement); + initialBoard.setDupeFlag(dupeTemp); + initialBoard.setViewFlag(viewTemp); + + // check if given value is the only remaining value + if (candidates.size() == 1) { + if (candidates.get(0).getPuzzleElement(puzzleElement).getData() + == finalCell.getData()) { + return null; + } + return super.getInvalidUseOfRuleMessage() + ": Wrong number in the cell."; + } + return super.getInvalidUseOfRuleMessage() + ":This cell is not forced."; + } + + private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { + SkyscrapersBoard emptyCase = board.copy(); + emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); + DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); + if (duplicate.checkContradictionAt(emptyCase, cell) == null) { + System.out.println("no contradiction ln"); + return true; + } + return false; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); + SkyscrapersBoard lightUpBoard = (SkyscrapersBoard) node.getBoard().copy(); + // System.out.println(lightUpBoard.getPuzzleElements().size()); + for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { + SkyscrapersCell cell = (SkyscrapersCell) element; + if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { + // cell.setData(SkyscrapersType.BULB.value); + lightUpBoard.addModifiedData(cell); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleCellDirectRule.java index 49dc33677..a853c657d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleCellDirectRule.java @@ -1,117 +1,132 @@ -package edu.rpi.legup.puzzle.skyscrapers.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - -import java.util.ArrayList; - -public class LastVisibleCellDirectRule extends DirectRule { - - public LastVisibleCellDirectRule() { - super("SKYS-BASC-0001", "Last Visible Cell", - "There is only one cell on this row/col for this number that does not create a visibility contradiction", - "edu/rpi/legup/images/skyscrapers/rules/FixedMax.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - //last cell for number based on preemptive visibility rules - SkyscrapersBoard initialBoard = (SkyscrapersBoard) transition.getParents().get(0).getBoard(); - SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); - SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); - SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); - if (initCell.getType() != SkyscrapersType.UNKNOWN || finalCell.getType() != SkyscrapersType.Number) { - return super.getInvalidUseOfRuleMessage() + ": Modified cells must transition from unknown to number"; - } - - //set all rules used by case rule to false except for dupe, get all cases - boolean dupeTemp = initialBoard.getDupeFlag(); - boolean viewTemp = initialBoard.getViewFlag(); - initialBoard.setDupeFlag(false); - initialBoard.setViewFlag(true); - CellForNumberCaseRule caseRule = new CellForNumberCaseRule(); - ArrayList XCandidates = caseRule.getCasesFor(initialBoard, initialBoard.getWestClues().get(finalCell.getLocation().y), (Integer) finalCell.getData()); - ArrayList YCandidates = caseRule.getCasesFor(initialBoard, initialBoard.getNorthClues().get(finalCell.getLocation().x), (Integer) finalCell.getData()); - initialBoard.setDupeFlag(dupeTemp); - initialBoard.setViewFlag(viewTemp); - - System.out.println(XCandidates.size()); - System.out.println(YCandidates.size()); - - //return null if either pass, both messages otherwise - String xCheck = candidateCheck(XCandidates, puzzleElement, finalCell); - String yCheck = candidateCheck(YCandidates, puzzleElement, finalCell); - if (xCheck == null || yCheck == null) { - return null; - } - return super.getInvalidUseOfRuleMessage() + "\nRow" + xCheck + "\nCol" + yCheck; - } - - //helper to check if candidate list is valid - private String candidateCheck(ArrayList candidates, PuzzleElement puzzleElement, SkyscrapersCell finalCell) { - if (candidates.size() == 1) { - if (((SkyscrapersCell) candidates.get(0).getPuzzleElement(puzzleElement)).getType() == SkyscrapersType.Number) { - if (candidates.get(0).getPuzzleElement(puzzleElement).getData() == finalCell.getData()) { - return null; - } - return ": Wrong number in the cell."; - } - return ": No case for this cell."; - } - return ": This cell is not forced."; - } - - private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { - SkyscrapersBoard emptyCase = board.copy(); - emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); - DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); - if (duplicate.checkContradictionAt(emptyCase, cell) == null) { - System.out.println("no contradiction ln"); - return true; - } - return false; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); - SkyscrapersBoard modBoard = (SkyscrapersBoard) node.getBoard().copy(); - System.out.println(modBoard.getPuzzleElements().size()); - for (PuzzleElement element : modBoard.getPuzzleElements()) { - System.out.println("123"); - SkyscrapersCell cell = (SkyscrapersCell) element; - if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { - //cell.setData(SkyscrapersType.BULB.value); - modBoard.addModifiedData(cell); - } - } - System.out.println(modBoard.getModifiedData().isEmpty()); - if (modBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return modBoard; - } - } -} +package edu.rpi.legup.puzzle.skyscrapers.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; +import java.util.ArrayList; + +public class LastVisibleCellDirectRule extends DirectRule { + + public LastVisibleCellDirectRule() { + super( + "SKYS-BASC-0001", + "Last Visible Cell", + "There is only one cell on this row/col for this number that does not create a" + + " visibility contradiction", + "edu/rpi/legup/images/skyscrapers/rules/FixedMax.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + // last cell for number based on preemptive visibility rules + SkyscrapersBoard initialBoard = + (SkyscrapersBoard) transition.getParents().get(0).getBoard(); + SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); + SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); + if (initCell.getType() != SkyscrapersType.UNKNOWN + || finalCell.getType() != SkyscrapersType.Number) { + return super.getInvalidUseOfRuleMessage() + + ": Modified cells must transition from unknown to number"; + } + + // set all rules used by case rule to false except for dupe, get all cases + boolean dupeTemp = initialBoard.getDupeFlag(); + boolean viewTemp = initialBoard.getViewFlag(); + initialBoard.setDupeFlag(false); + initialBoard.setViewFlag(true); + CellForNumberCaseRule caseRule = new CellForNumberCaseRule(); + ArrayList XCandidates = + caseRule.getCasesFor( + initialBoard, + initialBoard.getWestClues().get(finalCell.getLocation().y), + (Integer) finalCell.getData()); + ArrayList YCandidates = + caseRule.getCasesFor( + initialBoard, + initialBoard.getNorthClues().get(finalCell.getLocation().x), + (Integer) finalCell.getData()); + initialBoard.setDupeFlag(dupeTemp); + initialBoard.setViewFlag(viewTemp); + + // System.out.println(XCandidates.size()); + // System.out.println(YCandidates.size()); + + // return null if either pass, both messages otherwise + String xCheck = candidateCheck(XCandidates, puzzleElement, finalCell); + String yCheck = candidateCheck(YCandidates, puzzleElement, finalCell); + if (xCheck == null || yCheck == null) { + return null; + } + return super.getInvalidUseOfRuleMessage() + "\nRow" + xCheck + "\nCol" + yCheck; + } + + // helper to check if candidate list is valid + private String candidateCheck( + ArrayList candidates, PuzzleElement puzzleElement, SkyscrapersCell finalCell) { + if (candidates.size() == 1) { + if (((SkyscrapersCell) candidates.get(0).getPuzzleElement(puzzleElement)).getType() + == SkyscrapersType.Number) { + if (candidates.get(0).getPuzzleElement(puzzleElement).getData() + == finalCell.getData()) { + return null; + } + return ": Wrong number in the cell."; + } + return ": No case for this cell."; + } + return ": This cell is not forced."; + } + + private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { + SkyscrapersBoard emptyCase = board.copy(); + emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); + DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); + if (duplicate.checkContradictionAt(emptyCase, cell) == null) { + System.out.println("no contradiction ln"); + return true; + } + return false; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); + SkyscrapersBoard modBoard = (SkyscrapersBoard) node.getBoard().copy(); + // System.out.println(modBoard.getPuzzleElements().size()); + for (PuzzleElement element : modBoard.getPuzzleElements()) { + SkyscrapersCell cell = (SkyscrapersCell) element; + if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { + // cell.setData(SkyscrapersType.BULB.value); + modBoard.addModifiedData(cell); + } + } + // System.out.println(modBoard.getModifiedData().isEmpty()); + if (modBoard.getModifiedData().isEmpty()) { + return null; + } else { + return modBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleNumberDirectRule.java index d3d4ff2ab..da1057b56 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleNumberDirectRule.java @@ -1,99 +1,104 @@ -package edu.rpi.legup.puzzle.skyscrapers.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - -import java.util.ArrayList; - -public class LastVisibleNumberDirectRule extends DirectRule { - - public LastVisibleNumberDirectRule() { - super("SKYS-BASC-0005", "Last Visible Number", - "There is only one number for this cell that does not create a visibility contradiction", - "edu/rpi/legup/images/skyscrapers/rules/OneEdge.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - //last number for cell based upon preemptive visibility rules - SkyscrapersBoard initialBoard = (SkyscrapersBoard) transition.getParents().get(0).getBoard(); - SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); - SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); - SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); - if (initCell.getType() != SkyscrapersType.UNKNOWN || finalCell.getType() != SkyscrapersType.Number) { - return super.getInvalidUseOfRuleMessage() + ": Modified cells must transition from unknown to number"; - } - - //set all rules used by case rule to false except for dupe, get all cases - boolean dupeTemp = initialBoard.getDupeFlag(); - boolean viewTemp = initialBoard.getViewFlag(); - initialBoard.setDupeFlag(false); - initialBoard.setViewFlag(true); - NumberForCellCaseRule caseRule = new NumberForCellCaseRule(); - ArrayList candidates = caseRule.getCases(initialBoard, puzzleElement); - initialBoard.setDupeFlag(dupeTemp); - initialBoard.setViewFlag(viewTemp); - - //check if given value is the only remaining value - if (candidates.size() == 1) { - if (candidates.get(0).getPuzzleElement(puzzleElement).getData() == finalCell.getData()) { - return null; - } - return super.getInvalidUseOfRuleMessage() + ": Wrong number in the cell."; - } - return super.getInvalidUseOfRuleMessage() + ":This cell is not forced."; - } - - private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { - SkyscrapersBoard emptyCase = board.copy(); - emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); - DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); - if (duplicate.checkContradictionAt(emptyCase, cell) == null) { - System.out.println("no contradiction ln"); - return true; - } - return false; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); - SkyscrapersBoard lightUpBoard = (SkyscrapersBoard) node.getBoard().copy(); - System.out.println(lightUpBoard.getPuzzleElements().size()); - for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { - System.out.println("123"); - SkyscrapersCell cell = (SkyscrapersCell) element; - if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { - //cell.setData(SkyscrapersType.BULB.value); - lightUpBoard.addModifiedData(cell); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.skyscrapers.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; +import java.util.ArrayList; + +public class LastVisibleNumberDirectRule extends DirectRule { + + public LastVisibleNumberDirectRule() { + super( + "SKYS-BASC-0005", + "Last Visible Number", + "There is only one number for this cell that does not create a visibility" + + " contradiction", + "edu/rpi/legup/images/skyscrapers/rules/OneEdge.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + // last number for cell based upon preemptive visibility rules + SkyscrapersBoard initialBoard = + (SkyscrapersBoard) transition.getParents().get(0).getBoard(); + SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); + SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); + if (initCell.getType() != SkyscrapersType.UNKNOWN + || finalCell.getType() != SkyscrapersType.Number) { + return super.getInvalidUseOfRuleMessage() + + ": Modified cells must transition from unknown to number"; + } + + // set all rules used by case rule to false except for dupe, get all cases + boolean dupeTemp = initialBoard.getDupeFlag(); + boolean viewTemp = initialBoard.getViewFlag(); + initialBoard.setDupeFlag(false); + initialBoard.setViewFlag(true); + NumberForCellCaseRule caseRule = new NumberForCellCaseRule(); + ArrayList candidates = caseRule.getCases(initialBoard, puzzleElement); + initialBoard.setDupeFlag(dupeTemp); + initialBoard.setViewFlag(viewTemp); + + // check if given value is the only remaining value + if (candidates.size() == 1) { + if (candidates.get(0).getPuzzleElement(puzzleElement).getData() + == finalCell.getData()) { + return null; + } + return super.getInvalidUseOfRuleMessage() + ": Wrong number in the cell."; + } + return super.getInvalidUseOfRuleMessage() + ":This cell is not forced."; + } + + private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { + SkyscrapersBoard emptyCase = board.copy(); + emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); + DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); + if (duplicate.checkContradictionAt(emptyCase, cell) == null) { + System.out.println("no contradiction ln"); + return true; + } + return false; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); + SkyscrapersBoard lightUpBoard = (SkyscrapersBoard) node.getBoard().copy(); + // System.out.println(lightUpBoard.getPuzzleElements().size()); + for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { + SkyscrapersCell cell = (SkyscrapersCell) element; + if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { + // cell.setData(SkyscrapersType.BULB.value); + lightUpBoard.addModifiedData(cell); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NEdgeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NEdgeDirectRule.java index 9ba726ae4..bbc202e72 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NEdgeDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NEdgeDirectRule.java @@ -1,100 +1,106 @@ -package edu.rpi.legup.puzzle.skyscrapers.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - -import java.awt.Point; - -public class NEdgeDirectRule extends DirectRule { - - public NEdgeDirectRule() { - super("SKYS-BASC-0004", "N Edge", - "If the maximum number appears on an edge, the row or column's numbers appear in ascending order, starting at that edge.", - "edu/rpi/legup/images/skyscrapers/rules/NEdge.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SkyscrapersBoard initialBoard = (SkyscrapersBoard) transition.getParents().get(0).getBoard(); - SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); - SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); - SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(initCell.getType() == SkyscrapersType.UNKNOWN && finalCell.getType() == SkyscrapersType.Number)) { - return super.getInvalidUseOfRuleMessage() + ": Modified cells must be number"; - } - - SkyscrapersBoard emptyCase = initialBoard.copy(); - emptyCase.getPuzzleElement(finalCell).setData(SkyscrapersType.UNKNOWN.value); - Point loc = finalCell.getLocation(); - int max = initialBoard.getHeight(); - - if (initialBoard.getWestClues().get(loc.y).getData() == max && finalCell.getData() == loc.x + 1) { - return null; - } - if (initialBoard.getEastClues().get(loc.y).getData() == max && finalCell.getData() == max - loc.x) { - return null; - } - if (initialBoard.getNorthClues().get(loc.x).getData() == max && finalCell.getData() == loc.y + 1) { - return null; - } - if (initialBoard.getSouthClues().get(loc.x).getData() == max && finalCell.getData() == max - loc.y) { - return null; - } - - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced."; - - } - - private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { - SkyscrapersBoard emptyCase = board.copy(); - emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); - DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); - if (duplicate.checkContradictionAt(emptyCase, cell) == null) { - System.out.println("no contradiction ln"); - return true; - } - return false; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); - SkyscrapersBoard lightUpBoard = (SkyscrapersBoard) node.getBoard().copy(); - System.out.println(lightUpBoard.getPuzzleElements().size()); - for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { - System.out.println("123"); - SkyscrapersCell cell = (SkyscrapersCell) element; - if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { - //cell.setData(SkyscrapersType.BULB.value); - lightUpBoard.addModifiedData(cell); - } - } - if (lightUpBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return lightUpBoard; - } - } -} +package edu.rpi.legup.puzzle.skyscrapers.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; +import java.awt.Point; + +public class NEdgeDirectRule extends DirectRule { + + public NEdgeDirectRule() { + super( + "SKYS-BASC-0004", + "N Edge", + "If the maximum number appears on an edge, the row or column's numbers appear in" + + " ascending order, starting at that edge.", + "edu/rpi/legup/images/skyscrapers/rules/NEdge.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement index of the puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + SkyscrapersBoard initialBoard = + (SkyscrapersBoard) transition.getParents().get(0).getBoard(); + SkyscrapersCell initCell = (SkyscrapersCell) initialBoard.getPuzzleElement(puzzleElement); + SkyscrapersBoard finalBoard = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell finalCell = (SkyscrapersCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(initCell.getType() == SkyscrapersType.UNKNOWN + && finalCell.getType() == SkyscrapersType.Number)) { + return super.getInvalidUseOfRuleMessage() + ": Modified cells must be number"; + } + + SkyscrapersBoard emptyCase = initialBoard.copy(); + emptyCase.getPuzzleElement(finalCell).setData(SkyscrapersType.UNKNOWN.value); + Point loc = finalCell.getLocation(); + int max = initialBoard.getHeight(); + + if (initialBoard.getWestClues().get(loc.y).getData() == max + && finalCell.getData() == loc.x + 1) { + return null; + } + if (initialBoard.getEastClues().get(loc.y).getData() == max + && finalCell.getData() == max - loc.x) { + return null; + } + if (initialBoard.getNorthClues().get(loc.x).getData() == max + && finalCell.getData() == loc.y + 1) { + return null; + } + if (initialBoard.getSouthClues().get(loc.x).getData() == max + && finalCell.getData() == max - loc.y) { + return null; + } + + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced."; + } + + private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) { + SkyscrapersBoard emptyCase = board.copy(); + emptyCase.getPuzzleElement(cell).setData(SkyscrapersType.UNKNOWN.value); + DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule(); + if (duplicate.checkContradictionAt(emptyCase, cell) == null) { + System.out.println("no contradiction ln"); + return true; + } + return false; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + SkyscrapersBoard initialBoard = (SkyscrapersBoard) node.getBoard(); + SkyscrapersBoard lightUpBoard = (SkyscrapersBoard) node.getBoard().copy(); + // System.out.println(lightUpBoard.getPuzzleElements().size()); + for (PuzzleElement element : lightUpBoard.getPuzzleElements()) { + SkyscrapersCell cell = (SkyscrapersCell) element; + if (cell.getType() == SkyscrapersType.UNKNOWN && isForced(initialBoard, cell)) { + // cell.setData(SkyscrapersType.BULB.value); + lightUpBoard.addModifiedData(cell); + } + } + if (lightUpBoard.getModifiedData().isEmpty()) { + return null; + } else { + return lightUpBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java index 3bf0de70a..4f8e1df6b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java @@ -7,9 +7,7 @@ import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersClue; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - import java.awt.*; import java.util.ArrayList; import java.util.HashSet; @@ -19,7 +17,9 @@ public class NumberForCellCaseRule extends CaseRule { public NumberForCellCaseRule() { - super("SKYS-CASE-0001", "Number For Cell", + super( + "SKYS-CASE-0001", + "Number For Cell", "A blank cell must have height of 1 to n.", "edu/rpi/legup/images/skyscrapers/cases/NumberForCell.png"); } @@ -40,13 +40,16 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement puzzleElement to determine the possible cases for * @return a list of elements the specified could be */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } SkyscrapersCell cell = (SkyscrapersCell) puzzleElement; SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board; @@ -59,17 +62,18 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { newCell.setData(i); newCase.addModifiedData(newCell); - //if flags + // if flags boolean passed = true; if (skyscrapersboard.getDupeFlag()) { DuplicateNumberContradictionRule DupeRule = new DuplicateNumberContradictionRule(); passed = passed && DupeRule.checkContradictionAt(newCase, newCell) != null; } if (skyscrapersboard.getViewFlag()) { - PreemptiveVisibilityContradictionRule ViewRule = new PreemptiveVisibilityContradictionRule(); + PreemptiveVisibilityContradictionRule ViewRule = + new PreemptiveVisibilityContradictionRule(); passed = passed && ViewRule.checkContradictionAt(newCase, newCell) != null; } - //how should unresolved be handled? should it be? + // how should unresolved be handled? should it be? if (passed) { cases.add(newCase); } @@ -88,48 +92,56 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { public String checkRuleRaw(TreeTransition transition) { List childTransitions = transition.getParents().get(0).getChildren(); if (childTransitions.size() == 0) { - //System.out.println("0"); return "This case rule must have at least one child."; - } - else { - if (childTransitions.size() != getCases(transition.getBoard(), childTransitions.get(0).getBoard().getModifiedData().iterator().next()).size()) { + } else { + if (childTransitions.size() + != getCases( + transition.getBoard(), + childTransitions + .get(0) + .getBoard() + .getModifiedData() + .iterator() + .next()) + .size()) { return "Wrong number of children."; } } - - //TreeTransition case1 = childTransitions.get(0); - //TreeTransition case2 = childTransitions.get(1); + // TreeTransition case1 = childTransitions.get(0); + // TreeTransition case2 = childTransitions.get(1); TreeTransition case1 = childTransitions.get(0); - SkyscrapersCell mod1 = (SkyscrapersCell) case1.getBoard().getModifiedData().iterator().next(); + SkyscrapersCell mod1 = + (SkyscrapersCell) case1.getBoard().getModifiedData().iterator().next(); for (int i = 0; i < childTransitions.size(); i++) { TreeTransition case2 = childTransitions.get(i); if (case2.getBoard().getModifiedData().size() != 1) { - //System.out.println("1"); - return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; } - SkyscrapersCell mod2 = (SkyscrapersCell) case2.getBoard().getModifiedData().iterator().next(); + SkyscrapersCell mod2 = + (SkyscrapersCell) case2.getBoard().getModifiedData().iterator().next(); if (!mod1.getLocation().equals(mod2.getLocation())) { - //System.out.println("2"); - return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; } if (!(mod2.getType() == SkyscrapersType.Number)) { - //System.out.println("3"); - return super.getInvalidUseOfRuleMessage() + ": This case rule must assign a number."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must assign a number."; } } - //System.out.println("no contradiction"); + // System.out.println("no contradiction"); return null; } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement index of the puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -137,28 +149,28 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid - * Overridden by case rules dependent on more than just the modified data + * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be + * valid Overridden by case rules dependent on more than just the modified data * - * @param board board state at application + * @param board board state at application * @param puzzleElement selected puzzleElement - * @return List of puzzle elements (typically cells) this application of the case rule depends upon. - * Defaults to any element modified by any case + * @return List of puzzle elements (typically cells) this application of the case rule depends + * upon. Defaults to any element modified by any case */ @Override public List dependentElements(Board board, PuzzleElement puzzleElement) { List elements = new ArrayList<>(); SkyscrapersBoard puzzleBoard = (SkyscrapersBoard) board; - SkyscrapersCell point = (SkyscrapersCell)puzzleBoard.getPuzzleElement(puzzleElement); + SkyscrapersCell point = (SkyscrapersCell) puzzleBoard.getPuzzleElement(puzzleElement); List cells = new ArrayList<>(List.of(point)); // if dependent on row/col if (puzzleBoard.getDupeFlag() || puzzleBoard.getViewFlag()) { // add all cells in row/col intersecting given point - cells.addAll(puzzleBoard.getRowCol(point.getLocation().x,SkyscrapersType.ANY,false)); - cells.addAll(puzzleBoard.getRowCol(point.getLocation().y,SkyscrapersType.ANY,true)); + cells.addAll(puzzleBoard.getRowCol(point.getLocation().x, SkyscrapersType.ANY, false)); + cells.addAll(puzzleBoard.getRowCol(point.getLocation().y, SkyscrapersType.ANY, true)); } for (SkyscrapersCell cell : cells) { diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PreemptiveVisibilityContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PreemptiveVisibilityContradictionRule.java index 1be26f49a..dc274eb15 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PreemptiveVisibilityContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PreemptiveVisibilityContradictionRule.java @@ -6,28 +6,29 @@ import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - import java.awt.*; -import java.util.Queue; import java.util.LinkedList; import java.util.List; +import java.util.Queue; public class PreemptiveVisibilityContradictionRule extends ContradictionRule { public PreemptiveVisibilityContradictionRule() { - super("SKYS-CONT-0006", "Preemptive Visibility", + super( + "SKYS-CONT-0006", + "Preemptive Visibility", "Visibility constraints are not met given an incomplete row/col", "edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png"); } /** - * Checks whether there is an instance of a visibility contradiction in every possible row/col based on the specific - * puzzleElement index using this rule + * Checks whether there is an instance of a visibility contradiction in every possible row/col + * based on the specific puzzleElement index using this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement - * @return null if the all possible rows/cols contain a contradiction at the specified puzzleElement, - * otherwise error message + * @return null if the all possible rows/cols contain a contradiction at the specified + * puzzleElement, otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -35,12 +36,13 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { SkyscrapersCell cell = (SkyscrapersCell) puzzleElement; Point loc = cell.getLocation(); - //Initialize instances of necessary contradiction and case rules - InsufficientVisibilityContradictionRule tooFew = new InsufficientVisibilityContradictionRule(); + // Initialize instances of necessary contradiction and case rules + InsufficientVisibilityContradictionRule tooFew = + new InsufficientVisibilityContradictionRule(); ExceedingVisibilityContradictionRule tooMany = new ExceedingVisibilityContradictionRule(); CellForNumberCaseRule caseRule = new CellForNumberCaseRule(); - //Initialize skyscraperBoard queues for rows and cols + // Initialize skyscraperBoard queues for rows and cols Queue rowQ = new LinkedList<>(); rowQ.add(skyscrapersBoard); Queue colQ = new LinkedList<>(); @@ -48,18 +50,18 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { // find all cases for the corresponding row and column for each possible skyscraper height - //Add every possible case for all heights for each corresponding row and column + // Add every possible case for all heights for each corresponding row and column for (int i = 0; i < skyscrapersBoard.getWidth(); i++) { int num = i + 1; - //check row west clue + // check row west clue List rows; int size = rowQ.size(); for (int j = 0; j < size; j++) { - SkyscrapersBoard temp = rowQ.poll(); //get row from the top of the stack + SkyscrapersBoard temp = rowQ.poll(); // get row from the top of the stack - //don't do anything if already in row + // don't do anything if already in row boolean exists = false; for (SkyscrapersCell c : temp.getRowCol(loc.y, SkyscrapersType.Number, true)) { if (c.getData() == num) { @@ -70,36 +72,37 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { if (exists) { rowQ.add(temp); - } - else { - //set flags + } else { + // set flags boolean dupeTemp = temp.getDupeFlag(); boolean viewTemp = temp.getViewFlag(); temp.setDupeFlag(false); temp.setViewFlag(false); - //get all cases for corresponding row based on west clue - rows = caseRule.getCasesFor(temp, skyscrapersBoard.getWestClues().get(loc.y), num); + // get all cases for corresponding row based on west clue + rows = + caseRule.getCasesFor( + temp, skyscrapersBoard.getWestClues().get(loc.y), num); - //reset flags + // reset flags temp.setDupeFlag(dupeTemp); temp.setViewFlag(viewTemp); - //add all row cases to row queue + // add all row cases to row queue for (Board k : rows) { rowQ.add((SkyscrapersBoard) k); } } } - //check col north clue + // check col north clue List cols; size = colQ.size(); for (int j = 0; j < size; j++) { - SkyscrapersBoard temp = colQ.poll(); //get row from the top of the stack + SkyscrapersBoard temp = colQ.poll(); // get row from the top of the stack - //don't do anything if already in col + // don't do anything if already in col boolean exists = false; for (SkyscrapersCell c : temp.getRowCol(loc.x, SkyscrapersType.Number, false)) { if (c.getData() == num) { @@ -110,22 +113,23 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { if (exists) { colQ.add(temp); - } - else { - //set flags + } else { + // set flags boolean dupeTemp = temp.getDupeFlag(); boolean viewTemp = temp.getViewFlag(); temp.setDupeFlag(false); temp.setViewFlag(false); - //get all cases for corresponding col based on north clue - cols = caseRule.getCasesFor(temp, skyscrapersBoard.getNorthClues().get(loc.x), num); + // get all cases for corresponding col based on north clue + cols = + caseRule.getCasesFor( + temp, skyscrapersBoard.getNorthClues().get(loc.x), num); - //reset flags + // reset flags temp.setDupeFlag(dupeTemp); temp.setViewFlag(viewTemp); - //add all row cases to row queue + // add all row cases to row queue for (Board k : cols) { colQ.add((SkyscrapersBoard) k); } @@ -136,16 +140,24 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { String rowTooFew; String rowTooMany; boolean rowContradiction = true; - //check if each case board has a contradiction + // check if each case board has a contradiction while (rowQ.size() > 0) { SkyscrapersBoard fullRow = rowQ.poll(); - //checks if there is a contradiction given the row based on the west clue - rowTooFew = tooFew.checkContradictionAt(fullRow, cell); // is cell the correct puzzle element to check? + // checks if there is a contradiction given the row based on the west clue + rowTooFew = + tooFew.checkContradictionAt( + fullRow, cell); // is cell the correct puzzle element to check? rowTooMany = tooMany.checkContradictionAt(fullRow, cell); - //boolean that checks if there is a contradiction within all rows - rowContradiction = rowContradiction && (rowTooFew == null || rowTooMany == null);// !null means there isn't a contradiction, so there must be a valid permutation of the array + // boolean that checks if there is a contradiction within all rows + rowContradiction = + rowContradiction + && (rowTooFew == null + || rowTooMany + == null); // !null means there isn't a contradiction, so + // there must be a valid + // permutation of the array } String colTooFew; @@ -154,15 +166,16 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { while (colQ.size() > 0) { SkyscrapersBoard fullCol = colQ.poll(); - //checks if there is a contradiction given the col baesd on the north clue + // checks if there is a contradiction given the col baesd on the north clue colTooFew = tooFew.checkContradictionAt(fullCol, cell); colTooMany = tooMany.checkContradictionAt(fullCol, cell); - //boolean that checks if there is a contradiction within all the cols + // boolean that checks if there is a contradiction within all the cols colContradiction = colContradiction && (colTooFew == null || colTooMany == null); } - //if every possible permutation results in contradictions return null, else no contradiction + // if every possible permutation results in contradictions return null, else no + // contradiction if (rowContradiction || colContradiction) { return null; } @@ -179,7 +192,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { public String checkContradiction(Board board) { SkyscrapersBoard skyscrapersBoard = (SkyscrapersBoard) board; for (int i = 0; i < skyscrapersBoard.getWidth(); i++) { - //checks the middle diagonal (checkContradictionAt checks row/col off each) + // checks the middle diagonal (checkContradictionAt checks row/col off each) String checkStr = checkContradictionAt(board, skyscrapersBoard.getCell(i, i)); if (checkStr == null) { return checkStr; @@ -187,6 +200,4 @@ public String checkContradiction(Board board) { } return "No instance of the contradiction " + this.ruleName + " here"; } - - } diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedCellContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedCellContradictionRule.java index ada47efde..d4a3d0486 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedCellContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedCellContradictionRule.java @@ -3,30 +3,27 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.ContradictionRule; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - import java.awt.*; import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; public class UnresolvedCellContradictionRule extends ContradictionRule { public UnresolvedCellContradictionRule() { - super("SKYS-CONT-0004", "Unresolved Cell", + super( + "SKYS-CONT-0004", + "Unresolved Cell", "Elimination leaves no possible number for a cell.", "edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedNumberContradictionRule.java index 21a48caaf..fed429988 100644 --- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedNumberContradictionRule.java @@ -1,34 +1,33 @@ package edu.rpi.legup.puzzle.skyscrapers.rules; - import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType; - import java.awt.*; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; public class UnresolvedNumberContradictionRule extends ContradictionRule { public UnresolvedNumberContradictionRule() { - super("SKYS-CONT-0005", "Unresolved Number", + super( + "SKYS-CONT-0005", + "Unresolved Number", "No possible cell for a number without a duplicate contradiction.", - //specify a number? defaulting to every number for now. expand to more than duplicate? + // specify a number? defaulting to every number for now. expand to more than + // duplicate? "edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -39,39 +38,45 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { CellForNumberCaseRule caseRule = new CellForNumberCaseRule(); for (int i = 0; i < skyscrapersBoard.getWidth(); i++) { int num = i + 1; - //check row - //isn't already present + // check row + // isn't already present boolean exists = false; - for (SkyscrapersCell presentCell : skyscrapersBoard.getRowCol(loc.y, SkyscrapersType.Number, true)) { + for (SkyscrapersCell presentCell : + skyscrapersBoard.getRowCol(loc.y, SkyscrapersType.Number, true)) { if (presentCell.getData() == num) { exists = true; break; } } if (!exists) { - //and no possible cases - if (caseRule.getCasesFor(board, skyscrapersBoard.getWestClues().get(loc.y), num).size() == 0) { + // and no possible cases + if (caseRule.getCasesFor(board, skyscrapersBoard.getWestClues().get(loc.y), num) + .size() + == 0) { return null; } } - //check col - //same process as for row + // check col + // same process as for row exists = false; - for (SkyscrapersCell presentCell : skyscrapersBoard.getRowCol(loc.x, SkyscrapersType.Number, false)) { + for (SkyscrapersCell presentCell : + skyscrapersBoard.getRowCol(loc.x, SkyscrapersType.Number, false)) { if (presentCell.getData() == num) { exists = true; break; } } if (!exists) { - if (caseRule.getCasesFor(board, skyscrapersBoard.getNorthClues().get(loc.x), num).size() == 0) { + if (caseRule.getCasesFor(board, skyscrapersBoard.getNorthClues().get(loc.x), num) + .size() + == 0) { return null; } } } - //System.out.print("Does not contain a contradiction at this index"); + // System.out.print("Does not contain a contradiction at this index"); return super.getNoContradictionMessage(); } @@ -85,7 +90,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { public String checkContradiction(Board board) { SkyscrapersBoard skyscrapersBoard = (SkyscrapersBoard) board; for (int i = 0; i < skyscrapersBoard.getWidth(); i++) { - //checks the middle diagonal (checkContradictionAt checks row/col off each) + // checks the middle diagonal (checkContradictionAt checks row/col off each) String checkStr = checkContradictionAt(board, skyscrapersBoard.getCell(i, i)); if (checkStr == null) { return null; @@ -94,4 +99,3 @@ public String checkContradiction(Board board) { return "No instance of the contradiction " + this.ruleName + " here"; } } - diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java new file mode 100644 index 000000000..39092bbc6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattle.java @@ -0,0 +1,35 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.gameboard.Board; + +public class StarBattle extends Puzzle { + public StarBattle() { + super(); + this.name = "StarBattle"; + + this.importer = new StarBattleImporter(this); + this.exporter = new StarBattleExporter(this); + + this.factory = new StarBattleCellFactory(); + } + + @Override + public void initializeView() { + boardView = new StarBattleView((StarBattleBoard) currentBoard); + addBoardListener(boardView); + } + + @Override + public Board generatePuzzle(int difficulty) { + return null; + } + + @Override + public boolean isBoardComplete(Board board) { + return true; + } + + @Override + public void onBoardChange(Board board) {} +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java new file mode 100644 index 000000000..5132f33e4 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleBoard.java @@ -0,0 +1,113 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.model.gameboard.GridBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import java.util.*; + +public class StarBattleBoard extends GridBoard { + + private int size; + private int puzzleNum; + protected List regions; + + // private ArrayList groupSizes; + + public StarBattleBoard(int size, int num) { + super(size, size); + this.size = size; + this.puzzleNum = num; + this.regions = new ArrayList<>(); + for (int i = 0; i < size; i++) { + regions.add(new StarBattleRegion()); + } + } + + @Override + public StarBattleCell getCell(int x, int y) { + return (StarBattleCell) super.getCell(x, y); + } + + /* + public StarBattleCell getCell(int groupIndex, int x, int y) { + return getCell(x + (groupIndex % groupSize) * groupSize, y + (groupIndex / groupSize) * groupSize); + }*/ + + public int getSize() { + return size; + } + + public Set getRow(int rowNum) { + Set row = new HashSet<>(); + for (int i = 0; i < size; i++) { + row.add(getCell(i, rowNum)); + } + return row; + } + + public int getPuzzleNumber() { + return puzzleNum; + } + + public Set getCol(int colNum) { + Set column = new HashSet<>(); + for (int i = 0; i < size; i++) { + column.add(getCell(colNum, i)); + } + return column; + } + + public StarBattleRegion getRegion(int index) { + if (index >= size) { + return null; + } + return regions.get(index); + } + + public StarBattleRegion getRegion(StarBattleCell cell) { + return getRegion(cell.getGroupIndex()); + } + + public void setRegion(int regionNum, StarBattleRegion region) { + regions.set(regionNum, region); + } + + public int columnStars(int columnIndex) { + int stars = 0; + if (columnIndex < size) { + for (StarBattleCell c : this.getCol(columnIndex)) { + if (c.getType() == StarBattleCellType.STAR) { + ++stars; + } + } + } + return stars; + } + + public int rowStars(int rowIndex) { + int stars = 0; + if (rowIndex < size) { + for (StarBattleCell c : this.getRow(rowIndex)) { + if (c.getType() == StarBattleCellType.STAR) { + ++stars; + } + } + } + return stars; + } + + public StarBattleBoard copy() { + StarBattleBoard copy = new StarBattleBoard(size, puzzleNum); + for (int x = 0; x < this.dimension.width; x++) { + for (int y = 0; y < this.dimension.height; y++) { + copy.setCell(x, y, getCell(x, y).copy()); + } + if (x < this.regions.size()) { + copy.regions.add(this.getRegion(x).copy()); + } + } + for (PuzzleElement e : modifiedData) { + copy.getPuzzleElement(e).setModifiable(false); + } + return copy; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java new file mode 100644 index 000000000..ddae8f882 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCell.java @@ -0,0 +1,87 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.model.elements.Element; +import edu.rpi.legup.model.gameboard.GridCell; +import java.awt.*; +import java.awt.event.MouseEvent; + +public class StarBattleCell extends GridCell { + private int groupIndex; + private int max; + + /** + * StarBattleCell Constructor - creates a new StarBattle cell to hold the puzzleElement + * + * @param value value of the star battle cell denoting its state + * @param location location of the cell on the board + * @param groupIndex indicates what group # the cell is in. + * @param size size of the star battle cell + */ + public StarBattleCell(int value, Point location, int groupIndex, int size) { + super(value, location); + this.groupIndex = groupIndex; + this.max = size; + } + + public int getGroupIndex() { + return groupIndex; + } + + @Override + public void setType(Element e, MouseEvent m) { + switch (e.getElementID()) { + case "STBL-PLAC-0001": + this.data = -3; + break; + case "STBL-PLAC-0002": + this.data = -2; + break; + case "STBL-PLAC-0003": + this.data = -1; + break; + + case "STBL-UNPL-0001": // Not sure how button events work + switch (m.getButton()) { + case MouseEvent.BUTTON1: + if (this.data > 0 || this.data < -3) { + this.data = -3; + } else { + this.data = this.data + 1; + } + break; + case MouseEvent.BUTTON3: + if (this.data > -4) { + this.data = this.data - 1; + } else { + this.data = -1; // Unsure + } + break; + } + break; + } + } + + public StarBattleCellType getType() { + switch (data) { + case -3: + return StarBattleCellType.UNKNOWN; + case -2: + return StarBattleCellType.STAR; + case -1: + return StarBattleCellType.BLACK; + default: + if (data >= 0) { + return StarBattleCellType.UNKNOWN; + } + } + return null; + } + + public StarBattleCell copy() { + StarBattleCell copy = new StarBattleCell(data, (Point) location.clone(), groupIndex, max); + copy.setIndex(index); + copy.setModifiable(isModifiable); + copy.setGiven(isGiven); + return copy; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java new file mode 100644 index 000000000..eb2a830f6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellFactory.java @@ -0,0 +1,66 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.ElementFactory; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public class StarBattleCellFactory extends ElementFactory { + @Override + public StarBattleCell importCell(Node node, Board board) throws InvalidFileFormatException { + try { + if (!node.getNodeName().equalsIgnoreCase("cell")) { + throw new InvalidFileFormatException( + "starbattle Factory: unknown puzzleElement puzzleElement"); + } + + StarBattleBoard starbattleBoard = (StarBattleBoard) board; + int size = starbattleBoard.getSize(); + + NamedNodeMap attributeList = node.getAttributes(); + int value = Integer.valueOf(attributeList.getNamedItem("value").getNodeValue()); + int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); + int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); + int groupIndex = + Integer.valueOf(attributeList.getNamedItem("groupIndex").getNodeValue()); + if (x >= size || y >= size) { + throw new InvalidFileFormatException( + "starbattle Factory: cell location out of bounds"); + } + if (groupIndex >= size || groupIndex < 0) { + throw new InvalidFileFormatException("starbattle Factory: not in a valid region"); + } + if (value != 0) { // ALL INITIAL PUZZLES ARE BLANK, SUBJECT TO CHANGE + throw new InvalidFileFormatException("starbattle Factory: cell unknown value"); + } + + StarBattleCell cell = new StarBattleCell(value, new Point(x, y), groupIndex, size); + cell.setIndex(y * size + x); + return cell; + } catch (NumberFormatException e1) { + e1.printStackTrace(); + throw new InvalidFileFormatException( + "starbattle Factory: unknown value where integer expected"); + } catch (NullPointerException e2) { + e2.printStackTrace(); + throw new InvalidFileFormatException("starbattle Factory: could not find attribute(s)"); + } + } + + public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleElement) { + org.w3c.dom.Element cellElement = document.createElement("cell"); + + StarBattleCell cell = (StarBattleCell) puzzleElement; + Point loc = cell.getLocation(); + + cellElement.setAttribute("value", String.valueOf(cell.getData())); + cellElement.setAttribute("x", String.valueOf(loc.x)); + cellElement.setAttribute("y", String.valueOf(loc.y)); + + return cellElement; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java new file mode 100644 index 000000000..e48e46fcb --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleCellType.java @@ -0,0 +1,14 @@ +// StarBattleCellType.java +package edu.rpi.legup.puzzle.starbattle; + +public enum StarBattleCellType { + STAR(-2), + BLACK(-1), + UNKNOWN(0); + + public int value; + + StarBattleCellType(int value) { + this.value = value; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java new file mode 100644 index 000000000..ba19361c9 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleController.java @@ -0,0 +1,36 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.controller.ElementController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import java.awt.event.MouseEvent; + +public class StarBattleController extends ElementController { + @Override + public void changeCell(MouseEvent e, PuzzleElement data) { + StarBattleCell cell = (StarBattleCell) data; + if (e.getButton() == MouseEvent.BUTTON1) { + if (e.isControlDown()) { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { + if (cell.getData() >= 0) { + data.setData(-2); + } else { + data.setData(cell.getData() + 1); + } + } + } else { + if (e.getButton() == MouseEvent.BUTTON3) { + if (cell.getData() == -2) { + data.setData(0); + } else { + data.setData(cell.getData() - 1); + } + } + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java new file mode 100644 index 000000000..66d59d364 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleElementView.java @@ -0,0 +1,46 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.ui.boardview.GridElementView; +import java.awt.*; + +public class StarBattleElementView extends GridElementView { + + public StarBattleElementView(StarBattleCell cell) { + super(cell); + } + + @Override + public StarBattleCell getPuzzleElement() { + return (StarBattleCell) super.getPuzzleElement(); + } + + @Override + public void drawElement(Graphics2D graphics2D) { + StarBattleCell cell = (StarBattleCell) puzzleElement; + StarBattleCellType type = cell.getType(); + if (type == StarBattleCellType.STAR) { + graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.drawImage( + StarBattleView.STAR, + location.x, + location.y, + size.width, + size.height, + Color.WHITE, + null); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + } else if (type == StarBattleCellType.BLACK) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.BLACK); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + } else if (type == StarBattleCellType.UNKNOWN) { + graphics2D.setStroke(new BasicStroke(1)); + graphics2D.setColor(Color.LIGHT_GRAY); + graphics2D.fillRect(location.x, location.y, size.width, size.height); + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java new file mode 100644 index 000000000..f2d2c4d80 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleExporter.java @@ -0,0 +1,33 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.model.PuzzleExporter; +import org.w3c.dom.Document; + +public class StarBattleExporter extends PuzzleExporter { + public StarBattleExporter(StarBattle starbattle) { + super(starbattle); + } + + @Override + protected org.w3c.dom.Element createBoardElement(Document newDocument) { + StarBattleBoard board = (StarBattleBoard) puzzle.getTree().getRootNode().getBoard(); + org.w3c.dom.Element boardElement = newDocument.createElement("board"); + boardElement.setAttribute("size", String.valueOf(board.getSize())); + boardElement.setAttribute("puzzle_num", String.valueOf(board.getPuzzleNumber())); + for (StarBattleRegion sb_region : board.regions) { + org.w3c.dom.Element regionsElement = newDocument.createElement("region"); + org.w3c.dom.Element cellsElement = newDocument.createElement("cells"); + for (StarBattleCell cell : sb_region.getCells()) { + if (cell.getData() == 0) { + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, cell); + cellsElement.appendChild(cellElement); + } + regionsElement.appendChild(cellsElement); + } + boardElement.appendChild(regionsElement); + } + + return boardElement; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java new file mode 100644 index 000000000..2a608c893 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleImporter.java @@ -0,0 +1,98 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.model.PuzzleImporter; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.Point; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class StarBattleImporter extends PuzzleImporter { + + public StarBattleImporter(StarBattle starbattle) { + super(starbattle); + } + + /** Puzzle setting to support row and column inputs */ + @Override + public boolean acceptsRowsAndColumnsInput() { + return true; + } + + /** Puzzle setting to disable support for text input */ + @Override + public boolean acceptsTextInput() { + return false; + } + + /** + * Constructs empty StarBattle gameboard as per the provided dimensions + * + * @param rows number of rows and columns for the gameboard + */ + @Override + public void initializeBoard(int rows, int columns) { + int puzzle_num = 1; + StarBattleBoard StarBattleBoard = new StarBattleBoard(rows, puzzle_num); + puzzle.setCurrentBoard(StarBattleBoard); + } + + /** + * Constructs StarBattle gameboard + * + * @param node xml document node + * @throws InvalidFileFormatException if file is invalid + */ + @Override + public void initializeBoard(Node node) throws InvalidFileFormatException { + Element puzzleElement = (Element) node; + int puzzle_num = Integer.parseInt(puzzleElement.getAttribute("puzzle_num")); + NodeList regionNodes = puzzleElement.getElementsByTagName("region"); + int size = Integer.parseInt(puzzleElement.getAttribute("size")); + if (regionNodes.getLength() != size) { + throw new InvalidFileFormatException( + "Not the current amount of regions in the puzzle."); + } + + StarBattleBoard StarBattleBoard = + new StarBattleBoard( + size, puzzle_num); // Initialize the board with width and height from XML + + for (int i = 0; i < regionNodes.getLength(); i++) { + Element regionElement = (Element) regionNodes.item(i); + NodeList cellNodes = regionElement.getElementsByTagName("cell"); + StarBattleRegion region_i = new StarBattleRegion(); + + for (int j = 0; j < cellNodes.getLength(); j++) { + Element cellElement = (Element) cellNodes.item(j); + int x = Integer.parseInt(cellElement.getAttribute("x")); + int y = Integer.parseInt(cellElement.getAttribute("y")); + int value = Integer.parseInt(cellElement.getAttribute("value")); + + Point cellPoint = new Point(x, y); + + // Create the StarBattleCell with the cell type and value + StarBattleCell cell = new StarBattleCell(value, cellPoint, i, size); + cell.setIndex(y * size + x); // Calculate the index based on size + cell.setModifiable(true); + + // Add the cell to the board + StarBattleBoard.setCell(x, y, cell); + region_i.addCell(cell); + } + StarBattleBoard.setRegion(i, region_i); + } + + puzzle.setCurrentBoard(StarBattleBoard); + } + + /** + * Initialize board via string of statements. + * + * @throws UnsupportedOperationException since StarBattle does not support text input + */ + @Override + public void initializeBoard(String[] statements) throws UnsupportedOperationException { + throw new UnsupportedOperationException("Star Battle does not accept text input"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java new file mode 100644 index 000000000..b35d80655 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleRegion.java @@ -0,0 +1,27 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.model.gameboard.GridRegion; + +public class StarBattleRegion extends GridRegion { + public StarBattleRegion() { + super(); + } + + public StarBattleRegion copy() { + StarBattleRegion copy = new StarBattleRegion(); + for (StarBattleCell c : regionCells) { + copy.addCell(c.copy()); + } + return copy; + } + + public int numStars() { + int stars = 0; + for (StarBattleCell c : regionCells) { + if (c.getType() == StarBattleCellType.STAR) { + ++stars; + } + } + return stars; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java new file mode 100644 index 000000000..550b5495d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/StarBattleView.java @@ -0,0 +1,38 @@ +package edu.rpi.legup.puzzle.starbattle; + +import edu.rpi.legup.controller.BoardController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.ui.boardview.GridBoardView; +import java.awt.*; +import java.io.IOException; +import javax.imageio.ImageIO; + +public class StarBattleView extends GridBoardView { + static Image STAR; + + static { + try { + STAR = + ImageIO.read( + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/starbattle/star.gif")); + } catch (IOException e) { + // pass + } + } + + public StarBattleView(StarBattleBoard board) { + super(new BoardController(), new StarBattleController(), board.getDimension()); + + for (PuzzleElement puzzleElement : board.getPuzzleElements()) { + StarBattleCell cell = (StarBattleCell) puzzleElement; + Point loc = cell.getLocation(); + StarBattleElementView elementView = new StarBattleElementView(cell); + elementView.setIndex(cell.getIndex()); + elementView.setSize(elementSize); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(elementView); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java new file mode 100644 index 000000000..c4bbf7297 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/BlackTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.starbattle.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class BlackTile extends PlaceableElement { + public BlackTile() { + super( + "STBL-PLAC-0002", + "Black Tile", + "The black tile that shows where you cannot place a star", + "edu/rpi/legup/images/lightup/black.gif"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java new file mode 100644 index 000000000..793d4dbeb --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/StarTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.starbattle.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class StarTile extends PlaceableElement { + public StarTile() { + super( + "STBL-PLAC-0001", + "Star Tile", + "The star tile, the token of the game.", + "edu/rpi/legup/images/starbattle/star.gif"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java new file mode 100644 index 000000000..30921de8d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/UnknownTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.starbattle.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class UnknownTile extends PlaceableElement { + public UnknownTile() { + super( + "STBL-UNPL-0001", + "Unknown Tile", + "An empty tile", + "edu/rpi/legup/images/starbattle/star.gif"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java new file mode 100644 index 000000000..2227eb37a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/WhiteTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.starbattle.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class WhiteTile extends PlaceableElement { + public WhiteTile() { + super( + "STBL-PLAC-0001", + "White Tile", + "The white tile", + "edu/rpi/legup/images/starbattle/white.gif"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt new file mode 100644 index 000000000..82352bd04 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/elements/starbattle_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +STBL-ELEM-0001 : BlackTile +STBL-ELEM-0002 : StarTile +STBL-ELEM-0003 : UnknownTile +STBL-ELEM-0004 : WhiteTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java new file mode 100644 index 000000000..2ab66cf93 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/BlackoutDirectRule.java @@ -0,0 +1,64 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; + +public class BlackoutDirectRule extends DirectRule { + + public BlackoutDirectRule() { + super( + "STBL-BASC-0001", + "Blackout", + "If a row, column, or region has enough stars, its unknown spaces are black.", + "edu/rpi/legup/images/starbattle/rules/BlackOutDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new TooManyStarsContradictionRule(); + + StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + + if (cell.getType() != StarBattleCellType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + + StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); + modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.STAR.value); + if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + return "Black cells must be placed in a row, region, or column with enough stars!"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java new file mode 100644 index 000000000..88f0072e5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ClashingOrbitContradictionRule.java @@ -0,0 +1,59 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +import java.awt.*; + +public class ClashingOrbitContradictionRule extends ContradictionRule { + + public ClashingOrbitContradictionRule() { + super( + "STBL-CONT-0003", + "Clashing Orbit", + "No two stars can be adjacent to each other.", + "edu/rpi/legup/images/starbattle/contradictions/ClashingOrbitContradictionRule.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + StarBattleBoard starbattleBoard = (StarBattleBoard) board; + StarBattleCell cell = (StarBattleCell) starbattleBoard.getPuzzleElement(puzzleElement); + + // Contradiction rule can only be applied to cells with a star in it + if (cell.getType() != StarBattleCellType.STAR) { + return super.getNoContradictionMessage(); + } + + // check neighboring cells for a star + Point location = cell.getLocation(); + + int rowStart = Math.max(location.x - 1, 0); + int rowEnd = Math.min(location.x + 1, starbattleBoard.getSize() - 1); + int colStart = Math.max(location.y - 1, 0); + int colEnd = Math.min(location.y + 1, starbattleBoard.getSize() - 1); + + for (int row = rowStart; row <= rowEnd; row++) { + for (int col = colStart; col <= colEnd; col++) { + if (starbattleBoard.getCell(row, col).getType() == StarBattleCellType.STAR + && (row != location.x || col != location.y)) { + return null; + } + } + } + + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java new file mode 100644 index 000000000..433567460 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRegionsDirectRule.java @@ -0,0 +1,95 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +import java.util.HashSet; +import java.util.Set; + +public class ColumnsWithinRegionsDirectRule extends DirectRule { + public ColumnsWithinRegionsDirectRule() { + super( + "STBL-BASC-0002", + "Columns Within Regions", + "If a number of columns is fully contained by a number of regions with an equal number of missing stars, spaces of other columns in those regions must be black.", + "edu/rpi/legup/images/starbattle/rules/ColumnsWithinRegionsDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + // assumption: the rule has been applied to its fullest extent and the rows and regions + // are now mutually encompassing + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + if (cell.getType() != StarBattleCellType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + // the columns that are contained + Set columns = new HashSet(); + // the regions that contain them + Set regions = new HashSet(); + // columns and regions to process + Set columnsToCheck = new HashSet(); + Set regionsToCheck = new HashSet(); + int columnStars = 0; + int regionStars = 0; + regions.add(cell.getGroupIndex()); + regionsToCheck.add(cell.getGroupIndex()); + + while (!columnsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { + for (int r : regionsToCheck) { + regionStars += board.getRegion(r).numStars(); + for (PuzzleElement c : board.getRegion(r).getCells()) { + int column = ((StarBattleCell) c).getLocation().x; + if (columns.add(column)) { + columnsToCheck.add(column); + } + } + regionsToCheck.remove(r); + } + for (int c : columnsToCheck) { + columnStars += board.columnStars(c); + for (int i = 0; i < board.getSize(); ++i) { + int region = board.getCell(c, i).getGroupIndex(); + if (regions.add(region)) { + regionsToCheck.add(region); + } + } + columnsToCheck.remove(c); + } + } + // are the columns and regions missing an equal amount of stars + if (board.getPuzzleNumber() * columns.size() - columnStars + != board.getPuzzleNumber() * regions.size() - regionStars) { + return "The number of missing stars in the columns and regions must be equal and every extraneous cell must be black!"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java new file mode 100644 index 000000000..5d108a0cd --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/ColumnsWithinRowsDirectRule.java @@ -0,0 +1,99 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +import java.util.HashSet; +import java.util.Set; + +public class ColumnsWithinRowsDirectRule extends DirectRule { + + public ColumnsWithinRowsDirectRule() { + super( + "STBL-BASC-0003", + "Columns Within Rows", + "If a number of columns is fully contained by a number of rows with an equal number of missing stars, spaces of other columns in those rows must be black.", + "edu/rpi/legup/images/starbattle/rules/ColumnsWithinRowsDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + + // assumption: the rule has been applied to its fullest extent and the rows and columns + // are now mutually encompassing + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + if (cell.getType() != StarBattleCellType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + + // the columns that are contained + Set columns = new HashSet(); + // the rows that contain them + Set rows = new HashSet(); + // columns and rows to process + Set columnsToCheck = new HashSet(); + Set rowsToCheck = new HashSet(); + int columnStars = 0; + int rowStars = 0; + int firstRow = cell.getLocation().y; + rows.add(firstRow); + rowsToCheck.add(firstRow); + + while (!columnsToCheck.isEmpty() || !rowsToCheck.isEmpty()) { + for (int r : rowsToCheck) { + rowStars += board.rowStars(r); + for (PuzzleElement c : board.getRow(r)) { + int column = ((StarBattleCell) c).getLocation().x; + if (columns.add(column)) { + columnsToCheck.add(column); + } + } + rowsToCheck.remove(r); + } + for (int c : columnsToCheck) { + columnStars += board.columnStars(c); + for (PuzzleElement r : board.getCol(c)) { + int row = ((StarBattleCell) r).getLocation().y; + if (rows.add(row)) { + rowsToCheck.add(row); + } + } + columnsToCheck.remove(c); + } + } + // are the columns and regions missing an equal amount of stars + if (board.getPuzzleNumber() * columns.size() - columnStars + != board.getPuzzleNumber() * rows.size() - rowStars) { + return "The number of missing stars in the columns and rows must be equal and every extraneous cell must be black!"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java new file mode 100644 index 000000000..80ae9a4c8 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/FinishWithStarsDirectRule.java @@ -0,0 +1,65 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; + +public class FinishWithStarsDirectRule extends DirectRule { + + public FinishWithStarsDirectRule() { + super( + "STBL-BASC-0004", + "Finish With Stars", + "Unknown spaces must be stars if there are just enough in a row, column, or region to satisfy the puzzle number.", + "edu/rpi/legup/images/starbattle/rules/FinishWithStarDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new TooFewStarsContradictionRule(); + + StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + + if (cell.getType() != StarBattleCellType.STAR) { + return "Only star cells are allowed for this rule!"; + } + + StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); + modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.BLACK.value); + if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + return "Star cells must be placed in a row, region, or column without extra spaces!"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java new file mode 100644 index 000000000..7022a06ac --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinColumnsDirectRule.java @@ -0,0 +1,45 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class RegionsWithinColumnsDirectRule extends DirectRule { + public RegionsWithinColumnsDirectRule() { + super( + "STBL-BASC-0005", + "Regions Within Columns", + "If a number of regions is fully contained by a number of columns with an equal number of missing stars, spaces of other regions in those columns must be black.", + "edu/rpi/legup/images/starbattle/rules/RegionsWithinColumnsDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + ColumnsWithinRegionsDirectRule correspondingRule = new ColumnsWithinRegionsDirectRule(); + return correspondingRule.checkRuleRawAt(transition, puzzleElement); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java new file mode 100644 index 000000000..7ab50d42b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RegionsWithinRowsDirectRule.java @@ -0,0 +1,46 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class RegionsWithinRowsDirectRule extends DirectRule { + public RegionsWithinRowsDirectRule() { + super( + "STBL-BASC-0006", + "Regions Within Rows", + "If a number of regions is fully contained by a number of rows with an equal number of missing stars, spaces of other regions in those rows must be black.", + "edu/rpi/legup/images/starbattle/rules/RegionsWithinRowsDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + + RowsWithinRegionsDirectRule correspondingRule = new RowsWithinRegionsDirectRule(); + return correspondingRule.checkRuleRawAt(transition, puzzleElement); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java new file mode 100644 index 000000000..2df20e464 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinColumnsDirectRule.java @@ -0,0 +1,47 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +public class RowsWithinColumnsDirectRule extends DirectRule { + + public RowsWithinColumnsDirectRule() { + super( + "STBL-BASC-0007", + "Rows Withing Columns", + "If a number of rows is fully contained by a number of columns with an equal number of missing stars, spaces of other rows in those columns must be black.", + "edu/rpi/legup/images/starbattle/rules/RowsWithinColumnsDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + + ColumnsWithinRowsDirectRule correspondingRule = new ColumnsWithinRowsDirectRule(); + return correspondingRule.checkRuleRawAt(transition, puzzleElement); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java new file mode 100644 index 000000000..78f8f00e7 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/RowsWithinRegionsDirectRule.java @@ -0,0 +1,96 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +import java.util.HashSet; +import java.util.Set; + +public class RowsWithinRegionsDirectRule extends DirectRule { + public RowsWithinRegionsDirectRule() { + super( + "STBL-BASC-0008", + "Rows Within Regions", + "If a number of rows is fully contained by a number of regions with an equal number of missing stars, spaces of other rows in those regions must be black.", + "edu/rpi/legup/images/starbattle/rules/RowsWithinRegionsDirectRule.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + + // assumption: the rule has been applied to its fullest extent and the rows and regions + // are now mutually encompassing + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + if (cell.getType() != StarBattleCellType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + // the rows that are contained + Set rows = new HashSet(); + // the regions that contain them + Set regions = new HashSet(); + // rows and regions to process + Set rowsToCheck = new HashSet(); + Set regionsToCheck = new HashSet(); + int rowStars = 0; + int regionStars = 0; + regions.add(cell.getGroupIndex()); + regionsToCheck.add(cell.getGroupIndex()); + + while (!rowsToCheck.isEmpty() || !regionsToCheck.isEmpty()) { + for (int r : regionsToCheck) { + regionStars += board.getRegion(r).numStars(); + for (PuzzleElement ro : board.getRegion(r).getCells()) { + int row = ((StarBattleCell) ro).getLocation().y; + if (rows.add(row)) { + rowsToCheck.add(row); + } + } + regionsToCheck.remove(r); + } + for (int r : rowsToCheck) { + rowStars += board.rowStars(r); + for (int i = 0; i < board.getSize(); ++i) { + int region = board.getCell(i, r).getGroupIndex(); + if (regions.add(region)) { + regionsToCheck.add(region); + } + } + rowsToCheck.remove(r); + } + } + // are the columns and regions missing an equal amount of stars + if (board.getPuzzleNumber() * rows.size() - rowStars + != board.getPuzzleNumber() * regions.size() - regionStars) { + return "The number of missing stars in the rows and regions must be equal and every extraneous cell must be black!"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java new file mode 100644 index 000000000..efd86bd7b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/StarOrEmptyCaseRule.java @@ -0,0 +1,110 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +import java.util.ArrayList; +import java.util.List; + +public class StarOrEmptyCaseRule extends CaseRule { + + public StarOrEmptyCaseRule() { + super( + "STBL-CASE-0002", + "Star or Empty", + "Each unknown space is either a star or empty.", + "edu/rpi/legup/images/starbattle/cases/StarOrEmptyCaseRule.png"); + } + + /** + * Checks whether the {@link TreeTransition} logically follows from the parent node using this + * rule. This method is the one that should overridden in child classes. + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + List childTransitions = transition.getParents().get(0).getChildren(); + if (childTransitions.size() != 2) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must have 2 children."; + } + + TreeTransition case1 = childTransitions.get(0); + TreeTransition case2 = childTransitions.get(1); + if (case1.getBoard().getModifiedData().size() != 1 + || case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; + } + + StarBattleCell mod1 = (StarBattleCell) case1.getBoard().getModifiedData().iterator().next(); + StarBattleCell mod2 = (StarBattleCell) case2.getBoard().getModifiedData().iterator().next(); + if (!mod1.getLocation().equals(mod2.getLocation())) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; + } + + if (!((mod1.getType() == StarBattleCellType.STAR + && mod2.getType() == StarBattleCellType.BLACK) + || (mod2.getType() == StarBattleCellType.STAR + && mod1.getType() == StarBattleCellType.BLACK))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must create a star cell and a black cell."; + } + + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + StarBattleBoard starBattleBoard = (StarBattleBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(starBattleBoard, this); + starBattleBoard.setModifiable(false); + for (PuzzleElement element : starBattleBoard.getPuzzleElements()) { + if (((StarBattleCell) element).getType() == StarBattleCellType.UNKNOWN) { + caseBoard.addPickableElement(element); + } + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + + Board case1 = board.copy(); + PuzzleElement data1 = case1.getPuzzleElement(puzzleElement); + data1.setData(StarBattleCellType.STAR.value); + case1.addModifiedData(data1); + cases.add(case1); + + Board case2 = board.copy(); + PuzzleElement data2 = case2.getPuzzleElement(puzzleElement); + data2.setData(StarBattleCellType.BLACK.value); + case2.addModifiedData(data2); + cases.add(case2); + + return cases; + } + + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return checkRuleRaw(transition); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java new file mode 100644 index 000000000..89857875d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/SurroundStarDirectRule.java @@ -0,0 +1,64 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; + +public class SurroundStarDirectRule extends DirectRule { + + public SurroundStarDirectRule() { + super( + "STBL-BASC-0009", + "Surround Star", + "Any space adjacent to a star must be black.", + "edu/rpi/legup/images/starbattle/rules/SurroundStar.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + StarBattleBoard board = (StarBattleBoard) transition.getBoard(); + StarBattleBoard origBoard = (StarBattleBoard) transition.getParents().get(0).getBoard(); + ContradictionRule contraRule = new ClashingOrbitContradictionRule(); + + StarBattleCell cell = (StarBattleCell) board.getPuzzleElement(puzzleElement); + + if (cell.getType() != StarBattleCellType.BLACK) { + return "Only black cells are allowed for this rule!"; + } + + StarBattleBoard modified = (StarBattleBoard) origBoard.copy(); + modified.getPuzzleElement(puzzleElement).setData(StarBattleCellType.STAR.value); + if (contraRule.checkContradictionAt(modified, puzzleElement) != null) { + return "Black cells must be placed adjacent to a star!"; + } + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java new file mode 100644 index 000000000..e88b7c6b9 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooFewStarsContradictionRule.java @@ -0,0 +1,63 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +import edu.rpi.legup.puzzle.starbattle.StarBattleRegion; +import java.awt.*; + +public class TooFewStarsContradictionRule extends ContradictionRule { + + public TooFewStarsContradictionRule() { + super( + "STBL-CONT-0002", + "Too Few Stars", + "There are too few stars in this region/row/column and there are not enough places to put the remaining stars.", + "edu/rpi/legup/images/starbattle/contradictions/TooFewStarsContradictionRule.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + StarBattleBoard sbBoard = (StarBattleBoard) board; + StarBattleCell cell = (StarBattleCell) puzzleElement; + Point location = cell.getLocation(); + int column = location.x; + int row = location.y; + int rowCount = 0; + int columnCount = 0; + for (int i = 0; i < sbBoard.getSize(); ++i) { + if (sbBoard.getCell(row, i).getType() != StarBattleCellType.BLACK) { + ++rowCount; + } + if (sbBoard.getCell(i, column).getType() != StarBattleCellType.BLACK) { + ++columnCount; + } + } + if (rowCount < sbBoard.getPuzzleNumber() || columnCount < sbBoard.getPuzzleNumber()) { + return null; + } + StarBattleRegion region = sbBoard.getRegion(cell); + int regionCount = 0; + for (StarBattleCell c : region.getCells()) { + if (c.getType() != StarBattleCellType.BLACK) { + ++regionCount; + } + } + if (regionCount < sbBoard.getPuzzleNumber()) { + return null; + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java new file mode 100644 index 000000000..12603a6ba --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/starbattle/rules/TooManyStarsContradictionRule.java @@ -0,0 +1,113 @@ +package edu.rpi.legup.puzzle.starbattle.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +import edu.rpi.legup.puzzle.starbattle.StarBattleRegion; +import java.awt.*; +import java.util.List; + +public class TooManyStarsContradictionRule extends ContradictionRule { + private final String INVALID_USE_MESSAGE = + "Contradiction must be applied to a cell containing a star."; + + public TooManyStarsContradictionRule() { + super( + "STBL-CONT-0001", + "Too Many Stars", + "There are too many stars in this region/row/column.", + "edu/rpi/legup/images/starbattle/contradictions/TooManyStarsContradictionRule.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + StarBattleBoard starbattleBoard = (StarBattleBoard) board; + StarBattleCell cell = (StarBattleCell) starbattleBoard.getPuzzleElement(puzzleElement); + Point location = cell.getLocation(); + int starCount = 0; + int puzzleNum = starbattleBoard.getPuzzleNumber(); + boolean valid = true; + + if (cell.getType() != StarBattleCellType.STAR) { + return this.INVALID_USE_MESSAGE; + } + + // check row + for (int i = location.x - 1; i >= 0; i--) { + StarBattleCell check = starbattleBoard.getCell(i, location.y); + if (check.getType() == StarBattleCellType.STAR) { + starCount++; + if (starCount >= puzzleNum) { + valid = false; + break; + } + } + } + + for (int i = location.x + 1; i < starbattleBoard.getWidth(); i++) { + StarBattleCell check = starbattleBoard.getCell(i, location.y); + if (check.getType() == StarBattleCellType.STAR) { + starCount++; + if (starCount >= puzzleNum) { + valid = false; + break; + } + } + } + + // check column + starCount = 0; + for (int j = location.y - 1; j >= 0; j--) { + StarBattleCell check = starbattleBoard.getCell(location.x, j); + if (check.getType() == StarBattleCellType.STAR) { + starCount++; + if (starCount >= puzzleNum) { + valid = false; + break; + } + } + } + + for (int j = location.y + 1; j < starbattleBoard.getWidth(); j++) { + StarBattleCell check = starbattleBoard.getCell(location.x, j); + if (check.getType() == StarBattleCellType.STAR) { + starCount++; + if (starCount >= puzzleNum) { + valid = false; + break; + } + } + } + + // check region + starCount = 0; + StarBattleRegion reg = starbattleBoard.getRegion(cell); + List cellList = reg.getCells(); // list of cells + for (int k = 0; k < cellList.size(); k++) { + if (cellList.get(k).getType() == StarBattleCellType.STAR) { + starCount++; + if (starCount > puzzleNum) { + valid = false; + break; + } + } + } + + if (valid) { + return super.getNoContradictionMessage(); + } + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/GroupType.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/GroupType.java index a716258fa..a7cd9ac12 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/GroupType.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/GroupType.java @@ -1,5 +1,7 @@ package edu.rpi.legup.puzzle.sudoku; public enum GroupType { - REGION, ROW, COLUMN + REGION, + ROW, + COLUMN } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java new file mode 100644 index 000000000..f7893ca32 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/ModelSudokuBoard.java @@ -0,0 +1,17 @@ +package edu.rpi.legup.puzzle.sudoku; + +public class ModelSudokuBoard { + public int getModelRegionNumbers(int index) { + int columnMod = index % 3 + 1; + int rowMod = ((index / 9) % 3) * 3; + return columnMod + rowMod; + } + + public int getModelRowNumbers(int index) { + return index % 9 + 1; + } + + public int getModelColumnNumbers(int index) { + return index / 9 + 1; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java index 8af2aca2e..c5f9eec2a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/PossibleNumberCaseBoard.java @@ -2,8 +2,7 @@ import edu.rpi.legup.model.gameboard.CaseBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.sudoku.rules.PossibleNumberCaseRule; - +import edu.rpi.legup.puzzle.sudoku.rules.PossibleCellsForNumberRegionCaseRule; import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; @@ -15,8 +14,8 @@ public class PossibleNumberCaseBoard extends CaseBoard { private Set pickableRows; private Set pickableCols; - - public PossibleNumberCaseBoard(SudokuBoard baseBoard, PossibleNumberCaseRule caseRule, SudokuCell cell) { + public PossibleNumberCaseBoard( + SudokuBoard baseBoard, PossibleCellsForNumberRegionCaseRule caseRule, SudokuCell cell) { super(baseBoard, caseRule); this.cell = cell; this.pickableRegions = new HashSet<>(); @@ -37,16 +36,14 @@ public boolean isPickable(PuzzleElement puzzleElement, MouseEvent e) { return true; } } - } - else { + } else { if (e.isControlDown()) { for (int c : pickableCols) { if (c == sudokuCell.getLocation().x) { return true; } } - } - else { + } else { for (int r : pickableRegions) { if (r == sudokuCell.getGroupIndex()) { return true; diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java index ac082e427..c27269536 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/Sudoku.java @@ -9,9 +9,7 @@ public class Sudoku extends Puzzle { private SudokuView boardView; - /** - * Sudoku Constructor - */ + /** Sudoku Constructor */ public Sudoku() { super(); @@ -27,12 +25,12 @@ public BoardView getBoardView() { return boardView; } - /** - * Initializes the game board - */ + /** Initializes the game board */ @Override public void initializeView() { boardView = new SudokuView((SudokuBoard) currentBoard); + boardView.setBoard(currentBoard); + addBoardListener(boardView); } /** @@ -50,8 +48,8 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Sudoku * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Sudoku, false otherwise */ public boolean isValidDimensions(int rows, int columns) { @@ -66,7 +64,8 @@ public boolean isValidDimensions(int rows, int columns) { } // For Sudoku, the number of rows and columns must be a perfect square - // Note: we don't need to check the columns since by this point, we have verified that the number of rows + // Note: we don't need to check the columns since by this point, we have verified that the + // number of rows // equals the number of columns double sqrtRows = Math.sqrt(rows); if (sqrtRows - Math.floor(sqrtRows) != 0) { @@ -107,7 +106,5 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { - - } + public void onBoardChange(Board board) {} } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuBoard.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuBoard.java index ed3048c88..46e6020bb 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuBoard.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.*; import java.util.HashSet; import java.util.Set; @@ -35,23 +34,23 @@ public SudokuCell getCell(int x, int y) { } /** - * Gets the SudokuCell in the specified group index at the x and y location given - * The group index must be by less than the width (or height) of the board and the - * x and y location is relative to the group. This means the x and y values must be - * less the square root of the width (or height) of the board. + * Gets the SudokuCell in the specified group index at the x and y location given The group + * index must be by less than the width (or height) of the board and the x and y location is + * relative to the group. This means the x and y values must be less the square root of the + * width (or height) of the board. * * @param groupIndex group index of the cell - * @param x x location relative to the group - * @param y y location relative to the group + * @param x x location relative to the group + * @param y y location relative to the group * @return cell in the specified group index at the given x and y location */ public SudokuCell getCell(int groupIndex, int x, int y) { - return getCell(x + (groupIndex % groupSize) * groupSize, y + (groupIndex / groupSize) * groupSize); + return getCell( + x + (groupIndex % groupSize) * groupSize, y + (groupIndex / groupSize) * groupSize); } /** - * Gets the size of the sudoku board - * Standard board is 9x9 + * Gets the size of the sudoku board Standard board is 9x9 * * @return size of the board */ @@ -60,8 +59,7 @@ public int getSize() { } /** - * Gets the minor group size of the sudoku board - * Standard board is 3x3x3x3 + * Gets the minor group size of the sudoku board Standard board is 3x3x3x3 * * @return minor group size */ @@ -139,8 +137,8 @@ public Set getPossibleValues(SudokuCell cell) { } /** - * Called when a {@link PuzzleElement} data on this has changed and passes in the equivalent puzzle element with - * the new data. + * Called when a {@link PuzzleElement} data on this has changed and passes in the equivalent + * puzzle element with the new data. * * @param puzzleElement equivalent puzzle element with the new data. */ diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java index 0e1595d03..4e194ae2c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCell.java @@ -1,8 +1,9 @@ package edu.rpi.legup.puzzle.sudoku; +import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; +import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; @@ -60,4 +61,36 @@ public SudokuCell copy() { copy.setGiven(isGiven); return copy; } + + /** + * Sets the type of this NurikabeCell + * + * @param e element to set the type of this nurikabe cell to + */ + @Override + public void setType(Element e, MouseEvent m) { + if (e.getElementName().equals("Number Tile")) { + if (m.getButton() == MouseEvent.BUTTON1) { + if (this.data <= 0 || this.data > 8) { + this.data = 1; + } + else { + this.data = this.data + 1; + } + } + else { + if (m.getButton() == MouseEvent.BUTTON3) { + if (this.data > 1) { + this.data = this.data - 1; + } + else { + this.data = 9; + } + } + } + } + else if (e.getElementName().equals("Unknown Tile")) { + this.data = 0; + } + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java index 18b6cd0a8..bcad1a0ce 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellController.java @@ -1,46 +1,37 @@ package edu.rpi.legup.puzzle.sudoku; -/*import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - - -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.treetent.TreeTentCell;*/ - import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.model.gameboard.PuzzleElement; - - import java.awt.event.MouseEvent; public class SudokuCellController extends ElementController { @Override - public void changeCell(MouseEvent e, PuzzleElement data) { SudokuCell cell = (SudokuCell) data; - System.out.print(111); + if (e.getButton() == MouseEvent.BUTTON1) { if (e.isControlDown()) { - this.boardView.getSelectionPopupMenu().show(boardView, this.boardView.getCanvas().getX() + e.getX(), this.boardView.getCanvas().getY() + e.getY()); - } - else { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { if (cell.getData() < cell.getMax()) { data.setData(cell.getData() + 1); - } - else { + } else { data.setData(0); } } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() > 0) { data.setData(cell.getData() - 1); - } - else { + } else { data.setData(cell.getMax()); } } } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellFactory.java index 90f84d519..1ef24ea59 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuCellFactory.java @@ -4,17 +4,16 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class SudokuCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid @@ -23,7 +22,8 @@ public class SudokuCellFactory extends ElementFactory { public SudokuCell importCell(Node node, Board board) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("cell")) { - throw new InvalidFileFormatException("Sudoku Factory: unknown puzzleElement puzzleElement"); + throw new InvalidFileFormatException( + "Sudoku Factory: unknown puzzleElement puzzleElement"); } SudokuBoard sudokuBoard = (SudokuBoard) board; @@ -44,11 +44,10 @@ public SudokuCell importCell(Node node, Board board) throws InvalidFileFormatExc SudokuCell cell = new SudokuCell(value, new Point(x, y), groupIndex, size); cell.setIndex(y * size + x); return cell; - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Sudoku Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Sudoku Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("Sudoku Factory: could not find attribute(s)"); } } @@ -56,7 +55,7 @@ public SudokuCell importCell(Node node, Board board) throws InvalidFileFormatExc /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuElementView.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuElementView.java index 46d7e4ec7..c3d236b53 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuElementView.java @@ -3,7 +3,6 @@ import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.model.gameboard.GridCell; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; public class SudokuElementView extends GridElementView { @@ -50,18 +49,24 @@ public void drawElement(Graphics2D graphics2D) { FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = String.valueOf(val); int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + int yText = + location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); graphics2D.drawString(value, xText, yText); - } - else { - boolean annotate = LegupPreferences.getInstance().getUserPref(LegupPreferences.SHOW_ANNOTATIONS).equalsIgnoreCase(Boolean.toString(true)); + } else { + boolean annotate = + LegupPreferences.getInstance() + .getUserPref(LegupPreferences.SHOW_ANNOTATIONS) + .equalsIgnoreCase(Boolean.toString(true)); if (annotate) { graphics2D.setColor(FONT_COLOR); graphics2D.setFont(ANNOTATE_FONT); FontMetrics metrics = graphics2D.getFontMetrics(FONT); String value = String.valueOf(cell.getAnnotations()); int xText = location.x + (size.width - metrics.stringWidth(value)) / 2; - int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + int yText = + location.y + + ((size.height - metrics.getHeight()) / 2) + + metrics.getAscent(); graphics2D.drawString(value, xText, yText); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuExporter.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuExporter.java index 45e320293..f10aabae1 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuExporter.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.PuzzleExporter; import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; import org.w3c.dom.Document; public class SudokuExporter extends PuzzleExporter { @@ -16,8 +15,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { SudokuBoard board; if (puzzle.getTree() != null) { board = (SudokuBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (SudokuBoard) puzzle.getBoardView().getBoard(); } @@ -28,7 +26,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { SudokuCell cell = (SudokuCell) puzzleElement; if (cell.getData() != 0) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java index dccec52d4..5084279c3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuImporter.java @@ -2,12 +2,11 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class SudokuImporter extends PuzzleImporter { public SudokuImporter(Sudoku sudoku) { super(sudoku); @@ -26,7 +25,7 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException if board can not be created */ @@ -61,11 +60,13 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("Sudoku Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "Sudoku Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("Sudoku Importer: no puzzleElement found for board"); + throw new InvalidFileFormatException( + "Sudoku Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); NodeList elementDataList = dataElement.getElementsByTagName("cell"); @@ -77,16 +78,19 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { size = Integer.valueOf(boardElement.getAttribute("size")); minorSize = (int) Math.sqrt(size); if (minorSize * minorSize != size) { - throw new InvalidFileFormatException("Sudoku Importer: invalid board dimensions"); + throw new InvalidFileFormatException( + "Sudoku Importer: invalid board dimensions"); } sudokuBoard = new SudokuBoard(size); - } - else { + } else { throw new InvalidFileFormatException("Sudoku Importer: invalid board dimensions"); } for (int i = 0; i < elementDataList.getLength(); i++) { - SudokuCell cell = (SudokuCell) puzzle.getFactory().importCell(elementDataList.item(i), sudokuBoard); + SudokuCell cell = + (SudokuCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), sudokuBoard); Point loc = cell.getLocation(); if (cell.getData() != 0) { cell.setModifiable(false); @@ -106,20 +110,11 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { } } } -// -// for(int y = 0; y < size; y++) -// { -// for(int x = 0; x < size; x++) -// { -// SudokuCell cell = sudokuBoard.getCell(x, y); -// System.err.println("(" + x + ", " + y + ") - " + cell.getGroupIndex()); -// } -// } puzzle.setCurrentBoard(sudokuBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("Sudoku Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "Sudoku Importer: unknown value where integer expected"); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java index bb25c3e21..d2a8d95ab 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/SudokuView.java @@ -5,10 +5,9 @@ import edu.rpi.legup.ui.boardview.ElementView; import edu.rpi.legup.ui.boardview.GridBoardView; import edu.rpi.legup.ui.boardview.SelectionItemView; - -import javax.swing.*; import java.awt.*; import java.util.Set; +import javax.swing.*; public class SudokuView extends GridBoardView { private static final Color STROKE_COLOR = new Color(0, 0, 0); @@ -21,21 +20,26 @@ public SudokuView(SudokuBoard board) { int minorSize = (int) Math.sqrt(gridSize.width); for (int i = 0; i < gridSize.height; i++) { for (int k = 0; k < gridSize.width; k++) { - Point location = new Point(k * elementSize.width + (k / minorSize) * 4 + 5, - i * elementSize.height + (i / minorSize) * 4 + 5); + Point location = + new Point( + k * elementSize.width + (k / minorSize) * 4 + 5,// + i * elementSize.height + (i / minorSize) * 4 + 5); +// Point location = +// new Point( +// k * elementSize.width, +// i * elementSize.height); SudokuElementView element = new SudokuElementView(board.getCell(k, i)); element.setIndex(i * gridSize.width + k); + element.setIndex(i * gridSize.width); element.setSize(elementSize); element.setLocation(location); elementViews.add(element); } } - } /** - * Gets the SudokuElementView from the puzzleElement index or - * null if out of bounds + * Gets the SudokuElementView from the puzzleElement index or null if out of bounds * * @param index index of the ElementView * @return SudokuElementView at the specified index @@ -49,7 +53,9 @@ public void drawGrid(Graphics2D graphics2D) { int minorSize = (int) Math.sqrt(gridSize.width); graphics2D.setColor(STROKE_COLOR); graphics2D.setStroke(MAJOR_STOKE); - graphics2D.drawRect(3, 3, + graphics2D.drawRect( + 3, + 3, gridSize.width * (elementSize.width + 1) + 3, gridSize.height * (elementSize.height + 1) + 3); @@ -81,8 +87,7 @@ public void drawBoard(Graphics2D graphics2D) { ElementView element = elementViews.get(i * gridSize.height + k); if (!element.isHover()) { element.draw(graphics2D); - } - else { + } else { hover = element; } } @@ -107,8 +112,7 @@ public void drawCaseBoard(Graphics2D graphics2D) { ElementView element = elementViews.get(i * gridSize.height + k); if (!element.isHover()) { element.draw(graphics2D); - } - else { + } else { hover = element; } } @@ -117,7 +121,10 @@ public void drawCaseBoard(Graphics2D graphics2D) { graphics2D.setColor(new Color(0x1A, 0x23, 0x7E, 200)); for (int r : caseBoard.getPickableRegions()) { Set region = sudokuBoard.getRegion(r); - int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE, w = Integer.MIN_VALUE, h = Integer.MIN_VALUE; + int x = Integer.MAX_VALUE, + y = Integer.MAX_VALUE, + w = Integer.MIN_VALUE, + h = Integer.MIN_VALUE; for (SudokuCell c : region) { x = Math.min(x, c.getLocation().x); y = Math.min(y, c.getLocation().y); @@ -134,8 +141,8 @@ public void drawCaseBoard(Graphics2D graphics2D) { graphics2D.fillRect(x + 4, y + 4, w - 8, h - 8); } -// if(hover != null) -// hover.draw(graphics2D); + // if(hover != null) + // hover.draw(graphics2D); } protected Dimension getProperSize() { @@ -151,10 +158,14 @@ public DataSelectionView getSelectionPopupMenu() { selectionView.setLayout(layout); for (int r = 1; r <= 3; r++) { for (int c = 1; c <= 3; c++) { - SudokuElementView element = new SudokuElementView(new SudokuCell((r - 1) * 3 + c, null, 0, gridSize.width)); + SudokuElementView element = + new SudokuElementView( + new SudokuCell((r - 1) * 3 + c, null, 0, gridSize.width)); element.setSize(new Dimension(32, 32)); element.setLocation(new Point(0, 0)); - SelectionItemView item = new SelectionItemView(element.getPuzzleElement(), new ImageIcon(element.getImage())); + SelectionItemView item = + new SelectionItemView( + element.getPuzzleElement(), new ImageIcon(element.getImage())); item.addActionListener(elementController); item.setHorizontalTextPosition(SwingConstants.CENTER); selectionView.add(item); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java index e3159d87c..b8f4a596c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/NumberTile.java @@ -1,28 +1,14 @@ + package edu.rpi.legup.puzzle.sudoku.elements; import edu.rpi.legup.model.elements.PlaceableElement; public class NumberTile extends PlaceableElement { - private int object_num; - public NumberTile() { - super("SUDO-PLAC-0001", "Number Tile", "A numbered tile", null); - object_num = 0; - } - - /** - * @return this object's tile number... - */ - public int getTileNumber() { - return object_num; + super( + "SUDO-ELEM-0001", + "Number Tile", + "A number tile", + "edu/rpi/legup/images/sudoku/tiles/NumberTile.png"); } - - /** - * @param num Amount to set tile object to. - */ - public void setTileNumber(int num) { - object_num = num; - } - - -} +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java new file mode 100644 index 000000000..162ba46d1 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/UnknownTile.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.sudoku.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class UnknownTile extends PlaceableElement { + public UnknownTile() { + super( + "SUDO-ELEM-0002", + "Unknown Tile", + "A blank tile", + "edu/rpi/legup/images/sudoku/tiles/UnknownTile.png"); + } +} \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt new file mode 100644 index 000000000..b8df27eb6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/elements/sudoku_elements_reference_sheet.txt @@ -0,0 +1,2 @@ +SUDO-ELEM-0001 : NumberTile +SUDO-ELEM-0002 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java deleted file mode 100644 index 0be30fa36..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/AdvancedDeductionDirectRule.java +++ /dev/null @@ -1,96 +0,0 @@ -package edu.rpi.legup.puzzle.sudoku.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -public class AdvancedDeductionDirectRule extends DirectRule { - - public AdvancedDeductionDirectRule() { - super("SUDO-BASC-0001", "Advanced Deduction", - "Use of group logic deduces more answers by means of forced by Location and forced by Deduction", - "edu/rpi/legup/images/sudoku/AdvancedDeduction.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); - SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - - SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); - int index = cell.getIndex(); - int groupSize = initialBoard.getWidth(); - int groupDim = (int) Math.sqrt(groupSize); - int rowIndex = index / groupSize; - int colIndex = index % groupSize; - int relX = rowIndex / groupDim; - int relY = colIndex % groupDim; - int groupNum = rowIndex / groupDim * groupDim + colIndex / groupDim; - boolean[][] possible = new boolean[groupDim][groupDim]; - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupDim; x++) { - SudokuCell c = initialBoard.getCell(groupNum, x, y); - if (c.getData() == cell.getData() && x != relX && y != relY) { - return super.getRuleName() + ": Duplicate value in sub-region"; - } - possible[y][x] = c.getData() == 0; - } - } - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupSize; x++) { - SudokuCell r = initialBoard.getCell(x, (groupNum / groupDim) * groupDim + y); - SudokuCell c = initialBoard.getCell((groupNum % groupDim) * groupDim + y, x); - if (r.getData() == cell.getData()) { - for (int i = 0; i < groupDim; i++) { - possible[y][i] = false; - } - } - if (c.getData() == cell.getData()) { - for (int i = 0; i < groupDim; i++) { - possible[i][y] = false; - } - } - } - } - boolean isForced = false; - for (int y = 0; y < groupDim; y++) { - for (int x = 0; x < groupDim; x++) { - if (possible[y][x] && !isForced) { - isForced = true; - } - else { - if (possible[y][x]) { - return super.getInvalidUseOfRuleMessage() + ": Not forced"; - } - } - } - } - if (!isForced) { - return super.getInvalidUseOfRuleMessage() + ": Not forced"; - } - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java index 51d963247..6544bf7c3 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastCellForNumberDirectRule.java @@ -1,93 +1,189 @@ -package edu.rpi.legup.puzzle.sudoku.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -import java.util.Set; - -public class LastCellForNumberDirectRule extends DirectRule { - public LastCellForNumberDirectRule() { - super("SUDO-BASC-0002", "Last Cell for Number", - "This is the only cell open in its group for some number.", - "edu/rpi/legup/images/sudoku/forcedByElimination.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); - SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - - SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); - if (cell.getData() == 0) { - return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; - } - - int size = initialBoard.getSize(); - - Set region = initialBoard.getRegion(cell.getGroupIndex()); - Set row = initialBoard.getRow(cell.getLocation().y); - Set col = initialBoard.getCol(cell.getLocation().x); - - boolean contains = false; - if (region.size() == size - 1) { - for (SudokuCell c : region) { - if (cell.getData() == c.getData()) { - contains = true; - break; - } - } - if (!contains) { - return null; - } - } - if (row.size() == size - 1) { - contains = false; - for (SudokuCell c : row) { - if (cell.getData() == c.getData()) { - contains = true; - break; - } - } - if (!contains) { - return null; - } - } - if (col.size() == size - 1) { - contains = false; - for (SudokuCell c : col) { - if (cell.getData() == c.getData()) { - contains = true; - break; - } - } - if (!contains) { - return null; - } - } - return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.Set; + +public class LastCellForNumberDirectRule extends DirectRule { + public LastCellForNumberDirectRule() { + super( + "SUDO-BASC-0002", + "Last Cell for Number", + "This is the only cell open in its group for some number.", + "edu/rpi/legup/images/sudoku/rules/forcedByElimination.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); + SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); + + SudokuCell cell = (SudokuCell) finalBoard.getPuzzleElement(puzzleElement); + + // Check if empty cell placed + if (cell.getData() == 0) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + + // Get defaults + Set region = initialBoard.getRegion(cell.getGroupIndex()); + Set row = initialBoard.getRow(cell.getLocation().y); + Set col = initialBoard.getCol(cell.getLocation().x); + + // Check if new cell conflicts group + for (SudokuCell c : region) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + for (SudokuCell c : row) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + for (SudokuCell c : col) { + if (c.getData() == cell.getData()) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + } + + // // + // Loop to see if the number is constrained to the cell + boolean restrained = true; + for (SudokuCell c : region) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set crow = initialBoard.getRow(c.getLocation().y); + Set ccol = initialBoard.getCol(c.getLocation().x); + boolean contains = false; + for (SudokuCell rc : crow) { + if (rc.getData() == cell.getData()) { + contains = true; + } + } + for (SudokuCell cc : ccol) { + if (cc.getData() == cell.getData()) { + contains = true; + } + } + // Stop if another cell can hold number + if (!contains) { + restrained = false; + break; + } + } + // Output if success + if (restrained) { + return null; + } + + // // + // Loop to see if the number is constrained to the cell + restrained = true; + for (SudokuCell c : row) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set cregion = initialBoard.getRegion(c.getGroupIndex()); + Set ccol = initialBoard.getCol(c.getLocation().x); + boolean contains = false; + for (SudokuCell rc : cregion) { + if (rc.getData() == cell.getData()) { + contains = true; + } + } + for (SudokuCell cc : ccol) { + if (cc.getData() == cell.getData()) { + contains = true; + } + } + // Stop if another cell can hold number + if (!contains) { + restrained = false; + break; + } + } + // Output if success + if (restrained) { + return null; + } + + // // + // Loop to see if the number is constrained to the cell + restrained = true; + for (SudokuCell c : col) { + // Test if its not a valid testing cell + if (c.getData() != 0) { + continue; + } + if (c.getLocation().y == cell.getLocation().y + && c.getLocation().x == cell.getLocation().x) { + continue; + } + // Check if cell is eligible to hold number + Set cregion = initialBoard.getRegion(c.getGroupIndex()); + Set crow = initialBoard.getRow(c.getLocation().y); + boolean contains = false; + for (SudokuCell rc : cregion) { + if (rc.getData() == cell.getData()) { + contains = true; + } + } + for (SudokuCell cc : crow) { + if (cc.getData() == cell.getData()) { + contains = true; + } + } + // Stop if another cell can hold number + if (!contains) { + restrained = false; + break; + } + } + // Output if success + if (restrained) { + return null; + } + + // Output fail + return super.getInvalidUseOfRuleMessage() + ": Cell is not forced at this index"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java index 28e64ce7b..333d91749 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/LastNumberForCellDirectRule.java @@ -1,77 +1,94 @@ -package edu.rpi.legup.puzzle.sudoku.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -import java.util.HashSet; - -public class LastNumberForCellDirectRule extends DirectRule { - - public LastNumberForCellDirectRule() { - super("SUDO-BASC-0003", "Last Number for Cell", - "This is the only number left that can fit in the cell of a group.", - "edu/rpi/legup/images/sudoku/forcedByDeduction.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); - SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); - - int index = puzzleElement.getIndex(); - int groupSize = initialBoard.getWidth(); - int groupDim = (int) Math.sqrt(groupSize); - int rowIndex = index / groupSize; - int colIndex = index % groupSize; - int groupNum = rowIndex / groupDim * groupDim + colIndex % groupDim; - HashSet numbers = new HashSet<>(); - for (int i = 1; i <= groupSize; i++) { - numbers.add(i); - } - for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(groupNum, i % groupDim, i / groupDim); - numbers.remove(cell.getData()); - } - for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(i, colIndex); - numbers.remove(cell.getData()); - } - for (int i = 0; i < groupSize; i++) { - SudokuCell cell = initialBoard.getCell(rowIndex, i); - numbers.remove(cell.getData()); - } - if (numbers.size() > 1) { - return super.getInvalidUseOfRuleMessage() + ": The number at the index is not forced"; - } - else { - if (numbers.size() == 1 && numbers.iterator().next() != finalBoard.getPuzzleElement(puzzleElement).getData()) { - return super.getInvalidUseOfRuleMessage() + ": The number at the index is forced but not correct"; - } - } - return null; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.HashSet; + +public class LastNumberForCellDirectRule extends DirectRule { + + public LastNumberForCellDirectRule() { + super( + "SUDO-BASC-0003", + "Last Number for Cell", + "This is the only number left that can fit in the cell of a group.", + "edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + SudokuBoard initialBoard = (SudokuBoard) transition.getParents().get(0).getBoard(); + SudokuBoard finalBoard = (SudokuBoard) transition.getBoard(); + + // Assign basics + int groupSize = initialBoard.getWidth(); + int groupDim = (int) Math.sqrt(groupSize); + + // Get position info + int index = puzzleElement.getIndex(); + int rowIndex = index / groupSize; + int colIndex = index % groupSize; + int groupNum = (rowIndex / groupDim) * groupDim + (colIndex / groupDim); + + // Create hashset of all numbers + HashSet numbers = new HashSet<>(); + for (int i = 1; i <= groupSize; i++) { + numbers.add(i); + } + + // Run through region, row, col to see contradicitng numbers + for (int i = 0; i < groupSize; i++) { + SudokuCell cell = initialBoard.getCell(groupNum, i % groupDim, i / groupDim); + numbers.remove(cell.getData()); + } + for (int i = 0; i < groupSize; i++) { + SudokuCell cell = initialBoard.getCell(i, rowIndex); + numbers.remove(cell.getData()); + } + for (int i = 0; i < groupSize; i++) { + SudokuCell cell = initialBoard.getCell(colIndex, i); + numbers.remove(cell.getData()); + } + + // Check if plausible + if (numbers.size() > 1) { + return super.getInvalidUseOfRuleMessage() + ": The number at the index is not forced"; + } else { + if (numbers.size() == 1 + && numbers.iterator().next() + != finalBoard.getPuzzleElement(puzzleElement).getData()) { + return super.getInvalidUseOfRuleMessage() + + ": The number at the index is forced but not correct"; + } + } + if (numbers.toArray(new Integer[1])[0] == puzzleElement.getData()) { + return null; + } + return super.getInvalidUseOfRuleMessage() + + ": The number at the index is forced but not correct"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java new file mode 100644 index 000000000..c8d627634 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberColumnContradictionRule.java @@ -0,0 +1,90 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.HashSet; +import java.util.Set; + +public class NoCellForNumberColumnContradictionRule extends ContradictionRule { + + public NoCellForNumberColumnContradictionRule() { + super( + "SUDO-CONT-0003", + "No Cell for Number (Column)", + "Process of elimination yields no valid numbers for an empty cell in a column.", + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set col = sudokuBoard.getCol(cell.getGroupIndex()); + Set numbersNotInColumn = new HashSet<>(); + + for (int i = 1; i <= groupSize; i++) { + numbersNotInColumn.add(i); + } + for (SudokuCell c : col) { + if (c.getData() != 0) { + numbersNotInColumn.remove(c.getData()); + } + } + + for (Integer i : numbersNotInColumn) { + // Check if number can be in cell + boolean canFit = false; + for (SudokuCell c : col) { + if (c.getData() != 0) { + continue; + } + + // Get row and col groups + Set region = sudokuBoard.getRow(c.getLocation().y); + Set row = sudokuBoard.getCol(c.getLocation().x); + + // Check if it alr exists in row or col + boolean duplicate = false; + for (SudokuCell rc : region) { + if (rc.getData() == i) { + duplicate = true; + } + } + for (SudokuCell cc : row) { + if (cc.getData() == i) { + duplicate = true; + } + } + + // If there is no duplicate it can exist in the region + if (!duplicate) { + canFit = true; + break; + } + } + // If the number can't fit anywhere in region then contradiction + if (!canFit) { + return null; + } + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java new file mode 100644 index 000000000..f5106b858 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRegionContradictionRule.java @@ -0,0 +1,90 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.HashSet; +import java.util.Set; + +public class NoCellForNumberRegionContradictionRule extends ContradictionRule { + + public NoCellForNumberRegionContradictionRule() { + super( + "SUDO-CONT-0001", + "No Cell for Number (Region)", + "Process of elimination yields no valid numbers for an empty cell in a region.", + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set region = sudokuBoard.getRegion(cell.getGroupIndex()); + Set numbersNotInRegion = new HashSet<>(); + + for (int i = 1; i <= groupSize; i++) { + numbersNotInRegion.add(i); + } + for (SudokuCell c : region) { + if (c.getData() != 0) { + numbersNotInRegion.remove(c.getData()); + } + } + + for (Integer i : numbersNotInRegion) { + // Check if number can be in cell + boolean canFit = false; + for (SudokuCell c : region) { + if (c.getData() != 0) { + continue; + } + + // Get row and col groups + Set row = sudokuBoard.getRow(c.getLocation().y); + Set col = sudokuBoard.getCol(c.getLocation().x); + + // Check if it alr exists in row or col + boolean duplicate = false; + for (SudokuCell rc : row) { + if (rc.getData() == i) { + duplicate = true; + } + } + for (SudokuCell cc : col) { + if (cc.getData() == i) { + duplicate = true; + } + } + + // If there is no duplicate it can exist in the region + if (!duplicate) { + canFit = true; + break; + } + } + // If the number can't fit anywhere in region then contradiction + if (!canFit) { + return null; + } + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java new file mode 100644 index 000000000..e3f9f764a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoCellForNumberRowContradictionRule.java @@ -0,0 +1,90 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.HashSet; +import java.util.Set; + +public class NoCellForNumberRowContradictionRule extends ContradictionRule { + + public NoCellForNumberRowContradictionRule() { + super( + "SUDO-CONT-0002", + "No Cell for Number (Row)", + "Process of elimination yields no valid numbers for an empty cell in a row.", + "edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + SudokuBoard sudokuBoard = (SudokuBoard) board; + SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); + if (cell.getData() != 0) { + return super.getNoContradictionMessage(); + } + + int groupSize = sudokuBoard.getSize(); + + Set row = sudokuBoard.getRow(cell.getGroupIndex()); + Set numbersNotInRow = new HashSet<>(); + + for (int i = 1; i <= groupSize; i++) { + numbersNotInRow.add(i); + } + for (SudokuCell c : row) { + if (c.getData() != 0) { + numbersNotInRow.remove(c.getData()); + } + } + + for (Integer i : numbersNotInRow) { + // Check if number can be in cell + boolean canFit = false; + for (SudokuCell c : row) { + if (c.getData() != 0) { + continue; + } + + // Get row and col groups + Set region = sudokuBoard.getRow(c.getLocation().y); + Set col = sudokuBoard.getCol(c.getLocation().x); + + // Check if it alr exists in row or col + boolean duplicate = false; + for (SudokuCell rc : region) { + if (rc.getData() == i) { + duplicate = true; + } + } + for (SudokuCell cc : col) { + if (cc.getData() == i) { + duplicate = true; + } + } + + // If there is no duplicate it can exist in the region + if (!duplicate) { + canFit = true; + break; + } + } + // If the number can't fit anywhere in region then contradiction + if (!canFit) { + return null; + } + } + return super.getNoContradictionMessage(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java similarity index 66% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java index fb87764fe..6ea8f0a2a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoSolutionContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/NoNumberForCellContradictionRule.java @@ -5,25 +5,27 @@ import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; - import java.util.HashSet; import java.util.Set; -public class NoSolutionContradictionRule extends ContradictionRule { +public class NoNumberForCellContradictionRule extends ContradictionRule { - public NoSolutionContradictionRule() { - super("SUDO-CONT-0001", "No Solution for Cell", + public NoNumberForCellContradictionRule() { + super( + "SUDO-CONT-0004", + "No Number for Cell", "Process of elimination yields no valid numbers for an empty cell.", - "edu/rpi/legup/images/sudoku/NoSolution.png"); + "edu/rpi/legup/images/sudoku/rules/NoSolution.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -39,21 +41,19 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Set row = sudokuBoard.getRow(cell.getLocation().y); Set col = sudokuBoard.getCol(cell.getLocation().x); Set solution = new HashSet<>(); - for (int i = 1; i <= groupSize; i++) { - solution.add(i); - } - - for (SudokuCell c : region) { - solution.remove(c.getData()); + for (SudokuCell s : region) { + solution.add(s.getData()); } - for (SudokuCell c : row) { - solution.remove(c.getData()); + for (SudokuCell s : row) { + solution.add(s.getData()); } - for (SudokuCell c : col) { - solution.remove(c.getData()); + + for (SudokuCell s : col) { + solution.add(s.getData()); } + solution.remove(0); - if (solution.isEmpty()) { + if (solution.size() == 9) { return null; } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java new file mode 100644 index 000000000..bab0bc79b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberColumnCaseRule.java @@ -0,0 +1,107 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.GroupType; +import edu.rpi.legup.puzzle.sudoku.ModelSudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.ArrayList; +import java.util.Set; + +public class PossibleCellsForNumberColumnCaseRule extends CaseRule { + + // Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + // Old board for caseBoard reference + private SudokuBoard lagBoard; + + public PossibleCellsForNumberColumnCaseRule() { + super( + "SUDO-CASE-0004", + "Possible Cells for Number - Column", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelColumnNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return getCases(board, puzzleElement, 1, GroupType.COLUMN); + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases( + Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + ArrayList cases = new ArrayList<>(); + SudokuBoard sudokuBoard = lagBoard; + SudokuCell sourceCell = (SudokuCell) puzzleElement; + + Set group = sudokuBoard.getCol(sourceCell.getLocation().x); + for (SudokuCell cell : group) { + if (cell.getData() == 0) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelColumnNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); + } + } + return cases; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java new file mode 100644 index 000000000..47e408369 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRegionCaseRule.java @@ -0,0 +1,104 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.*; +import java.util.ArrayList; +import java.util.Set; + +public class PossibleCellsForNumberRegionCaseRule extends CaseRule { + + // Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + // Old board for caseBoard reference + private SudokuBoard lagBoard; + + public PossibleCellsForNumberRegionCaseRule() { + super( + "SUDO-CASE-0002", + "Possible Cells for Number - Region", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelRegionNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return getCases(board, puzzleElement, 1, GroupType.REGION); + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases( + Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + ArrayList cases = new ArrayList<>(); + SudokuBoard sudokuBoard = lagBoard; + SudokuCell sourceCell = (SudokuCell) puzzleElement; + + Set group = sudokuBoard.getRegion(sourceCell.getGroupIndex()); + for (SudokuCell cell : group) { + if (cell.getData() == 0) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelRegionNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); + } + } + return cases; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java new file mode 100644 index 000000000..868541377 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellsForNumberRowCaseRule.java @@ -0,0 +1,107 @@ +package edu.rpi.legup.puzzle.sudoku.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.GroupType; +import edu.rpi.legup.puzzle.sudoku.ModelSudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import java.util.ArrayList; +import java.util.Set; + +public class PossibleCellsForNumberRowCaseRule extends CaseRule { + + // Board math for translating indexes to numbers + private ModelSudokuBoard model = new ModelSudokuBoard(); + + // Old board for caseBoard reference + private SudokuBoard lagBoard; + + public PossibleCellsForNumberRowCaseRule() { + super( + "SUDO-CASE-0003", + "Possible Cells for Number - Row", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + SudokuBoard sudokuBoard = (SudokuBoard) board.copy(); + lagBoard = (SudokuBoard) sudokuBoard.copy(); + CaseBoard caseBoard = new CaseBoard(sudokuBoard, this); + for (PuzzleElement puzzleElement : sudokuBoard.getPuzzleElements()) { + puzzleElement.setData(model.getModelRowNumbers(puzzleElement.getIndex())); + caseBoard.addPickableElement(puzzleElement); + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return getCases(board, puzzleElement, 1, GroupType.ROW); + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases( + Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + ArrayList cases = new ArrayList<>(); + SudokuBoard sudokuBoard = lagBoard; + SudokuCell sourceCell = (SudokuCell) puzzleElement; + + Set group = sudokuBoard.getRow(sourceCell.getLocation().y); + for (SudokuCell cell : group) { + if (cell.getData() == 0) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(cell); + element.setData(model.getModelRowNumbers(sourceCell.getIndex())); + newCase.addModifiedData(element); + cases.add(newCase); + } + } + return cases; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java deleted file mode 100644 index 27d6b58b7..000000000 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumberCaseRule.java +++ /dev/null @@ -1,131 +0,0 @@ -package edu.rpi.legup.puzzle.sudoku.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.CaseBoard; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.CaseRule; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.sudoku.GroupType; -import edu.rpi.legup.puzzle.sudoku.PossibleNumberCaseBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -public class PossibleNumberCaseRule extends CaseRule { - - public PossibleNumberCaseRule() { - super("SUDO-CASE-0002", "Possible Numbers for Cell", - "An empty cell has a limited set of possible numbers that can fill it.", - "edu/rpi/legup/images/sudoku/PossibleValues.png"); - } - - /** - * Checks whether the transition logically follows from the parent node using this rule - * - * @param transition transition to check - * @return null if the child node logically follow from the parent node, otherwise error message - */ - @Override - public String checkRuleRaw(TreeTransition transition) { - return null; - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - return null; - } - - @Override - public CaseBoard getCaseBoard(Board board) { - SudokuBoard sudokuBoard = (SudokuBoard) board; - PossibleNumberCaseBoard caseBoard = new PossibleNumberCaseBoard(sudokuBoard, this, null); - for (int i = 0; i < sudokuBoard.getSize(); i++) { - caseBoard.addPickableRegion(i); - caseBoard.addPickableRow(i); - caseBoard.addPickableCol(i); - } - return caseBoard; - } - - /** - * Gets the possible cases at a specific location based on this case rule - * - * @param board the current board state - * @param puzzleElement equivalent puzzleElement - * @return a list of elements the specified could be - */ - @Override - public ArrayList getCases(Board board, PuzzleElement puzzleElement) { - return getCases(board, puzzleElement, 1, GroupType.REGION); - } - - /** - * Gets the possible cases at a specific location based on this case rule - * - * @param board the current board state - * @param puzzleElement equivalent puzzleElement - * @param value value that the rule will be applied from - * @param groupType group type - * @return a list of elements the specified could be - */ - public ArrayList getCases(Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { - ArrayList cases = new ArrayList<>(); - SudokuBoard sudokuBoard = (SudokuBoard) board; - List caseCells = new ArrayList<>(); - SudokuCell cell = (SudokuCell) puzzleElement; - - Set group; - if (groupType == GroupType.REGION) { - group = sudokuBoard.getRegion(cell.getGroupIndex()); - } - else { - if (groupType == GroupType.ROW) { - group = sudokuBoard.getRow(cell.getLocation().y); - } - else { - group = sudokuBoard.getCol(cell.getLocation().x); - } - } - - for (SudokuCell c : group) { - if (c.getData() == 0) { - Set blockableCells = sudokuBoard.getRegion(c.getGroupIndex()); - blockableCells.addAll(sudokuBoard.getRow(c.getLocation().y)); - blockableCells.addAll(sudokuBoard.getCol(c.getLocation().x)); - - boolean repeat = false; - for (SudokuCell bc : blockableCells) { - if (bc.getData() == value) { - repeat = true; - break; - } - } - if (!repeat) { - caseCells.add(c); - } - } - } - - for (SudokuCell c : caseCells) { - Board newCase = sudokuBoard.copy(); - PuzzleElement element = newCase.getPuzzleElement(c); - element.setData(value); - newCase.addModifiedData(element); - cases.add(newCase); - } - - return cases; - } -} diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java similarity index 52% rename from src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java rename to src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java index 373b60457..e17acc26b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleCellCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/PossibleNumbersForCellCaseRule.java @@ -5,18 +5,18 @@ import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.sudoku.SudokuBoard; -import edu.rpi.legup.puzzle.sudoku.SudokuCell; - +import edu.rpi.legup.puzzle.sudoku.*; import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; +import java.util.List; + +public class PossibleNumbersForCellCaseRule extends CaseRule { -public class PossibleCellCaseRule extends CaseRule { - public PossibleCellCaseRule() { - super("SUDO-CASE-0001", "Possible Cells for Number", - "A number has a limited set of cells in which it can be placed.", - "edu/rpi/legup/images/sudoku/possible_cells_number.png"); + public PossibleNumbersForCellCaseRule() { + super( + "SUDO-CASE-0001", + "Possible Numbers for Cell", + "An empty cell has a limited set of possible numbers that can fill it.", + "edu/rpi/legup/images/sudoku/rules/PossibleValues.png"); } /** @@ -31,13 +31,13 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -59,48 +59,40 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { - ArrayList cases = new ArrayList<>(); - SudokuBoard sudokuBoard = (SudokuBoard) board; - SudokuCell cell = (SudokuCell) puzzleElement; - - Set possibleValue = new HashSet<>(); - for (int i = 1; i <= sudokuBoard.getSize(); i++) { - possibleValue.add(i); - } - - int groupNum = cell.getGroupIndex(); - for (SudokuCell c : sudokuBoard.getRegion(groupNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } - } - - int rowNum = cell.getLocation().y; - for (SudokuCell c : sudokuBoard.getRegion(rowNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } - } + return getCases(board, puzzleElement, 1, GroupType.REGION); + } - int colNum = cell.getLocation().x; - for (SudokuCell c : sudokuBoard.getRegion(colNum)) { - if (c.getData().equals(c.getData())) { - possibleValue.remove(c.getData()); - } + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @param value value that the rule will be applied from + * @param groupType group type + * @return a list of elements the specified could be + */ + public ArrayList getCases( + Board board, PuzzleElement puzzleElement, int value, GroupType groupType) { + ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; } - for (Integer i : possibleValue) { - SudokuBoard newCase = sudokuBoard.copy(); + SudokuBoard sudokuBoard = (SudokuBoard) board; + List caseCells = new ArrayList<>(); + SudokuCell cell = (SudokuCell) puzzleElement; - PuzzleElement newCasePuzzleElement = newCase.getPuzzleElement(puzzleElement); - newCasePuzzleElement.setData(i); - newCase.addModifiedData(newCasePuzzleElement); + for (int i = 1; i <= 9; i++) { + Board newCase = sudokuBoard.copy(); + PuzzleElement element = newCase.getPuzzleElement(puzzleElement); + element.setData(i); + newCase.addModifiedData(element); cases.add(newCase); } diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java index 4a5cc2074..f8172d071 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/RepeatedNumberContradictionRule.java @@ -5,61 +5,75 @@ import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.sudoku.SudokuBoard; import edu.rpi.legup.puzzle.sudoku.SudokuCell; - import java.util.HashSet; import java.util.Set; public class RepeatedNumberContradictionRule extends ContradictionRule { public RepeatedNumberContradictionRule() { - super("SUDO-CONT-0002", "Repeated Numbers", + super( + "SUDO-CONT-0005", + "Repeated Numbers", "Two identical numbers are placed in the same group.", - "edu/rpi/legup/images/sudoku/RepeatedNumber.png"); + "edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + // Get board to check SudokuBoard sudokuBoard = (SudokuBoard) board; - SudokuCell cell = (SudokuCell) sudokuBoard.getPuzzleElement(puzzleElement); - if (cell.getData() == 0) { - return super.getNoContradictionMessage(); - } - Set region = sudokuBoard.getRegion(cell.getGroupIndex()); - Set row = sudokuBoard.getRow(cell.getLocation().y); - Set col = sudokuBoard.getCol(cell.getLocation().x); + // Loop all group indexes + for (int i = 0; i < 9; i++) { + // Get regions and sets to check duplicates + Set region = sudokuBoard.getRegion(i); + Set regionDup = new HashSet<>(); + + Set row = sudokuBoard.getRow(i); + Set rowDup = new HashSet<>(); - Set regionDup = new HashSet<>(); - Set rowDup = new HashSet<>(); - Set colDup = new HashSet<>(); + Set col = sudokuBoard.getCol(i); + Set colDup = new HashSet<>(); - for (SudokuCell c : region) { - if (regionDup.contains(c.getData())) { - return null; + // Check for non zero duplicates to trigger contradiction + for (SudokuCell c : region) { + if (c.getData() == 0) { + continue; + } + if (regionDup.contains(c.getData())) { + return null; + } + regionDup.add(c.getData()); } - regionDup.add(c.getData()); - } - for (SudokuCell c : row) { - if (rowDup.contains(c.getData())) { - return null; + for (SudokuCell c : row) { + if (c.getData() == 0) { + continue; + } + if (rowDup.contains(c.getData())) { + return null; + } + rowDup.add(c.getData()); } - rowDup.add(c.getData()); - } - for (SudokuCell c : col) { - if (colDup.contains(c.getData())) { - return null; + for (SudokuCell c : col) { + if (c.getData() == 0) { + continue; + } + if (colDup.contains(c.getData())) { + return null; + } + colDup.add(c.getData()); } - colDup.add(c.getData()); } return super.getNoContradictionMessage(); diff --git a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt index a8635330d..ceffa168c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt +++ b/src/main/java/edu/rpi/legup/puzzle/sudoku/rules/sudoku_reference_sheet.txt @@ -1,9 +1,13 @@ -SUDO-BASC-0001 : AdvancedDeductionDirectRule SUDO-BASC-0002 : LastCellForNumberDirectRule SUDO-BASC-0003 : LastNumberForCellDirectRule -SUDO-CONT-0001 : NoSolutionContradictionRule -SUDO-CONT-0002 : RepeatedNumberContradictionRule +SUDO-CONT-0001 : NoCellForNumberRegionContradictionRule +SUDO-CONT-0002 : NoCellForNumberRowContradictionRule +SUDO-CONT-0003 : NoCellForNumberColumnContradictionRule +SUDO-CONT-0004 : NoNumberForCellContradictionRule +SUDO-CONT-0005 : RepeatedNumberContradictionRule -SUDO-CASE-0001 : PossibleCellCaseRule -SUDO-CASE-0002 : PossibleNumberCaseRule \ No newline at end of file +SUDO-CASE-0001 : PossibleNumbersForCellCaseRule +SUDO-CASE-0002 : PossibleCellsForNumberRegionCaseRule +SUDO-CASE-0003 : PossibleCellsForNumberRowCaseRule +SUDO-CASE-0004 : PossibleCellsForNumberColumnCaseRule \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/Thermometer.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/Thermometer.java new file mode 100644 index 000000000..8138104f5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/Thermometer.java @@ -0,0 +1,56 @@ +package edu.rpi.legup.puzzle.thermometer; + +import edu.rpi.legup.model.Puzzle; +import edu.rpi.legup.model.gameboard.Board; + +// basically just copy-pasted from dev guide on wiki +public class Thermometer extends Puzzle { + public Thermometer() { + super(); + + this.name = "Thermometer"; + + this.importer = new ThermometerImporter(this); + this.exporter = new ThermometerExporter(this); + // we do not have a thermometerCellFactory class as + // thermometerVial has its own thermometerCell factory method + } + + /** Initializes the game board. Called by the invoker of the class */ + @Override + public void initializeView() { + boardView = new ThermometerView((ThermometerBoard) currentBoard); + boardView.setBoard(currentBoard); + addBoardListener(boardView); + } + + /** + * Generates a random edu.rpi.legup.puzzle based on the difficulty + * + * @param difficulty level of difficulty (1-10) + * @return board of the random edu.rpi.legup.puzzle + */ + @Override + public Board generatePuzzle(int difficulty) { + return null; + } + + /** + * Determines if the current board is a valid state + * + * @param board board to check for validity + * @return true if board is valid, false otherwise + */ + @Override + public boolean isBoardComplete(Board board) { + return true; + } + + /** + * Callback for when the board puzzleElement changes + * + * @param board the board that has changed + */ + @Override + public void onBoardChange(Board board) {} +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerBoard.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerBoard.java new file mode 100644 index 000000000..95ff7ff83 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerBoard.java @@ -0,0 +1,139 @@ +package edu.rpi.legup.puzzle.thermometer; + +import edu.rpi.legup.model.gameboard.GridBoard; +import java.awt.*; +import java.util.ArrayList; + +public class ThermometerBoard extends GridBoard { + + // an array containing all of our vials on the board + private ArrayList thermometerVials; + + // representations of the number requirements along rows and columns of the board + // we use rotation to store the number + private ArrayList colNumbers; + private ArrayList rowNumbers; + + private ThermometerCell dummyCell; + + // constructors for the boards and variables + public ThermometerBoard(int width, int height) { + super(width, height); + + // initializing the row/col number arrays with zeros, so they can be + // easily updated using the setRow/ColNumber functions + colNumbers = new ArrayList<>(); + for (int i = 0; i < width - 1; i++) { + ThermometerCell cell = + new ThermometerCell( + new Point(i, height - 1), + ThermometerType.UNKNOWN, + ThermometerFill.UNKNOWN, + 0); + cell.setIndex((height - 1) * height + i); + colNumbers.add(cell); + this.setCell(i, height - 1, cell); + } + rowNumbers = new ArrayList<>(); + for (int i = 0; i < height - 1; i++) { + ThermometerCell cell = + new ThermometerCell( + new Point(width - 1, i), + ThermometerType.UNKNOWN, + ThermometerFill.UNKNOWN, + 0); + cell.setIndex(i * height + (width - 1)); + rowNumbers.add(cell); + this.setCell(width - 1, i, cell); + } + + // setting a dummy cell so board doesn't have null cells + dummyCell = + new ThermometerCell( + new Point(width - 1, height - 1), + ThermometerType.UNKNOWN, + ThermometerFill.UNKNOWN, + -1); + dummyCell.setIndex((height - 1) * height + width); + this.setCell(width - 1, height - 1, dummyCell); + + // creating our empty vial of thermometers to add to + thermometerVials = new ArrayList<>(); + } + + // setters and accessors for our array of vials + public void addVial(ThermometerVial v) { + thermometerVials.add(v); + } + + public ArrayList getVials() { + return thermometerVials; + } + + // our setters for row/col numbers with simple input verification + public boolean setRowNumber(int row, int num) { + // first check is to verify we are updating an element in range + // second check is to verify the new number can be achieved by the puzzle + if (row < rowNumbers.size() && num <= colNumbers.size()) { + rowNumbers.get(row).setRotation(num); + return true; + } + return false; + } + + public boolean setColNumber(int col, int num) { + // first check is to verify we are updating an element in range + // second check is to verify the new number can be achieved by the puzzle + if (col < colNumbers.size() && num <= rowNumbers.size()) { + colNumbers.get(col).setRotation(num); + return true; + } + return false; + } + + // basic accessors for row/col numbers + public int getRowNumber(int row) { + if (row < 0 || row >= rowNumbers.size()) return -1; + return rowNumbers.get(row).getRotation(); + } + + public int getColNumber(int col) { + if (col < 0 || col >= rowNumbers.size()) return -1; + return colNumbers.get(col).getRotation(); + } + + // Accessors for saving row/column + public ArrayList getRowNumbers() { + return rowNumbers; + } + + public ArrayList getColNumbers() { + return colNumbers; + } + + // we all suck at programming so instead of using provided array list + // we use our own array lists to keep track of the vials + // marginally useful because it means we are guaranteed to get a + // thermometer cell when calling get cell, but using some type casting + // this override function could very likely be refactored out + @Override + public ThermometerCell getCell(int x, int y) { + for (ThermometerVial vial : this.thermometerVials) { + for (ThermometerCell cell : vial.getCells()) { + if (cell.getLocation().x == x && cell.getLocation().y == y) return cell; + } + } + + for (ThermometerCell cell : rowNumbers) { + if (cell.getLocation().x == x && cell.getLocation().y == y) return cell; + } + + for (ThermometerCell cell : colNumbers) { + if (cell.getLocation().x == x && cell.getLocation().y == y) return cell; + } + + if (x == this.getWidth() - 1 && y == this.getHeight() - 1) return dummyCell; + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerCell.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerCell.java new file mode 100644 index 000000000..175a455b4 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerCell.java @@ -0,0 +1,67 @@ +package edu.rpi.legup.puzzle.thermometer; + +import edu.rpi.legup.model.gameboard.GridCell; +import java.awt.Point; + +public class ThermometerCell extends GridCell { + + // information about the cell needed to display it + private ThermometerType type; + private ThermometerFill fill; + private int rotation; + + public ThermometerCell(Point location, ThermometerType t, ThermometerFill f, int r) { + // since we do not use get/set data value int can be any value + super(1, location); + type = t; + fill = f; + rotation = r; + } + + // Note: setdata does not work for our purposes + public void setType(ThermometerType t) { + type = t; + } + + public ThermometerType getType() { + return type; + } + + public void setFill(ThermometerFill f) { + fill = f; + } + + public ThermometerFill getFill() { + return fill; + } + + public void setRotation(int r) { + rotation = r; + } + + public int getRotation() { + return rotation; + } + + @Override + public ThermometerCell copy() { + ThermometerCell copy = + new ThermometerCell((Point) location.clone(), this.type, this.fill, this.rotation); + copy.setIndex(index); + copy.setModifiable(isModifiable); + copy.setGiven(isGiven); + return copy; + } + + @Override + public String toString() { + return "(" + + location.getX() + + ", " + + location.getY() + + ") TYPE = " + + getType() + + " FILL = " + + getFill(); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerController.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerController.java new file mode 100644 index 000000000..cd2135bd7 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerController.java @@ -0,0 +1,44 @@ +package edu.rpi.legup.puzzle.thermometer; + +import edu.rpi.legup.controller.ElementController; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import java.awt.event.MouseEvent; + +public class ThermometerController extends ElementController { + + // method for updating thermometer cells since number cells have unknown for + // their fill type we don't need to worry about end user modifying them with this + @Override + public void changeCell(MouseEvent e, PuzzleElement data) { + ThermometerCell cell = (ThermometerCell) data; + + if (e.getButton() == MouseEvent.BUTTON1) { + if (e.isControlDown()) { + this.boardView + .getSelectionPopupMenu() + .show( + boardView, + this.boardView.getCanvas().getX() + e.getX(), + this.boardView.getCanvas().getY() + e.getY()); + } else { + if (cell.getFill() == ThermometerFill.EMPTY) { + cell.setFill(ThermometerFill.FILLED); + } else if (cell.getFill() == ThermometerFill.FILLED) { + cell.setFill(ThermometerFill.BLOCKED); + } else { + cell.setFill(ThermometerFill.EMPTY); + } + } + } else if (e.getButton() == MouseEvent.BUTTON3) { + if (cell.getFill() == ThermometerFill.EMPTY) { + cell.setFill(ThermometerFill.BLOCKED); + } else if (cell.getFill() == ThermometerFill.BLOCKED) { + cell.setFill(ThermometerFill.FILLED); + } else { + cell.setFill(ThermometerFill.EMPTY); + } + } else if (e.getButton() == MouseEvent.BUTTON2) { + System.out.println("[DEBUG] " + cell); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerElementView.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerElementView.java new file mode 100644 index 000000000..0657e95b0 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerElementView.java @@ -0,0 +1,311 @@ +package edu.rpi.legup.puzzle.thermometer; + +import edu.rpi.legup.ui.boardview.GridElementView; +import java.awt.*; +import java.io.IOException; +import javax.imageio.ImageIO; + +public class ThermometerElementView extends GridElementView { + + // mixture of stuff stolen from tree tent and dev guide + private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); + private static final Color FONT_COLOR = Color.BLACK; + + public ThermometerElementView(ThermometerCell cell) { + super(cell); + } + + @Override + public ThermometerCell getPuzzleElement() { + return (ThermometerCell) super.getPuzzleElement(); + } + + // method for drawing a thermometer cell + // basically copy/pasted from tree tent drawing tent images + @Override + public void drawElement(Graphics2D graphics2D) { + + ThermometerCell cell = (ThermometerCell) puzzleElement; + ThermometerType type = cell.getType(); + ThermometerFill fill = cell.getFill(); + int rotation = cell.getRotation(); + + graphics2D.drawImage( + imageSrc(type, fill, rotation), + location.x, + location.y, + size.width, + size.height, + null, + null); + + graphics2D.setColor(Color.BLACK); + graphics2D.drawRect(location.x, location.y, size.width, size.height); + } + + // modified code from tree trent to display images + private Image imageSrc(ThermometerType t, ThermometerFill f, int r) { + + // will have a 36 switch case at end to determine which image gets opened + int result = 0; + + // 100 = NORTH, 200 = WEST, 300 = SOUTH, 400 = EAST + switch (r) { + case 0 -> result += 100; + case 90 -> result += 400; + case 180 -> result += 300; + case 270 -> result += 200; + default -> { + System.out.println("ThermometerElementView: Invalid Rotation"); + return null; + } + } + + // 10 = EMPTY, 20 = FILLED, 30 = BLOCKED + switch (f) { + case ThermometerFill.EMPTY -> result += 10; + case ThermometerFill.FILLED -> result += 20; + case ThermometerFill.BLOCKED -> result += 30; + default -> { + System.out.println("ThermometerElementView: Invalid Fill"); + return null; + } + } + + // 1 = HEAD, 2 = SHAFT, 3 = TIP + switch (t) { + case ThermometerType.HEAD -> result += 1; + case ThermometerType.SHAFT -> result += 2; + case ThermometerType.TIP -> result += 3; + default -> { + System.out.println("ThermometerElementView: Invalid Type"); + return null; + } + } + + try { + switch (result) { + case 111 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png")); + } + + case 112 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png")); + } + + case 113 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipEmpN.png")); + } + + case 121 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadFillN.png")); + } + + case 122 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png")); + } + + case 123 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipFillN.png")); + } + + case 131 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png")); + } + + case 132 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png")); + } + + case 133 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipBlockN.png")); + } + + case 211 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png")); + } + + case 212 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png")); + } + + case 213 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipEmpE.png")); + } + + case 221 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadFillE.png")); + } + + case 222 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png")); + } + + case 223 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipFillE.png")); + } + + case 231 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png")); + } + + case 232 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png")); + } + + case 233 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipBlockE.png")); + } + + case 311 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png")); + } + + case 312 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png")); + } + + case 313 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipEmpS.png")); + } + + case 321 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadFillS.png")); + } + + case 322 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png")); + } + + case 323 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipFillS.png")); + } + + case 331 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png")); + } + + case 332 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png")); + } + + case 333 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipBlockS.png")); + } + + case 411 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png")); + } + + case 412 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png")); + } + + case 413 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipEmpW.png")); + } + + case 421 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadFillW.png")); + } + + case 422 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftFillW.png")); + } + + case 423 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipFillW.png")); + } + + case 431 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png")); + } + + case 432 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png")); + } + + case 433 -> { + return ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/thermometer/Elements/TipBlockW.png")); + } + } + } catch (IOException e) { + System.out.println("ThermometerElementView: Unexpected Issue"); + return null; + } + + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerExporter.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerExporter.java new file mode 100644 index 000000000..d4e6dbd39 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerExporter.java @@ -0,0 +1,72 @@ +package edu.rpi.legup.puzzle.thermometer; + +import edu.rpi.legup.model.PuzzleExporter; +import java.util.ArrayList; +import org.w3c.dom.Document; + +public class ThermometerExporter extends PuzzleExporter { + + public ThermometerExporter(Thermometer thermometer) { + super(thermometer); + } + + @Override + protected org.w3c.dom.Element createBoardElement(Document newDocument) { + ThermometerBoard board = (ThermometerBoard) puzzle.getTree().getRootNode().getBoard(); + + // Creating the XML section for the board + org.w3c.dom.Element boardElement = newDocument.createElement("board"); + boardElement.setAttribute("width", String.valueOf(board.getWidth() - 1)); + boardElement.setAttribute("height", String.valueOf(board.getHeight() - 1)); + + // Creating the XML section for the vials and appending to the board + org.w3c.dom.Element vialsElement = newDocument.createElement("vials"); + ArrayList vials = board.getVials(); + for (ThermometerVial vial : vials) { + org.w3c.dom.Element vialElement = newDocument.createElement("vial"); + // The way the vials are created are with the head (bulb) position and the final + // position + // This implementation doesn't allow for curved thermometers, but for right now that's + // fine + vialElement.setAttribute( + "headx", String.valueOf((int) vial.getHead().getLocation().getX())); + vialElement.setAttribute( + "heady", String.valueOf((int) vial.getHead().getLocation().getY())); + vialElement.setAttribute( + "tailx", String.valueOf((int) vial.getTail().getLocation().getX())); + vialElement.setAttribute( + "taily", String.valueOf((int) vial.getTail().getLocation().getY())); + vialsElement.appendChild(vialElement); + } + boardElement.appendChild(vialsElement); + + // Creating the XML section for the row numbers and appending to the board + org.w3c.dom.Element rowNumbersElement = newDocument.createElement("rowNumbers"); + ArrayList rowNumbers = board.getRowNumbers(); + // The row numbers are the numbers on the right most column, labeling how many filled + // sections + // are in the row + for (ThermometerCell cell : rowNumbers) { + int number = cell.getRotation(); + org.w3c.dom.Element rowNumberElement = newDocument.createElement("row"); + rowNumberElement.setAttribute("value", String.valueOf(number)); + rowNumbersElement.appendChild(rowNumberElement); + } + boardElement.appendChild(rowNumbersElement); + + // Creating the XML section for the col numbers and appending ot the board + org.w3c.dom.Element colNumbersElement = newDocument.createElement("colNumbers"); + // The col numbers are the numbers on the bottom row, labeling how many filled sections + // are in the column + ArrayList colNumbers = board.getColNumbers(); + for (ThermometerCell cell : colNumbers) { + int number = cell.getRotation(); + org.w3c.dom.Element colNumberElement = newDocument.createElement("col"); + colNumberElement.setAttribute("value", String.valueOf(number)); + colNumbersElement.appendChild(colNumberElement); + } + boardElement.appendChild(colNumbersElement); + + return boardElement; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerFill.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerFill.java new file mode 100644 index 000000000..34a1ff12e --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerFill.java @@ -0,0 +1,8 @@ +package edu.rpi.legup.puzzle.thermometer; + +public enum ThermometerFill { + UNKNOWN, + EMPTY, + FILLED, + BLOCKED; +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerImporter.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerImporter.java new file mode 100644 index 000000000..711418d63 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerImporter.java @@ -0,0 +1,196 @@ +package edu.rpi.legup.puzzle.thermometer; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +import edu.rpi.legup.model.PuzzleImporter; +import edu.rpi.legup.save.InvalidFileFormatException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class ThermometerImporter extends PuzzleImporter { + + // basic stuff stolen from dev guide/filled in by default + public ThermometerImporter(Thermometer thermometer) { + super(thermometer); + } + + @Override + public boolean acceptsRowsAndColumnsInput() { + return false; + } + + @Override + public boolean acceptsTextInput() { + return false; + } + + @Override + public void initializeBoard(int rows, int columns) {} + + // method for initializing board from an xml file which has + // a provided width/height + @Override + public void initializeBoard(Node node) throws InvalidFileFormatException { + // sticking everything in a try statement because god has forsaken everyone + try { + // checking basic formatting of file + if (!node.getNodeName().equalsIgnoreCase("board")) { + throw new InvalidFileFormatException( + "thermometer Importer: cannot find board puzzleElement"); + } + + // getting the list of vials to turn into real vials + Element boardElement = (Element) node; + if (boardElement.getElementsByTagName("vials").getLength() == 0) { + throw new InvalidFileFormatException( + "thermometer Importer: no puzzleElement found for board"); + } + Element dataElement = (Element) boardElement.getElementsByTagName("vials").item(0); + NodeList elementDataList = dataElement.getElementsByTagName("vial"); + + // checking both a width and height were provided for the board + ThermometerBoard thermometerBoard = null; + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { + + // grabbing the height/width of the board + int width = Integer.parseInt(boardElement.getAttribute("width")); + int height = Integer.parseInt(boardElement.getAttribute("height")); + + // grabbing the lists of rowNumbers/colNumbers + Element rowElement = + (Element) boardElement.getElementsByTagName("rowNumbers").item(0); + NodeList rowNodeList = rowElement.getElementsByTagName("row"); + + Element colElement = + (Element) boardElement.getElementsByTagName("colNumbers").item(0); + NodeList colNodeList = colElement.getElementsByTagName("col"); + + // checking that the number of row and col numbers agrees with height/width of board + if (colNodeList.getLength() != width) { + throw new InvalidFileFormatException( + "Mismatch between width and number of colNums.\n colNodeList.length:" + + colNodeList.getLength() + + " width:" + + width); + } + if (rowNodeList.getLength() != height) { + throw new InvalidFileFormatException( + "thermometer Importer: no rowNumbers found for board"); + } + + // finally creating our thermometer board, we add one to the size since row/col + // numbers + // are considered cells on the grid + thermometerBoard = new ThermometerBoard(width + 1, height + 1); + // adding row and column numbers to our board + importRowColNums(rowNodeList, colNodeList, thermometerBoard); + } else { + throw new InvalidFileFormatException( + "thermometer Importer: invalid board height/width"); + } + + // grabbing height/width from board, need to subtract 1 + // because grids height/width is 1 bigger than number of vials on board + int width = thermometerBoard.getWidth() - 1; + int height = thermometerBoard.getHeight() - 1; + + // adding in the vials + for (int i = 0; i < elementDataList.getLength(); i++) { + importThermometerVial(elementDataList.item(i), thermometerBoard); + } + + // verifying all vial cells were filled by vials + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (thermometerBoard.getCell(x, y) == null) { + throw new InvalidFileFormatException( + "Thermometer importer Undefined tile at (" + x + "," + y + ")"); + } + } + } + + puzzle.setCurrentBoard(thermometerBoard); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "thermometer Importer: unknown value where integer expected"); + } + } + + @Override + public void initializeBoard(String[] statements) + throws UnsupportedOperationException, IllegalArgumentException {} + + private void importRowColNums(NodeList rowNodes, NodeList colNodes, ThermometerBoard board) + throws InvalidFileFormatException { + + // going through our list or row nodes grabbed from the xml file and + // then calling the thermometer boards setRowNumber function to update the value + for (int i = 0; i < rowNodes.getLength(); i++) { + Node node = rowNodes.item(i); + int rowNum = + Integer.parseInt(node.getAttributes().getNamedItem("value").getNodeValue()); + if (!board.setRowNumber(i, rowNum)) { + throw new InvalidFileFormatException("thermometer Importer: out of bounds rowNum"); + } + } + + // same process but for col numbers + for (int i = 0; i < colNodes.getLength(); i++) { + Node node = colNodes.item(i); + int colNum = + Integer.parseInt(node.getAttributes().getNamedItem("value").getNodeValue()); + if (!board.setColNumber(i, colNum)) { + throw new InvalidFileFormatException("thermometer Importer: out of bounds colNum"); + } + } + } + + private void importThermometerVial(Node node, ThermometerBoard board) + throws InvalidFileFormatException { + // head is the top of the thermometer and tip is the end of the thermometer + // thermometers in the xml are specified only by their head and tip cells + int headX = Integer.parseInt(node.getAttributes().getNamedItem("headx").getNodeValue()); + int headY = Integer.parseInt(node.getAttributes().getNamedItem("heady").getNodeValue()); + int tipX = Integer.parseInt(node.getAttributes().getNamedItem("tailx").getNodeValue()); + int tipY = Integer.parseInt(node.getAttributes().getNamedItem("taily").getNodeValue()); + + // making sure we can add the vial before doing so + if (verifyVial(headX, headY, tipX, tipY, board)) { + // adding the vial to the board + board.addVial(new ThermometerVial(headX, headY, tipX, tipY, board)); + } else { + throw new InvalidFileFormatException("thermometer Vial Factory: overlapping vials"); + } + } + + private boolean verifyVial(int headX, int headY, int tipX, int tipY, ThermometerBoard board) { + // figuring out which axis the thermometer travels along + if (headX == tipX) { + // finding start and end of Vial + int top = min(headY, tipY); + int bottom = max(headY, tipY); + + // verifying that every cell along path is currently unconstructed + for (int i = top; i <= bottom; i++) { + if (board.getCell(headX, i) != null) return false; + } + } else if (headY == tipY) { + // finding start and end of Vial + // I have words to say to james + int left = min(headX, tipX); + int right = max(headX, tipX); + + // verifying that every cell along path is currently unconstructed + for (int i = left; i <= right; i++) { + if (board.getCell(i, headY) != null) return false; + } + } else { + // thermometer does not line up along a single axis + return false; + } + return true; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerNumberView.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerNumberView.java new file mode 100644 index 000000000..4a00b8a18 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerNumberView.java @@ -0,0 +1,37 @@ +package edu.rpi.legup.puzzle.thermometer; + +import edu.rpi.legup.model.gameboard.GridCell; +import edu.rpi.legup.ui.boardview.GridElementView; +import java.awt.*; + +public class ThermometerNumberView extends GridElementView { + private static final Font FONT = new Font("TimesRoman", Font.BOLD, 16); + private static final Color FONT_COLOR = Color.BLACK; + + public ThermometerNumberView(GridCell cell) { + super(cell); + } + + @Override + public GridCell getPuzzleElement() { + return (GridCell) super.getPuzzleElement(); + } + + @Override + public void drawElement(Graphics2D graphics2D) { + ThermometerCell cell = (ThermometerCell) puzzleElement; + + graphics2D.setColor(FONT_COLOR); + graphics2D.setFont(FONT); + FontMetrics metrics = graphics2D.getFontMetrics(FONT); + int val; + + if (cell != null) val = cell.getRotation(); + else val = -1; + + int xText = location.x + (size.width - metrics.stringWidth(String.valueOf(val))) / 2; + int yText = location.y + ((size.height - metrics.getHeight()) / 2) + metrics.getAscent(); + + graphics2D.drawString(String.valueOf(val), xText, yText); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerType.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerType.java new file mode 100644 index 000000000..f482411a5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerType.java @@ -0,0 +1,8 @@ +package edu.rpi.legup.puzzle.thermometer; + +public enum ThermometerType { + UNKNOWN, + HEAD, + SHAFT, + TIP; +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerVial.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerVial.java new file mode 100644 index 000000000..2cba64363 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerVial.java @@ -0,0 +1,103 @@ +package edu.rpi.legup.puzzle.thermometer; + +import java.awt.*; +import java.util.ArrayList; + +public class ThermometerVial { + private ArrayList cells; + + public ThermometerVial(int headX, int headY, int tipX, int tipY, ThermometerBoard board) { + // basic constructor, instantiating our members field and then + // calling helper function to do all the heavy lifting + cells = new ArrayList(); + fillData(headX, headY, tipX, tipY, board); + } + + // function called by the constructor which adds in all of the cells to the array + // as well as updates their type on the board + private void fillData(int headX, int headY, int tipX, int tipY, ThermometerBoard board) { + // not totally happy with layout of code but most readable version I can think of atm + // top left coordinate is 0,0 cells are added from head to tip always + // because cells have already been verified by time constructor is called + // we can guarantee that only the x or only the y coordinates wont line up + if (headY < tipY) { + addCell(headX, headY, ThermometerType.HEAD, 0, board); + for (int i = headY + 1; i < tipY; i++) { + addCell(headX, i, ThermometerType.SHAFT, 0, board); + } + addCell(tipX, tipY, ThermometerType.TIP, 0, board); + } else if (tipY < headY) { + addCell(headX, headY, ThermometerType.HEAD, 180, board); + for (int i = headY - 1; i > tipY; i--) { + addCell(headX, i, ThermometerType.SHAFT, 180, board); + } + addCell(tipX, tipY, ThermometerType.TIP, 180, board); + } else if (headX < tipX) { + addCell(headX, headY, ThermometerType.HEAD, 90, board); + for (int i = headX + 1; i < tipX; i++) { + addCell(i, headY, ThermometerType.SHAFT, 90, board); + } + addCell(tipX, tipY, ThermometerType.TIP, 90, board); + } else { + addCell(headX, headY, ThermometerType.HEAD, 270, board); + for (int i = headX - 1; i > tipX; i--) { + addCell(i, headY, ThermometerType.SHAFT, 270, board); + } + addCell(tipX, tipY, ThermometerType.TIP, 270, board); + } + } + + // helper function for adding a single cell + private void addCell(int x, int y, ThermometerType t, int rotation, ThermometerBoard board) { + ThermometerCell cell = + new ThermometerCell(new Point(x, y), t, ThermometerFill.EMPTY, rotation); + cell.setIndex(y * board.getHeight() + x); + this.cells.add(cell); + // still important for element view stuff + board.setCell(x, y, cell); + } + + // TODO (probably) DOES NOT WORK AS INTENDED + // BECAUSE MOST RULES GET A PUZZLE ELEMENT PASSED IN AND WEIRD + // TYPE CASTING STUFF, PAY ATTENTION TO THIS WHEN WE START + // DEBUGGING RULES + // a basic accessor to check if a cell is contained in vial + public boolean containsCell(ThermometerCell cell) { + for (ThermometerCell c : cells) { + if (c.getLocation() == cell.getLocation()) { + return true; + } + } + return false; + } + + // Returns cell containing head of thermometer + public ThermometerCell getHead() { + return cells.getFirst(); + } + + // Returns cell containing tail of thermometer + public ThermometerCell getTail() { + return cells.getLast(); + } + + // Retruns all cells in vial, from head to tip + public ArrayList getCells() { + return cells; + } + + // checking for discontinuous flow inside of vial + public boolean continuousFlow() { + // bool which is true until it runs into an empty/blocked cell in the vial + // if an empty cell in the vial is found while flow is set to false + // we know there is a break in the flow + boolean flow = true; + + for (ThermometerCell c : cells) { + if (c.getFill() != ThermometerFill.FILLED && flow) flow = false; + + if (c.getFill() == ThermometerFill.FILLED && !flow) return false; + } + return true; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerView.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerView.java new file mode 100644 index 000000000..444037cfe --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/ThermometerView.java @@ -0,0 +1,48 @@ +package edu.rpi.legup.puzzle.thermometer; + +import edu.rpi.legup.controller.BoardController; +import edu.rpi.legup.ui.boardview.GridBoardView; +import java.awt.*; + +public class ThermometerView extends GridBoardView { + + public ThermometerView(ThermometerBoard board) { + super(new BoardController(), new ThermometerController(), board.getDimension()); + + // loop for displaying the vial cells + // stolen largely from dev guide + for (ThermometerVial vial : board.getVials()) { + for (ThermometerCell cell : vial.getCells()) { + Point loc = cell.getLocation(); + ThermometerElementView elementView = new ThermometerElementView(cell); + elementView.setIndex(cell.getIndex()); + elementView.setSize(elementSize); + elementView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(elementView); + } + } + + // loop for displaying row numbers, same as above + for (ThermometerCell rowNum : board.getRowNumbers()) { + Point loc = rowNum.getLocation(); + ThermometerNumberView numberView = new ThermometerNumberView(rowNum); + numberView.setIndex(rowNum.getIndex()); + numberView.setSize(elementSize); + numberView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(numberView); + } + + // loop for displaying col numbers, also same as above + for (ThermometerCell colNum : board.getColNumbers()) { + Point loc = colNum.getLocation(); + ThermometerNumberView numberView = new ThermometerNumberView(colNum); + numberView.setIndex(colNum.getIndex()); + numberView.setSize(elementSize); + numberView.setLocation( + new Point(loc.x * elementSize.width, loc.y * elementSize.height)); + elementViews.add(numberView); + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckE.java new file mode 100644 index 000000000..8f0507ab5 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileBlckE extends PlaceableElement { + public HeadTileBlckE() { + super( + "Therm-PLAC-0001", + "Head Tile Block East", + "The tile corresponding to the blocked head of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckN.java new file mode 100644 index 000000000..f195c299b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileBlckN extends PlaceableElement { + public HeadTileBlckN() { + super( + "Therm-PLAC-0002", + "Head Tile Block North", + "The tile corresponding to the blocked head of a north thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckS.java new file mode 100644 index 000000000..d9e4c4a6a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileBlckS extends PlaceableElement { + public HeadTileBlckS() { + super( + "Therm-PLAC-0003", + "Head Tile Block South", + "The tile corresponding to the blocked head of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckW.java new file mode 100644 index 000000000..2bcbfdf2d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileBlckW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileBlckW extends PlaceableElement { + public HeadTileBlckW() { + super( + "Therm-PLAC-0004", + "Head Tile Block West", + "The tile corresponding to the blocked head of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpE.java new file mode 100644 index 000000000..0b678ed73 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileEmpE extends PlaceableElement { + public HeadTileEmpE() { + super( + "Therm-PLAC-0005", + "Head Tile Empty East", + "The tile corresponding to the empty head of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpN.java new file mode 100644 index 000000000..b865b0cae --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileEmpN extends PlaceableElement { + public HeadTileEmpN() { + super( + "Therm-PLAC-0006", + "Head Tile Empty North", + "The tile corresponding to the empty head of a North thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpS.java new file mode 100644 index 000000000..40989d814 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileEmpS extends PlaceableElement { + public HeadTileEmpS() { + super( + "Therm-PLAC-0007", + "Head Tile Empty South", + "The tile corresponding to the empty head of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpW.java new file mode 100644 index 000000000..ba344ff8a --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileEmpW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileEmpW extends PlaceableElement { + public HeadTileEmpW() { + super( + "Therm-PLAC-0008", + "Head Tile Empty West", + "The tile corresponding to the empty head of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillE.java new file mode 100644 index 000000000..e8bfb8f82 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileFillE extends PlaceableElement { + public HeadTileFillE() { + super( + "Therm-PLAC-0009", + "Head Tile Filled East", + "The tile corresponding to the filled head of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadFillE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillN.java new file mode 100644 index 000000000..4a835601c --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileFillN extends PlaceableElement { + public HeadTileFillN() { + super( + "Therm-PLAC-0010", + "Head Tile Filled North", + "The tile corresponding to the filled head of a north thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadFillN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillS.java new file mode 100644 index 000000000..df559ec6f --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileFillS extends PlaceableElement { + public HeadTileFillS() { + super( + "Therm-PLAC-0011", + "Head Tile Filled South", + "The tile corresponding to the filled head of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadFillS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillW.java new file mode 100644 index 000000000..80194ceaf --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/HeadTileFillW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class HeadTileFillW extends PlaceableElement { + public HeadTileFillW() { + super( + "Therm-PLAC-0012", + "Head Tile Filled West", + "The tile corresponding to the filled head of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/HeadFillW.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckE.java new file mode 100644 index 000000000..7080b9a47 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileBlckE extends PlaceableElement { + public ShaftTileBlckE() { + super( + "Therm-PLAC-0013", + "Shaft Tile Blocked East", + "The tile corresponding to a Blocked middle segment of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckN.java new file mode 100644 index 000000000..760baf624 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileBlckN extends PlaceableElement { + public ShaftTileBlckN() { + super( + "Therm-PLAC-0014", + "Shaft Tile Blocked North", + "The tile corresponding to a Blocked middle segment of a north thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckS.java new file mode 100644 index 000000000..ec14a669d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileBlckS extends PlaceableElement { + public ShaftTileBlckS() { + super( + "Therm-PLAC-0015", + "Shaft Tile Blocked South", + "The tile corresponding to a Blocked middle segment of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckW.java new file mode 100644 index 000000000..183fd798c --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileBlckW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileBlckW extends PlaceableElement { + public ShaftTileBlckW() { + super( + "Therm-PLAC-0016", + "Shaft Tile Blocked West", + "The tile corresponding to a Blocked middle segment of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpE.java new file mode 100644 index 000000000..771c1afc3 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileEmpE extends PlaceableElement { + public ShaftTileEmpE() { + super( + "Therm-PLAC-0017", + "Shaft Tile Empty East", + "The tile corresponding to an empty middle segment of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpN.java new file mode 100644 index 000000000..c2ec4e0ab --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileEmpN extends PlaceableElement { + public ShaftTileEmpN() { + super( + "Therm-PLAC-0018", + "Shaft Tile Empty North", + "The tile corresponding to an empty middle segment of a north thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpS.java new file mode 100644 index 000000000..fc2828ddb --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileEmpS extends PlaceableElement { + public ShaftTileEmpS() { + super( + "Therm-PLAC-0019", + "Shaft Tile Empty South", + "The tile corresponding to an empty middle segment of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpW.java new file mode 100644 index 000000000..ce0e7bce3 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileEmpW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileEmpW extends PlaceableElement { + public ShaftTileEmpW() { + super( + "Therm-PLAC-0020", + "Shaft Tile Empty West", + "The tile corresponding to an empty middle segment of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillE.java new file mode 100644 index 000000000..a8aeb44ed --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileFillE extends PlaceableElement { + public ShaftTileFillE() { + super( + "Therm-PLAC-0021", + "Shaft Tile Filled East", + "The tile corresponding to a filled middle segment of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillN.java new file mode 100644 index 000000000..0366c3d0b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileFillN extends PlaceableElement { + public ShaftTileFillN() { + super( + "Therm-PLAC-0022", + "Shaft Tile Filled North", + "The tile corresponding to a filled middle segment of a north thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillS.java new file mode 100644 index 000000000..b55d2a1f9 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileFillS extends PlaceableElement { + public ShaftTileFillS() { + super( + "Therm-PLAC-0023", + "Shaft Tile Filled South", + "The tile corresponding to a filled middle segment of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillW.java new file mode 100644 index 000000000..3b2cd0454 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/ShaftTileFillW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class ShaftTileFillW extends PlaceableElement { + public ShaftTileFillW() { + super( + "Therm-PLAC-0024", + "Shaft Tile Filled West", + "The tile corresponding to a filled middle segment of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckE.java new file mode 100644 index 000000000..ea94846c2 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileBlckE extends PlaceableElement { + public TipTileBlckE() { + super( + "Therm-PLAC-0025", + "Tip Tile Block East", + "The tile corresponding to the Blocked tip of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipBlockE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckN.java new file mode 100644 index 000000000..25ae8afda --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileBlckN extends PlaceableElement { + public TipTileBlckN() { + super( + "Therm-PLAC-0026", + "Tip Tile Block North", + "The tile corresponding to the Blocked tip of a north thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipBlockN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckS.java new file mode 100644 index 000000000..e19082162 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileBlckS extends PlaceableElement { + public TipTileBlckS() { + super( + "Therm-PLAC-0027", + "Tip Tile Block South", + "The tile corresponding to the Blocked tip of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipBlockS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckW.java new file mode 100644 index 000000000..a0c49bc77 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileBlckW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileBlckW extends PlaceableElement { + public TipTileBlckW() { + super( + "Therm-PLAC-0028", + "Tip Tile Block West", + "The tile corresponding to the Blocked tip of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipBlockW.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpE.java new file mode 100644 index 000000000..6595da855 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileEmpE extends PlaceableElement { + public TipTileEmpE() { + super( + "Therm-PLAC-0029", + "Tip Tile Empty East", + "The tile corresponding to the empty tip of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipEmpE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpN.java new file mode 100644 index 000000000..cacfe5d5d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileEmpN extends PlaceableElement { + public TipTileEmpN() { + super( + "Therm-PLAC-0030", + "Tip Tile Empty North", + "The tile corresponding to the empty tip of a north thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipEmpN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpS.java new file mode 100644 index 000000000..2815b9fa1 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileEmpS extends PlaceableElement { + public TipTileEmpS() { + super( + "Therm-PLAC-0031", + "Tip Tile Empty South", + "The tile corresponding to the empty tip of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipEmpS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpW.java new file mode 100644 index 000000000..3bd77495f --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileEmpW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileEmpW extends PlaceableElement { + public TipTileEmpW() { + super( + "Therm-PLAC-0032", + "Tip Tile Empty West", + "The tile corresponding to the empty tip of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipEmpW.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillE.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillE.java new file mode 100644 index 000000000..8c9953dd2 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillE.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileFillE extends PlaceableElement { + public TipTileFillE() { + super( + "Therm-PLAC-0033", + "Tip Tile Fill East", + "The tile corresponding to the filled tip of an east thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipFillE.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillN.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillN.java new file mode 100644 index 000000000..f5ce01c7b --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillN.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileFillN extends PlaceableElement { + public TipTileFillN() { + super( + "Therm-PLAC-0034", + "Tip Tile Fill North", + "The tile corresponding to the filled tip of a north thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipFillN.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillS.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillS.java new file mode 100644 index 000000000..05d68fe81 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillS.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileFillS extends PlaceableElement { + public TipTileFillS() { + super( + "Therm-PLAC-0035", + "Tip Tile Fill South", + "The tile corresponding to the filled tip of a south thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipFillS.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillW.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillW.java new file mode 100644 index 000000000..6aa486ba1 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/elements/TipTileFillW.java @@ -0,0 +1,13 @@ +package edu.rpi.legup.puzzle.thermometer.elements; + +import edu.rpi.legup.model.elements.PlaceableElement; + +public class TipTileFillW extends PlaceableElement { + public TipTileFillW() { + super( + "Therm-PLAC-0036", + "Tip Tile Fill West", + "The tile corresponding to the filled tip of a west thermometer", + "edu/rpi/legup/images/thermometer/Elements/TipFillW.png"); + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/DiscontinuousMercuryContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/DiscontinuousMercuryContradictionRule.java new file mode 100644 index 000000000..b013b3493 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/DiscontinuousMercuryContradictionRule.java @@ -0,0 +1,62 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.thermometer.ThermometerBoard; +import edu.rpi.legup.puzzle.thermometer.ThermometerCell; +import edu.rpi.legup.puzzle.thermometer.ThermometerVial; +import java.util.ArrayList; + +// TODO: Rule is untested +public class DiscontinuousMercuryContradictionRule extends ContradictionRule { + + private final String NO_CONTRADICTION_MESSAGE = + "Does not contain a contradiction at this index"; + private final String INVALID_USE_MESSAGE = "Contradiction must be a vial"; + + public DiscontinuousMercuryContradictionRule() { + super( + "THERM-CONT-0001", + "Discontinuous Mercury", + "A vial has a filled cell after an empty or blocked cell", + "edu/rpi/legup/images/thermometer/MercuryInBody.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + // User can click on any cell in a vial with a discontinuous flow + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + // useful variables + ThermometerBoard thermometerBoard = (ThermometerBoard) board; + + ThermometerCell cell = (ThermometerCell) thermometerBoard.getPuzzleElement(puzzleElement); + + ArrayList thermometerVials = thermometerBoard.getVials(); + + // finding out which vial contains the specified cell + for (int i = 0; i < thermometerVials.size(); i++) { + ThermometerVial thermometerVial = thermometerVials.get(i); + // if a vial contains the clicked on cell + // checking if the vial has a break in the flow + if (thermometerVial.containsCell(cell)) { + if (thermometerVial.continuousFlow()) { + return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE; + } else { + return null; + } + } + } + + // if none of the vials contain the clicked on cell yell at user + return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithBlockedDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithBlockedDirectRule.java new file mode 100644 index 000000000..d09b98300 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithBlockedDirectRule.java @@ -0,0 +1,44 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +// TODO: Rule is unimplemented +public class FinishWithBlockedDirectRule extends DirectRule { + public FinishWithBlockedDirectRule() { + super( + "THERM-BASC-0004", + "Finish With Blocked", + "Remaining tiles must be blocked once requirement is satisfied", + "edu/rpi/legup/images/thermometer/FinishWithBlocked.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithMercuryDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithMercuryDirectRule.java new file mode 100644 index 000000000..09fb8874d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/FinishWithMercuryDirectRule.java @@ -0,0 +1,44 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +// TODO: Rule is unimplemented +public class FinishWithMercuryDirectRule extends DirectRule { + public FinishWithMercuryDirectRule() { + super( + "THERM-BASC-0003", + "Finish with Mercury", + "Remaining tiles must be filled to satisfy requirement", + "edu/rpi/legup/images/thermometer/FinishWithMercury.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MercuryOrBlockedCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MercuryOrBlockedCaseRule.java new file mode 100644 index 000000000..a0644aec0 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MercuryOrBlockedCaseRule.java @@ -0,0 +1,114 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.thermometer.*; +import java.util.ArrayList; +import java.util.List; + +// TODO: Rule is untested +public class MercuryOrBlockedCaseRule extends CaseRule { + public MercuryOrBlockedCaseRule() { + super( + "THERM-CASE-0001", + "Mercury or Blocked", + "Each unassigned tile must be filled with mercury or blocked.", + "edu/rpi/legup/images/thermometer/MercOrBlocked.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + List childTransitions = transition.getParents().get(0).getChildren(); + if (childTransitions.size() != 2) { + return super.getInvalidUseOfRuleMessage() + ": This case rule must have 2 children."; + } + + TreeTransition case1 = childTransitions.get(0); + TreeTransition case2 = childTransitions.get(1); + if (case1.getBoard().getModifiedData().size() != 1 + || case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; + } + + ThermometerCell mod1 = + (ThermometerCell) case1.getBoard().getModifiedData().iterator().next(); + ThermometerCell mod2 = + (ThermometerCell) case2.getBoard().getModifiedData().iterator().next(); + if (!mod1.getLocation().equals(mod2.getLocation())) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; + } + + if (!((mod1.getFill() == ThermometerFill.BLOCKED + && mod2.getFill() == ThermometerFill.FILLED) + || (mod2.getFill() == ThermometerFill.BLOCKED + && mod1.getFill() == ThermometerFill.FILLED))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have a filled or blocked cell."; + } + + return null; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + ThermometerBoard thermometerBoard = (ThermometerBoard) board.copy(); + CaseBoard caseBoard = new CaseBoard(thermometerBoard, this); + thermometerBoard.setModifiable(false); + for (PuzzleElement element : thermometerBoard.getPuzzleElements()) { + if (((ThermometerCell) element).getFill() == ThermometerFill.UNKNOWN) { + caseBoard.addPickableElement(element); + } + } + return caseBoard; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + ArrayList cases = new ArrayList<>(); + Board case1 = board.copy(); + ThermometerCell data1 = (ThermometerCell) case1.getPuzzleElement(puzzleElement); + data1.setFill(ThermometerFill.FILLED); + case1.addModifiedData(data1); + cases.add(case1); + + Board case2 = board.copy(); + ThermometerCell data2 = (ThermometerCell) case2.getPuzzleElement(puzzleElement); + data2.setFill(ThermometerFill.BLOCKED); + case2.addModifiedData(data2); + cases.add(case2); + + return cases; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MinimumFillDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MinimumFillDirectRule.java new file mode 100644 index 000000000..ab389d6ff --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/MinimumFillDirectRule.java @@ -0,0 +1,44 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +// TODO: Rule is unimplemented +public class MinimumFillDirectRule extends DirectRule { + public MinimumFillDirectRule() { + super( + "THERM-BASC-0005", + "Minimum Fill", + "Some thermometers must be filled a minimum amount to satisfy requirement", + "edu/rpi/legup/images/thermometer/MinimumFill.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/PriorFilledDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/PriorFilledDirectRule.java new file mode 100644 index 000000000..61622ddb1 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/PriorFilledDirectRule.java @@ -0,0 +1,101 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.thermometer.ThermometerBoard; +import edu.rpi.legup.puzzle.thermometer.ThermometerCell; +import edu.rpi.legup.puzzle.thermometer.ThermometerFill; +import edu.rpi.legup.puzzle.thermometer.ThermometerVial; +import java.util.ArrayList; + +// TODO: Rule is untested +public class PriorFilledDirectRule extends DirectRule { + + public PriorFilledDirectRule() { + super( + "THERM-BASC-0002", + "Prior is Filled", + "All tiles proceeding a filled tile in a vial must be filled", + "edu/rpi/legup/images/thermometer/PriorIsFilled.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + ThermometerBoard initialBoard = + (ThermometerBoard) transition.getParents().get(0).getBoard(); + ThermometerBoard finalBoard = (ThermometerBoard) transition.getBoard(); + + ThermometerCell cell = (ThermometerCell) finalBoard.getPuzzleElement(puzzleElement); + if (cell.getFill() != ThermometerFill.FILLED) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not filled at this index"; + } + + ArrayList allVials = finalBoard.getVials(); + ThermometerVial host = null; + for (ThermometerVial vials : allVials) { + if (vials.containsCell((cell))) { + host = vials; + } + } + if (host == null) return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 1"; + int x = (int) cell.getLocation().getX(); + int y = (int) cell.getLocation().getX(); + + // Identifies next cell from tail location, checks if it is filled + if (host.getTail() == cell) { + return super.getInvalidUseOfRuleMessage() + ": rule can not apply to tail"; + } else if (host.getTail().getLocation().getX() == x) { + if (host.getTail().getLocation().getY() > y) { + if (initialBoard.getCell(x, y + 1).getFill() == ThermometerFill.FILLED) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell"; + } + } else if (host.getTail().getLocation().getY() < y) { + if (initialBoard.getCell(x, y - 1).getFill() == ThermometerFill.FILLED) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell"; + } + } else return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 2"; + } else if (host.getTail().getLocation().getY() == y) { + if (host.getTail().getLocation().getX() > x) { + if (initialBoard.getCell(x + 1, y).getFill() == ThermometerFill.FILLED) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell"; + } + } else if (host.getTail().getLocation().getX() < x) { + if (initialBoard.getCell(x - 1, y).getFill() == ThermometerFill.FILLED) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell"; + } + } else return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 2.1"; + } + return super.getInvalidUseOfRuleMessage() + "Something went wrong - 3"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/RestEmptyDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/RestEmptyDirectRule.java new file mode 100644 index 000000000..486c5c1da --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/RestEmptyDirectRule.java @@ -0,0 +1,101 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.thermometer.ThermometerBoard; +import edu.rpi.legup.puzzle.thermometer.ThermometerCell; +import edu.rpi.legup.puzzle.thermometer.ThermometerFill; +import edu.rpi.legup.puzzle.thermometer.ThermometerVial; +import java.util.ArrayList; + +// TODO: Rule is untested +public class RestEmptyDirectRule extends DirectRule { + + public RestEmptyDirectRule() { + super( + "THERM-BASC-0001", + "Rest is Empty", + "All tiles following a blocked tile in a vial must be blocked", + "edu/rpi/legup/images/thermometer/RestIsEmpty.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + ThermometerBoard initialBoard = + (ThermometerBoard) transition.getParents().get(0).getBoard(); + ThermometerBoard finalBoard = (ThermometerBoard) transition.getBoard(); + + ThermometerCell cell = (ThermometerCell) finalBoard.getPuzzleElement(puzzleElement); + if (cell.getFill() != ThermometerFill.BLOCKED) { + return super.getInvalidUseOfRuleMessage() + ": Cell is not blocked at this index"; + } + + ArrayList allVials = finalBoard.getVials(); + ThermometerVial host = null; + for (ThermometerVial vials : allVials) { + if (vials.containsCell((cell))) { + host = vials; + } + } + if (host == null) return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 1"; + int x = (int) cell.getLocation().getX(); + int y = (int) cell.getLocation().getX(); + + // Identifies previous cell from head location, checks if it is blocked + if (host.getHead() == cell) { + return super.getInvalidUseOfRuleMessage() + ": rule can not apply to head"; + } else if (host.getHead().getLocation().getX() == x) { + if (host.getHead().getLocation().getY() > y) { + if (initialBoard.getCell(x, y + 1).getFill() == ThermometerFill.BLOCKED) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell"; + } + } else if (host.getHead().getLocation().getY() < y) { + if (initialBoard.getCell(x, y - 1).getFill() == ThermometerFill.BLOCKED) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell"; + } + } else return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 2"; + } else if (host.getHead().getLocation().getY() == y) { + if (host.getHead().getLocation().getX() > x) { + if (initialBoard.getCell(x + 1, y).getFill() == ThermometerFill.BLOCKED) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell"; + } + } else if (host.getHead().getLocation().getX() < x) { + if (initialBoard.getCell(x - 1, y).getFill() == ThermometerFill.BLOCKED) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + "rule does not apply to this cell"; + } + } else return super.getInvalidUseOfRuleMessage() + ": Something went wrong - 2.1"; + } + return super.getInvalidUseOfRuleMessage() + "Something went wrong - 3"; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/SatisfyMercuryCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/SatisfyMercuryCaseRule.java new file mode 100644 index 000000000..05c861281 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/SatisfyMercuryCaseRule.java @@ -0,0 +1,62 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.CaseBoard; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.CaseRule; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.thermometer.*; +import java.util.ArrayList; + +// TODO:This rule is unimplemented +public class SatisfyMercuryCaseRule extends CaseRule { + public SatisfyMercuryCaseRule() { + super( + "THERM-CASE-0002", + "Satisfy Mercury", + "There are multiple ways column/row requirements can be fufilled", + "edu/rpi/legup/images/thermometer/SatisfyMercury.png"); + } + + /** + * Checks whether the transition logically follows from the parent node using this rule + * + * @param transition transition to check + * @return null if the child node logically follow from the parent node, otherwise error message + */ + @Override + public String checkRuleRaw(TreeTransition transition) { + return null; + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Gets the possible cases at a specific location based on this case rule + * + * @param board the current board state + * @param puzzleElement equivalent puzzleElement + * @return a list of elements the specified could be + */ + @Override + public ArrayList getCases(Board board, PuzzleElement puzzleElement) { + return null; + } + + @Override + public CaseBoard getCaseBoard(Board board) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/ThermometerTooLargeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/ThermometerTooLargeDirectRule.java new file mode 100644 index 000000000..d679781b7 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/ThermometerTooLargeDirectRule.java @@ -0,0 +1,44 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; + +// TODO: Rule is unimplemented +public class ThermometerTooLargeDirectRule extends DirectRule { + public ThermometerTooLargeDirectRule() { + super( + "THERM-BASC-0006", + "Thermometer Too Large", + "If thermometer is larger than required mercury, some of it must be blocked", + "edu/rpi/legup/images/thermometer/ThermometerTooLarge.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + return null; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooFewMercuryContradiction.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooFewMercuryContradiction.java new file mode 100644 index 000000000..8750eb64d --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooFewMercuryContradiction.java @@ -0,0 +1,57 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.thermometer.ThermometerBoard; +import edu.rpi.legup.puzzle.thermometer.ThermometerCell; +import edu.rpi.legup.puzzle.thermometer.ThermometerFill; + +// TODO: Rule is untested +public class TooFewMercuryContradiction extends ContradictionRule { + + private final String Invalid_Use_Message = "Mercury can still reach limit"; + + public TooFewMercuryContradiction() { + super( + "THERM-CONT-0002", + "Too Few Mercury", + "Not enough mercury in column/row to fufill requirement", + "edu/rpi/legup/images/thermometer/NotEnoughMercury.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + // Checks if row or column of input element has too many blocked tiles + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + ThermometerBoard grid = (ThermometerBoard) board; + ThermometerCell cell = (ThermometerCell) grid.getPuzzleElement(puzzleElement); + int blocked = 0; + for (int i = 0; i < grid.getHeight(); i++) { + if (grid.getCell((int) cell.getLocation().getX(), i).getFill() + == ThermometerFill.BLOCKED) { + blocked++; + } + } + if (grid.getRowNumber((int) cell.getLocation().getX()) > blocked) return null; + + blocked = 0; + for (int i = 0; i < grid.getWidth(); i++) { + if (grid.getCell(i, (int) cell.getLocation().getY()).getFill() + == ThermometerFill.BLOCKED) { + blocked++; + } + } + if (grid.getColNumber((int) cell.getLocation().getY()) > blocked) return null; + + return Invalid_Use_Message; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooManyMercuryContradiction.java b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooManyMercuryContradiction.java new file mode 100644 index 000000000..06b8a017c --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/TooManyMercuryContradiction.java @@ -0,0 +1,56 @@ +package edu.rpi.legup.puzzle.thermometer.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; +import edu.rpi.legup.puzzle.thermometer.ThermometerBoard; +import edu.rpi.legup.puzzle.thermometer.ThermometerCell; +import edu.rpi.legup.puzzle.thermometer.ThermometerFill; + +// TODO: Rule is untested +public class TooManyMercuryContradiction extends ContradictionRule { + + private final String Invalid_Use_Message = "Mercury does not exceed limit"; + + public TooManyMercuryContradiction() { + super( + "THERM-CONT-0003", + "Too Many Mercury", + "More mercury in column/row than target", + "edu/rpi/legup/images/thermometer/TooManyMercury.png"); + } + + /** + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule + * + * @param board board to check contradiction + * @param puzzleElement equivalent puzzleElement + * @return null if the transition contains a contradiction at the specified puzzleElement, + * otherwise error message + */ + @Override + public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { + ThermometerBoard grid = (ThermometerBoard) board; + ThermometerCell cell = (ThermometerCell) grid.getPuzzleElement(puzzleElement); + int filled = 0; + for (int i = 0; i < grid.getHeight(); i++) { + if (grid.getCell((int) cell.getLocation().getX(), i).getFill() + == ThermometerFill.FILLED) { + filled++; + } + } + if (grid.getRowNumber((int) cell.getLocation().getX()) > filled) return null; + + filled = 0; + for (int i = 0; i < grid.getWidth(); i++) { + if (grid.getCell(i, (int) cell.getLocation().getY()).getFill() + == ThermometerFill.FILLED) { + filled++; + } + } + if (grid.getColNumber((int) cell.getLocation().getY()) > filled) return null; + + return Invalid_Use_Message; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/thermometer_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/thermometer_reference_sheet.txt new file mode 100644 index 000000000..546fb89a6 --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/thermometer/rules/thermometer_reference_sheet.txt @@ -0,0 +1,16 @@ +THERM-BASC-0001 : RestEmptyDirectRule +THERM-BASC-0002 : PriorFilledDirectRule +THERM-BASC-0003 : FinishWithMercuryDirectRule +THERM-BASC-0004 : FinishWithBlockedDirectRule +THERM-BASC-0005 : MinimumFillDirectRule +THERM-BASC-0006 : ThermometerTooLargeDirectRule + +THERM-CONT-0001 : DiscontinuousMercuryContradictionRule +THERM-CONT-0002 : TooFewMercuryContradiction +THERM-CONT-0003 : TooManyMercuryContradiction + +THERM-CASE-0001 : MercuryOrBlockedCaseRule +THERM-CASE-0002 : SatisfyMercuryCaseRule + +Images can be found/edited here: +https://docs.google.com/presentation/d/1YHNog2fGvLJEx4kbJZiwwAlP-m2-E1O7hGh0HJ7S0gE/edit?usp=sharing \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/ClueCommand.java b/src/main/java/edu/rpi/legup/puzzle/treetent/ClueCommand.java index 30af5af51..a11f5f05b 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/ClueCommand.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/ClueCommand.java @@ -1,5 +1,7 @@ package edu.rpi.legup.puzzle.treetent; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.history.CommandError; import edu.rpi.legup.history.PuzzleCommand; import edu.rpi.legup.model.Puzzle; @@ -7,14 +9,11 @@ import edu.rpi.legup.ui.proofeditorui.treeview.TreeElementView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - public class ClueCommand extends PuzzleCommand { private TreeViewSelection selection; private TreeTentClueView clueView; @@ -28,9 +27,7 @@ public ClueCommand(TreeViewSelection selection, TreeTentClueView clueView) { this.emptyCells = new ArrayList<>(); } - /** - * Executes a command - */ + /** Executes a command */ @Override public void executeCommand() { Puzzle puzzle = getInstance().getPuzzleModule(); @@ -52,8 +49,7 @@ public void executeCommand() { if (transition == null) { transition = tree.addNewTransition(treeNode); addTran.put(treeNode, transition); - } - else { + } else { treeNode.addChild(transition); } @@ -62,8 +58,7 @@ public void executeCommand() { newSelection.addToSelection(treeView.getElementView(finalTran)); board = (TreeTentBoard) finalTran.getBoard(); - } - else { + } else { finalTran = (TreeTransition) treeElement; newSelection.addToSelection(treeView.getElementView(treeElement)); } @@ -88,7 +83,7 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { @@ -105,8 +100,7 @@ public String getErrorString() { if (!node.getChildren().isEmpty()) { return CommandError.UNMODIFIABLE_BOARD.toString(); } - } - else { + } else { if (!board.isModifiable()) { return CommandError.UNMODIFIABLE_BOARD.toString(); } @@ -114,17 +108,23 @@ public String getErrorString() { List tempList = new ArrayList<>(); TreeTentClue clue = clueView.getPuzzleElement(); - if (clue.getType() == TreeTentType.CLUE_NORTH || clue.getType() == TreeTentType.CLUE_SOUTH) { - int col = clue.getType() == TreeTentType.CLUE_NORTH ? clue.getClueIndex() : clue.getClueIndex() - 1; + if (clue.getType() == TreeTentType.CLUE_NORTH + || clue.getType() == TreeTentType.CLUE_SOUTH) { + int col = + clue.getType() == TreeTentType.CLUE_NORTH + ? clue.getClueIndex() + : clue.getClueIndex() - 1; for (int i = 0; i < board.getWidth(); i++) { TreeTentCell cell = board.getCell(col, i); if (cell.getType() == TreeTentType.UNKNOWN && cell.isModifiable()) { tempList.add(cell); } } - } - else { - int row = clue.getType() == TreeTentType.CLUE_WEST ? clue.getClueIndex() : clue.getClueIndex() - 1; + } else { + int row = + clue.getType() == TreeTentType.CLUE_WEST + ? clue.getClueIndex() + : clue.getClueIndex() - 1; for (int i = 0; i < board.getWidth(); i++) { TreeTentCell cell = board.getCell(i, row); if (cell.getType() == TreeTentType.UNKNOWN && cell.isModifiable()) { @@ -140,9 +140,7 @@ public String getErrorString() { return null; } - /** - * Undoes an command - */ + /** Undoes an command */ @Override public void undoCommand() { Puzzle puzzle = getInstance().getPuzzleModule(); @@ -163,8 +161,7 @@ public void undoCommand() { puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(finalTran)); board = (TreeTentBoard) finalTran.getBoard(); - } - else { + } else { finalTran = (TreeTransition) treeElement; } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/EditLineCommand.java b/src/main/java/edu/rpi/legup/puzzle/treetent/EditLineCommand.java index d2f8575f1..feece58a9 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/EditLineCommand.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/EditLineCommand.java @@ -1,5 +1,7 @@ package edu.rpi.legup.puzzle.treetent; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.history.CommandError; import edu.rpi.legup.history.PuzzleCommand; import edu.rpi.legup.model.Puzzle; @@ -8,27 +10,23 @@ import edu.rpi.legup.ui.proofeditorui.treeview.TreeElementView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; - import java.awt.*; import java.util.List; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - public class EditLineCommand extends PuzzleCommand { private TreeTentElementView start; private TreeTentElementView end; private TreeViewSelection selection; - public EditLineCommand(TreeViewSelection selection, TreeTentElementView start, ElementView endDrag) { + public EditLineCommand( + TreeViewSelection selection, TreeTentElementView start, ElementView endDrag) { this.selection = selection; this.start = start; this.end = getViewInDirection(endDrag); } - /** - * Executes a command - */ + /** Executes a command */ @Override public void executeCommand() { Puzzle puzzle = getInstance().getPuzzleModule(); @@ -49,8 +47,7 @@ public void executeCommand() { puzzle.notifyTreeListeners(listener -> listener.onTreeElementAdded(transition)); board = (TreeTentBoard) transition.getBoard(); - } - else { + } else { transition = (TreeTransition) treeElement; } @@ -73,8 +70,7 @@ public void executeCommand() { board.getLines().add(line); notifyLine = line; transition.propagateAddition(notifyLine); - } - else { + } else { board.removeModifiedData(dupLine); board.getLines().remove(dupLine); notifyLine = dupLine; @@ -85,7 +81,8 @@ public void executeCommand() { puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(transition)); - final TreeViewSelection newSelection = new TreeViewSelection(treeView.getElementView(transition)); + final TreeViewSelection newSelection = + new TreeViewSelection(treeView.getElementView(transition)); puzzle.notifyTreeListeners(listener -> listener.onTreeSelectionChanged(newSelection)); } @@ -93,7 +90,7 @@ public void executeCommand() { * Gets the reason why the command cannot be executed * * @return if command cannot be executed, returns reason for why the command cannot be executed, - * otherwise null if command can be executed + * otherwise null if command can be executed */ @Override public String getErrorString() { @@ -114,13 +111,15 @@ public String getErrorString() { if (!node.getChildren().isEmpty()) { return CommandError.UNMODIFIABLE_BOARD.toString(); } - } - else { + } else { if (!board.isModifiable()) { return CommandError.UNMODIFIABLE_BOARD.toString(); } } - TreeTentLine line = new TreeTentLine((TreeTentCell) start.getPuzzleElement(), (TreeTentCell) end.getPuzzleElement()); + TreeTentLine line = + new TreeTentLine( + (TreeTentCell) start.getPuzzleElement(), + (TreeTentCell) end.getPuzzleElement()); for (TreeTentLine l : board.getLines()) { if (line.compare(l) && !l.isModifiable()) { return CommandError.UNMODIFIABLE_DATA.toString(); @@ -129,17 +128,16 @@ public String getErrorString() { TreeTentCell startCell = (TreeTentCell) start.getPuzzleElement(); TreeTentCell endCell = (TreeTentCell) end.getPuzzleElement(); - if (!((startCell.getType() == TreeTentType.TENT && endCell.getType() == TreeTentType.TREE) || - (endCell.getType() == TreeTentType.TENT && startCell.getType() == TreeTentType.TREE))) { + if (!((startCell.getType() == TreeTentType.TENT && endCell.getType() == TreeTentType.TREE) + || (endCell.getType() == TreeTentType.TENT + && startCell.getType() == TreeTentType.TREE))) { return "The line must connect a tree to a tent."; } return null; } - /** - * Undoes an command - */ + /** Undoes an command */ @Override public void undoCommand() { Puzzle puzzle = getInstance().getPuzzleModule(); @@ -159,8 +157,7 @@ public void undoCommand() { puzzle.notifyTreeListeners(listener -> listener.onTreeElementRemoved(transition)); board = (TreeTentBoard) transition.getBoard(); - } - else { + } else { transition = (TreeTransition) treeElement; } @@ -182,8 +179,7 @@ public void undoCommand() { board.addModifiedData(line); board.getLines().add(line); notifyLine = line; - } - else { + } else { board.removeModifiedData(dupLine); board.getLines().remove(dupLine); notifyLine = dupLine; @@ -206,24 +202,21 @@ private TreeTentElementView getViewInDirection(ElementView endDrag) { Point endLoc = endDrag.getLocation(); double radians = Math.atan2(startLoc.y - endLoc.y, endLoc.x - startLoc.x); if (radians >= Math.PI / 4 && radians < 3 * Math.PI / 4) { - //up + // up xIndex = startLoc.x / size.width; yIndex = (startLoc.y / size.height) - 1; - } - else { + } else { if (radians >= -Math.PI / 4 && radians < Math.PI / 4) { - //right + // right xIndex = (startLoc.x / size.width) + 1; yIndex = startLoc.y / size.height; - } - else { + } else { if (radians >= -3 * Math.PI / 4 && radians < -Math.PI / 4) { - //down + // down xIndex = startLoc.x / size.width; yIndex = (startLoc.y / size.height) + 1; - } - else { - //left + } else { + // left xIndex = (startLoc.x / size.width) - 1; yIndex = startLoc.y / size.height; } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java index 172584cd0..4b0113232 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTent.java @@ -3,6 +3,7 @@ import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.ContradictionRule; import java.util.List; @@ -19,9 +20,7 @@ public TreeTent() { this.factory = new TreeTentCellFactory(); } - /** - * Initializes the game board. Called by the invoker of the class - */ + /** Initializes the game board. Called by the invoker of the class */ @Override public void initializeView() { TreeTentBoard board = (TreeTentBoard) currentBoard; @@ -44,8 +43,8 @@ public Board generatePuzzle(int difficulty) { /** * Determines if the given dimensions are valid for Tree Tent * - * @param rows the number of rows - * @param columns the number of columns + * @param rows the number of rows + * @param columns the number of columns * @return true if the given dimensions are valid for Tree Tent, false otherwise */ public boolean isValidDimensions(int rows, int columns) { @@ -61,7 +60,20 @@ public boolean isValidDimensions(int rows, int columns) { */ @Override public boolean isBoardComplete(Board board) { - return false; + TreeTentBoard treeTentBoard = (TreeTentBoard) board; + + for (ContradictionRule rule : contradictionRules) { + if (rule.checkContradiction(treeTentBoard) == null) { + return false; + } + } + for (PuzzleElement data : treeTentBoard.getPuzzleElements()) { + TreeTentCell cell = (TreeTentCell) data; + if (cell.getType() == TreeTentType.UNKNOWN) { + return false; + } + } + return true; } /** @@ -70,13 +82,10 @@ public boolean isBoardComplete(Board board) { * @param board the board that has changed */ @Override - public void onBoardChange(Board board) { - - } + public void onBoardChange(Board board) {} /** - * @return if it is valid - * TreeTent puzzle must have same number of clues as the dimension size + * @return if it is valid TreeTent puzzle must have same number of clues as the dimension size */ @Override public boolean checkValidity() { diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java index dc809f34d..c8962aa03 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentBoard.java @@ -3,7 +3,6 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.gameboard.GridBoard; import edu.rpi.legup.model.gameboard.PuzzleElement; - import java.awt.*; import java.util.ArrayList; import java.util.List; @@ -54,29 +53,36 @@ public TreeTentCell getCell(int x, int y) { @Override public PuzzleElement getPuzzleElement(PuzzleElement element) { - switch (element.getIndex()) { - case -2: - return element; - case -1: - TreeTentLine line = (TreeTentLine) element; - TreeTentLine thisLine = null; - for (TreeTentLine l : lines) { - if (line.compare(l)) { - thisLine = l; - break; - } - } - return thisLine; - default: - return super.getPuzzleElement(element); + return switch (element.getIndex()) { + case -2 -> element; + case -1 -> element; + default -> super.getPuzzleElement(element); + }; + } + + @Override + public void setPuzzleElement(int index, PuzzleElement puzzleElement) { + if (index == -1) { + lines.add((TreeTentLine) puzzleElement); + } else if (index < puzzleElements.size()) { + puzzleElements.set(index, puzzleElement); + } + } + + @Override + public void notifyChange(PuzzleElement puzzleElement) { + int index = puzzleElement.getIndex(); + if (index == -1) { + lines.add((TreeTentLine) puzzleElement); + } else if (index < puzzleElements.size()) { + puzzleElements.set(index, puzzleElement); } } public TreeTentClue getClue(int x, int y) { if (x == getWidth() && 0 <= y && y < getHeight()) { return rowClues.get(y); - } - else { + } else { if (y == getHeight() && 0 <= x && x < getWidth()) { return colClues.get(x); } @@ -85,7 +91,8 @@ public TreeTentClue getClue(int x, int y) { } /** - * Called when a {@link PuzzleElement} has been added and passes in the equivalent puzzle element with the data. + * Called when a {@link PuzzleElement} has been added and passes in the equivalent puzzle + * element with the data. * * @param puzzleElement equivalent puzzle element with the data. */ @@ -97,7 +104,8 @@ public void notifyAddition(PuzzleElement puzzleElement) { } /** - * Called when a {@link PuzzleElement} has been deleted and passes in the equivalent puzzle element with the data. + * Called when a {@link PuzzleElement} has been deleted and passes in the equivalent puzzle + * element with the data. * * @param puzzleElement equivalent puzzle element with the data. */ @@ -118,8 +126,8 @@ public void notifyDeletion(PuzzleElement puzzleElement) { * * @param cell The cell to get adjacent cells from. * @param type The cell types to get. - * @return List of adjacent cells in the form { up, right, down, left }. - * If an adjacent cell is null, it will not be added to the list. + * @return List of adjacent cells in the form { up, right, down, left }. If an adjacent cell is + * null, it will not be added to the list. */ public List getAdjacent(TreeTentCell cell, TreeTentType type) { List adj = new ArrayList<>(); @@ -138,7 +146,8 @@ public List getAdjacent(TreeTentCell cell, TreeTentType type) { * * @param cell the base cell * @param type the type to look for - * @return a list of TreeTentCells that are diagonals of the given TreeTentCell and are of the given TreeTentType + * @return a list of TreeTentCells that are diagonals of the given TreeTentCell and are of the + * given TreeTentType */ public List getDiagonals(TreeTentCell cell, TreeTentType type) { List dia = new ArrayList<>(); @@ -166,22 +175,21 @@ public List getDiagonals(TreeTentCell cell, TreeTentType type) { * Creates and returns a list of TreeTentCells that match the given TreeTentType * * @param index the row or column number - * @param type type of TreeTent element - * @param isRow boolean value beased on whether a row of column is being checked + * @param type type of TreeTent element + * @param isRow boolean value based on whether a row of column is being checked * @return List of TreeTentCells that match the given TreeTentType */ public List getRowCol(int index, TreeTentType type, boolean isRow) { List list = new ArrayList<>(); if (isRow) { - for (int i = 0; i < dimension.height; i++) { + for (int i = 0; i < dimension.width; i++) { TreeTentCell cell = getCell(i, index); if (cell.getType() == type) { list.add(cell); } } - } - else { - for (int i = 0; i < dimension.width; i++) { + } else { + for (int i = 0; i < dimension.height; i++) { TreeTentCell cell = getCell(index, i); if (cell.getType() == type) { list.add(cell); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCell.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCell.java index b6411a5cf..c7c9f0d21 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCell.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCell.java @@ -2,7 +2,6 @@ import edu.rpi.legup.model.elements.Element; import edu.rpi.legup.model.gameboard.GridCell; - import java.awt.*; import java.awt.event.MouseEvent; diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCellFactory.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCellFactory.java index 20b8066a4..a3553940d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCellFactory.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentCellFactory.java @@ -4,17 +4,16 @@ import edu.rpi.legup.model.gameboard.ElementFactory; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import java.awt.*; - public class TreeTentCellFactory extends ElementFactory { /** * Creates a puzzleElement based on the xml document Node and adds it to the board * - * @param node node that represents the puzzleElement + * @param node node that represents the puzzleElement * @param board board to add the newly created cell * @return newly created cell from the xml document Node * @throws InvalidFileFormatException if file is invalid @@ -32,39 +31,39 @@ public PuzzleElement importCell(Node node, Board board) throws InvalidFileFormat int x = Integer.valueOf(attributeList.getNamedItem("x").getNodeValue()); int y = Integer.valueOf(attributeList.getNamedItem("y").getNodeValue()); if (x >= width || y >= height) { - throw new InvalidFileFormatException("TreeTent Factory: cell location out of bounds"); + throw new InvalidFileFormatException( + "TreeTent Factory: cell location out of bounds"); } if (value < 0 || value > 3) { throw new InvalidFileFormatException("TreeTent Factory: cell unknown value"); } TreeTentCell cell = new TreeTentCell(TreeTentType.valueOf(value), new Point(x, y)); - cell.setIndex(y * height + x); + cell.setIndex(y * width + x); return cell; - } - else { + } else { if (node.getNodeName().equalsIgnoreCase("line")) { int x1 = Integer.valueOf(attributeList.getNamedItem("x1").getNodeValue()); int y1 = Integer.valueOf(attributeList.getNamedItem("y1").getNodeValue()); int x2 = Integer.valueOf(attributeList.getNamedItem("x2").getNodeValue()); int y2 = Integer.valueOf(attributeList.getNamedItem("y2").getNodeValue()); if (x1 >= width || y1 >= height || x2 >= width || y2 >= height) { - throw new InvalidFileFormatException("TreeTent Factory: line location out of bounds"); + throw new InvalidFileFormatException( + "TreeTent Factory: line location out of bounds"); } TreeTentCell c1 = treeTentBoard.getCell(x1, y1); TreeTentCell c2 = treeTentBoard.getCell(x2, y2); return new TreeTentLine(c1, c2); - } - else { - throw new InvalidFileFormatException("TreeTent Factory: unknown puzzleElement puzzleElement"); + } else { + throw new InvalidFileFormatException( + "TreeTent Factory: unknown puzzleElement puzzleElement"); } } - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("TreeTent Factory: unknown value where integer expected"); - } - catch (NullPointerException e) { + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "TreeTent Factory: unknown value where integer expected"); + } catch (NullPointerException e) { throw new InvalidFileFormatException("TreeTent Factory: could not find attribute(s)"); } } @@ -72,7 +71,7 @@ public PuzzleElement importCell(Node node, Board board) throws InvalidFileFormat /** * Creates a xml document puzzleElement from a cell for exporting * - * @param document xml document + * @param document xml document * @param puzzleElement PuzzleElement cell * @return xml PuzzleElement */ @@ -88,8 +87,7 @@ public org.w3c.dom.Element exportCell(Document document, PuzzleElement puzzleEle cellElement.setAttribute("y", String.valueOf(loc.y)); return cellElement; - } - else { + } else { org.w3c.dom.Element lineElement = document.createElement("line"); TreeTentLine line = (TreeTentLine) puzzleElement; diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentClue.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentClue.java index bcba7dc94..7b93f1301 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentClue.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentClue.java @@ -50,6 +50,6 @@ public void setType(TreeTentType type) { } public TreeTentClue copy() { - return null; + return new TreeTentClue(data, clueIndex, type); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentClueView.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentClueView.java index 4e7b24b13..d1b230d20 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentClueView.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentClueView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.treetent; import edu.rpi.legup.ui.boardview.ElementView; - import java.awt.*; public class TreeTentClueView extends ElementView { diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentController.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentController.java index 1f431594c..667c2ba7d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentController.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentController.java @@ -1,5 +1,7 @@ package edu.rpi.legup.puzzle.treetent; +import static edu.rpi.legup.app.GameBoardFacade.getInstance; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.history.AutoCaseRuleCommand; @@ -13,11 +15,8 @@ import edu.rpi.legup.ui.proofeditorui.treeview.TreePanel; import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; - import java.awt.event.MouseEvent; -import static edu.rpi.legup.app.GameBoardFacade.getInstance; - public class TreeTentController extends ElementController { private ElementView lastCellPressed; @@ -33,16 +32,20 @@ public TreeTentController() { public void mousePressed(MouseEvent e) { if (e.getButton() != MouseEvent.BUTTON2) { BoardView boardView = getInstance().getLegupUI().getBoardView(); - dragStart = boardView.getElement(e.getPoint()); - lastCellPressed = boardView.getElement(e.getPoint()); + if (boardView != null) { + dragStart = boardView.getElement(e.getPoint()); + lastCellPressed = boardView.getElement(e.getPoint()); + } } } @Override public void mouseReleased(MouseEvent e) { - if (GameBoardFacade.getInstance().getLegupUI().getTreePanel() != null && e.getButton() != MouseEvent.BUTTON2) { + if (GameBoardFacade.getInstance().getLegupUI().getTreePanel() != null + && e.getButton() != MouseEvent.BUTTON2) { TreePanel treePanel = GameBoardFacade.getInstance().getLegupUI().getTreePanel(); - TreeView treeView = GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); + TreeView treeView = + GameBoardFacade.getInstance().getLegupUI().getTreePanel().getTreeView(); BoardView boardView = getInstance().getLegupUI().getBoardView(); lastCellPressed = boardView.getElement(e.getPoint()); Board board = boardView.getBoard(); @@ -51,17 +54,17 @@ public void mouseReleased(MouseEvent e) { if (dragStart != null) { if (board instanceof CaseBoard) { CaseBoard caseBoard = (CaseBoard) board; - AutoCaseRuleCommand autoCaseRuleCommand = new AutoCaseRuleCommand(dragStart, selection, caseBoard.getCaseRule(), caseBoard, e); + AutoCaseRuleCommand autoCaseRuleCommand = + new AutoCaseRuleCommand( + dragStart, selection, caseBoard.getCaseRule(), caseBoard, e); if (autoCaseRuleCommand.canExecute()) { autoCaseRuleCommand.execute(); getInstance().getHistory().pushChange(autoCaseRuleCommand); treePanel.updateError(""); - } - else { + } else { treePanel.updateError(autoCaseRuleCommand.getError()); } - } - else { + } else { if (dragStart == lastCellPressed) { if (dragStart.getPuzzleElement().getIndex() >= 0) { ICommand edit = new EditDataCommand(lastCellPressed, selection, e); @@ -69,32 +72,32 @@ public void mouseReleased(MouseEvent e) { edit.execute(); getInstance().getHistory().pushChange(edit); treePanel.updateError(""); - } - else { + } else { treePanel.updateError(edit.getError()); } - } - else { - ClueCommand edit = new ClueCommand(selection, (TreeTentClueView) dragStart); + } else { + ClueCommand edit = + new ClueCommand(selection, (TreeTentClueView) dragStart); if (edit.canExecute()) { edit.execute(); getInstance().getHistory().pushChange(edit); treePanel.updateError(""); - } - else { + } else { treePanel.updateError(edit.getError()); } } - } - else { + } else { if (lastCellPressed != null) { if (dragStart instanceof TreeTentElementView) { - ICommand editLine = new EditLineCommand(selection, (TreeTentElementView) dragStart, lastCellPressed); + ICommand editLine = + new EditLineCommand( + selection, + (TreeTentElementView) dragStart, + lastCellPressed); if (editLine.canExecute()) { editLine.execute(); getInstance().getHistory().pushChange(editLine); - } - else { + } else { treePanel.updateError(editLine.getError()); } } @@ -104,6 +107,8 @@ public void mouseReleased(MouseEvent e) { } dragStart = null; lastCellPressed = null; + } else { + super.mouseReleased(e); } } @@ -113,26 +118,21 @@ public void changeCell(MouseEvent e, PuzzleElement element) { if (e.getButton() == MouseEvent.BUTTON1) { if (cell.getData() == TreeTentType.UNKNOWN) { element.setData(TreeTentType.GRASS); - } - else { + } else { if (cell.getData() == TreeTentType.GRASS) { element.setData(TreeTentType.TENT); - } - else { + } else { element.setData(TreeTentType.UNKNOWN); } } - } - else { + } else { if (e.getButton() == MouseEvent.BUTTON3) { if (cell.getData() == TreeTentType.UNKNOWN) { element.setData(TreeTentType.TENT); - } - else { + } else { if (cell.getData() == TreeTentType.GRASS) { element.setData(TreeTentType.UNKNOWN); - } - else { + } else { element.setData(TreeTentType.GRASS); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentElementView.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentElementView.java index 0c8698f83..1196ab075 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentElementView.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentElementView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.treetent; import edu.rpi.legup.ui.boardview.GridElementView; - import java.awt.*; import java.awt.geom.Rectangle2D; @@ -23,25 +22,47 @@ public void drawElement(Graphics2D graphics2D) { if (type == TreeTentType.UNKNOWN) { graphics2D.setStroke(new BasicStroke(1)); graphics2D.setColor(Color.LIGHT_GRAY); - graphics2D.fill(new Rectangle2D.Double(location.x + 0.5f, location.y + 0.5f, size.width - 1, size.height - 1)); + graphics2D.fill( + new Rectangle2D.Double( + location.x + 0.5f, location.y + 0.5f, size.width - 1, size.height - 1)); graphics2D.setColor(Color.BLACK); - graphics2D.draw(new Rectangle2D.Double(location.x + 0.5f, location.y + 0.5f, size.width - 1, size.height - 1)); - } - else { + graphics2D.draw( + new Rectangle2D.Double( + location.x + 0.5f, location.y + 0.5f, size.width - 1, size.height - 1)); + } else { if (type == TreeTentType.TREE) { - graphics2D.drawImage(TreeTentView.TREE, location.x, location.y, size.width, size.height, null, null); + graphics2D.drawImage( + TreeTentView.TREE, + location.x, + location.y, + size.width, + size.height, + null, + null); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == TreeTentType.GRASS) { - graphics2D.drawImage(TreeTentView.GRASS, location.x, location.y, size.width, size.height, null, null); + graphics2D.drawImage( + TreeTentView.GRASS, + location.x, + location.y, + size.width, + size.height, + null, + null); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); - } - else { + } else { if (type == TreeTentType.TENT) { - graphics2D.drawImage(TreeTentView.TENT, location.x, location.y, size.width, size.height, null, null); + graphics2D.drawImage( + TreeTentView.TENT, + location.x, + location.y, + size.width, + size.height, + null, + null); graphics2D.setColor(Color.BLACK); graphics2D.drawRect(location.x, location.y, size.width, size.height); } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentExporter.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentExporter.java index c438d8ee4..82c1b373d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentExporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentExporter.java @@ -21,8 +21,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { TreeTentBoard board; if (puzzle.getTree() != null) { board = (TreeTentBoard) puzzle.getTree().getRootNode().getBoard(); - } - else { + } else { board = (TreeTentBoard) puzzle.getBoardView().getBoard(); } @@ -34,7 +33,8 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { for (PuzzleElement puzzleElement : board.getPuzzleElements()) { TreeTentCell cell = (TreeTentCell) puzzleElement; if (cell.getData() != TreeTentType.UNKNOWN) { - org.w3c.dom.Element cellElement = puzzle.getFactory().exportCell(newDocument, puzzleElement); + org.w3c.dom.Element cellElement = + puzzle.getFactory().exportCell(newDocument, puzzleElement); cellsElement.appendChild(cellElement); } } @@ -52,7 +52,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) { org.w3c.dom.Element axisSouth = newDocument.createElement("axis"); axisSouth.setAttribute("side", "south"); - for (TreeTentClue clue : board.getRowClues()) { + for (TreeTentClue clue : board.getColClues()) { org.w3c.dom.Element clueElement = newDocument.createElement("clue"); clueElement.setAttribute("value", String.valueOf(clue.getData())); clueElement.setAttribute("index", String.valueOf(clue.getClueIndex())); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentImporter.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentImporter.java index 2b4861c9f..56dcca59f 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentImporter.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentImporter.java @@ -2,12 +2,13 @@ import edu.rpi.legup.model.PuzzleImporter; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import java.awt.*; - public class TreeTentImporter extends PuzzleImporter { public TreeTentImporter(TreeTent treeTent) { super(treeTent); @@ -26,7 +27,7 @@ public boolean acceptsTextInput() { /** * Creates an empty board for building * - * @param rows the number of rows on the board + * @param rows the number of rows on the board * @param columns the number of columns on the board * @throws RuntimeException if board can not be created */ @@ -66,11 +67,13 @@ public void initializeBoard(int rows, int columns) { public void initializeBoard(Node node) throws InvalidFileFormatException { try { if (!node.getNodeName().equalsIgnoreCase("board")) { - throw new InvalidFileFormatException("TreeTent Importer: cannot find board puzzleElement"); + throw new InvalidFileFormatException( + "TreeTent Importer: cannot find board puzzleElement"); } Element boardElement = (Element) node; if (boardElement.getElementsByTagName("cells").getLength() == 0) { - throw new InvalidFileFormatException("TreeTent Importer: no puzzleElement found for board"); + throw new InvalidFileFormatException( + "TreeTent Importer: no puzzleElement found for board"); } Element dataElement = (Element) boardElement.getElementsByTagName("cells").item(0); NodeList elementDataList = dataElement.getElementsByTagName("cell"); @@ -79,9 +82,9 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { if (!boardElement.getAttribute("size").isEmpty()) { int size = Integer.valueOf(boardElement.getAttribute("size")); treeTentBoard = new TreeTentBoard(size); - } - else { - if (!boardElement.getAttribute("width").isEmpty() && !boardElement.getAttribute("height").isEmpty()) { + } else { + if (!boardElement.getAttribute("width").isEmpty() + && !boardElement.getAttribute("height").isEmpty()) { int width = Integer.valueOf(boardElement.getAttribute("width")); int height = Integer.valueOf(boardElement.getAttribute("height")); treeTentBoard = new TreeTentBoard(width, height); @@ -96,7 +99,10 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int height = treeTentBoard.getHeight(); for (int i = 0; i < elementDataList.getLength(); i++) { - TreeTentCell cell = (TreeTentCell) puzzle.getFactory().importCell(elementDataList.item(i), treeTentBoard); + TreeTentCell cell = + (TreeTentCell) + puzzle.getFactory() + .importCell(elementDataList.item(i), treeTentBoard); Point loc = cell.getLocation(); if (cell.getData() != TreeTentType.UNKNOWN) { cell.setModifiable(false); @@ -109,7 +115,7 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { for (int x = 0; x < width; x++) { if (treeTentBoard.getCell(x, y) == null) { TreeTentCell cell = new TreeTentCell(TreeTentType.UNKNOWN, new Point(x, y)); - cell.setIndex(y * height + x); + cell.setIndex(y * width + x); cell.setModifiable(true); treeTentBoard.setCell(x, y, cell); } @@ -125,19 +131,31 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { Element axis2 = (Element) axes.item(1); if (!axis1.hasAttribute("side") || !axis1.hasAttribute("side")) { - throw new InvalidFileFormatException("TreeTent Importer: side attribute of axis not specified"); + throw new InvalidFileFormatException( + "TreeTent Importer: side attribute of axis not specified"); } String side1 = axis1.getAttribute("side"); String side2 = axis2.getAttribute("side"); - if (side1.equalsIgnoreCase(side2) || !(side1.equalsIgnoreCase("east") || side1.equalsIgnoreCase("south")) || - !(side2.equalsIgnoreCase("east") || side2.equalsIgnoreCase("south"))) { - throw new InvalidFileFormatException("TreeTent Importer: axes must be different and be {east | south}"); + if (side1.equalsIgnoreCase(side2) + || !(side1.equalsIgnoreCase("east") || side1.equalsIgnoreCase("south")) + || !(side2.equalsIgnoreCase("east") || side2.equalsIgnoreCase("south"))) { + throw new InvalidFileFormatException( + "TreeTent Importer: axes must be different and be {east | south}"); } - NodeList eastClues = side1.equalsIgnoreCase("east") ? axis1.getElementsByTagName("clue") : axis2.getElementsByTagName("clue"); - NodeList southClues = side1.equalsIgnoreCase("south") ? axis1.getElementsByTagName("clue") : axis2.getElementsByTagName("clue"); - - if (eastClues.getLength() != treeTentBoard.getHeight() || southClues.getLength() != treeTentBoard.getWidth()) { - throw new InvalidFileFormatException("TreeTent Importer: there must be same number of clues as the dimension of the board"); + NodeList eastClues = + side1.equalsIgnoreCase("east") + ? axis1.getElementsByTagName("clue") + : axis2.getElementsByTagName("clue"); + NodeList southClues = + side1.equalsIgnoreCase("south") + ? axis1.getElementsByTagName("clue") + : axis2.getElementsByTagName("clue"); + + if (eastClues.getLength() != treeTentBoard.getHeight() + || southClues.getLength() != treeTentBoard.getWidth()) { + throw new InvalidFileFormatException( + "TreeTent Importer: there must be same number of clues as the dimension of" + + " the board"); } for (int i = 0; i < eastClues.getLength(); i++) { @@ -146,13 +164,16 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int index = TreeTentClue.colStringToColNum(clue.getAttribute("index")); if (index - 1 < 0 || index - 1 > treeTentBoard.getHeight()) { - throw new InvalidFileFormatException("TreeTent Importer: clue index out of bounds"); + throw new InvalidFileFormatException( + "TreeTent Importer: clue index out of bounds"); } if (treeTentBoard.getRowClues().get(index - 1) != null) { throw new InvalidFileFormatException("TreeTent Importer: duplicate clue index"); } - treeTentBoard.getRowClues().set(index - 1, new TreeTentClue(value, index, TreeTentType.CLUE_EAST)); + treeTentBoard + .getRowClues() + .set(index - 1, new TreeTentClue(value, index, TreeTentType.CLUE_EAST)); } for (int i = 0; i < southClues.getLength(); i++) { @@ -161,27 +182,35 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { int index = Integer.valueOf(clue.getAttribute("index")); if (index - 1 < 0 || index - 1 > treeTentBoard.getWidth()) { - throw new InvalidFileFormatException("TreeTent Importer: clue index out of bounds"); + throw new InvalidFileFormatException( + "TreeTent Importer: clue index out of bounds"); } if (treeTentBoard.getColClues().get(index - 1) != null) { throw new InvalidFileFormatException("TreeTent Importer: duplicate clue index"); } - treeTentBoard.getColClues().set(index - 1, new TreeTentClue(value, index, TreeTentType.CLUE_SOUTH)); + treeTentBoard + .getColClues() + .set(index - 1, new TreeTentClue(value, index, TreeTentType.CLUE_SOUTH)); } if (boardElement.getElementsByTagName("lines").getLength() == 1) { Element linesElement = (Element) boardElement.getElementsByTagName("lines").item(0); NodeList linesList = linesElement.getElementsByTagName("line"); for (int i = 0; i < linesList.getLength(); i++) { - treeTentBoard.getLines().add((TreeTentLine) puzzle.getFactory().importCell(linesList.item(i), treeTentBoard)); + treeTentBoard + .getLines() + .add( + (TreeTentLine) + puzzle.getFactory() + .importCell(linesList.item(i), treeTentBoard)); } } puzzle.setCurrentBoard(treeTentBoard); - } - catch (NumberFormatException e) { - throw new InvalidFileFormatException("TreeTent Importer: unknown value where integer expected"); + } catch (NumberFormatException e) { + throw new InvalidFileFormatException( + "TreeTent Importer: unknown value where integer expected"); } } @@ -189,4 +218,12 @@ public void initializeBoard(Node node) throws InvalidFileFormatException { public void initializeBoard(String[] statements) throws UnsupportedOperationException { throw new UnsupportedOperationException("Tree Tent cannot accept text input"); } + + @Override + public List getImporterElements() { + List elements = new ArrayList<>(); + elements.add("cell"); + elements.add("line"); + return elements; + } } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentLine.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentLine.java index 9444cb425..dae10a1ae 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentLine.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentLine.java @@ -26,8 +26,10 @@ public void setC2(TreeTentCell c2) { } public boolean compare(TreeTentLine line) { - return ((line.getC1().getLocation().equals(data.getKey().getLocation()) && line.getC2().getLocation().equals(data.getValue().getLocation())) || - (line.getC1().getLocation().equals(data.getValue().getLocation()) && line.getC2().getLocation().equals(data.getKey().getLocation()))); + return ((line.getC1().getLocation().equals(data.getKey().getLocation()) + && line.getC2().getLocation().equals(data.getValue().getLocation())) + || (line.getC1().getLocation().equals(data.getValue().getLocation()) + && line.getC2().getLocation().equals(data.getKey().getLocation()))); } /** diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentLineView.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentLineView.java index 833dcb5b5..6d478cff8 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentLineView.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentLineView.java @@ -1,7 +1,6 @@ package edu.rpi.legup.puzzle.treetent; import edu.rpi.legup.ui.boardview.ElementView; - import java.awt.*; public class TreeTentLineView extends ElementView { @@ -24,7 +23,7 @@ public void draw(Graphics2D graphics2D) { int x2 = (p2.x + 1) * size.width + size.width / 2; int y2 = (p2.y + 1) * size.height + size.height / 2; - //graphics2D.setColor(LINE_COLOR); + // graphics2D.setColor(LINE_COLOR); graphics2D.setColor(line.isModified() ? Color.GREEN : Color.WHITE); graphics2D.setStroke(LINE_STROKE); graphics2D.drawLine(x1, y1, x2, y2); diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentType.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentType.java index 890cdfe29..230283418 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentType.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentType.java @@ -1,10 +1,14 @@ package edu.rpi.legup.puzzle.treetent; -import edu.rpi.legup.puzzle.masyu.MasyuType; - public enum TreeTentType { - UNKNOWN, TREE, GRASS, TENT, - CLUE_NORTH, CLUE_EAST, CLUE_SOUTH, CLUE_WEST; + UNKNOWN, + TREE, + GRASS, + TENT, + CLUE_NORTH, + CLUE_EAST, + CLUE_SOUTH, + CLUE_WEST; public static TreeTentType valueOf(int num) { switch (num) { @@ -18,4 +22,4 @@ public static TreeTentType valueOf(int num) { return UNKNOWN; } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentView.java b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentView.java index 23a500231..3b8cadad6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentView.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/TreeTentView.java @@ -6,26 +6,33 @@ import edu.rpi.legup.model.tree.TreeElement; import edu.rpi.legup.ui.boardview.ElementView; import edu.rpi.legup.ui.boardview.GridBoardView; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.imageio.ImageIO; import java.awt.*; import java.io.IOException; import java.util.ArrayList; +import javax.imageio.ImageIO; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class TreeTentView extends GridBoardView { - private final static Logger LOGGER = LogManager.getLogger(TreeTentView.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(TreeTentView.class.getName()); static Image TREE, GRASS, TENT; static { try { - TREE = ImageIO.read(ClassLoader.getSystemResourceAsStream("edu/rpi/legup/images/treetent/tree.png")); - GRASS = ImageIO.read(ClassLoader.getSystemResourceAsStream("edu/rpi/legup/images/treetent/grass.png")); - TENT = ImageIO.read(ClassLoader.getSystemResourceAsStream("edu/rpi/legup/images/treetent/tent.png")); - } - catch (IOException e) { + TREE = + ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/treetent/tree.png")); + GRASS = + ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/treetent/grass.png")); + TENT = + ImageIO.read( + ClassLoader.getSystemResourceAsStream( + "edu/rpi/legup/images/treetent/tent.png")); + } catch (IOException e) { LOGGER.error("Failed to open TreeTent images"); } } @@ -53,7 +60,8 @@ public TreeTentView(TreeTentBoard board) { TreeTentElementView elementView = new TreeTentElementView(cell); elementView.setIndex(cell.getIndex()); elementView.setSize(elementSize); - elementView.setLocation(new Point((loc.x + 1) * elementSize.width, (loc.y + 1) * elementSize.height)); + elementView.setLocation( + new Point((loc.x + 1) * elementSize.width, (loc.y + 1) * elementSize.height)); elementViews.add(elementView); } @@ -64,12 +72,16 @@ public TreeTentView(TreeTentBoard board) { } for (int i = 0; i < gridSize.height; i++) { - TreeTentClueView row = new TreeTentClueView(new TreeTentClue(i, i, TreeTentType.CLUE_WEST)); + TreeTentClueView row = + new TreeTentClueView(new TreeTentClue(i, i, TreeTentType.CLUE_WEST)); row.setLocation(new Point(0, (i + 1) * elementSize.height)); row.setSize(elementSize); TreeTentClueView clue = new TreeTentClueView(board.getRowClues().get(i)); - clue.setLocation(new Point((gridSize.width + 1) * elementSize.width, (i + 1) * elementSize.height)); + clue.setLocation( + new Point( + (gridSize.width + 1) * elementSize.width, + (i + 1) * elementSize.height)); clue.setSize(elementSize); westClues.add(row); @@ -77,12 +89,16 @@ public TreeTentView(TreeTentBoard board) { } for (int i = 0; i < gridSize.width; i++) { - TreeTentClueView col = new TreeTentClueView(new TreeTentClue(i, i, TreeTentType.CLUE_NORTH)); + TreeTentClueView col = + new TreeTentClueView(new TreeTentClue(i, i, TreeTentType.CLUE_NORTH)); col.setLocation(new Point((i + 1) * elementSize.width, 0)); col.setSize(elementSize); TreeTentClueView clue = new TreeTentClueView(board.getColClues().get(i)); - clue.setLocation(new Point((i + 1) * elementSize.width, (gridSize.height + 1) * elementSize.height)); + clue.setLocation( + new Point( + (i + 1) * elementSize.width, + (gridSize.height + 1) * elementSize.height)); clue.setSize(elementSize); northClues.add(col); @@ -91,15 +107,18 @@ public TreeTentView(TreeTentBoard board) { } /** - * Gets the ElementView from the location specified or - * null if one does not exists at that location + * Gets the ElementView from the location specified or null if one does not exists at that + * location * * @param point location on the viewport * @return ElementView at the specified location */ @Override public ElementView getElement(Point point) { - Point scaledPoint = new Point((int) Math.round(point.x / getScale()), (int) Math.round(point.y / getScale())); + Point scaledPoint = + new Point( + (int) Math.round(point.x / getScale()), + (int) Math.round(point.y / getScale())); for (ElementView element : elementViews) { if (element.isWithinBounds(scaledPoint)) { return element; @@ -167,8 +186,7 @@ public void onTreeElementChanged(TreeElement treeElement) { TreeTentBoard treeTentBoard; if (board instanceof CaseBoard) { treeTentBoard = (TreeTentBoard) ((CaseBoard) board).getBaseBoard(); - } - else { + } else { treeTentBoard = (TreeTentBoard) board; } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java index b85b5e337..1d33b9035 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/GrassTile.java @@ -5,7 +5,10 @@ public class GrassTile extends PlaceableElement { public GrassTile() { - super("TREE-PlAC-0002", "Grass Tile", "The grass crest tile", "edu/rpi/legup/images/treetent/grass.png"); + super( + "TREE-ELEM-0001", + "Grass Tile", + "The grass crest tile", + "edu/rpi/legup/images/treetent/grass.png"); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java index 2f4fee1eb..96124a98d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TentTile.java @@ -5,7 +5,10 @@ public class TentTile extends PlaceableElement { public TentTile() { - super("TREE-PLAC-0001", "Tent Tile", "The tent tile", "edu/rpi/legup/images/treetent/tent.png"); + super( + "TREE-ELEM-0002", + "Tent Tile", + "The tent tile", + "edu/rpi/legup/images/treetent/tent.png"); } - -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java index a91928fe4..3d94cbfba 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/TreeTile.java @@ -1,12 +1,14 @@ package edu.rpi.legup.puzzle.treetent.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; import edu.rpi.legup.model.elements.PlaceableElement; -public class TreeTile extends NonPlaceableElement { +public class TreeTile extends PlaceableElement { public TreeTile() { - super("TREE-UNPL-0001", "Tree Tile", "The tree tile", "edu/rpi/legup/images/treetent/tree.png"); + super( + "TREE-ELEM-0003", + "Tree Tile", + "The tree tile", + "edu/rpi/legup/images/treetent/tree.png"); } - } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java index 73c8ca263..99b75b60c 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/UnknownTile.java @@ -1,9 +1,13 @@ package edu.rpi.legup.puzzle.treetent.elements; -import edu.rpi.legup.model.elements.NonPlaceableElement; +import edu.rpi.legup.model.elements.PlaceableElement; -public class UnknownTile extends NonPlaceableElement { +public class UnknownTile extends PlaceableElement { public UnknownTile() { - super("TREE-UNPL-0002", "Unknown Tile", "The blank tile", "edu/rpi/legup/images/treetent/UnknownTile.png"); + super( + "TREE-ELEM-0004", + "Unknown Tile", + "The blank tile", + "edu/rpi/legup/images/treetent/UnknownTile.png"); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt new file mode 100644 index 000000000..e0cfc1dfa --- /dev/null +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/elements/treetent_elements_reference_sheet.txt @@ -0,0 +1,4 @@ +TREE-ELEM-0001 : GrassTile +TREE-ELEM-0002 : TentTile +TREE-ELEM-0003 : TreeTile +TREE-ELEM-0004 : UnknownTile \ No newline at end of file diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/EmptyFieldDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/EmptyFieldDirectRule.java index adfad52f6..c91a60b1a 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/EmptyFieldDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/EmptyFieldDirectRule.java @@ -1,87 +1,89 @@ -package edu.rpi.legup.puzzle.treetent.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentLine; -import edu.rpi.legup.puzzle.treetent.TreeTentType; - -import java.util.List; - -public class EmptyFieldDirectRule extends DirectRule { - public EmptyFieldDirectRule() { - super("TREE-BASC-0001", "Empty Field", - "Blank cells not adjacent to an unlinked tree are grass.", - "edu/rpi/legup/images/treetent/noTreesAround.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - if (puzzleElement instanceof TreeTentLine) { - return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule"; - } - TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); - TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); - TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); - TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(finalCell.getType() == TreeTentType.GRASS && initCell.getType() == TreeTentType.UNKNOWN)) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be grass"; - } - - if (isForced(finalBoard, finalCell)) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be empty."; - } - } - - /** - * Returns a boolean value based on whether the specified cell has adjacent cells (true - no adjacent, false - has adjacent) - * - * @param board the TreeTent board - * @param cell the specified TreeTent cell - * @return true - no adjacent, false - has adjacent - */ - private boolean isForced(TreeTentBoard board, TreeTentCell cell) { - List adjCells = board.getAdjacent(cell, TreeTentType.TREE); - return adjCells.isEmpty(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); - for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { - TreeTentCell cell = (TreeTentCell) element; - if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { - cell.setData(TreeTentType.GRASS); - treeTentBoard.addModifiedData(cell); - } - } - if (treeTentBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return treeTentBoard; - } - } -} +package edu.rpi.legup.puzzle.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.TreeTentType; +import java.util.List; + +public class EmptyFieldDirectRule extends DirectRule { + public EmptyFieldDirectRule() { + super( + "TREE-BASC-0001", + "Empty Field", + "Blank cells not adjacent to an unlinked tree are grass.", + "edu/rpi/legup/images/treetent/noTreesAround.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + if (puzzleElement instanceof TreeTentLine) { + return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule"; + } + TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); + TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); + TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); + TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(finalCell.getType() == TreeTentType.GRASS + && initCell.getType() == TreeTentType.UNKNOWN)) { + return super.getInvalidUseOfRuleMessage() + ": This cell must be grass"; + } + + if (isForced(finalBoard, finalCell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be empty."; + } + } + + /** + * Returns a boolean value based on whether the specified cell has adjacent cells (true - no + * adjacent, false - has adjacent) + * + * @param board the TreeTent board + * @param cell the specified TreeTent cell + * @return true - no adjacent, false - has adjacent + */ + private boolean isForced(TreeTentBoard board, TreeTentCell cell) { + List adjCells = board.getAdjacent(cell, TreeTentType.TREE); + return adjCells.isEmpty(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); + for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { + TreeTentCell cell = (TreeTentCell) element; + if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { + cell.setData(TreeTentType.GRASS); + treeTentBoard.addModifiedData(cell); + } + } + if (treeTentBoard.getModifiedData().isEmpty()) { + return null; + } else { + return treeTentBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java index 698b3aa5e..8fe9b6873 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FillinRowCaseRule.java @@ -7,17 +7,18 @@ import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.TreeTentClue; - +import edu.rpi.legup.puzzle.treetent.TreeTentType; +import java.awt.*; import java.util.ArrayList; import java.util.List; -import java.awt.*; public class FillinRowCaseRule extends CaseRule { public FillinRowCaseRule() { - super("TREE-CASE-0001", "Fill In row", + super( + "TREE-CASE-0001", + "Fill In row", "A row must have the number of tents of its clue.", "edu/rpi/legup/images/treetent/case_rowcount.png"); } @@ -36,8 +37,14 @@ public CaseBoard getCaseBoard(Board board) { ArrayList clues = treeTentBoard.getRowClues(); clues.addAll(treeTentBoard.getColClues()); for (PuzzleElement element : clues) { - // if ((((TreeTentCell) element).getType() == TreeTentType.CLUE_SOUTH && treeTentBoard.getRowCol(((TreeTentCell)element).getLocation().y, TreeTentType.UNKNOWN, true).size() != 0) || - // (((TreeTentCell) element).getType() == TreeTentType.CLUE_EAST && treeTentBoard.getRowCol(((TreeTentCell)element).getLocation().x, TreeTentType.UNKNOWN, false).size() != 0)) { + // if ((((TreeTentCell) element).getType() == TreeTentType.CLUE_SOUTH && + // treeTentBoard.getRowCol(((TreeTentCell)element).getLocation().y, + // TreeTentType.UNKNOWN, + // true).size() != 0) || + // (((TreeTentCell) element).getType() == TreeTentType.CLUE_EAST && + // treeTentBoard.getRowCol(((TreeTentCell)element).getLocation().x, + // TreeTentType.UNKNOWN, + // false).size() != 0)) { // caseBoard.addPickableElement(element); // } caseBoard.addPickableElement(element); @@ -48,13 +55,17 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { - ArrayList cases = new ArrayList(); + if (puzzleElement == null) { + return new ArrayList(); + } + ArrayList cases; + List group; int tentsLeft; TreeTentClue clue = ((TreeTentClue) puzzleElement); @@ -62,74 +73,144 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { TreeTentBoard tBoard = (TreeTentBoard) board; if (clue.getType() == TreeTentType.CLUE_SOUTH) { group = tBoard.getRowCol(clueIndex, TreeTentType.UNKNOWN, false); - tentsLeft = tBoard.getRowClues().get(clueIndex).getData() - tBoard.getRowCol(clueIndex, TreeTentType.TENT, false).size(); + tentsLeft = + tBoard.getColClues().get(clueIndex).getData() + - tBoard.getRowCol(clueIndex, TreeTentType.TENT, false).size(); cases = genCombinations(tBoard, group, tentsLeft, clueIndex, false); - } - else { + } else { group = tBoard.getRowCol(clueIndex, TreeTentType.UNKNOWN, true); - tentsLeft = tBoard.getRowClues().get(clueIndex).getData() - tBoard.getRowCol(clueIndex, TreeTentType.TENT, true).size(); + tentsLeft = + tBoard.getRowClues().get(clueIndex).getData() + - tBoard.getRowCol(clueIndex, TreeTentType.TENT, true).size(); cases = genCombinations(tBoard, group, tentsLeft, clueIndex, true); } - //generate every combination (nCr) - //call goodBoard for each generated combination - //alternitive would be to implement collision avoidance while generating instead of after + // generate every combination (nCr) + // call goodBoard for each generated combination + // alternative would be to implement collision avoidance while generating instead of after if (cases.size() > 0) { return cases; } return null; } - private ArrayList genCombinations(TreeTentBoard iBoard, List tiles, int target, Integer index, boolean isRow) { - return genCombRecursive(iBoard, tiles, tiles, target, 0, new ArrayList(), index, isRow); + /** + * @param iBoard the board to place tents onto + * @param tiles the locations where tents can be placed + * @param target the target number of tents to place + * @param index the index of tiles which is trying to be placed + * @param isRow Used to check validity of board + * @return the list of boards created + */ + private ArrayList genCombinations( + TreeTentBoard iBoard, + List tiles, + int target, + Integer index, + boolean isRow) { + ArrayList generatedBoards = new ArrayList<>(); + genCombRecursive( + iBoard, + tiles, + target, + 0, + new ArrayList(), + 0, + index, + generatedBoards, + isRow); + return generatedBoards; } - private ArrayList genCombRecursive(TreeTentBoard iBoard, List original, List tiles, int target, int current, List selected, Integer index, boolean isRow) { - ArrayList b = new ArrayList<>(); + /** + * Recursive function to generate all ways of placing the target number of tents from the list + * of tiles to fill. + * + * @param iBoard The board + * @param tiles Unknown Tiles to fill + * @param target number of tents to place + * @param current number of tents already placed + * @param currentTile index of the next tile to add + * @param selected the cells which have tents + * @param index The index of the clue + * @param isRow Used for checking if the board is good + *

The generated boards are placed into generatedBoards (passed by reference) + */ + private void genCombRecursive( + TreeTentBoard iBoard, + List tiles, + int target, + int current, + List selected, + int currentTile, + Integer index, + ArrayList generatedBoards, + boolean isRow) { + // Base Case: Enough tents have been placed if (target == current) { - TreeTentBoard temp = iBoard.copy(); - for (TreeTentCell c : original) { - if (selected.contains(c)) { - PuzzleElement change = temp.getPuzzleElement(c); - change.setData(TreeTentType.TENT); - temp.addModifiedData(change); + TreeTentBoard boardCopy = iBoard.copy(); + // Selected Tiles should already be filled + // Fill in other tiles with Grass + for (TreeTentCell tile : tiles) { + if (!selected.contains(tile)) { + PuzzleElement element = boardCopy.getPuzzleElement(tile); + element.setData(TreeTentType.GRASS); + boardCopy.addModifiedData(element); } - else { - PuzzleElement change = temp.getPuzzleElement(c); - change.setData(TreeTentType.GRASS); - temp.addModifiedData(change); - } - } - if (goodBoard(temp, index, isRow)) { - b.add(temp); - } - return b; + // board validity is checked after placing every tent + // because the base case doesn't place any tents, the board + // should still be valid + generatedBoards.add(boardCopy); + return; } - for (int i = 0; i < tiles.size(); ++i) { - List sub = tiles.subList(i + 1, tiles.size()); - List next = new ArrayList(selected); - next.add(tiles.get(i)); - b.addAll(genCombRecursive(iBoard, original, sub, target, current + 1, next, index, isRow)); + + // Recursive Case: + // Looking at the group of possible tiles, save one of the tiles into selected, + // Place it on the board, + // Check if the board is good and recurse + // + // Backtracking: + // Remove the placed tent from the board and selected + for (int i = currentTile; i < tiles.size(); ++i) { + TreeTentCell tile = tiles.get(i); + selected.add(tile); + PuzzleElement element = iBoard.getPuzzleElement(tile); + element.setData(TreeTentType.TENT); + iBoard.addModifiedData(element); + if (goodBoard(iBoard, index, isRow)) { + genCombRecursive( + iBoard, + tiles, + target, + current + 1, + selected, + i + 1, + index, + generatedBoards, + isRow); + } + element.setData(TreeTentType.UNKNOWN); + iBoard.addModifiedData(element); + selected.remove(tile); } - return b; } - //Effectively runs TouchingTents check on all the added tents to make sure that the proposed board is valid. - //Could check more or less in the future depending on how "smart" this case rule should be. + // Effectively runs TouchingTents check on all the added tents to make sure that the proposed + // board is valid. + // Could check more or less in the future depending on how "smart" this case rule should be. private boolean goodBoard(TreeTentBoard board, Integer index, boolean isRow) { List tents; if (isRow) { tents = board.getRowCol(index, TreeTentType.TENT, true); - } - else { + } else { tents = board.getRowCol(index, TreeTentType.TENT, false); } for (TreeTentCell t : tents) { List adj = board.getAdjacent(t, TreeTentType.TENT); List diag = board.getDiagonals(t, TreeTentType.TENT); - if (adj.size() > 0 || diag.size() > 0) { + if (!adj.isEmpty() || !diag.isEmpty()) { return false; } } @@ -148,13 +229,13 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -162,13 +243,13 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid - * Overridden by case rules dependent on more than just the modified data + * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be + * valid Overridden by case rules dependent on more than just the modified data * - * @param board board state at application + * @param board board state at application * @param puzzleElement selected puzzleElement - * @return List of puzzle elements (typically cells) this application of the case rule depends upon. - * Defaults to any element modified by any case + * @return List of puzzle elements (typically cells) this application of the case rule depends + * upon. Defaults to any element modified by any case */ @Override public List dependentElements(Board board, PuzzleElement puzzleElement) { @@ -179,7 +260,7 @@ public List dependentElements(Board board, PuzzleElement puzzleEl // add all elements of filled row for (int i = 0; i < treeTentBoard.getWidth(); i++) { - TreeTentCell cell = treeTentBoard.getCell(i, clue.getClueIndex()-1); + TreeTentCell cell = treeTentBoard.getCell(i, clue.getClueIndex() - 1); elements.add(board.getPuzzleElement((cell))); } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FinishWithGrassDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FinishWithGrassDirectRule.java index 40ee11e99..838a3ca24 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FinishWithGrassDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FinishWithGrassDirectRule.java @@ -1,86 +1,87 @@ -package edu.rpi.legup.puzzle.treetent.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentLine; -import edu.rpi.legup.puzzle.treetent.TreeTentType; - -import java.awt.*; -import java.util.List; - -public class FinishWithGrassDirectRule extends DirectRule { - - public FinishWithGrassDirectRule() { - super("TREE-BASC-0002", "Finish with Grass", - "Grass can be added to finish a row or column that has reached its tent limit.", - "edu/rpi/legup/images/treetent/finishGrass.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - if (puzzleElement instanceof TreeTentLine) { - return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule"; - } - TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); - TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); - TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); - TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(finalCell.getType() == TreeTentType.GRASS && initCell.getType() == TreeTentType.UNKNOWN)) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be grass."; - } - - if (isForced(initialBoard, initCell)) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be grass."; - } - } - - private boolean isForced(TreeTentBoard board, TreeTentCell cell) { - Point loc = cell.getLocation(); - List tentsRow = board.getRowCol(loc.y, TreeTentType.TENT, true); - List tentsCol = board.getRowCol(loc.x, TreeTentType.TENT, false); - - return tentsRow.size() >= board.getRowClues().get(loc.y).getData() || - tentsCol.size() >= board.getColClues().get(loc.x).getData(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); - for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { - TreeTentCell cell = (TreeTentCell) element; - if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { - cell.setData(TreeTentType.GRASS); - treeTentBoard.addModifiedData(cell); - } - } - if (treeTentBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return treeTentBoard; - } - } -} +package edu.rpi.legup.puzzle.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.TreeTentType; +import java.awt.*; +import java.util.List; + +public class FinishWithGrassDirectRule extends DirectRule { + + public FinishWithGrassDirectRule() { + super( + "TREE-BASC-0002", + "Finish with Grass", + "Grass can be added to finish a row or column that has reached its tent limit.", + "edu/rpi/legup/images/treetent/finishGrass.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + if (puzzleElement instanceof TreeTentLine) { + return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule"; + } + TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); + TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); + TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); + TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(finalCell.getType() == TreeTentType.GRASS + && initCell.getType() == TreeTentType.UNKNOWN)) { + return super.getInvalidUseOfRuleMessage() + ": This cell must be grass."; + } + + if (isForced(initialBoard, initCell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be grass."; + } + } + + private boolean isForced(TreeTentBoard board, TreeTentCell cell) { + Point loc = cell.getLocation(); + List tentsRow = board.getRowCol(loc.y, TreeTentType.TENT, true); + List tentsCol = board.getRowCol(loc.x, TreeTentType.TENT, false); + + return tentsRow.size() >= board.getRowClues().get(loc.y).getData() + || tentsCol.size() >= board.getColClues().get(loc.x).getData(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); + for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { + TreeTentCell cell = (TreeTentCell) element; + if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { + cell.setData(TreeTentType.GRASS); + treeTentBoard.addModifiedData(cell); + } + } + if (treeTentBoard.getModifiedData().isEmpty()) { + return null; + } else { + return treeTentBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FinishWithTentsDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FinishWithTentsDirectRule.java index 145a9760a..ae1a72e9d 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FinishWithTentsDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/FinishWithTentsDirectRule.java @@ -1,88 +1,90 @@ -package edu.rpi.legup.puzzle.treetent.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentLine; -import edu.rpi.legup.puzzle.treetent.TreeTentType; - -import java.awt.*; -import java.util.List; - -public class FinishWithTentsDirectRule extends DirectRule { - - public FinishWithTentsDirectRule() { - super("TREE-BASC-0003", "Finish with Tents", - "Tents can be added to finish a row or column that has one open spot per required tent.", - "edu/rpi/legup/images/treetent/finishTent.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - if (puzzleElement instanceof TreeTentLine) { - return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule."; - } - TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); - TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); - TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); - TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(initCell.getType() == TreeTentType.UNKNOWN && finalCell.getType() == TreeTentType.TENT)) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be a tent."; - } - - if (isForced(initialBoard, initCell)) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be tent."; - } - } - - private boolean isForced(TreeTentBoard board, TreeTentCell cell) { - Point loc = cell.getLocation(); - List tentsRow = board.getRowCol(loc.y, TreeTentType.TENT, true); - List unknownsRow = board.getRowCol(loc.y, TreeTentType.UNKNOWN, true); - List tentsCol = board.getRowCol(loc.x, TreeTentType.TENT, false); - List unknownsCol = board.getRowCol(loc.x, TreeTentType.UNKNOWN, false); - - return unknownsRow.size() <= board.getRowClues().get(loc.y).getData() - tentsRow.size() || - unknownsCol.size() <= board.getColClues().get(loc.x).getData() - tentsCol.size(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); - for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { - TreeTentCell cell = (TreeTentCell) element; - if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { - cell.setData(TreeTentType.TENT); - treeTentBoard.addModifiedData(cell); - } - } - if (treeTentBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return treeTentBoard; - } - } -} +package edu.rpi.legup.puzzle.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.TreeTentType; +import java.awt.*; +import java.util.List; + +public class FinishWithTentsDirectRule extends DirectRule { + + public FinishWithTentsDirectRule() { + super( + "TREE-BASC-0003", + "Finish with Tents", + "Tents can be added to finish a row or column that has one open spot per required" + + " tent.", + "edu/rpi/legup/images/treetent/finishTent.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + if (puzzleElement instanceof TreeTentLine) { + return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule."; + } + TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); + TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); + TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); + TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(initCell.getType() == TreeTentType.UNKNOWN + && finalCell.getType() == TreeTentType.TENT)) { + return super.getInvalidUseOfRuleMessage() + ": This cell must be a tent."; + } + + if (isForced(initialBoard, initCell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be tent."; + } + } + + private boolean isForced(TreeTentBoard board, TreeTentCell cell) { + Point loc = cell.getLocation(); + List tentsRow = board.getRowCol(loc.y, TreeTentType.TENT, true); + List unknownsRow = board.getRowCol(loc.y, TreeTentType.UNKNOWN, true); + List tentsCol = board.getRowCol(loc.x, TreeTentType.TENT, false); + List unknownsCol = board.getRowCol(loc.x, TreeTentType.UNKNOWN, false); + + return unknownsRow.size() <= board.getRowClues().get(loc.y).getData() - tentsRow.size() + || unknownsCol.size() <= board.getColClues().get(loc.x).getData() - tentsCol.size(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); + for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { + TreeTentCell cell = (TreeTentCell) element; + if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { + cell.setData(TreeTentType.TENT); + treeTentBoard.addModifiedData(cell); + } + } + if (treeTentBoard.getModifiedData().isEmpty()) { + return null; + } else { + return treeTentBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LastCampingSpotDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LastCampingSpotDirectRule.java index ffb33e4c0..53f7b9831 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LastCampingSpotDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LastCampingSpotDirectRule.java @@ -1,102 +1,104 @@ -package edu.rpi.legup.puzzle.treetent.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentLine; -import edu.rpi.legup.puzzle.treetent.TreeTentType; - -import java.util.List; - -public class LastCampingSpotDirectRule extends DirectRule { - - public LastCampingSpotDirectRule() { - super("TREE-BASC-0004", "Last Camping Spot", - "If an unlinked tree is adjacent to only one blank cell and not adjacent to any unlinked tents, the blank cell must be a tent.", - "edu/rpi/legup/images/treetent/oneTentPosition.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - if (puzzleElement instanceof TreeTentLine) { - return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule."; - } - TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); - TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); - TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); - TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(initCell.getType() == TreeTentType.UNKNOWN && finalCell.getType() == TreeTentType.TENT)) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be a tent."; - } - - if (isForced(finalBoard, finalCell)) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be tent."; - } - } - - private boolean isForced(TreeTentBoard board, TreeTentCell cell) { - List adjTrees = board.getAdjacent(cell, TreeTentType.TREE); - for (TreeTentCell c : adjTrees) { - List unkAroundTree = board.getAdjacent(c, TreeTentType.UNKNOWN); - List tntAroundTree = board.getAdjacent(c, TreeTentType.TENT); - if (unkAroundTree.size() == 0) { - if (tntAroundTree.size() == 1) { - return true; - } - else { - for (TreeTentCell t : tntAroundTree) { - if (t == cell) { - continue; - } - List treesAroundTents = board.getAdjacent(t, TreeTentType.TREE); - if (treesAroundTents.size() == 1) { - return false; - } - } - return true; - } - } - } - return false; - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); - for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { - TreeTentCell cell = (TreeTentCell) element; - if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { - cell.setData(TreeTentType.TENT); - treeTentBoard.addModifiedData(cell); - } - } - if (treeTentBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return treeTentBoard; - } - } -} +package edu.rpi.legup.puzzle.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.TreeTentType; +import java.util.List; + +public class LastCampingSpotDirectRule extends DirectRule { + + public LastCampingSpotDirectRule() { + super( + "TREE-BASC-0004", + "Last Camping Spot", + "If an unlinked tree is adjacent to only one blank cell and not adjacent to any" + + " unlinked tents, the blank cell must be a tent.", + "edu/rpi/legup/images/treetent/oneTentPosition.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + if (puzzleElement instanceof TreeTentLine) { + return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule."; + } + TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); + TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); + TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); + TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(initCell.getType() == TreeTentType.UNKNOWN + && finalCell.getType() == TreeTentType.TENT)) { + return super.getInvalidUseOfRuleMessage() + ": This cell must be a tent."; + } + + if (isForced(finalBoard, finalCell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be tent."; + } + } + + private boolean isForced(TreeTentBoard board, TreeTentCell cell) { + List adjTrees = board.getAdjacent(cell, TreeTentType.TREE); + for (TreeTentCell c : adjTrees) { + List unkAroundTree = board.getAdjacent(c, TreeTentType.UNKNOWN); + List tntAroundTree = board.getAdjacent(c, TreeTentType.TENT); + if (unkAroundTree.size() == 0) { + if (tntAroundTree.size() == 1) { + return true; + } else { + for (TreeTentCell t : tntAroundTree) { + if (t == cell) { + continue; + } + List treesAroundTents = + board.getAdjacent(t, TreeTentType.TREE); + if (treesAroundTents.size() == 1) { + return false; + } + } + return true; + } + } + } + return false; + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); + for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { + TreeTentCell cell = (TreeTentCell) element; + if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { + cell.setData(TreeTentType.TENT); + treeTentBoard.addModifiedData(cell); + } + } + if (treeTentBoard.getModifiedData().isEmpty()) { + return null; + } else { + return treeTentBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java index 39b1d0251..cbe91c3a7 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTentCaseRule.java @@ -6,10 +6,9 @@ import edu.rpi.legup.model.rules.CaseRule; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.TreeTentCell; import edu.rpi.legup.puzzle.treetent.TreeTentLine; - +import edu.rpi.legup.puzzle.treetent.TreeTentType; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -17,7 +16,9 @@ public class LinkTentCaseRule extends CaseRule { public LinkTentCaseRule() { - super("TREE-CASE-0002", "Links from tent", + super( + "TREE-CASE-0002", + "Links from tent", "A tent must link to exactly one adjacent tree.", "edu/rpi/legup/images/treetent/caseLinkTent.png"); } @@ -28,11 +29,15 @@ public CaseBoard getCaseBoard(Board board) { treeTentBoard.setModifiable(false); CaseBoard caseBoard = new CaseBoard(treeTentBoard, this); for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { - if (((TreeTentCell) element).getType() == TreeTentType.TENT && !getCases(board, element).isEmpty()) { + if (((TreeTentCell) element).getType() == TreeTentType.TENT + && !getCases(board, element).isEmpty()) { Boolean canAdd = true; List lines = treeTentBoard.getLines(); for (TreeTentLine l : lines) { - if (l.getC1().getLocation().equals(((TreeTentCell) element).getLocation()) || l.getC2().getLocation().equals(((TreeTentCell) element).getLocation())) { + if (l.getC1().getLocation().equals(((TreeTentCell) element).getLocation()) + || l.getC2() + .getLocation() + .equals(((TreeTentCell) element).getLocation())) { canAdd = false; break; } @@ -48,13 +53,17 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList(); + if (puzzleElement == null) { + return cases; + } + TreeTentCell cell = (TreeTentCell) puzzleElement; List adj = ((TreeTentBoard) board).getAdjacent(cell, TreeTentType.TREE); List lines = ((TreeTentBoard) board).getLines(); @@ -62,13 +71,17 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { for (TreeTentCell tree : adj) { Boolean makeline = true; for (TreeTentLine l : ((TreeTentBoard) board).getLines()) { - if (l.getC1().getLocation().equals(tree.getLocation()) || l.getC2().getLocation().equals(tree.getLocation())) { + if (l.getC1().getLocation().equals(tree.getLocation()) + || l.getC2().getLocation().equals(tree.getLocation())) { makeline = false; } } if (makeline) { TreeTentBoard temp = ((TreeTentBoard) board).copy(); - TreeTentLine l = new TreeTentLine((TreeTentCell) temp.getPuzzleElement(cell), (TreeTentCell) temp.getPuzzleElement(tree)); + TreeTentLine l = + new TreeTentLine( + (TreeTentCell) temp.getPuzzleElement(cell), + (TreeTentCell) temp.getPuzzleElement(tree)); temp.getLines().add(l); temp.addModifiedData(l); cases.add(temp); @@ -87,12 +100,14 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { public String checkRuleRaw(TreeTransition transition) { Set modCells = transition.getBoard().getModifiedData(); if (modCells.size() != 1) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case"; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case"; } PuzzleElement mod = modCells.iterator().next(); TreeTentLine line = mod instanceof TreeTentLine ? (TreeTentLine) mod : null; if (line == null) { - return super.getInvalidUseOfRuleMessage() + ": This case rule only involves tree and tent connection lines"; + return super.getInvalidUseOfRuleMessage() + + ": This case rule only involves tree and tent connection lines"; } TreeTentCell tent = null; if (line.getC1().getType() == TreeTentType.TENT) { @@ -122,7 +137,8 @@ public String checkRuleRaw(TreeTransition transition) { } PuzzleElement tElement = tBoard.getModifiedData().iterator().next(); if (!(tElement instanceof TreeTentLine)) { - return super.getInvalidUseOfRuleMessage() + ": This case rule only involves tree and tent connection lines"; + return super.getInvalidUseOfRuleMessage() + + ": This case rule only involves tree and tent connection lines"; } if (cLine.compare((TreeTentLine) tElement)) { hasLine = true; @@ -138,13 +154,13 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -152,13 +168,13 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid - * Overridden by case rules dependent on more than just the modified data + * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be + * valid Overridden by case rules dependent on more than just the modified data * - * @param board board state at application + * @param board board state at application * @param puzzleElement selected puzzleElement - * @return List of puzzle elements (typically cells) this application of the case rule depends upon. - * Defaults to any element modified by any case + * @return List of puzzle elements (typically cells) this application of the case rule depends + * upon. Defaults to any element modified by any case */ @Override public List dependentElements(Board board, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java index 72ffd62eb..153692ad0 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/LinkTreeCaseRule.java @@ -9,7 +9,6 @@ import edu.rpi.legup.puzzle.treetent.TreeTentCell; import edu.rpi.legup.puzzle.treetent.TreeTentLine; import edu.rpi.legup.puzzle.treetent.TreeTentType; - import java.awt.Point; import java.util.ArrayList; import java.util.List; @@ -18,7 +17,9 @@ public class LinkTreeCaseRule extends CaseRule { public LinkTreeCaseRule() { - super("TREE-CASE-0003", "Links from tree", + super( + "TREE-CASE-0003", + "Links from tree", "A tree must link to exactly one adjacent tent.", "edu/rpi/legup/images/treetent/caseLinkTree.png"); } @@ -29,13 +30,16 @@ public CaseBoard getCaseBoard(Board board) { treeTentBoard.setModifiable(false); CaseBoard caseBoard = new CaseBoard(treeTentBoard, this); for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { - if (((TreeTentCell) element).getType() == TreeTentType.TREE && - !getCases(treeTentBoard, element).isEmpty()) { + if (((TreeTentCell) element).getType() == TreeTentType.TREE + && !getCases(treeTentBoard, element).isEmpty()) { Boolean canAdd = true; List lines = treeTentBoard.getLines(); for (TreeTentLine l : lines) { - if (l.getC1().getLocation().equals(((TreeTentCell) element).getLocation()) || l.getC2().getLocation().equals(((TreeTentCell) element).getLocation())) { + if (l.getC1().getLocation().equals(((TreeTentCell) element).getLocation()) + || l.getC2() + .getLocation() + .equals(((TreeTentCell) element).getLocation())) { canAdd = false; break; } @@ -43,7 +47,6 @@ public CaseBoard getCaseBoard(Board board) { if (canAdd) { caseBoard.addPickableElement(element); } - } } return caseBoard; @@ -52,20 +55,25 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ @Override public ArrayList getCases(Board board, PuzzleElement puzzleElement) { ArrayList cases = new ArrayList<>(); + if (puzzleElement == null) { + return cases; + } + TreeTentBoard treeTentBoard = (TreeTentBoard) board; TreeTentCell cell = (TreeTentCell) puzzleElement; List adjCells = treeTentBoard.getAdjacent(cell, TreeTentType.TENT); for (TreeTentCell c : adjCells) { Boolean makeline = true; for (TreeTentLine l : treeTentBoard.getLines()) { - if (l.getC1().getLocation().equals(c.getLocation()) || l.getC2().getLocation().equals(c.getLocation())) { + if (l.getC1().getLocation().equals(c.getLocation()) + || l.getC2().getLocation().equals(c.getLocation())) { makeline = false; } } @@ -90,12 +98,14 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) { public String checkRuleRaw(TreeTransition transition) { Set modCells = transition.getBoard().getModifiedData(); if (modCells.size() != 1) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case"; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case"; } PuzzleElement mod = modCells.iterator().next(); TreeTentLine line = mod instanceof TreeTentLine ? (TreeTentLine) mod : null; if (line == null) { - return super.getInvalidUseOfRuleMessage() + ": This case rule only involves tree and tent connection lines"; + return super.getInvalidUseOfRuleMessage() + + ": This case rule only involves tree and tent connection lines"; } TreeTentCell tree = null; if (line.getC1().getType() == TreeTentType.TREE) { @@ -125,7 +135,8 @@ public String checkRuleRaw(TreeTransition transition) { } PuzzleElement tElement = tBoard.getModifiedData().iterator().next(); if (!(tElement instanceof TreeTentLine)) { - return super.getInvalidUseOfRuleMessage() + ": This case rule only involves tree and tent connection lines"; + return super.getInvalidUseOfRuleMessage() + + ": This case rule only involves tree and tent connection lines"; } if (cLine.compare((TreeTentLine) tElement)) { hasLine = true; @@ -141,13 +152,13 @@ public String checkRuleRaw(TreeTransition transition) { } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { @@ -155,17 +166,18 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem } /** - * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be valid - * Overridden by case rules dependent on more than just the modified data + * Returns the elements necessary for the cases returned by getCases(board,puzzleElement) to be + * valid Overridden by case rules dependent on more than just the modified data * - * @param board board state at application + * @param board board state at application * @param puzzleElement selected puzzleElement - * @return List of puzzle elements (typically cells) this application of the case rule depends upon. - * Defaults to any element modified by any case + * @return List of puzzle elements (typically cells) this application of the case rule depends + * upon. Defaults to any element modified by any case */ @Override public List dependentElements(Board board, PuzzleElement puzzleElement) { - List elements = new ArrayList<>(List.of(board.getPuzzleElement(puzzleElement))); + List elements = + new ArrayList<>(List.of(board.getPuzzleElement(puzzleElement))); TreeTentBoard treeTentBoard = (TreeTentBoard) board; TreeTentCell point = (TreeTentCell) puzzleElement; diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/NoTentForTreeContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/NoTentForTreeContradictionRule.java index 2e5c2f043..912fa6d20 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/NoTentForTreeContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/NoTentForTreeContradictionRule.java @@ -5,27 +5,29 @@ import edu.rpi.legup.model.rules.ContradictionRule; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.TreeTentLine; - -import java.util.List; +import edu.rpi.legup.puzzle.treetent.TreeTentType; import java.util.Iterator; +import java.util.List; public class NoTentForTreeContradictionRule extends ContradictionRule { public NoTentForTreeContradictionRule() { - super("TREE-CONT-0001", "No Tent For Tree", + super( + "TREE-CONT-0001", + "No Tent For Tree", "Each tree must link to a tent.", "edu/rpi/legup/images/treetent/contra_NoTentForTree.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -38,8 +40,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int adjUnknown = treeTentBoard.getAdjacent(cell, TreeTentType.UNKNOWN).size(); if (adjTent == 0 && adjUnknown == 0) { return null; - } - else { + } else { if (adjTent != 0) { List lines = treeTentBoard.getLines(); List adjTents = treeTentBoard.getAdjacent(cell, TreeTentType.TENT); @@ -47,10 +48,12 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Iterator i = adjTents.iterator(); while (i.hasNext()) { TreeTentCell t = i.next(); - if (t.getLocation().equals(l.getC1().getLocation()) && !(cell.getLocation().equals(l.getC2().getLocation()))) { + if (t.getLocation().equals(l.getC1().getLocation()) + && !(cell.getLocation().equals(l.getC2().getLocation()))) { i.remove(); } - if (t.getLocation().equals(l.getC2().getLocation()) && !(cell.getLocation().equals(l.getC2().getLocation()))) { + if (t.getLocation().equals(l.getC2().getLocation()) + && !(cell.getLocation().equals(l.getC2().getLocation()))) { i.remove(); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/NoTreeForTentContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/NoTreeForTentContradictionRule.java index 67f023dd7..9bc3fddea 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/NoTreeForTentContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/NoTreeForTentContradictionRule.java @@ -7,25 +7,27 @@ import edu.rpi.legup.puzzle.treetent.TreeTentCell; import edu.rpi.legup.puzzle.treetent.TreeTentLine; import edu.rpi.legup.puzzle.treetent.TreeTentType; - -import java.util.List; import java.util.Iterator; +import java.util.List; public class NoTreeForTentContradictionRule extends ContradictionRule { public NoTreeForTentContradictionRule() { - super("TREE-CONT-0002", "No Tree For Tent", + super( + "TREE-CONT-0002", + "No Tree For Tent", "Each tent must link to a tree.", "edu/rpi/legup/images/treetent/contra_NoTreeForTent.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -40,10 +42,12 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { Iterator i = adjTrees.iterator(); while (i.hasNext()) { TreeTentCell t = i.next(); - if (t.getLocation().equals(l.getC1().getLocation()) && !(cell.getLocation().equals(l.getC2().getLocation()))) { + if (t.getLocation().equals(l.getC1().getLocation()) + && !(cell.getLocation().equals(l.getC2().getLocation()))) { i.remove(); } - if (t.getLocation().equals(l.getC2().getLocation()) && !(cell.getLocation().equals(l.getC2().getLocation()))) { + if (t.getLocation().equals(l.getC2().getLocation()) + && !(cell.getLocation().equals(l.getC2().getLocation()))) { i.remove(); } } @@ -51,8 +55,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int adjTree = adjTrees.size(); if (adjTree == 0) { return null; - } - else { + } else { return super.getNoContradictionMessage(); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/SurroundTentWithGrassDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/SurroundTentWithGrassDirectRule.java index 44e9dfcc4..e800dc416 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/SurroundTentWithGrassDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/SurroundTentWithGrassDirectRule.java @@ -1,85 +1,86 @@ -package edu.rpi.legup.puzzle.treetent.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentLine; -import edu.rpi.legup.puzzle.treetent.TreeTentType; - -import java.util.List; - -public class SurroundTentWithGrassDirectRule extends DirectRule { - - public SurroundTentWithGrassDirectRule() { - super("TREE-BASC-0005", "Surround Tent with Grass", - "Blank cells adjacent or diagonal to a tent are grass.", - "edu/rpi/legup/images/treetent/aroundTent.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - if (puzzleElement == null) { - return null; - } - if (puzzleElement instanceof TreeTentLine) { - return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule."; - } - TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); - TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); - TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); - TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); - if (!(initCell.getType() == TreeTentType.UNKNOWN && finalCell.getType() == TreeTentType.GRASS)) { - return super.getInvalidUseOfRuleMessage() + ": This cell must be a tent."; - } - - if (isForced(initialBoard, initCell)) { - return null; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be tent."; - } - } - - private boolean isForced(TreeTentBoard board, TreeTentCell cell) { - List tents = board.getAdjacent(cell, TreeTentType.TENT); - tents.addAll(board.getDiagonals(cell, TreeTentType.TENT)); - return !tents.isEmpty(); - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); - for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { - TreeTentCell cell = (TreeTentCell) element; - if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { - cell.setData(TreeTentType.GRASS); - treeTentBoard.addModifiedData(cell); - } - } - if (treeTentBoard.getModifiedData().isEmpty()) { - return null; - } - else { - return treeTentBoard; - } - } -} +package edu.rpi.legup.puzzle.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.TreeTentType; +import java.util.List; + +public class SurroundTentWithGrassDirectRule extends DirectRule { + + public SurroundTentWithGrassDirectRule() { + super( + "TREE-BASC-0005", + "Surround Tent with Grass", + "Blank cells adjacent or diagonal to a tent are grass.", + "edu/rpi/legup/images/treetent/aroundTent.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + if (puzzleElement == null) { + return null; + } + if (puzzleElement instanceof TreeTentLine) { + return super.getInvalidUseOfRuleMessage() + ": Line is not valid for this rule."; + } + TreeTentBoard initialBoard = (TreeTentBoard) transition.getParents().get(0).getBoard(); + TreeTentCell initCell = (TreeTentCell) initialBoard.getPuzzleElement(puzzleElement); + TreeTentBoard finalBoard = (TreeTentBoard) transition.getBoard(); + TreeTentCell finalCell = (TreeTentCell) finalBoard.getPuzzleElement(puzzleElement); + if (!(initCell.getType() == TreeTentType.UNKNOWN + && finalCell.getType() == TreeTentType.GRASS)) { + return super.getInvalidUseOfRuleMessage() + ": This cell must be a tent."; + } + + if (isForced(initialBoard, initCell)) { + return null; + } else { + return super.getInvalidUseOfRuleMessage() + ": This cell is not forced to be tent."; + } + } + + private boolean isForced(TreeTentBoard board, TreeTentCell cell) { + List tents = board.getAdjacent(cell, TreeTentType.TENT); + tents.addAll(board.getDiagonals(cell, TreeTentType.TENT)); + return !tents.isEmpty(); + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + TreeTentBoard treeTentBoard = (TreeTentBoard) node.getBoard().copy(); + for (PuzzleElement element : treeTentBoard.getPuzzleElements()) { + TreeTentCell cell = (TreeTentCell) element; + if (cell.getType() == TreeTentType.UNKNOWN && isForced(treeTentBoard, cell)) { + cell.setData(TreeTentType.GRASS); + treeTentBoard.addModifiedData(cell); + } + } + if (treeTentBoard.getModifiedData().isEmpty()) { + return null; + } else { + return treeTentBoard; + } + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TentForTreeDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TentForTreeDirectRule.java index 03a83e516..8044faa0e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TentForTreeDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TentForTreeDirectRule.java @@ -1,124 +1,125 @@ -package edu.rpi.legup.puzzle.treetent.rules; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentLine; -import edu.rpi.legup.puzzle.treetent.TreeTentType; - -import java.util.ArrayList; - -import java.util.List; - -public class TentForTreeDirectRule extends DirectRule { - - public TentForTreeDirectRule() { - super("TREE-BASC-0006", "Tent for Tree", - "If only one unlinked tent and no blank cells are adjacent to an unlinked tree, the unlinked tree must link to the unlinked tent.", - "edu/rpi/legup/images/treetent/NewTreeLink.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - if (!(puzzleElement instanceof TreeTentLine)) { - return super.getInvalidUseOfRuleMessage() + ": Lines must be created for this rule."; - } - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentLine line = (TreeTentLine) board.getPuzzleElement(puzzleElement); - TreeTentCell tree, tent; - if (line.getC1().getType() == TreeTentType.TREE && line.getC2().getType() == TreeTentType.TENT) { - tree = line.getC1(); - tent = line.getC2(); - } - else { - if (line.getC2().getType() == TreeTentType.TREE && line.getC1().getType() == TreeTentType.TENT) { - tree = line.getC2(); - tent = line.getC1(); - } - else { - return super.getInvalidUseOfRuleMessage() + ": This line must connect a tree to a tent."; - } - } - int forced = isForced(board, tree, tent, line); - if (forced == 1) { - return null; - } - else { - if (forced == -1) { - return super.getInvalidUseOfRuleMessage() + ": This tree already has a link"; - } - else { - if (forced == -2) { - return super.getInvalidUseOfRuleMessage() + ": This tent already has a link"; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This tree and tent don't need to be linked."; - } - } - } - } - - private Integer isForced(TreeTentBoard board, TreeTentCell tree, TreeTentCell tent, TreeTentLine line) { - List adjTents = board.getAdjacent(tree, TreeTentType.TENT); - adjTents.remove(tent); - List lines = board.getLines(); - lines.remove(line); - for (TreeTentLine l : lines) { - ArrayList toRemove = new ArrayList<>(); - if (l.getC1().getLocation().equals(tree.getLocation()) || l.getC2().getLocation().equals(tree.getLocation())) { - return -2; - } - for (TreeTentCell c : adjTents) { - if (l.getC1().getLocation().equals(c.getLocation())) { - if (l.getC2().getLocation().equals(tree.getLocation())) { - return -1; - } - toRemove.add(c); - - } - else { - if (l.getC2().getLocation().equals(c.getLocation())) { - if (l.getC1().getLocation().equals(tree.getLocation())) { - return -1; - } - toRemove.add(c); - } - } - } - for (TreeTentCell c : toRemove) { - adjTents.remove(c); - } - toRemove.clear(); - } - if (adjTents.size() == 0) { - return 1; - } - else { - return 0; - } - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.TreeTentType; +import java.util.ArrayList; +import java.util.List; + +public class TentForTreeDirectRule extends DirectRule { + + public TentForTreeDirectRule() { + super( + "TREE-BASC-0006", + "Tent for Tree", + "If only one unlinked tent and no blank cells are adjacent to an unlinked tree, the" + + " unlinked tree must link to the unlinked tent.", + "edu/rpi/legup/images/treetent/NewTreeLink.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + if (!(puzzleElement instanceof TreeTentLine)) { + return super.getInvalidUseOfRuleMessage() + ": Lines must be created for this rule."; + } + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentLine line = (TreeTentLine) board.getPuzzleElement(puzzleElement); + TreeTentCell tree, tent; + if (line.getC1().getType() == TreeTentType.TREE + && line.getC2().getType() == TreeTentType.TENT) { + tree = line.getC1(); + tent = line.getC2(); + } else { + if (line.getC2().getType() == TreeTentType.TREE + && line.getC1().getType() == TreeTentType.TENT) { + tree = line.getC2(); + tent = line.getC1(); + } else { + return super.getInvalidUseOfRuleMessage() + + ": This line must connect a tree to a tent."; + } + } + int forced = isForced(board, tree, tent, line); + if (forced == 1) { + return null; + } else { + if (forced == -1) { + return super.getInvalidUseOfRuleMessage() + ": This tree already has a link"; + } else { + if (forced == -2) { + return super.getInvalidUseOfRuleMessage() + ": This tent already has a link"; + } else { + return super.getInvalidUseOfRuleMessage() + + ": This tree and tent don't need to be linked."; + } + } + } + } + + private Integer isForced( + TreeTentBoard board, TreeTentCell tree, TreeTentCell tent, TreeTentLine line) { + List adjTents = board.getAdjacent(tree, TreeTentType.TENT); + adjTents.remove(tent); + List lines = board.getLines(); + lines.remove(line); + for (TreeTentLine l : lines) { + ArrayList toRemove = new ArrayList<>(); + if (l.getC1().getLocation().equals(tree.getLocation()) + || l.getC2().getLocation().equals(tree.getLocation())) { + return -2; + } + for (TreeTentCell c : adjTents) { + if (l.getC1().getLocation().equals(c.getLocation())) { + if (l.getC2().getLocation().equals(tree.getLocation())) { + return -1; + } + toRemove.add(c); + + } else { + if (l.getC2().getLocation().equals(c.getLocation())) { + if (l.getC1().getLocation().equals(tree.getLocation())) { + return -1; + } + toRemove.add(c); + } + } + } + for (TreeTentCell c : toRemove) { + adjTents.remove(c); + } + toRemove.clear(); + } + if (adjTents.size() == 0) { + return 1; + } else { + return 0; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TentOrGrassCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TentOrGrassCaseRule.java index b0e9db109..63478f83e 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TentOrGrassCaseRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TentOrGrassCaseRule.java @@ -8,14 +8,15 @@ import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.TreeTentCell; import edu.rpi.legup.puzzle.treetent.TreeTentType; - import java.util.ArrayList; import java.util.List; public class TentOrGrassCaseRule extends CaseRule { public TentOrGrassCaseRule() { - super("TREE-CASE-0004", "Tent or Grass", + super( + "TREE-CASE-0004", + "Tent or Grass", "Each blank cell is either a tent or grass.", "edu/rpi/legup/images/treetent/caseTentOrGrass.png"); } @@ -36,7 +37,7 @@ public CaseBoard getCaseBoard(Board board) { /** * Gets the possible cases at a specific location based on this case rule * - * @param board the current board state + * @param board the current board state * @param puzzleElement equivalent puzzleElement * @return a list of elements the specified could be */ @@ -74,33 +75,36 @@ public String checkRuleRaw(TreeTransition transition) { TreeTransition case1 = childTransitions.get(0); TreeTransition case2 = childTransitions.get(1); - if (case1.getBoard().getModifiedData().size() != 1 || - case2.getBoard().getModifiedData().size() != 1) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must have 1 modified cell for each case."; + if (case1.getBoard().getModifiedData().size() != 1 + || case2.getBoard().getModifiedData().size() != 1) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have 1 modified cell for each case."; } TreeTentCell mod1 = (TreeTentCell) case1.getBoard().getModifiedData().iterator().next(); TreeTentCell mod2 = (TreeTentCell) case2.getBoard().getModifiedData().iterator().next(); if (!mod1.getLocation().equals(mod2.getLocation())) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must modify the same cell for each case."; + return super.getInvalidUseOfRuleMessage() + + ": This case rule must modify the same cell for each case."; } - if (!((mod1.getType() == TreeTentType.TENT && mod2.getType() == TreeTentType.GRASS) || - (mod2.getType() == TreeTentType.TENT && mod1.getType() == TreeTentType.GRASS))) { - return super.getInvalidUseOfRuleMessage() + ": This case rule must have a tent and a grass cell."; + if (!((mod1.getType() == TreeTentType.TENT && mod2.getType() == TreeTentType.GRASS) + || (mod2.getType() == TreeTentType.TENT && mod1.getType() == TreeTentType.GRASS))) { + return super.getInvalidUseOfRuleMessage() + + ": This case rule must have a tent and a grass cell."; } return null; } /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule * - * @param transition transition to check + * @param transition transition to check * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message */ @Override public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TooFewTentsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TooFewTentsContradictionRule.java index 92b951feb..7b3f43dbe 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TooFewTentsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TooFewTentsContradictionRule.java @@ -6,24 +6,26 @@ import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.TreeTentCell; import edu.rpi.legup.puzzle.treetent.TreeTentType; - import java.awt.*; public class TooFewTentsContradictionRule extends ContradictionRule { public TooFewTentsContradictionRule() { - super("TREE-CONT-0003", "Too Few Tents", + super( + "TREE-CONT-0003", + "Too Few Tents", "Rows and columns cannot have fewer tents than their clue.", "edu/rpi/legup/images/treetent/too_few_tents.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -36,11 +38,10 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int rowUnknowns = treeTentBoard.getRowCol(loc.y, TreeTentType.UNKNOWN, true).size(); int colUnknowns = treeTentBoard.getRowCol(loc.x, TreeTentType.UNKNOWN, false).size(); - if (rowTents + rowUnknowns < treeTentBoard.getRowClues().get(loc.y).getData() || - colTents + colUnknowns < treeTentBoard.getColClues().get(loc.x).getData()) { + if (rowTents + rowUnknowns < treeTentBoard.getRowClues().get(loc.y).getData() + || colTents + colUnknowns < treeTentBoard.getColClues().get(loc.x).getData()) { return null; - } - else { + } else { return super.getNoContradictionMessage(); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TooManyTentsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TooManyTentsContradictionRule.java index 8bc908d0c..dcc65feb6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TooManyTentsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TooManyTentsContradictionRule.java @@ -6,24 +6,26 @@ import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.TreeTentCell; import edu.rpi.legup.puzzle.treetent.TreeTentType; - import java.awt.*; public class TooManyTentsContradictionRule extends ContradictionRule { public TooManyTentsContradictionRule() { - super("TREE-CONT-0004", "Too Many Tents", + super( + "TREE-CONT-0004", + "Too Many Tents", "Rows and columns cannot have more tents than their clue.", "edu/rpi/legup/images/treetent/too_many_tents.png"); } /** - * Checks whether the transition has a contradiction at the specific puzzleElement index using this rule + * Checks whether the transition has a contradiction at the specific puzzleElement index using + * this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent puzzleElement * @return null if the transition contains a contradiction at the specified puzzleElement, - * otherwise error message + * otherwise error message */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -34,11 +36,10 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int rowTents = treeTentBoard.getRowCol(loc.y, TreeTentType.TENT, true).size(); int colTents = treeTentBoard.getRowCol(loc.x, TreeTentType.TENT, false).size(); - if (rowTents > treeTentBoard.getRowClues().get(loc.y).getData() || - colTents > treeTentBoard.getColClues().get(loc.x).getData()) { + if (rowTents > treeTentBoard.getRowClues().get(loc.y).getData() + || colTents > treeTentBoard.getColClues().get(loc.x).getData()) { return null; - } - else { + } else { return super.getNoContradictionMessage(); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TouchingTentsContradictionRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TouchingTentsContradictionRule.java index a07153a31..d9dd36e12 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TouchingTentsContradictionRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TouchingTentsContradictionRule.java @@ -10,20 +10,21 @@ public class TouchingTentsContradictionRule extends ContradictionRule { public TouchingTentsContradictionRule() { - super("TREE-CONT-0005", "Touching Tents", + super( + "TREE-CONT-0005", + "Touching Tents", "Tents cannot touch other tents.", "edu/rpi/legup/images/treetent/contra_adjacentTents.png"); } /** - * Checks whether the transition has a contradiction at the specific - * {@link PuzzleElement} index using this rule + * Checks whether the transition has a contradiction at the specific {@link PuzzleElement} index + * using this rule * - * @param board board to check contradiction + * @param board board to check contradiction * @param puzzleElement equivalent {@link PuzzleElement} - * @return null if the transition contains a - * contradiction at the specified puzzleElement, - * otherwise error message. + * @return null if the transition contains a contradiction at the specified + * puzzleElement, otherwise error message. */ @Override public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { @@ -36,8 +37,7 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) { int diagTree = treeTentBoard.getDiagonals(cell, TreeTentType.TENT).size(); if (adjTree > 0 || diagTree > 0) { return null; - } - else { + } else { return super.getNoContradictionMessage(); } } diff --git a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TreeForTentDirectRule.java b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TreeForTentDirectRule.java index 63d43e9a4..d4360c7f6 100644 --- a/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TreeForTentDirectRule.java +++ b/src/main/java/edu/rpi/legup/puzzle/treetent/rules/TreeForTentDirectRule.java @@ -1,122 +1,124 @@ -package edu.rpi.legup.puzzle.treetent.rules; - -import java.util.List; -import java.util.ArrayList; - -import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.model.rules.DirectRule; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.treetent.TreeTentLine; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentType; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; - -public class TreeForTentDirectRule extends DirectRule { - public TreeForTentDirectRule() { - super("TREE-BASC-0007", "Tree for Tent", - "If only one unlinked tree is adjacent to an unlinked tent, the unlinked tent must link to the unlinked tree.", - "edu/rpi/legup/images/treetent/NewTentLink.png"); - } - - /** - * Checks whether the child node logically follows from the parent node - * at the specific puzzleElement index using this rule - * - * @param transition transition to check - * @param puzzleElement equivalent puzzleElement - * @return null if the child node logically follow from the parent node at the specified puzzleElement, - * otherwise error message - */ - @Override - public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { - if (!(puzzleElement instanceof TreeTentLine)) { - return super.getInvalidUseOfRuleMessage() + ": Lines must be created for this rule."; - } - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentLine line = (TreeTentLine) board.getPuzzleElement(puzzleElement); - TreeTentCell tree, tent; - if (line.getC1().getType() == TreeTentType.TREE && line.getC2().getType() == TreeTentType.TENT) { - tree = line.getC1(); - tent = line.getC2(); - } - else { - if (line.getC2().getType() == TreeTentType.TREE && line.getC1().getType() == TreeTentType.TENT) { - tree = line.getC2(); - tent = line.getC1(); - } - else { - return super.getInvalidUseOfRuleMessage() + ": This line must connect a tree to a tent."; - } - } - int forced = isForced(board, tree, tent, line); - if (forced == 1) { - return null; - } - else { - if (forced == -1) { - return super.getInvalidUseOfRuleMessage() + ": This tent already has a link"; - } - else { - if (forced == -2) { - return super.getInvalidUseOfRuleMessage() + ": This tree already has a link"; - } - else { - return super.getInvalidUseOfRuleMessage() + ": This tree and tent don't need to be linked."; - } - } - } - } - - private Integer isForced(TreeTentBoard board, TreeTentCell tree, TreeTentCell tent, TreeTentLine line) { - List adjTrees = board.getAdjacent(tent, TreeTentType.TREE); - adjTrees.remove(tree); - List lines = board.getLines(); - lines.remove(line); - for (TreeTentLine l : lines) { - ArrayList toRemove = new ArrayList<>(); - if (l.getC1().getLocation().equals(tree.getLocation()) || l.getC2().getLocation().equals(tree.getLocation())) { - return -2; - } - for (TreeTentCell c : adjTrees) { - if (l.getC1().getLocation().equals(c.getLocation())) { - if (l.getC2().getLocation().equals(tent.getLocation())) { - return -1; - } - toRemove.add(c); - - } - else { - if (l.getC2().getLocation().equals(c.getLocation())) { - if (l.getC1().getLocation().equals(tent.getLocation())) { - return -1; - } - toRemove.add(c); - } - } - } - for (TreeTentCell c : toRemove) { - adjTrees.remove(c); - } - toRemove.clear(); - } - if (adjTrees.size() == 0) { - return 1; - } - else { - return 0; - } - } - - /** - * Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}. - * - * @param node tree node used to create default transition board - * @return default board or null if this rule cannot be applied to this tree node - */ - @Override - public Board getDefaultBoard(TreeNode node) { - return null; - } -} +package edu.rpi.legup.puzzle.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.rules.DirectRule; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.TreeTentType; +import java.util.ArrayList; +import java.util.List; + +public class TreeForTentDirectRule extends DirectRule { + public TreeForTentDirectRule() { + super( + "TREE-BASC-0007", + "Tree for Tent", + "If only one unlinked tree is adjacent to an unlinked tent, the unlinked tent must" + + " link to the unlinked tree.", + "edu/rpi/legup/images/treetent/NewTentLink.png"); + } + + /** + * Checks whether the child node logically follows from the parent node at the specific + * puzzleElement index using this rule + * + * @param transition transition to check + * @param puzzleElement equivalent puzzleElement + * @return null if the child node logically follow from the parent node at the specified + * puzzleElement, otherwise error message + */ + @Override + public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) { + if (!(puzzleElement instanceof TreeTentLine)) { + return super.getInvalidUseOfRuleMessage() + ": Lines must be created for this rule."; + } + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentLine line = (TreeTentLine) board.getPuzzleElement(puzzleElement); + TreeTentCell tree, tent; + if (line.getC1().getType() == TreeTentType.TREE + && line.getC2().getType() == TreeTentType.TENT) { + tree = line.getC1(); + tent = line.getC2(); + } else { + if (line.getC2().getType() == TreeTentType.TREE + && line.getC1().getType() == TreeTentType.TENT) { + tree = line.getC2(); + tent = line.getC1(); + } else { + return super.getInvalidUseOfRuleMessage() + + ": This line must connect a tree to a tent."; + } + } + int forced = isForced(board, tree, tent, line); + if (forced == 1) { + return null; + } else { + if (forced == -1) { + return super.getInvalidUseOfRuleMessage() + ": This tent already has a link"; + } else { + if (forced == -2) { + return super.getInvalidUseOfRuleMessage() + ": This tree already has a link"; + } else { + return super.getInvalidUseOfRuleMessage() + + ": This tree and tent don't need to be linked."; + } + } + } + } + + private Integer isForced( + TreeTentBoard board, TreeTentCell tree, TreeTentCell tent, TreeTentLine line) { + List adjTrees = board.getAdjacent(tent, TreeTentType.TREE); + adjTrees.remove(tree); + List lines = board.getLines(); + lines.remove(line); + for (TreeTentLine l : lines) { + ArrayList toRemove = new ArrayList<>(); + if (l.getC1().getLocation().equals(tree.getLocation()) + || l.getC2().getLocation().equals(tree.getLocation())) { + return -2; + } + for (TreeTentCell c : adjTrees) { + if (l.getC1().getLocation().equals(c.getLocation())) { + if (l.getC2().getLocation().equals(tent.getLocation())) { + return -1; + } + toRemove.add(c); + + } else { + if (l.getC2().getLocation().equals(c.getLocation())) { + if (l.getC1().getLocation().equals(tent.getLocation())) { + return -1; + } + toRemove.add(c); + } + } + } + for (TreeTentCell c : toRemove) { + adjTrees.remove(c); + } + toRemove.clear(); + } + if (adjTrees.size() == 0) { + return 1; + } else { + return 0; + } + } + + /** + * Creates a transition {@link Board} that has this rule applied to it using the {@link + * TreeNode}. + * + * @param node tree node used to create default transition board + * @return default board or null if this rule cannot be applied to this tree node + */ + @Override + public Board getDefaultBoard(TreeNode node) { + return null; + } +} diff --git a/src/main/java/edu/rpi/legup/save/ExportFileException.java b/src/main/java/edu/rpi/legup/save/ExportFileException.java index 46ebac9e0..9def1f392 100644 --- a/src/main/java/edu/rpi/legup/save/ExportFileException.java +++ b/src/main/java/edu/rpi/legup/save/ExportFileException.java @@ -5,5 +5,4 @@ public class ExportFileException extends Exception { public ExportFileException(String message) { super("Export File Exception: " + message); } - } diff --git a/src/main/java/edu/rpi/legup/save/InvalidFileFormatException.java b/src/main/java/edu/rpi/legup/save/InvalidFileFormatException.java index 94c229411..1e24c5762 100644 --- a/src/main/java/edu/rpi/legup/save/InvalidFileFormatException.java +++ b/src/main/java/edu/rpi/legup/save/InvalidFileFormatException.java @@ -5,5 +5,4 @@ public class InvalidFileFormatException extends Exception { public InvalidFileFormatException(String message) { super("InvalidFileFormatException: " + message); } - } diff --git a/src/main/java/edu/rpi/legup/save/SavableBoard.java b/src/main/java/edu/rpi/legup/save/SavableBoard.java index a7799a15a..bd246303b 100644 --- a/src/main/java/edu/rpi/legup/save/SavableBoard.java +++ b/src/main/java/edu/rpi/legup/save/SavableBoard.java @@ -1,10 +1,5 @@ package edu.rpi.legup.save; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import java.io.FileInputStream; import java.io.InputStream; @@ -17,7 +12,5 @@ public class SavableBoard { public SavableBoard(String filePath) throws Exception { this.filePath = filePath; this.inputStream = new FileInputStream(filePath); - - } } diff --git a/src/main/java/edu/rpi/legup/save/SavableProof.java b/src/main/java/edu/rpi/legup/save/SavableProof.java index 101e56125..4f6e4697c 100644 --- a/src/main/java/edu/rpi/legup/save/SavableProof.java +++ b/src/main/java/edu/rpi/legup/save/SavableProof.java @@ -1,5 +1,3 @@ package edu.rpi.legup.save; -public class SavableProof { - -} +public class SavableProof {} diff --git a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java index fa049ab38..b1aa24eca 100644 --- a/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java +++ b/src/main/java/edu/rpi/legup/ui/CreatePuzzleDialog.java @@ -3,40 +3,50 @@ import edu.rpi.legup.app.Config; import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.controller.CursorController; - -import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Arrays; import java.util.Objects; +import javax.swing.*; +/** + * Provides the user interface components for creating a new puzzle in the Legup application. + * This package includes classes for displaying dialog boxes to configure and initialize puzzles. + */ public class CreatePuzzleDialog extends JDialog { private HomePanel homePanel; private String[] games; private JComboBox gameBox; - private ActionListener gameBoxListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JComboBox comboBox = (JComboBox) e.getSource(); - String puzzleName = (String) comboBox.getSelectedItem(); - if (puzzleName.equals("ShortTruthTable")) { - textInputScrollPane.setVisible(true); - rowsLabel.setVisible(false); - rows.setVisible(false); - columnsLabel.setVisible(false); - columns.setVisible(false); - } - else { - textInputScrollPane.setVisible(false); - rowsLabel.setVisible(true); - rows.setVisible(true); - columnsLabel.setVisible(true); - columns.setVisible(true); - } - } - }; + private ActionListener gameBoxListener = + new ActionListener() { + /** + * An ActionListener that handles changes in the drop-down menu for selecting puzzle types. + * When a new item is selected in the drop-down menu, this listener updates the visibility of + * the text input area and the row/column input fields based on the selected puzzle type. + * If "ShortTruthTable" is selected, the text input area is shown and the row/column fields are hidden. + * For other puzzle types, the row/column fields are shown and the text input area is hidden. + */ + @Override + public void actionPerformed(ActionEvent e) { + JComboBox comboBox = (JComboBox) e.getSource(); + String puzzleName = (String) comboBox.getSelectedItem(); + if (puzzleName.equals("ShortTruthTable")) { + textInputScrollPane.setVisible(true); + rowsLabel.setVisible(false); + rows.setVisible(false); + columnsLabel.setVisible(false); + columns.setVisible(false); + } else { + textInputScrollPane.setVisible(false); + rowsLabel.setVisible(true); + rows.setVisible(true); + columnsLabel.setVisible(true); + columns.setVisible(true); + } + } + }; private JLabel puzzleLabel; private JLabel rowsLabel; @@ -48,54 +58,69 @@ public void actionPerformed(ActionEvent e) { private JScrollPane textInputScrollPane; private JButton ok = new JButton("Ok"); - private ActionListener okButtonListener = new ActionListener() { - /** - * Attempts to open the puzzle editor interface for the given game with the given dimensions - * @param ae the event to be processed - */ - @Override - public void actionPerformed(ActionEvent ae) { - String game = Config.convertDisplayNameToClassName((String) gameBox.getSelectedItem()); - - // Check if all 3 TextFields are filled - if (game.equals("ShortTruthTable") && textArea.getText().equals("")) { - System.out.println("Unfilled fields"); - return; - } - if (!game.equals("ShortTruthTable") && (game.equals("") || rows.getText().equals("") || columns.getText().equals(""))) { - System.out.println("Unfilled fields"); - return; - } - - try { - if (game.equals("ShortTruthTable")) { - homePanel.openEditorWithNewPuzzle("ShortTruthTable", textArea.getText().split("\n")); + private ActionListener okButtonListener = + new ActionListener() { + /** + * Attempts to open the puzzle editor interface for the given game with the given + * dimensions + * + * @param ae the event to be processed + */ + @Override + public void actionPerformed(ActionEvent ae) { + String game = getGame(); + + // Check if all 3 TextFields are filled + if (game.equals("ShortTruthTable") && textArea.getText().isEmpty()) { + System.out.println("Unfilled fields"); + return; + } + if (!game.equals("ShortTruthTable") + && (game.isEmpty() + || getRows().isEmpty() + || getColumns().isEmpty())) { + System.out.println("Unfilled fields"); + return; + } + + try { + if (game.equals("ShortTruthTable")) { + homePanel.openEditorWithNewPuzzle( + "ShortTruthTable", textArea.getText().split("\n")); + } else { + homePanel.openEditorWithNewPuzzle( + game, + Integer.valueOf(getRows()), + Integer.valueOf(getColumns())); + } + setVisible(false); + } catch (IllegalArgumentException e) { + System.out.println("Failed to open editor with new puzzle"); + e.printStackTrace(System.out); + } } - else { - homePanel.openEditorWithNewPuzzle(game, Integer.valueOf(rows.getText()), Integer.valueOf(columns.getText())); - } - setVisible(false); - } - catch (IllegalArgumentException e) { - System.out.println("Failed to open editor with new puzzle"); - e.printStackTrace(System.out); - } - } - }; + }; private JButton cancel = new JButton("Cancel"); - private ActionListener cancelButtonListener = new ActionListener() { - /** - * Dispose the puzzle creation dialog - * - * @param e the event to be processed - */ - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }; - + private ActionListener cancelButtonListener = + new ActionListener() { + /** + * Dispose the puzzle creation dialog + * + * @param e the event to be processed + */ + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }; + + /** + * Constructs a new CreatePuzzleDialog + * + * @param parent the parent frame of the dialog + * @param homePanel the home panel where the created puzzle will be added + */ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) { super(parent, true); @@ -140,7 +165,11 @@ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) { c.add(columns); textArea = new JTextArea(); - textInputScrollPane = new JScrollPane(textArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + textInputScrollPane = + new JScrollPane( + textArea, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); textInputScrollPane.setBounds(10, 70, this.getWidth() - 30, 50); c.add(textInputScrollPane); @@ -153,8 +182,7 @@ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) { rows.setVisible(false); columnsLabel.setVisible(false); columns.setVisible(false); - } - else { + } else { textInputScrollPane.setVisible(false); rowsLabel.setVisible(true); rows.setVisible(true); @@ -166,42 +194,89 @@ public CreatePuzzleDialog(JFrame parent, HomePanel homePanel) { gameBox.addActionListener(cursorSelectedGame); ActionListener cursorPressedOk = CursorController.createListener(this, okButtonListener); ok.addActionListener(cursorPressedOk); - ActionListener cursorPressedCancel = CursorController.createListener(this, cancelButtonListener); + ActionListener cursorPressedCancel = + CursorController.createListener(this, cancelButtonListener); cancel.addActionListener(cursorPressedCancel); } + /** + * Initializes the puzzle options available for selection in the dialog. + * The options are retrieved from the game board facade and sorted alphabetically. + */ public void initPuzzles() { - this.games = GameBoardFacade.getInstance().getConfig().getFileCreationEnabledPuzzles().toArray(new String[0]); + this.games = + GameBoardFacade.getInstance() + .getConfig() + .getFileCreationEnabledPuzzles() + .toArray(new String[0]); Arrays.sort(this.games); gameBox = new JComboBox(this.games); } - // ^This method seems useless and never got covered + + /** + * Handles the action events for the dialog, including interactions with the Ok and Cancel buttons + * + * @param e The action event to be processed + */ public void actionPerformed(ActionEvent e) { if (e.getSource() == ok) { String game = Config.convertDisplayNameToClassName((String) gameBox.getSelectedItem()); try { if (game.equals("ShortTruthTable")) { - this.homePanel.openEditorWithNewPuzzle("ShortTruthTable", this.textArea.getText().split("\n")); - } - else { - this.homePanel.openEditorWithNewPuzzle(game, Integer.valueOf(this.rows.getText()), Integer.valueOf(this.columns.getText())); - + this.homePanel.openEditorWithNewPuzzle( + "ShortTruthTable", this.textArea.getText().split("\n")); + } else { + this.homePanel.openEditorWithNewPuzzle( + game, + Integer.valueOf(this.rows.getText()), + Integer.valueOf(this.columns.getText())); } this.setVisible(false); + } catch (IllegalArgumentException exception) { + // Do nothing. This is here to prevent the dialog from closing if the dimensions are invalid. } - catch (IllegalArgumentException exception) { - // Don't do anything. This is here to prevent the dialog from closing if the dimensions are invalid. - } - } - else { + } else { if (e.getSource() == cancel) { this.setVisible(false); - } - else { + } else { // Unknown Action Event } } } -} \ No newline at end of file + + /** + * Retrieves the selected game from the combo box + * + * @return the class name of the selected game + */ + public String getGame() { + return Config.convertDisplayNameToClassName((String) gameBox.getSelectedItem()); + } + + /** + * Retrieves the number of rows specified in the dialog + * + * @return the number of rows as a string + */ + public String getRows() { + return rows.getText(); + } + + /** + * Retrieves the number of columns specified in the dialog + * + * @return the number of columns as a string + */ + public String getColumns() { + return columns.getText(); + } + + /** + * Retrieves the text entered in the text area, split by new lines. + * + * @return an array of strings, each representing as a line of text + */ + public String[] getTextArea() { return textArea.getText().split("\n"); } +} diff --git a/src/main/java/edu/rpi/legup/ui/DynamicView.java b/src/main/java/edu/rpi/legup/ui/DynamicView.java index 038f87d23..344885783 100644 --- a/src/main/java/edu/rpi/legup/ui/DynamicView.java +++ b/src/main/java/edu/rpi/legup/ui/DynamicView.java @@ -1,22 +1,25 @@ package edu.rpi.legup.ui; +import static java.awt.BorderLayout.*; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialFonts; - -import javax.imageio.ImageIO; -import javax.swing.*; -import javax.swing.event.ChangeEvent; import java.awt.*; import java.awt.event.*; import java.io.IOException; import java.util.Hashtable; import java.util.Objects; +import javax.imageio.ImageIO; +import javax.swing.*; +import javax.swing.event.ChangeEvent; -import static java.awt.BorderLayout.*; - +/** + * A JPanel that provides a dynamic view with zooming capabilities for different types of content. + * This class supports views such as game boards or proof trees, allowing users to zoom in and out. + */ public class DynamicView extends JPanel { private ScrollView scrollView; @@ -30,6 +33,12 @@ public class DynamicView extends JPanel { private static final Font INFO_FONT = MaterialFonts.REGULAR; private static final Color INFO_COLOR = MaterialColors.GRAY_900; + /** + * Constructs a new DynamicView with the specified ScrollView and view type + * + * @param scrollView the ScrollView that provides the content to be displayed and zoomed + * @param type the type of dynamic view to set up (e.g., BOARD or PROOF_TREE) + */ public DynamicView(ScrollView scrollView, DynamicViewType type) { this.scrollView = scrollView; @@ -42,16 +51,14 @@ public DynamicView(ScrollView scrollView, DynamicViewType type) { /** * Sets up the zoomer for the given DynamicViewType * - * @param type The DynamicView that we are setting up the zoomer for (so - * the zoomer for the board view or the zoomer for the proof - * tree view) + * @param type The DynamicView that we are setting up the zoomer for (so the zoomer for the + * board view or the zoomer for the proof tree view) * @return A JPanel containing the zoomer */ private JPanel setUpZoomer(DynamicViewType type) { if (type == DynamicViewType.BOARD) { return setUpBoardZoomer(); - } - else { + } else { if (type == DynamicViewType.PROOF_TREE) { return setUpProofTreeZoomer(); } @@ -79,17 +86,20 @@ private JPanel setUpBoardZoomer() { */ private JPanel setUpProofTreeZoomer() { final String label = "Resize Proof"; - ActionListener listener = (ActionListener) -> GameBoardFacade.getInstance().getLegupUI().getProofEditor().fitTreeViewToScreen(); + ActionListener listener = + (ActionListener) -> + GameBoardFacade.getInstance() + .getLegupUI() + .getProofEditor() + .fitTreeViewToScreen(); return this.setUpZoomerHelper(label, listener); } /** * Creates the zoomer * - * @param label A string containing the label to be displayed - * on the fit to screen button - * @param listener A listener that determines what the resize - * button will do + * @param label A string containing the label to be displayed on the fit to screen button + * @param listener A listener that determines what the resize button will do * @return A JPanel containing the zoomer */ private JPanel setUpZoomerHelper(final String label, ActionListener listener) { @@ -111,39 +121,51 @@ private JPanel setUpZoomerHelper(final String label, ActionListener listener) { JSlider zoomSlider = new JSlider(25, 400, 100); - JButton plus = new JButton(new ImageIcon(ImageIO.read( - Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource( - "edu/rpi/legup/imgs/add.png"))))); + JButton plus = + new JButton( + new ImageIcon( + ImageIO.read( + Objects.requireNonNull( + ClassLoader.getSystemClassLoader() + .getResource( + "edu/rpi/legup/imgs/add.png"))))); plus.setFocusPainted(false); plus.setFont(MaterialFonts.getRegularFont(10f)); plus.setPreferredSize(new Dimension(20, 20)); - plus.addActionListener((ActionEvent e) -> zoomSlider.setValue(zoomSlider.getValue() + 25)); - - - JButton minus = new JButton(new ImageIcon(ImageIO.read( - Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource( - "edu/rpi/legup/imgs/remove.png"))))); + plus.addActionListener( + (ActionEvent e) -> zoomSlider.setValue(zoomSlider.getValue() + 25)); + + JButton minus = + new JButton( + new ImageIcon( + ImageIO.read( + Objects.requireNonNull( + ClassLoader.getSystemClassLoader() + .getResource( + "edu/rpi/legup/imgs/remove.png"))))); minus.setFocusPainted(false); minus.setPreferredSize(new Dimension(20, 20)); minus.setFont(MaterialFonts.getRegularFont(10f)); - minus.addActionListener((ActionEvent e) -> zoomSlider.setValue(zoomSlider.getValue() - 25)); + minus.addActionListener( + (ActionEvent e) -> zoomSlider.setValue(zoomSlider.getValue() - 25)); this.scrollView.setWheelScrollingEnabled(true); zoomSlider.setPreferredSize(new Dimension(160, 30)); - scrollView.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - zoomSlider.setValue(scrollView.getZoom()); - zoomLabel.setText(zoomSlider.getValue() + "%"); - } - }); - - zoomSlider.addChangeListener((ChangeEvent e) -> { - scrollView.zoomTo(zoomSlider.getValue() / 100.0); - zoomLabel.setText(zoomSlider.getValue() + "%"); - }); - + scrollView.addComponentListener( + new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + zoomSlider.setValue(scrollView.getZoom()); + zoomLabel.setText(zoomSlider.getValue() + "%"); + } + }); + + zoomSlider.addChangeListener( + (ChangeEvent e) -> { + scrollView.zoomTo(zoomSlider.getValue() / 100.0); + zoomLabel.setText(zoomSlider.getValue() + "%"); + }); zoomSlider.setMajorTickSpacing(100); zoomSlider.setMinorTickSpacing(25); @@ -167,41 +189,71 @@ public void componentResized(ComponentEvent e) { zoomWrapper.setLayout(new BorderLayout()); zoomWrapper.add(status, WEST); zoomWrapper.add(zoomer, EAST); - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); } return zoomWrapper; } + /** + * Gets the ScrollView component associated with this DynamicView + * + * @return the ScrollView component + */ public ScrollView getScrollView() { return this.scrollView; } + /** + * Gets the zoom wrapper that contains the zooming controls + * + * @return the zoom wrapper with zooming controls + */ public JPanel getZoomWrapper() { return this.zoomWrapper; } + /** + * Gets the zoomer that contains the zoomer component + * + * @return the zoomer with the zoomer component + */ public JPanel getZoomer() { return this.zoomer; } + /** + * Updates the status label with an informational message + * + * @param message the informational message to display + */ public void updateInfo(String message) { status.setFont(INFO_FONT); status.setForeground(INFO_COLOR); status.setText(message); } + /** + * Updates the status label with an error message + * + * @param message the error message to display + */ public void updateError(String message) { status.setFont(ERROR_FONT); status.setForeground(ERROR_COLOR); status.setText(message); } + /** + * Clears the status label + */ public void resetStatus() { status.setText(""); } + /** + * Resets the view to its default state and zooms the content to fit the screen + */ public void reset() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); Board board1 = GameBoardFacade.getInstance().getBoard(); @@ -210,6 +262,9 @@ public void reset() { this.getScrollView().zoomFit(); } + /** + * Fits the board view to the screen + */ protected void fitBoardViewToScreen() { scrollView.zoomFit(); } diff --git a/src/main/java/edu/rpi/legup/ui/DynamicViewType.java b/src/main/java/edu/rpi/legup/ui/DynamicViewType.java index 8c2f285cd..d161f5b9c 100644 --- a/src/main/java/edu/rpi/legup/ui/DynamicViewType.java +++ b/src/main/java/edu/rpi/legup/ui/DynamicViewType.java @@ -1,5 +1,13 @@ package edu.rpi.legup.ui; +/** + * An enumeration representing the different types of dynamic views supported by the application. + * The two types of views are: + *

    + *
  • {@code BOARD} - Represents a dynamic view of a game board
  • + *
  • {@code PROOF_TREE} - Represents a dynamic view of a proof tree
  • + *
+ */ public enum DynamicViewType { BOARD, PROOF_TREE diff --git a/src/main/java/edu/rpi/legup/ui/HomePanel.java b/src/main/java/edu/rpi/legup/ui/HomePanel.java index 2270c92b8..f12ffdbf0 100644 --- a/src/main/java/edu/rpi/legup/ui/HomePanel.java +++ b/src/main/java/edu/rpi/legup/ui/HomePanel.java @@ -3,35 +3,36 @@ import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.controller.CursorController; -import edu.rpi.legup.save.InvalidFileFormatException; import edu.rpi.legup.model.Puzzle; -import edu.rpi.legup.model.PuzzleExporter; -import edu.rpi.legup.save.ExportFileException; - -import javax.swing.*; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import javax.xml.parsers.ParserConfigurationException; +import edu.rpi.legup.save.InvalidFileFormatException; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; +import java.io.FileWriter; +import java.net.URI; +import java.net.URL; import java.util.Objects; - +import javax.swing.*; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import java.io.FileWriter; -import java.net.URI; -import java.net.URL; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - +/** + * The {@code HomePanel} class represents the home panel of the LEGUP application. + * This panel provides buttons for functionalities of opening the proof editor, + * opening the puzzle editor, and performing batch grading. It also includes a menu bar with + * options for preferences. + */ public class HomePanel extends LegupPanel { - private final static Logger LOGGER = LogManager.getLogger(HomePanel.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(HomePanel.class.getName()); private LegupUI legupUI; private JFrame frame; private JButton[] buttons; @@ -41,91 +42,105 @@ public class HomePanel extends LegupPanel { private final int buttonSize = 100; - private ActionListener openProofListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Object[] items = legupUI.getProofEditor().promptPuzzle(); - if (items == null) { - // The attempt to prompt a puzzle ended gracefully (cancel) - return; - } - String fileName = (String) items[0]; - File puzzleFile = (File) items[1]; - legupUI.getProofEditor().loadPuzzle(fileName, puzzleFile); - } - }; - - private ActionListener openPuzzleListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Object[] items = legupUI.getPuzzleEditor().promptPuzzle(); - if (items == null) { - // The attempt to prompt a puzzle ended gracefully (cancel) - return; - } - String fileName = (String) items[0]; - File puzzleFile = (File) items[1]; - legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile); - } - }; + /** + * Initialize the proof solver to an empty panel with no puzzle + */ + private ActionListener openProofListener = + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + legupUI.getProofEditor().loadPuzzle("", null); + } + }; - public HomePanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { + /** + * Constructs a {@code HomePanel} with the specified {@code JFrame} and {@code LegupUI}. + * + * @param frame the main application frame + * @param legupUI the LEGUP user interface + */ + public HomePanel(JFrame frame, LegupUI legupUI) { this.legupUI = legupUI; this.frame = frame; setLayout(new GridLayout(1, 2)); + setPreferredSize(new Dimension(440, 250)); initText(); initButtons(); } + /** + * Creates and returns the menu bar for this panel + * + * @return the menu bar + */ public JMenuBar getMenuBar() { this.menuBar = new JMenuBar(); JMenu settings = new JMenu("Settings"); menuBar.add(settings); JMenuItem preferences = new JMenuItem("Preferences"); - preferences.addActionListener(a -> { - PreferencesDialog preferencesDialog = new PreferencesDialog(this.frame); - System.out.println("Preferences clicked"); - }); + preferences.addActionListener( + a -> { + PreferencesDialog preferencesDialog = new PreferencesDialog(this.frame); + System.out.println("Preferences clicked"); + }); settings.addSeparator(); settings.add(preferences); JMenuItem contribute = new JMenuItem("Contribute to Legup"); - contribute.addActionListener(l -> { - try { - java.awt.Desktop.getDesktop().browse(URI.create("https://github.com/Bram-Hub/Legup")); - } - catch (IOException e) { - LOGGER.error("Can't open web page"); - } - }); + contribute.addActionListener( + l -> { + try { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/Legup")); + } catch (IOException e) { + LOGGER.error("Can't open web page"); + } + }); settings.add(contribute); return this.menuBar; } + /** + * Makes the panel visible and sets the menu bar of the frame + */ @Override public void makeVisible() { render(); frame.setJMenuBar(this.getMenuBar()); } + /** + * Resizes the provided icon to the specified width and height + * + * @param icon the icon to resize + * @param width the target width + * @param height the target height + * @return the resized icon + */ private static ImageIcon resizeButtonIcon(ImageIcon icon, int width, int height) { Image image = icon.getImage(); Image resizedImage = image.getScaledInstance(width, height, Image.SCALE_SMOOTH); return new ImageIcon(resizedImage); } + /** + * Initializes the buttons for this panel + */ private void initButtons() { - this.buttons = new JButton[4]; + this.buttons = new JButton[3]; - this.buttons[0] = new JButton("Solve Puzzle") { - { - setSize(buttonSize, buttonSize); - setMaximumSize(getSize()); - } - }; + this.buttons[0] = + new JButton("Puzzle Solver") { + { + setSize(buttonSize, buttonSize); + setMaximumSize(getSize()); + } + }; - URL button0IconLocation = ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/homepanel/proof_file.png"); + URL button0IconLocation = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/homepanel/proof_file.png"); ImageIcon button0Icon = new ImageIcon(button0IconLocation); this.buttons[0].setFocusPainted(false); this.buttons[0].setIcon(resizeButtonIcon(button0Icon, this.buttonSize, this.buttonSize)); @@ -133,57 +148,49 @@ private void initButtons() { this.buttons[0].setVerticalTextPosition(AbstractButton.BOTTOM); this.buttons[0].addActionListener(CursorController.createListener(this, openProofListener)); - this.buttons[1] = new JButton("Create Puzzle") { - { - setSize(buttonSize, buttonSize); - setMaximumSize(getSize()); - } - }; - URL button1IconLocation = ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/homepanel/new_puzzle_file.png"); + this.buttons[1] = + new JButton("Puzzle Editor") { + { + setSize(buttonSize, buttonSize); + setMaximumSize(getSize()); + } + }; + URL button1IconLocation = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/homepanel/new_puzzle_file.png"); ImageIcon button1Icon = new ImageIcon(button1IconLocation); this.buttons[1].setFocusPainted(false); this.buttons[1].setIcon(resizeButtonIcon(button1Icon, this.buttonSize, this.buttonSize)); this.buttons[1].setHorizontalTextPosition(AbstractButton.CENTER); this.buttons[1].setVerticalTextPosition(AbstractButton.BOTTOM); - this.buttons[1].addActionListener(l -> this.openNewPuzzleDialog()); + this.buttons[1].addActionListener(l -> this.openPuzzleEditorDialog()); - this.buttons[2] = new JButton("Edit Puzzle") { - { - setSize(buttonSize, buttonSize); - setMaximumSize(getSize()); - } - }; - URL button2IconLocation = ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/homepanel/puzzle_file.png"); - ImageIcon button2Icon = new ImageIcon(button2IconLocation); + for (int i = 0; i < this.buttons.length - 1; i++) { // -1 to avoid the batch grader button + this.buttons[i].setBounds(200, 200, 700, 700); + } + this.buttons[2] = new JButton("Batch Grader"); this.buttons[2].setFocusPainted(false); - this.buttons[2].setIcon(resizeButtonIcon(button2Icon, this.buttonSize, this.buttonSize)); this.buttons[2].setHorizontalTextPosition(AbstractButton.CENTER); this.buttons[2].setVerticalTextPosition(AbstractButton.BOTTOM); - this.buttons[2].addActionListener(CursorController.createListener(this, openPuzzleListener)); // PLACEHOLDER - for (int i = 0; i < this.buttons.length-1; i++) { // -1 to avoid the batch grader button - this.buttons[i].setBounds(200, 200, 700, 700); - } - this.buttons[3] = new JButton("Batch Grader"); - this.buttons[3].setFocusPainted(false); - this.buttons[3].setHorizontalTextPosition(AbstractButton.CENTER); - this.buttons[3].setVerticalTextPosition(AbstractButton.BOTTOM); - - this.buttons[3].addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - try { - use_xml_to_check(); - } - catch (Exception ex) { - throw new RuntimeException(ex); - } - System.out.println("finished checking the folder"); - - } - }); + this.buttons[2].addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + use_xml_to_check(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + System.out.println("finished checking the folder"); + } + }); } + /** + * Opens a folder chooser dialog and grades puzzles in the selected folder. + * The results are written to a CSV file. + */ public void checkFolder() { GameBoardFacade facade = GameBoardFacade.getInstance(); /* @@ -230,7 +237,8 @@ public void checkFolder() { } writer.append(fileEntry.getName()); writer.append(","); - String fileName = folderEntry.getAbsolutePath() + File.separator + fileEntry.getName(); + String fileName = + folderEntry.getAbsolutePath() + File.separator + fileEntry.getName(); System.out.println("This is path " + fileName); File puzzleFile = new File(fileName); if (puzzleFile != null && puzzleFile.exists()) { @@ -238,21 +246,20 @@ public void checkFolder() { legupUI.displayPanel(1); legupUI.getProofEditor(); GameBoardFacade.getInstance().loadPuzzle(fileName); - String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); + String puzzleName = + GameBoardFacade.getInstance().getPuzzleModule().getName(); legupUI.setTitle(puzzleName + " - " + puzzleFile.getName()); facade = GameBoardFacade.getInstance(); Puzzle puzzle = facade.getPuzzleModule(); if (puzzle.isPuzzleComplete()) { writer.append("Solved"); System.out.println(fileEntry.getName() + " solved"); - } - else { + } else { writer.append("Not Solved"); System.out.println(fileEntry.getName() + " not solved"); } writer.append("\n"); - } - catch (InvalidFileFormatException e) { + } catch (InvalidFileFormatException e) { LOGGER.error(e.getMessage()); } } @@ -262,15 +269,19 @@ public void checkFolder() { writer.append("\n"); } } - } - catch (IOException ex) { + } catch (IOException ex) { LOGGER.error(ex.getMessage()); - this.buttons[3].addActionListener((ActionEvent e) -> use_xml_to_check()); + this.buttons[2].addActionListener((ActionEvent e) -> use_xml_to_check()); } } /** - * @effect batch grade using .xml parser - go through a collection of files and report their "solved?" status + * Processes XML files within a selected directory and generates a CSV report on their "solved?" status. + * The method allows the user to select a directory, and evaluates each XML file for a "solved?" status. + * Results are saved in a "result.csv" file. + * + * @effect Selects a directory, processes each XML file to check for "solved?" status, + * and writes results to "result.csv". Opens the CSV file upon completion. */ private void use_xml_to_check() { /* Select a folder, go through each .xml file in the subfolders, look for "isSolved" flag */ @@ -288,26 +299,24 @@ private void use_xml_to_check() { try (BufferedWriter writer = new BufferedWriter(new FileWriter(resultFile))) { writer.append("Name,File Name,Puzzle Type,Solved?,Last Saved\n"); // Go through student folders, recurse for inner folders - for (final File folderEntry : Objects.requireNonNull(folder.listFiles(File::isDirectory))) { + for (final File folderEntry : + Objects.requireNonNull(folder.listFiles(File::isDirectory))) { String path = folderEntry.getName(); // use this helper function to write to the .csv file recursive_parser(folderEntry, writer, path, path); } - } - catch (IOException ex) { + } catch (IOException ex) { LOGGER.error(ex.getMessage()); } if (resultFile.exists()) { try { Desktop desktop = Desktop.getDesktop(); desktop.open(resultFile); - } - catch (IOException ex) { + } catch (IOException ex) { LOGGER.error(ex.getMessage()); } } JOptionPane.showMessageDialog(null, "Batch grading complete."); - } /** @@ -321,8 +330,7 @@ public boolean isxmlfile(File file) { DocumentBuilder builder = factory.newDocumentBuilder(); builder.parse(file); flag = true; - } - catch (Exception e) { + } catch (Exception e) { flag = false; } return flag; @@ -335,7 +343,8 @@ public boolean isxmlfile(File file) { * @param name - student's name (the first subfolders of the main folder) * @throws IOException */ - private void recursive_parser(File folder, BufferedWriter writer, String path, String name) throws IOException { + private void recursive_parser(File folder, BufferedWriter writer, String path, String name) + throws IOException { // Empty folder if (Objects.requireNonNull(folder.listFiles()).length == 0) { writer.append(path).append(",Empty folder,Ungradeable\n"); @@ -368,94 +377,97 @@ private void recursive_parser(File folder, BufferedWriter writer, String path, S path = folder.getAbsolutePath() + File.separator + fileEntry.getName(); System.out.println(path); if (isxmlfile(fileEntry)) { - saxParser.parse(path, new DefaultHandler() { - @Override - public void startDocument() throws SAXException { - } - boolean solvedFlagExists = false; - boolean puzzleTypeExists = false; - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - // append file type to the writer - if (qName.equals("puzzle") && attributes.getQName(0) == "name" && !puzzleTypeExists) { - try { - writer.write(attributes.getValue(0)); - writer.write(","); - puzzleTypeExists = true; - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - // append the "solved?" status of the proof to the writer - else if (qName.equals("solved") && !solvedFlagExists) { - String isSolved = attributes.getValue(0); - String lastSaved = attributes.getValue(1); - if (isSolved != null) { - if (isSolved.equals("true")) { + saxParser.parse( + path, + new DefaultHandler() { + @Override + public void startDocument() throws SAXException {} + + boolean solvedFlagExists = false; + boolean puzzleTypeExists = false; + + @Override + public void startElement( + String uri, + String localName, + String qName, + Attributes attributes) + throws SAXException { + // append file type to the writer + if (qName.equals("puzzle") + && attributes.getQName(0) == "name" + && !puzzleTypeExists) { try { - writer.write("Solved"); - } - catch (IOException e) { + writer.write(attributes.getValue(0)); + writer.write(","); + puzzleTypeExists = true; + } catch (IOException e) { throw new RuntimeException(e); } } - else if (isSolved.equals("false")) { - try { - writer.write("Not Solved"); + // append the "solved?" status of the proof to the writer + else if (qName.equals("solved") && !solvedFlagExists) { + String isSolved = attributes.getValue(0); + String lastSaved = attributes.getValue(1); + if (isSolved != null) { + if (isSolved.equals("true")) { + try { + writer.write("Solved"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else if (isSolved.equals("false")) { + try { + writer.write("Not Solved"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + try { + writer.write("Error"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } - catch (IOException e) { - throw new RuntimeException(e); + // append when is this proof last saved + if (lastSaved != null) { + try { + writer.write(","); + writer.write(lastSaved); + } catch (IOException e) { + throw new RuntimeException(e); + } } + solvedFlagExists = true; } - else { - try { - writer.write("Error"); + } + + @Override + public void characters(char[] ch, int start, int length) + throws SAXException {} + + @Override + public void endElement(String uri, String localName, String qName) + throws SAXException {} + + @Override + public void endDocument() throws SAXException { + if (!puzzleTypeExists) { + try { + writer.write("not a LEGUP puzzle!"); + } catch (IOException e) { + throw new RuntimeException(e); } - catch (IOException e) { + } else if (!solvedFlagExists) { + try { + writer.write("missing flag!"); + } catch (IOException e) { throw new RuntimeException(e); } } } - // append when is this proof last saved - if (lastSaved != null) { - try { - writer.write(","); - writer.write(lastSaved); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - solvedFlagExists = true; - } - } - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - } - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - } - @Override - public void endDocument() throws SAXException { - if (!puzzleTypeExists) { - try { - writer.write("not a LEGUP puzzle!"); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - else if (!solvedFlagExists) { - try { - writer.write("missing flag!"); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - } - }); + }); } // If wrong file type, ungradeable else { @@ -463,14 +475,18 @@ else if (!solvedFlagExists) { } writer.write("\n"); } - } - catch (ParserConfigurationException | SAXException | IOException e) { + } catch (ParserConfigurationException | SAXException | IOException e) { LOGGER.error(e.getMessage()); } } + /** + * Initializes the text labels for the user interface. + * Sets up labels for welcome message, led by Bram, and version information. + */ private void initText() { - // TODO: add version text after auto-changing version label is implemented. (text[2] = version) + // TODO: add version text after auto-changing version label is implemented. (text[2] = + // version) this.text = new JLabel[2]; JLabel welcome = new JLabel("Welcome to LEGUP"); @@ -489,11 +505,14 @@ private void initText() { this.text[1] = credits; } + /** + * Renders the user interface components + */ private void render() { this.removeAll(); this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); - this.legupUI.setTitle("LEGUP: A Better Way to Learn Formal Logic"); + this.legupUI.setTitle("LEGUP: A Better Way To Learn Formal Logic"); JPanel buttons = new JPanel(); buttons.add(Box.createRigidArea(new Dimension(5, 0))); @@ -501,14 +520,10 @@ private void render() { buttons.add(Box.createRigidArea(new Dimension(5, 0))); buttons.add(this.buttons[1]); buttons.add(Box.createRigidArea(new Dimension(5, 0))); - buttons.add(this.buttons[2]); - buttons.add(Box.createRigidArea(new Dimension(5, 0))); - JPanel batchGraderButton = new JPanel(); - batchGraderButton.add(this.buttons[3]); + batchGraderButton.add(this.buttons[2]); batchGraderButton.setAlignmentX(Component.CENTER_ALIGNMENT); - this.add(Box.createRigidArea(new Dimension(0, 5))); for (int i = 0; i < this.text.length; i++) { this.add(this.text[i]); @@ -518,11 +533,28 @@ private void render() { this.add(Box.createRigidArea(new Dimension(0, 5))); } - private void openNewPuzzleDialog() { - CreatePuzzleDialog cpd = new CreatePuzzleDialog(this.frame, this); - cpd.setVisible(true); + /** + * Opens the puzzle editor dialog with no selected puzzle, leaving a blank panel + * + * @throws IllegalArgumentException if the configuration parameters are invalid (should never happen) + */ + private void openPuzzleEditorDialog() { + String game = ""; + int r = 0; + int c = 0; + + try { + this.openEditorWithNewPuzzle(game, r, c); + } catch (IllegalArgumentException e) { + System.out.println("Failed to open editor with new puzzle"); + e.printStackTrace(System.out); + } } + /** + * Opens a dialog to select a directory, recursively processes the directory to grade puzzles, + * and generates a CSV report of the grading results. + */ private void checkProofAll() { /* * Select dir to grade; recursively grade sub-dirs using traverseDir() @@ -535,7 +567,8 @@ private void checkProofAll() { */ LegupPreferences preferences = LegupPreferences.getInstance(); - File preferredDirectory = new File(preferences.getUserPref(LegupPreferences.WORK_DIRECTORY)); + File preferredDirectory = + new File(preferences.getUserPref(LegupPreferences.WORK_DIRECTORY)); folderBrowser = new JFileChooser(preferredDirectory); folderBrowser.showOpenDialog(this); @@ -553,18 +586,26 @@ private void checkProofAll() { writer.append("Name,File Name,Puzzle Type,Score,Solved?\n"); // Go through student folders - for (final File folderEntry : Objects.requireNonNull(folder.listFiles(File::isDirectory))) { + for (final File folderEntry : + Objects.requireNonNull(folder.listFiles(File::isDirectory))) { // Write path String path = folderEntry.getName(); traverseDir(folderEntry, writer, path); } - } - catch (IOException ex) { + } catch (IOException ex) { LOGGER.error(ex.getMessage()); } JOptionPane.showMessageDialog(null, "Batch grading complete."); } + /** + * Recursively traverses directories to grade puzzles and writes results to a CSV file + * + * @param folder the folder to traverse + * @param writer the BufferedWriter to write results to the CSV file + * @param path the current path within the directory structure + * @throws IOException if an I/O error occurs while writing to the CSV file + */ private void traverseDir(File folder, BufferedWriter writer, String path) throws IOException { // Recursively traverse directory GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -605,53 +646,73 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws writer.append(puzzle.getName()).append(","); if (puzzle.isPuzzleComplete()) { writer.append("Solved\n"); - } - else { + } else { writer.append("Unsolved\n"); } - } - catch (InvalidFileFormatException e) { + } catch (InvalidFileFormatException e) { writer.append(fName).append("InvalidFile,Ungradeable\n"); } - } - else { + } else { LOGGER.debug("Failed to run sim"); } } } - public void openEditorWithNewPuzzle(String game, int rows, int columns) throws IllegalArgumentException { - // Validate the dimensions - GameBoardFacade facade = GameBoardFacade.getInstance(); - boolean isValidDimensions = facade.validateDimensions(game, rows, columns); - if (!isValidDimensions) { - JOptionPane.showMessageDialog(null, - "The dimensions you entered are invalid. Please double check \n" + - "the number of rows and columns and try again.", - "ERROR: Invalid Dimensions", - JOptionPane.ERROR_MESSAGE); - throw new IllegalArgumentException("ERROR: Invalid dimensions given"); + /** + * Opens the puzzle editor for the specified puzzle with the specified dimensions + * + * @param game the name of the game + * @param rows the number of rows in the puzzle + * @param columns the number of columns in the puzzle + * @throws IllegalArgumentException if the dimensions are invalid + */ + public void openEditorWithNewPuzzle(String game, int rows, int columns) + throws IllegalArgumentException { + if (game.equals("")) { + this.legupUI.displayPanel(2); + this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); + } + else { + // Validate the dimensions + GameBoardFacade facade = GameBoardFacade.getInstance(); + boolean isValidDimensions = facade.validateDimensions(game, rows, columns); + if (!isValidDimensions) { + JOptionPane.showMessageDialog( + null, + "The dimensions you entered are invalid. Please double check \n" + + "the number of rows and columns and try again.", + "ERROR: Invalid Dimensions", + JOptionPane.ERROR_MESSAGE); + throw new IllegalArgumentException("ERROR: Invalid dimensions given"); + } + + if (this.legupUI == null) { + System.err.println("Error: legupUI is null in HomePanel"); + return; + } + + // Set game type on the puzzle editor + this.legupUI.displayPanel(2); + this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); } - // Set game type on the puzzle editor - this.legupUI.displayPanel(2); - this.legupUI.getPuzzleEditor().loadPuzzleFromHome(game, rows, columns); } /** - * Opens the puzzle editor for the specified game with the given statements + * Opens the puzzle editor for the specified puzzle with the given statements * - * @param game a String containing the name of the game - * @param statements an array of statements + * @param game a String containing the name of the game + * @param statements an array of statements */ public void openEditorWithNewPuzzle(String game, String[] statements) { // Validate the text input GameBoardFacade facade = GameBoardFacade.getInstance(); boolean isValidTextInput = facade.validateTextInput(game, statements); if (!isValidTextInput) { - JOptionPane.showMessageDialog(null, - "The input you entered is invalid. Please double check \n" + - "your statements and try again.", + JOptionPane.showMessageDialog( + null, + "The input you entered is invalid. Please double check \n" + + "your statements and try again.", "ERROR: Invalid Text Input", JOptionPane.ERROR_MESSAGE); throw new IllegalArgumentException("ERROR: Invalid dimensions given"); diff --git a/src/main/java/edu/rpi/legup/ui/LegupPanel.java b/src/main/java/edu/rpi/legup/ui/LegupPanel.java index 708348145..38c44cbe4 100644 --- a/src/main/java/edu/rpi/legup/ui/LegupPanel.java +++ b/src/main/java/edu/rpi/legup/ui/LegupPanel.java @@ -2,12 +2,18 @@ import javax.swing.*; +/** + * An abstract base class for panels in the LEGUP application. + * This class extends {@link JPanel} and defines common properties and methods + * for all panels in the LEGUP user interface + * (currently only implements toolbar scale) + */ public abstract class LegupPanel extends JPanel { - /** - * Alerts panel that it will be going visible now - */ - + /** Alerts panel that it will be going visible now */ protected final int TOOLBAR_ICON_SCALE = 40; + /** + * Abstract method to make the panel visible + */ public abstract void makeVisible(); } diff --git a/src/main/java/edu/rpi/legup/ui/LegupUI.java b/src/main/java/edu/rpi/legup/ui/LegupUI.java index 452bbb487..30857f05f 100644 --- a/src/main/java/edu/rpi/legup/ui/LegupUI.java +++ b/src/main/java/edu/rpi/legup/ui/LegupUI.java @@ -1,25 +1,26 @@ package edu.rpi.legup.ui; -import java.awt.*; -import java.awt.event.*; -import java.security.InvalidParameterException; -import java.util.Objects; - -import javax.swing.*; - - -import com.formdev.flatlaf.FlatLightLaf; import com.formdev.flatlaf.FlatDarkLaf; +import com.formdev.flatlaf.FlatLightLaf; import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.proofeditorui.treeview.TreePanel; - +import java.awt.*; +import java.awt.event.*; +import java.security.InvalidParameterException; +import java.util.Objects; +import javax.swing.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +/** + * The main user interface class for the LEGUP application. + * This class extends {@link JFrame} and implements {@link WindowListener} + * to manage the overall window and provide functionality for displaying various panels. + */ public class LegupUI extends JFrame implements WindowListener { - private final static Logger LOGGER = LogManager.getLogger(LegupUI.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(LegupUI.class.getName()); protected FileDialog fileDialog; protected JPanel window; @@ -27,22 +28,20 @@ public class LegupUI extends JFrame implements WindowListener { /** * Identifies operating system + * * @return operating system, either mac or win */ public static String getOS() { String os = System.getProperty("os.name").toLowerCase(); if (os.contains("mac")) { os = "mac"; - } - else { + } else { os = "win"; } return os; } - /** - * LegupUI Constructor - creates a new LegupUI to setup the menu and toolbar - */ + /** LegupUI Constructor - creates a new LegupUI to set up the menu and toolbar */ public LegupUI() { setTitle("LEGUP"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -51,12 +50,10 @@ public LegupUI() { try { if (Boolean.valueOf(prefs.getUserPref(LegupPreferences.DARK_MODE))) { UIManager.setLookAndFeel(new FlatDarkLaf()); - } - else { + } else { UIManager.setLookAndFeel(new FlatLightLaf()); } - } - catch (UnsupportedLookAndFeelException e) { + } catch (UnsupportedLookAndFeelException e) { System.err.println("Not supported ui look and feel"); } @@ -65,43 +62,61 @@ public LegupUI() { initPanels(); displayPanel(0); - setIconImage(new ImageIcon(Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource( - "edu/rpi/legup/images/Legup/Direct Rules.gif"))).getImage()); - - if (LegupPreferences.getInstance().getUserPref(LegupPreferences.START_FULL_SCREEN).equals(Boolean.toString(true))) { + setIconImage( + new ImageIcon( + Objects.requireNonNull( + ClassLoader.getSystemClassLoader() + .getResource( + "edu/rpi/legup/images/Legup/Direct" + + " Rules.gif"))) + .getImage()); + + if (LegupPreferences.getInstance() + .getUserPref(LegupPreferences.START_FULL_SCREEN) + .equals(Boolean.toString(true))) { setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH); } this.addWindowListener(this); - addKeyListener(new KeyAdapter() { - /** - * Invoked when a key has been typed. - * This event occurs when a key press is followed by a key release. - * - * @param e - */ - @Override - public void keyTyped(KeyEvent e) { - System.err.println(e.getKeyChar()); - super.keyTyped(e); - } - }); + addKeyListener( + new KeyAdapter() { + /** + * Invoked when a key has been typed. This event occurs when a key press is + * followed by a key release. + * + * @param e + */ + @Override + public void keyTyped(KeyEvent e) { + System.err.println(e.getKeyChar()); + super.keyTyped(e); + } + }); setMinimumSize(getPreferredSize()); setVisible(true); } + /** + * Initializes the panels used in the UI. + * Sets up the layout and adds panels to the window. + */ private void initPanels() { window = new JPanel(); window.setLayout(new BorderLayout()); add(window); panels = new LegupPanel[3]; - panels[0] = new HomePanel(this.fileDialog, this, this); + panels[0] = new HomePanel(this, this); panels[1] = new ProofEditorPanel(this.fileDialog, this, this); panels[2] = new PuzzleEditorPanel(this.fileDialog, this, this); - } + /** + * Displays the specified panel + * + * @param option the index of the panel to display + * @throws InvalidParameterException if the option is out of range + */ protected void displayPanel(int option) { if (option > panels.length || option < 0) { throw new InvalidParameterException("Invalid option"); @@ -115,22 +130,31 @@ protected void displayPanel(int option) { repaint(); } + /** + * Gets the ProofEditorPanel instance + * + * @return the ProofEditorPanel + */ public ProofEditorPanel getProofEditor() { return (ProofEditorPanel) panels[1]; } + /** + * Gets the PuzzleEditorPanel instance + * + * @return the PuzzleEditorPanel + */ public PuzzleEditorPanel getPuzzleEditor() { return (PuzzleEditorPanel) panels[2]; } + /** + * Repaints the tree view in the proof editor. + */ public void repaintTree() { getProofEditor().repaintTree(); } - private void directions() { - JOptionPane.showMessageDialog(null, "For every move you make, you must provide a rules for it (located in the Rules panel).\n" + "While working on the edu.rpi.legup.puzzle, you may click on the \"Check\" button to test your proof for correctness.", "Directions", JOptionPane.PLAIN_MESSAGE); - } - public void showStatus(String status, boolean error) { showStatus(status, error, 1); } @@ -143,27 +167,28 @@ public void showStatus(String status, boolean error, int timer) { // TODO: implement } - //ask to edu.rpi.legup.save current proof - public boolean noquit(String instr) { + /** + * Prompts the user to confirm if they want to exit LEGUP + * + * @param instr the prompt message + * @return true if the user chooses not to quit, false otherwise + */ + public boolean exit(String instr) { int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION); return n != JOptionPane.YES_OPTION; } @Override - public void windowOpened(WindowEvent e) { - - } + public void windowOpened(WindowEvent e) {} public void windowClosing(WindowEvent e) { if (GameBoardFacade.getInstance().getHistory().getIndex() > -1) { - if (noquit("Exiting LEGUP?")) { + if (exit("Exiting LEGUP?")) { this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - } - else { + } else { this.setDefaultCloseOperation(EXIT_ON_CLOSE); } - } - else { + } else { this.setDefaultCloseOperation(EXIT_ON_CLOSE); } } @@ -172,38 +197,55 @@ public void windowClosed(WindowEvent e) { System.exit(0); } - public void windowIconified(WindowEvent e) { - - } - - public void windowDeiconified(WindowEvent e) { + public void windowIconified(WindowEvent e) {} - } - - public void windowActivated(WindowEvent e) { - - } + public void windowDeiconified(WindowEvent e) {} - public void windowDeactivated(WindowEvent e) { + public void windowActivated(WindowEvent e) {} - } + public void windowDeactivated(WindowEvent e) {} + /** + * Gets the BoardView instance from the proof editor + * + * @return the BoardView + */ public BoardView getBoardView() { return getProofEditor().getBoardView(); } + /** + * Gets the BoardView instance from the puzzle editor + * + * @return the BoardView + */ public BoardView getEditorBoardView() { return getPuzzleEditor().getBoardView(); } + /** + * Gets the DynamicView instance from the proof editor + * + * @return the DynamicView + */ public DynamicView getDynamicBoardView() { return getProofEditor().getDynamicBoardView(); } + /** + * Gets the DynamicView instance from the puzzle editor. + * + * @return the DynamicView + */ public DynamicView getEditorDynamicBoardView() { return getPuzzleEditor().getDynamicBoardView(); } + /** + * Gets the TreePanel instance from the proof editor + * + * @return the TreePanel + */ public TreePanel getTreePanel() { return getProofEditor().getTreePanel(); } diff --git a/src/main/java/edu/rpi/legup/ui/ManualPuzzleCreatorDialog.java b/src/main/java/edu/rpi/legup/ui/ManualPuzzleCreatorDialog.java index 6e3fb4f67..01d696f19 100644 --- a/src/main/java/edu/rpi/legup/ui/ManualPuzzleCreatorDialog.java +++ b/src/main/java/edu/rpi/legup/ui/ManualPuzzleCreatorDialog.java @@ -1,13 +1,9 @@ package edu.rpi.legup.ui; -import javax.swing.*; import java.awt.*; +import javax.swing.*; public class ManualPuzzleCreatorDialog extends JDialog { - - public ManualPuzzleCreatorDialog() { - - } - + public ManualPuzzleCreatorDialog() {} } diff --git a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java index 24fc4602f..a6501e2a0 100644 --- a/src/main/java/edu/rpi/legup/ui/PickGameDialog.java +++ b/src/main/java/edu/rpi/legup/ui/PickGameDialog.java @@ -1,15 +1,11 @@ package edu.rpi.legup.ui; - import edu.rpi.legup.app.GameBoardFacade; - import java.awt.Container; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; - import java.io.File; - import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; @@ -19,6 +15,11 @@ import javax.swing.JLabel; import javax.swing.JTextField; +/** + * A dialog for selecting a game. + * This class extends {@link JDialog} and implements {@link ActionListener} + * to handle user interactions for selecting a game type and puzzle file. + */ public class PickGameDialog extends JDialog implements ActionListener { JLabel gameLabel = new JLabel("Game:"); String[] games; @@ -36,7 +37,6 @@ public class PickGameDialog extends JDialog implements ActionListener { JButton ok = new JButton("Ok"); JButton cancel = new JButton("Cancel"); - JCheckBox autotreeCheckBox = new JCheckBox("Auto-tree"); JCheckBox showtreeCheckBox = new JCheckBox("Show tree"); JCheckBox autojustifyCheckBox = new JCheckBox("Auto-justify"); @@ -47,9 +47,9 @@ public class PickGameDialog extends JDialog implements ActionListener { /** * Initialize the dialog * - * @param parent the parent JFrame - * @param pickBothAtOnce if true they can pick a game type and a specific edu.rpi.legup.puzzle, if - * false they can only pick a game type + * @param parent the parent JFrame + * @param pickBothAtOnce if true they can pick a game type and a specific edu.rpi.legup.puzzle, + * if false they can only pick a game type */ public PickGameDialog(JFrame parent, boolean pickBothAtOnce) { super(parent, true); @@ -75,15 +75,13 @@ public PickGameDialog(JFrame parent, boolean pickBothAtOnce) { if (pickBoth) { gameLabel.setBounds(10, 10, 70, 25); gameBox.setBounds(80, 10, 190, 25); - } - else { + } else { gameLabel.setBounds(10, 30, 70, 25); gameBox.setBounds(80, 30, 190, 25); } puzzleLabel.setBounds(10, 40, 70, 25); - puzzleBox.setBounds(80, 40, 190, 25); puzzleButton.setBounds(270, 40, 25, 25); @@ -93,7 +91,6 @@ public PickGameDialog(JFrame parent, boolean pickBothAtOnce) { c.add(gameLabel); c.add(gameBox); - if (pickBoth) { c.add(puzzleLabel); c.add(puzzleBox); @@ -114,6 +111,10 @@ public PickGameDialog(JFrame parent, boolean pickBothAtOnce) { c.add(autojustifyCheckBox); } + /** + * Initializes the available games and puzzles. + * Populates the {@link JComboBox} with game types and sets up the puzzle options. + */ public void initPuzzles() { Object[] o = GameBoardFacade.getInstance().getConfig().getPuzzleClassNames().toArray(); @@ -136,35 +137,53 @@ public void initPuzzles() { gameBox = new JComboBox(games); } + /** + * Gets the selected puzzle file path + * + * @return the puzzle file path as a String + */ public String getPuzzle() { return puzzleBox.getText(); } + /** + * Returns the selected puzzle + * + * @return the selected puzzle as a String + */ public String getGame() { return (String) gameBox.getSelectedItem(); } + /** + * Handles action events for the dialog components. + * Responds to user interactions such as selecting a puzzle, choosing a puzzle file, + * and pressing the 'Ok' or 'Cancel' buttons. + * + * @param e the action event + */ public void actionPerformed(ActionEvent e) { if (e.getSource() == gameBox) { int index = gameBox.getSelectedIndex(); - } - else { + } else { if (e.getSource() == ok) { okPressed = true; setVisible(false); - } - else { + } else { if (e.getSource() == cancel) { okPressed = false; setVisible(false); - } - else { + } else { if (e.getSource() == puzzleButton) { - File f = new File("puzzlefiles" + File.separator + gameBox.getSelectedItem().toString().toLowerCase() + File.separator); + File f = + new File( + "puzzlefiles" + + File.separator + + gameBox.getSelectedItem().toString().toLowerCase() + + File.separator); if (f.exists() && f.isDirectory()) { puzzleChooser = new JFileChooser(f); - } - else { + } else { puzzleChooser = new JFileChooser(); } if (puzzleChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { diff --git a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java index 4eee69d4d..c8639f796 100644 --- a/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java +++ b/src/main/java/edu/rpi/legup/ui/PreferencesDialog.java @@ -1,33 +1,43 @@ package edu.rpi.legup.ui; +import com.formdev.flatlaf.FlatDarkLaf; +import com.formdev.flatlaf.FlatLightLaf; import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialBorders; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialFonts; - -import javax.imageio.ImageIO; -import javax.swing.*; +import edu.rpi.legup.ui.proofeditorui.rulesview.RuleFrame; import java.awt.*; import java.awt.event.*; import java.io.File; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; +import javax.imageio.ImageIO; +import javax.swing.*; -import com.formdev.flatlaf.FlatLightLaf; -import com.formdev.flatlaf.FlatDarkLaf; -import edu.rpi.legup.ui.proofeditorui.rulesview.RuleFrame; -import edu.rpi.legup.ui.proofeditorui.rulesview.RulePanel; - +/** + * A dialog for managing user preferences in the LEGUP application. + * This dialog allows users to configure various settings such as screen mode, + * update preferences, work directory path, and specific features related to board and tree views. + * Users can access this dialog from the home screen or proof editor. + */ public class PreferencesDialog extends JDialog { - private RuleFrame rulesFrame; - private final static Logger LOGGER = Logger.getLogger(PreferencesDialog.class.getName()); + private static final Logger LOGGER = Logger.getLogger(PreferencesDialog.class.getName()); - private JCheckBox fullScreen, autoUpdate, darkMode, showMistakes, showAnnotations, allowDefault, generateCases, immFeedback, colorBlind; + private JCheckBox fullScreen, + autoUpdate, + darkMode, + showMistakes, + showAnnotations, + allowDefault, + generateCases, + immFeedback, + colorBlind; private JTextField workDirectory; @@ -35,19 +45,32 @@ public class PreferencesDialog extends JDialog { static { try { - folderIcon = ImageIO.read(PreferencesDialog.class.getResource("/edu/rpi/legup/imgs/folder.png")); - } - catch (IOException e) { + folderIcon = + ImageIO.read( + PreferencesDialog.class.getResource("/edu/rpi/legup/imgs/folder.png")); + } catch (IOException e) { LOGGER.log(Level.SEVERE, "Unable to locate icons"); } } + /** + * Creates a new instance of PreferencesDialog for the proof editor + * + * @param frame the parent frame + * @param rules the RuleFrame associated with the proof editor + * @return a new instance of PreferencesDialog + */ public static PreferencesDialog CreateDialogForProofEditor(Frame frame, RuleFrame rules) { PreferencesDialog p = new PreferencesDialog(frame); p.rulesFrame = rules; return p; } + /** + * Constructs a PreferencesDialog + * + * @param frame the parent frame + */ public PreferencesDialog(Frame frame) { super(frame); @@ -66,22 +89,25 @@ public PreferencesDialog(Frame frame) { JToolBar toolbar = new JToolBar(); toolbar.setBorder(null); JButton okButton = new JButton("Ok"); - okButton.addActionListener(l -> { - applyPreferences(); - this.setVisible(false); - this.dispose(); - }); + okButton.addActionListener( + l -> { + applyPreferences(); + this.setVisible(false); + this.dispose(); + }); toolbar.add(okButton); JButton cancelButton = new JButton("Cancel"); - cancelButton.addActionListener(l -> { - this.setVisible(false); - this.dispose(); - }); + cancelButton.addActionListener( + l -> { + this.setVisible(false); + this.dispose(); + }); toolbar.add(cancelButton); JButton applyButton = new JButton("Apply"); - applyButton.addActionListener(l -> { - applyPreferences(); - }); + applyButton.addActionListener( + l -> { + applyPreferences(); + }); toolbar.add(applyButton); bottomPanel.add(toolbar, BorderLayout.EAST); @@ -94,21 +120,29 @@ public PreferencesDialog(Frame frame) { setVisible(true); } + /** + * Toggles between dark mode and light mode based on the given preferences + * + * @param prefs the LegupPreferences instance holding user preferences + */ private void toggleDarkMode(LegupPreferences prefs) { try { if (Boolean.valueOf(prefs.getUserPref(LegupPreferences.DARK_MODE))) { UIManager.setLookAndFeel(new FlatDarkLaf()); - } - else { + } else { UIManager.setLookAndFeel(new FlatLightLaf()); } com.formdev.flatlaf.FlatLaf.updateUI(); - } - catch (UnsupportedLookAndFeelException e) { + } catch (UnsupportedLookAndFeelException e) { System.err.println("Not supported ui look and feel"); } } + /** + * Creates the general preferences tab + * + * @return a JScrollPane containing the general preferences panel + */ private JScrollPane createGeneralTab() { LegupPreferences prefs = LegupPreferences.getInstance(); JScrollPane scrollPane = new JScrollPane(); @@ -126,115 +160,162 @@ private JScrollPane createGeneralTab() { workDirectory = new JTextField(prefs.getUserPref(LegupPreferences.WORK_DIRECTORY)); workRow.add(workDirectory, BorderLayout.CENTER); JButton openDir = new JButton(new ImageIcon(folderIcon)); - openDir.addActionListener(a -> { - JFileChooser chooser = new JFileChooser(); - chooser.setCurrentDirectory(new File(workDirectory.getText())); - chooser.setDialogTitle("Choose work directory"); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - chooser.setVisible(true); - - if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - File newFile = chooser.getSelectedFile(); - workDirectory.setText(newFile.toString()); - } - }); + openDir.addActionListener( + a -> { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(workDirectory.getText())); + chooser.setDialogTitle("Choose work directory"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + chooser.setVisible(true); + + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + File newFile = chooser.getSelectedFile(); + workDirectory.setText(newFile.toString()); + } + }); workRow.add(openDir, BorderLayout.EAST); workRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, workRow.getPreferredSize().height)); contentPane.add(workRow); - fullScreen = new JCheckBox("Full Screen", Boolean.valueOf(prefs.getUserPref(LegupPreferences.START_FULL_SCREEN))); + fullScreen = + new JCheckBox( + "Full Screen", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.START_FULL_SCREEN))); fullScreen.setToolTipText("If checked this starts Legup in full screen."); JPanel fullScreenRow = new JPanel(); fullScreenRow.setLayout(new BorderLayout()); fullScreenRow.add(fullScreen, BorderLayout.WEST); - fullScreenRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, fullScreenRow.getPreferredSize().height)); + fullScreenRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, fullScreenRow.getPreferredSize().height)); contentPane.add(fullScreenRow); - autoUpdate = new JCheckBox("Automatically Check for Updates", Boolean.valueOf(prefs.getUserPref(LegupPreferences.AUTO_UPDATE))); - autoUpdate.setToolTipText("If checked this automatically checks for updates on startup of Legup"); + autoUpdate = + new JCheckBox( + "Automatically Check for Updates", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.AUTO_UPDATE))); + autoUpdate.setToolTipText( + "If checked this automatically checks for updates on startup of Legup"); JPanel autoUpdateRow = new JPanel(); autoUpdateRow.setLayout(new BorderLayout()); autoUpdateRow.add(autoUpdate, BorderLayout.WEST); - autoUpdateRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, autoUpdateRow.getPreferredSize().height)); + autoUpdateRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, autoUpdateRow.getPreferredSize().height)); contentPane.add(autoUpdateRow); -// contentPane.add(Box.createRigidArea(new Dimension(0, 10))); + // contentPane.add(Box.createRigidArea(new Dimension(0, 10))); - darkMode = new JCheckBox("Dark Mode", Boolean.valueOf(prefs.getUserPref(LegupPreferences.DARK_MODE))); + darkMode = + new JCheckBox( + "Dark Mode", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.DARK_MODE))); darkMode.setToolTipText("This turns dark mode on and off"); JPanel darkModeRow = new JPanel(); darkModeRow.setLayout(new BorderLayout()); darkModeRow.add(darkMode, BorderLayout.WEST); - darkModeRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, darkModeRow.getPreferredSize().height)); + darkModeRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, darkModeRow.getPreferredSize().height)); contentPane.add(darkModeRow); contentPane.add(Box.createRigidArea(new Dimension(0, 10))); contentPane.add(createLeftLabel("Board View Preferences")); contentPane.add(createLineSeparator()); - showMistakes = new JCheckBox("Show Mistakes", Boolean.valueOf(prefs.getUserPref(LegupPreferences.SHOW_MISTAKES))); - showMistakes.setToolTipText("If checked this show incorrectly applied rule applications in red on the board"); + showMistakes = + new JCheckBox( + "Show Mistakes", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.SHOW_MISTAKES))); + showMistakes.setToolTipText( + "If checked this show incorrectly applied rule applications in red on the board"); JPanel showMistakesRow = new JPanel(); showMistakesRow.setLayout(new BorderLayout()); showMistakesRow.add(showMistakes, BorderLayout.WEST); - showMistakesRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, showMistakesRow.getPreferredSize().height)); + showMistakesRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, showMistakesRow.getPreferredSize().height)); contentPane.add(showMistakesRow); - showAnnotations = new JCheckBox("Show Annotations", Boolean.valueOf(prefs.getUserPref(LegupPreferences.SHOW_ANNOTATIONS))); - showAnnotations.setToolTipText("If checked this show incorrectly applied rule applications in red on the board"); + showAnnotations = + new JCheckBox( + "Show Annotations", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.SHOW_ANNOTATIONS))); + showAnnotations.setToolTipText( + "If checked this show incorrectly applied rule applications in red on the board"); JPanel showAnnotationsRow = new JPanel(); showAnnotationsRow.setLayout(new BorderLayout()); showAnnotationsRow.add(showAnnotations, BorderLayout.WEST); - showAnnotationsRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, showAnnotationsRow.getPreferredSize().height)); + showAnnotationsRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, showAnnotationsRow.getPreferredSize().height)); contentPane.add(showAnnotationsRow); contentPane.add(Box.createRigidArea(new Dimension(0, 10))); contentPane.add(createLeftLabel("Tree View Preferences")); contentPane.add(createLineSeparator()); - allowDefault = new JCheckBox("Allow Default Rule Applications", Boolean.valueOf(prefs.getUserPref(LegupPreferences.ALLOW_DEFAULT_RULES))); + allowDefault = + new JCheckBox( + "Allow Default Rule Applications", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.ALLOW_DEFAULT_RULES))); allowDefault.setEnabled(false); - allowDefault.setToolTipText("If checked this automatically applies a rule where it can on the board"); + allowDefault.setToolTipText( + "If checked this automatically applies a rule where it can on the board"); JPanel allowDefaultRow = new JPanel(); allowDefaultRow.setLayout(new BorderLayout()); allowDefaultRow.add(allowDefault, BorderLayout.WEST); - allowDefaultRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, allowDefaultRow.getPreferredSize().height)); + allowDefaultRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, allowDefaultRow.getPreferredSize().height)); contentPane.add(allowDefaultRow); - generateCases = new JCheckBox("Automatically Generate Cases", Boolean.valueOf(prefs.getUserPref(LegupPreferences.AUTO_GENERATE_CASES))); - generateCases.setToolTipText("If checked this automatically generates all cases for a case rule"); + generateCases = + new JCheckBox( + "Automatically Generate Cases", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.AUTO_GENERATE_CASES))); + generateCases.setToolTipText( + "If checked this automatically generates all cases for a case rule"); JPanel generateCasesRow = new JPanel(); generateCasesRow.setLayout(new BorderLayout()); generateCasesRow.add(generateCases, BorderLayout.WEST); - generateCasesRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, generateCasesRow.getPreferredSize().height)); + generateCasesRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, generateCasesRow.getPreferredSize().height)); contentPane.add(generateCasesRow); contentPane.add(Box.createRigidArea(new Dimension(0, 10))); - immFeedback = new JCheckBox("Provide Immediate Feedback", Boolean.valueOf(prefs.getUserPref(LegupPreferences.IMMEDIATE_FEEDBACK))); - immFeedback.setToolTipText("If checked this will update the colors of the tree view elements immediately"); + immFeedback = + new JCheckBox( + "Provide Immediate Feedback", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.IMMEDIATE_FEEDBACK))); + immFeedback.setToolTipText( + "If checked this will update the colors of the tree view elements immediately"); JPanel immFeedbackRow = new JPanel(); immFeedbackRow.setLayout(new BorderLayout()); immFeedbackRow.add(immFeedback, BorderLayout.WEST); - immFeedbackRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, immFeedbackRow.getPreferredSize().height)); + immFeedbackRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, immFeedbackRow.getPreferredSize().height)); contentPane.add(immFeedbackRow); contentPane.add(createLeftLabel("Instructor Preferences")); contentPane.add(createLineSeparator()); - immFeedback = new JCheckBox("Instructor Mode", Boolean.valueOf(prefs.getUserPref(LegupPreferences.IMMEDIATE_FEEDBACK))); + immFeedback = + new JCheckBox( + "Instructor Mode", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.IMMEDIATE_FEEDBACK))); immFeedback.setToolTipText("Currently unimplemented, this does nothing right now"); immFeedbackRow.setLayout(new BorderLayout()); immFeedbackRow.add(immFeedback, BorderLayout.WEST); - immFeedbackRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, immFeedbackRow.getPreferredSize().height)); + immFeedbackRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, immFeedbackRow.getPreferredSize().height)); contentPane.add(immFeedbackRow); contentPane.add(createLeftLabel("Color Preferences")); contentPane.add(createLineSeparator()); - colorBlind = new JCheckBox("Deuteranomaly(red/green colorblindness)", Boolean.valueOf(prefs.getUserPref(LegupPreferences.COLOR_BLIND))); + colorBlind = + new JCheckBox( + "Deuteranomaly(red/green colorblindness)", + Boolean.valueOf(prefs.getUserPref(LegupPreferences.COLOR_BLIND))); JPanel colorBlindRow = new JPanel(); colorBlindRow.setLayout(new BorderLayout()); colorBlindRow.add(colorBlind, BorderLayout.WEST); - colorBlindRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, showMistakesRow.getPreferredSize().height)); + colorBlindRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, showMistakesRow.getPreferredSize().height)); contentPane.add(colorBlindRow); scrollPane.setViewportView(contentPane); @@ -282,6 +363,15 @@ private JScrollPane createPuzzleTab(Puzzle puzzle) { return scrollPane; } + /** + * Creates a JPanel that represents a single row for a rule in the rule list. + * Each row displays the rule's name and an area for showing keyboard shortcuts + * associated with the rule. The keyboard shortcuts are dynamically updated based + * on user input. + * + * @param rule the rule object to be displayed + * @return a JPanel representing the row for the rule + */ private JPanel createRuleRow(Rule rule) { JPanel ruleRow = new JPanel(); ruleRow.setLayout(new BorderLayout()); @@ -293,38 +383,40 @@ private JPanel createRuleRow(Rule rule) { ruleAcc.setHorizontalAlignment(JLabel.CENTER); ruleAcc.setBorder(MaterialBorders.LIGHT_LINE_BORDER); ruleAcc.setPreferredSize(new Dimension(60, 20)); - ruleAcc.addMouseListener(new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent e) { - ruleAcc.requestFocusInWindow(); - } - }); - - ruleAcc.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - int keyCode = e.getKeyCode(); - String combo = ""; - if (e.isControlDown()) { - combo += "Ctrl + "; - } - else { - if (e.isShiftDown()) { - combo += "Shift + "; + ruleAcc.addMouseListener( + new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + ruleAcc.requestFocusInWindow(); } - else { - if (e.isAltDown()) { - combo += "Alt + "; + }); + + ruleAcc.addKeyListener( + new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + int keyCode = e.getKeyCode(); + String combo = ""; + if (e.isControlDown()) { + combo += "Ctrl + "; + } else { + if (e.isShiftDown()) { + combo += "Shift + "; + } else { + if (e.isAltDown()) { + combo += "Alt + "; + } + } } + if (keyCode == KeyEvent.VK_CONTROL + || keyCode == KeyEvent.VK_SHIFT + || keyCode == KeyEvent.VK_ALT) { + return; + } + combo += KeyEvent.getKeyText(keyCode); + ruleAcc.setText(combo); } - } - if (keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_ALT) { - return; - } - combo += KeyEvent.getKeyText(keyCode); - ruleAcc.setText(combo); - } - }); + }); ruleRow.add(ruleAcc, BorderLayout.EAST); @@ -332,6 +424,14 @@ public void keyPressed(KeyEvent e) { return ruleRow; } + /** + * Creates a JPanel containing a left-aligned label with the specified text. + * This label is typically used for section headings or descriptive text in the + * preferences dialog. + * + * @param text the text to be displayed on the label + * @return a JPanel containing the left-aligned label + */ private JPanel createLeftLabel(String text) { JPanel labelRow = new JPanel(); labelRow.setLayout(new BorderLayout()); @@ -340,30 +440,49 @@ private JPanel createLeftLabel(String text) { label.setHorizontalAlignment(JLabel.LEFT); labelRow.add(label, BorderLayout.WEST); - labelRow.setMaximumSize(new Dimension(Integer.MAX_VALUE, labelRow.getPreferredSize().height)); + labelRow.setMaximumSize( + new Dimension(Integer.MAX_VALUE, labelRow.getPreferredSize().height)); return labelRow; } + /** + * Creates a JSeparator with a maximum height of 5 pixels. + * This separator is used to visually divide sections in the preferences dialog. + * + * @return a JSeparator with a fixed height + */ private JSeparator createLineSeparator() { JSeparator separator = new JSeparator(); separator.setMaximumSize(new Dimension(Integer.MAX_VALUE, 5)); return separator; } + /** + * Applies the current user preferences and updates the associated components. + * This method retrieves user preferences from the dialog's components and stores + * them in the {@link LegupPreferences} instance. It also updates the rule panels + * in the rules frame if it is not null. + */ public void applyPreferences() { LegupPreferences prefs = LegupPreferences.getInstance(); prefs.setUserPref(LegupPreferences.WORK_DIRECTORY, workDirectory.getText()); - prefs.setUserPref(LegupPreferences.START_FULL_SCREEN, Boolean.toString(fullScreen.isSelected())); + prefs.setUserPref( + LegupPreferences.START_FULL_SCREEN, Boolean.toString(fullScreen.isSelected())); prefs.setUserPref(LegupPreferences.AUTO_UPDATE, Boolean.toString(autoUpdate.isSelected())); prefs.setUserPref(LegupPreferences.DARK_MODE, Boolean.toString(darkMode.isSelected())); - prefs.setUserPref(LegupPreferences.SHOW_MISTAKES, Boolean.toString(showMistakes.isSelected())); - prefs.setUserPref(LegupPreferences.SHOW_ANNOTATIONS, Boolean.toString(showAnnotations.isSelected())); - prefs.setUserPref(LegupPreferences.ALLOW_DEFAULT_RULES, Boolean.toString(allowDefault.isSelected())); - prefs.setUserPref(LegupPreferences.AUTO_GENERATE_CASES, Boolean.toString(generateCases.isSelected())); - prefs.setUserPref(LegupPreferences.IMMEDIATE_FEEDBACK, Boolean.toString(immFeedback.isSelected())); + prefs.setUserPref( + LegupPreferences.SHOW_MISTAKES, Boolean.toString(showMistakes.isSelected())); + prefs.setUserPref( + LegupPreferences.SHOW_ANNOTATIONS, Boolean.toString(showAnnotations.isSelected())); + prefs.setUserPref( + LegupPreferences.ALLOW_DEFAULT_RULES, Boolean.toString(allowDefault.isSelected())); + prefs.setUserPref( + LegupPreferences.AUTO_GENERATE_CASES, Boolean.toString(generateCases.isSelected())); + prefs.setUserPref( + LegupPreferences.IMMEDIATE_FEEDBACK, Boolean.toString(immFeedback.isSelected())); prefs.setUserPref(LegupPreferences.COLOR_BLIND, Boolean.toString(colorBlind.isSelected())); - if(rulesFrame != null) { + if (rulesFrame != null) { rulesFrame.getCasePanel().updateRules(); rulesFrame.getDirectRulePanel().updateRules(); rulesFrame.getContradictionPanel().updateRules(); @@ -372,4 +491,4 @@ public void applyPreferences() { // toggle dark mode based on updated NIGHT_MODE variable toggleDarkMode(prefs); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java index e83f660e7..88c1ee427 100644 --- a/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/ProofEditorPanel.java @@ -17,14 +17,9 @@ import edu.rpi.legup.ui.boardview.BoardView; import edu.rpi.legup.ui.proofeditorui.rulesview.RuleFrame; import edu.rpi.legup.ui.proofeditorui.treeview.TreePanel; -import edu.rpi.legup.ui.proofeditorui.treeview.TreeView; +import edu.rpi.legup.ui.proofeditorui.treeview.TreeTransitionView; import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; import edu.rpi.legup.user.Submission; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.swing.*; -import javax.swing.border.TitledBorder; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -37,9 +32,21 @@ import java.net.URL; import java.util.List; import java.util.Objects; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +/** + * {@code ProofEditorPanel} is a panel that serves as the main user interface + * component for the proof editing functionality of LEGUP. It provides + * the graphical components and interactive elements necessary for editing and managing + * proofs, including toolbars, menus, and views for different aspects of proof editing. + * It also manages interactions with the rest of the application and updates the UI + * based on user actions and application state changes. + */ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { - private final static Logger LOGGER = LogManager.getLogger(ProofEditorPanel.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(ProofEditorPanel.class.getName()); private JMenuBar mBar; private TreePanel treePanel; private FileDialog fileDialog; @@ -48,10 +55,16 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private DynamicView dynamicBoardView; private JSplitPane topHalfPanel, mainPanel; private TitledBorder boardBorder; - - private JButton[] toolBarButtons; + private JButton[] toolBar1Buttons; + private JButton[] toolBar2Buttons; private JMenu file; - private JMenuItem newPuzzle, resetPuzzle, saveProofAs, saveProofChange, helpTutorial, preferences, exit; + private JMenuItem newPuzzle, + resetPuzzle, + saveProofAs, + saveProofChange, + helpTutorial, + preferences, + exit; private JMenu edit; private JMenuItem undo, redo, fitBoardToScreen, fitTreeToScreen; @@ -60,11 +73,11 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { private JMenu proof; private JMenuItem add, delete, merge, collapse; private JCheckBoxMenuItem allowDefault, caseRuleGen, imdFeedback; - private JMenu about, help; private JMenuItem helpLegup, aboutLegup; - private JToolBar toolBar; + private JToolBar toolBar1; + private JToolBar toolBar2; private BoardView boardView; private JFileChooser folderBrowser; @@ -78,9 +91,24 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { public static final int IMD_FEEDBACK = 32; public static final int INTERN_RO = 64; public static final int AUTO_JUST = 128; - final static int[] TOOLBAR_SEPARATOR_BEFORE = {2, 4, 8}; - private static final String[] PROFILES = {"No Assistance", "Rigorous Proof", "Casual Proof", "Assisted Proof", "Guided Proof", "Training-Wheels Proof", "No Restrictions"}; - private static final int[] PROF_FLAGS = {0, ALLOW_JUST | REQ_STEP_JUST, ALLOW_JUST, ALLOW_HINTS | ALLOW_JUST | AUTO_JUST, ALLOW_HINTS | ALLOW_JUST | REQ_STEP_JUST, ALLOW_HINTS | ALLOW_DEFAPP | ALLOW_JUST | IMD_FEEDBACK | INTERN_RO, ALLOW_HINTS | ALLOW_DEFAPP | ALLOW_FULLAI | ALLOW_JUST}; + private static final String[] PROFILES = { + "No Assistance", + "Rigorous Proof", + "Casual Proof", + "Assisted Proof", + "Guided Proof", + "Training-Wheels Proof", + "No Restrictions" + }; + private static final int[] PROF_FLAGS = { + 0, + ALLOW_JUST | REQ_STEP_JUST, + ALLOW_JUST, + ALLOW_HINTS | ALLOW_JUST | AUTO_JUST, + ALLOW_HINTS | ALLOW_JUST | REQ_STEP_JUST, + ALLOW_HINTS | ALLOW_DEFAPP | ALLOW_JUST | IMD_FEEDBACK | INTERN_RO, + ALLOW_HINTS | ALLOW_DEFAPP | ALLOW_FULLAI | ALLOW_JUST + }; private JMenu proofMode = new JMenu("Proof Mode"); private JCheckBoxMenuItem[] proofModeItems = new JCheckBoxMenuItem[PROF_FLAGS.length]; @@ -92,6 +120,13 @@ public class ProofEditorPanel extends LegupPanel implements IHistoryListener { protected JMenuItem testAI = new JMenuItem("Test AI!"); protected JMenuItem hintAI = new JMenuItem("Hint"); + /** + * Constructs a new {@code ProofEditorPanel} with the specified parameters + * + * @param fileDialog the {@code FileDialog} used for file operations + * @param frame the {@code JFrame} that contains this panel + * @param legupUI the {@code LegupUI} instance managing the user interface + */ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.fileDialog = fileDialog; this.frame = frame; @@ -100,23 +135,46 @@ public ProofEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { setPreferredSize(new Dimension(800, 700)); } + /** + * Makes the panel visible by setting up the toolbar and content components. + * This method also sets the menu bar of the frame to the one used by this panel. + */ @Override public void makeVisible() { this.removeAll(); - setupToolBar(); + setupToolBar1(); setupContent(); frame.setJMenuBar(getMenuBar()); } + /** + * Constructs and returns the {@code JMenuBar} for this panel. + * It populates it with various {@code JMenu} and {@code JMenuItem} components related + * to file operations, editing, viewing, and proof management. + * The menu bar includes: + *
    + *
  • {@code File} menu with options to open a new puzzle, reset the puzzle, save the proof, + * access preferences, and exit the editor.
  • + *
  • {@code Edit} menu with options for undo, redo, and fitting the board or tree to the screen.
  • + *
  • {@code Proof} menu with options for adding, deleting, merging, collapsing elements, + * and toggling settings related to rule applications and feedback.
  • + *
  • {@code About} menu with options to view information about the application and access help resources.
  • + *
+ *

+ * Accelerator keys are set based on the operating system (Mac or non-Mac). + * + * @return the {@code JMenuBar} instance containing the menus and menu items for this panel + */ public JMenuBar getMenuBar() { if (mBar != null) return mBar; mBar = new JMenuBar(); file = new JMenu("File"); newPuzzle = new JMenuItem("Open"); - resetPuzzle = new JMenuItem("Reset Puzzle"); -// genPuzzle = new JMenuItem("Puzzle Generators"); // TODO: implement puzzle generator + resetPuzzle = new JMenuItem("Reset"); + // genPuzzle = new JMenuItem("Puzzle Generators"); // TODO: implement puzzle + // generator saveProofAs = new JMenuItem("Save As"); // create a new file to save saveProofChange = new JMenuItem("Save"); // save to the current file preferences = new JMenuItem("Preferences"); @@ -139,9 +197,10 @@ public JMenuBar getMenuBar() { add = new JMenuItem("Add"); add.addActionListener(a -> treePanel.add()); if (os.equals("mac")) { - add.setAccelerator(KeyStroke.getKeyStroke('A', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + add.setAccelerator( + KeyStroke.getKeyStroke( + 'A', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { add.setAccelerator(KeyStroke.getKeyStroke('A', InputEvent.CTRL_DOWN_MASK)); } proof.add(add); @@ -149,9 +208,10 @@ public JMenuBar getMenuBar() { delete = new JMenuItem("Delete"); delete.addActionListener(a -> treePanel.delete()); if (os.equals("mac")) { - delete.setAccelerator(KeyStroke.getKeyStroke('D', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + delete.setAccelerator( + KeyStroke.getKeyStroke( + 'D', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { delete.setAccelerator(KeyStroke.getKeyStroke('D', InputEvent.CTRL_DOWN_MASK)); } proof.add(delete); @@ -159,9 +219,10 @@ public JMenuBar getMenuBar() { merge = new JMenuItem("Merge"); merge.addActionListener(a -> treePanel.merge()); if (os.equals("mac")) { - merge.setAccelerator(KeyStroke.getKeyStroke('M', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + merge.setAccelerator( + KeyStroke.getKeyStroke( + 'M', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { merge.setAccelerator(KeyStroke.getKeyStroke('M', InputEvent.CTRL_DOWN_MASK)); } proof.add(merge); @@ -169,33 +230,58 @@ public JMenuBar getMenuBar() { collapse = new JMenuItem("Collapse"); collapse.addActionListener(a -> treePanel.collapse()); if (os.equals("mac")) { - collapse.setAccelerator(KeyStroke.getKeyStroke('C', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + collapse.setAccelerator( + KeyStroke.getKeyStroke( + 'C', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { collapse.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_DOWN_MASK)); } collapse.setEnabled(false); proof.add(collapse); - allowDefault = new JCheckBoxMenuItem("Allow Default Rule Applications", - LegupPreferences.getInstance().getUserPref(LegupPreferences.ALLOW_DEFAULT_RULES).equalsIgnoreCase(Boolean.toString(true))); - allowDefault.addChangeListener(e -> { - LegupPreferences.getInstance().setUserPref(LegupPreferences.ALLOW_DEFAULT_RULES, Boolean.toString(allowDefault.isSelected())); - }); + allowDefault = + new JCheckBoxMenuItem( + "Allow Default Rule Applications", + LegupPreferences.getInstance() + .getUserPref(LegupPreferences.ALLOW_DEFAULT_RULES) + .equalsIgnoreCase(Boolean.toString(true))); + allowDefault.addChangeListener( + e -> { + LegupPreferences.getInstance() + .setUserPref( + LegupPreferences.ALLOW_DEFAULT_RULES, + Boolean.toString(allowDefault.isSelected())); + }); proof.add(allowDefault); - caseRuleGen = new JCheckBoxMenuItem("Automatically generate cases for CaseRule", - LegupPreferences.getInstance().getUserPref(LegupPreferences.AUTO_GENERATE_CASES).equalsIgnoreCase(Boolean.toString(true))); - caseRuleGen.addChangeListener(e -> { - LegupPreferences.getInstance().setUserPref(LegupPreferences.AUTO_GENERATE_CASES, Boolean.toString(caseRuleGen.isSelected())); - }); + caseRuleGen = + new JCheckBoxMenuItem( + "Automatically generate cases for CaseRule", + LegupPreferences.getInstance() + .getUserPref(LegupPreferences.AUTO_GENERATE_CASES) + .equalsIgnoreCase(Boolean.toString(true))); + caseRuleGen.addChangeListener( + e -> { + LegupPreferences.getInstance() + .setUserPref( + LegupPreferences.AUTO_GENERATE_CASES, + Boolean.toString(caseRuleGen.isSelected())); + }); proof.add(caseRuleGen); - imdFeedback = new JCheckBoxMenuItem("Provide immediate feedback", - LegupPreferences.getInstance().getUserPref(LegupPreferences.IMMEDIATE_FEEDBACK).equalsIgnoreCase(Boolean.toString(true))); - imdFeedback.addChangeListener(e -> { - LegupPreferences.getInstance().setUserPref(LegupPreferences.IMMEDIATE_FEEDBACK, Boolean.toString(imdFeedback.isSelected())); - }); + imdFeedback = + new JCheckBoxMenuItem( + "Provide immediate feedback", + LegupPreferences.getInstance() + .getUserPref(LegupPreferences.IMMEDIATE_FEEDBACK) + .equalsIgnoreCase(Boolean.toString(true))); + imdFeedback.addChangeListener( + e -> { + LegupPreferences.getInstance() + .setUserPref( + LegupPreferences.IMMEDIATE_FEEDBACK, + Boolean.toString(imdFeedback.isSelected())); + }); proof.add(imdFeedback); about = new JMenu("About"); @@ -206,79 +292,106 @@ public JMenuBar getMenuBar() { file.add(newPuzzle); newPuzzle.addActionListener((ActionEvent) -> loadPuzzle()); if (os.equals("mac")) { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('N', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + newPuzzle.setAccelerator( + KeyStroke.getKeyStroke( + 'N', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { newPuzzle.setAccelerator(KeyStroke.getKeyStroke('N', InputEvent.CTRL_DOWN_MASK)); } file.add(resetPuzzle); - resetPuzzle.addActionListener(a -> { - Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); - if (puzzle != null) { - Tree tree = GameBoardFacade.getInstance().getTree(); - TreeNode rootNode = tree.getRootNode(); - if (rootNode != null) { - int confirmReset = JOptionPane.showConfirmDialog(this, "Reset Puzzle to Root Node?", "Confirm Reset", JOptionPane.YES_NO_OPTION); - if (confirmReset == JOptionPane.YES_OPTION) { - - List children = rootNode.getChildren(); - children.forEach(t -> puzzle.notifyTreeListeners(l -> l.onTreeElementRemoved(t))); - children.forEach(t -> puzzle.notifyBoardListeners(l -> l.onTreeElementChanged(t))); - rootNode.clearChildren(); - final TreeViewSelection selection = new TreeViewSelection(treePanel.getTreeView().getElementView(rootNode)); - puzzle.notifyTreeListeners(l -> l.onTreeSelectionChanged(selection)); - puzzle.notifyBoardListeners(listener -> listener.onTreeElementChanged(selection.getFirstSelection().getTreeElement())); - GameBoardFacade.getInstance().getHistory().clear(); + resetPuzzle.addActionListener( + a -> { + Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); + if (puzzle != null) { + Tree tree = GameBoardFacade.getInstance().getTree(); + TreeNode rootNode = tree.getRootNode(); + if (rootNode != null) { + int confirmReset = + JOptionPane.showConfirmDialog( + this, + "Reset Puzzle to Root Node?", + "Confirm Reset", + JOptionPane.YES_NO_OPTION); + if (confirmReset == JOptionPane.YES_OPTION) { + + List children = rootNode.getChildren(); + children.forEach( + t -> + puzzle.notifyTreeListeners( + l -> l.onTreeElementRemoved(t))); + children.forEach( + t -> + puzzle.notifyBoardListeners( + l -> l.onTreeElementChanged(t))); + rootNode.clearChildren(); + final TreeViewSelection selection = + new TreeViewSelection( + treePanel.getTreeView().getElementView(rootNode)); + puzzle.notifyTreeListeners( + l -> l.onTreeSelectionChanged(selection)); + puzzle.notifyBoardListeners( + listener -> + listener.onTreeElementChanged( + selection + .getFirstSelection() + .getTreeElement())); + GameBoardFacade.getInstance().getHistory().clear(); + } + } } - } - } - }); + }); if (os.equals("mac")) { - resetPuzzle.setAccelerator(KeyStroke.getKeyStroke('R', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + resetPuzzle.setAccelerator( + KeyStroke.getKeyStroke( + 'R', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { resetPuzzle.setAccelerator(KeyStroke.getKeyStroke('R', InputEvent.CTRL_DOWN_MASK)); } + file.addSeparator(); file.add(saveProofAs); saveProofAs.addActionListener((ActionEvent) -> saveProofAs()); - - //save proof as... + // save proof as... if (os.equals("mac")) { - saveProofAs.setAccelerator(KeyStroke.getKeyStroke('S', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + saveProofAs.setAccelerator( + KeyStroke.getKeyStroke( + 'S', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { saveProofAs.setAccelerator(KeyStroke.getKeyStroke('S', InputEvent.CTRL_DOWN_MASK)); } // save proof change if (os.equals("mac")) { - saveProofChange.setAccelerator(KeyStroke.getKeyStroke('A', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + saveProofChange.setAccelerator( + KeyStroke.getKeyStroke( + 'A', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { saveProofChange.setAccelerator(KeyStroke.getKeyStroke('A', InputEvent.CTRL_DOWN_MASK)); } - file.add(saveProofChange); saveProofChange.addActionListener((ActionEvent) -> saveProofChange()); file.addSeparator(); // preference file.add(preferences); - preferences.addActionListener(a -> { - PreferencesDialog preferencesDialog = PreferencesDialog.CreateDialogForProofEditor(this.frame, this.ruleFrame); - }); + preferences.addActionListener( + a -> { + PreferencesDialog preferencesDialog = + PreferencesDialog.CreateDialogForProofEditor( + this.frame, this.ruleFrame); + }); file.addSeparator(); // help function if (os.equals("mac")) { - helpTutorial.setAccelerator(KeyStroke.getKeyStroke('H', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + helpTutorial.setAccelerator( + KeyStroke.getKeyStroke( + 'H', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { helpTutorial.setAccelerator(KeyStroke.getKeyStroke('H', InputEvent.CTRL_DOWN_MASK)); } file.add(helpTutorial); @@ -286,56 +399,75 @@ public JMenuBar getMenuBar() { helpTutorial.addActionListener((ActionEvent) -> helpTutorial()); file.addSeparator(); - - //exit + // exit file.add(exit); exit.addActionListener((ActionEvent) -> exitEditor()); if (os.equals("mac")) { - exit.setAccelerator(KeyStroke.getKeyStroke('Q', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + exit.setAccelerator( + KeyStroke.getKeyStroke( + 'Q', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { exit.setAccelerator(KeyStroke.getKeyStroke('Q', InputEvent.CTRL_DOWN_MASK)); } mBar.add(edit); - edit.add(undo); - undo.addActionListener((ActionEvent) -> - GameBoardFacade.getInstance().getHistory().undo()); + undo.addActionListener((ActionEvent) -> GameBoardFacade.getInstance().getHistory().undo()); if (os.equals("mac")) { - undo.setAccelerator(KeyStroke.getKeyStroke('Z', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + undo.setAccelerator( + KeyStroke.getKeyStroke( + 'Z', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { undo.setAccelerator(KeyStroke.getKeyStroke('Z', InputEvent.CTRL_DOWN_MASK)); } edit.add(redo); // Created action to support two keybinds (CTRL-SHIFT-Z, CTRL-Y) - Action redoAction = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - GameBoardFacade.getInstance().getHistory().redo(); - } - }; + Action redoAction = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + GameBoardFacade.getInstance().getHistory().redo(); + } + }; if (os.equals("mac")) { - redo.getInputMap(WHEN_IN_FOCUSED_WINDOW).put( - KeyStroke.getKeyStroke('Z', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + InputEvent.SHIFT_DOWN_MASK), "redoAction"); - redo.getInputMap(WHEN_IN_FOCUSED_WINDOW).put( - KeyStroke.getKeyStroke('Y', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "redoAction"); - redo.setAccelerator(KeyStroke.getKeyStroke('Z', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + InputEvent.SHIFT_DOWN_MASK)); - } - else { - redo.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('Y', InputEvent.CTRL_DOWN_MASK), "redoAction"); - redo.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('Z', InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK), "redoAction"); + redo.getInputMap(WHEN_IN_FOCUSED_WINDOW) + .put( + KeyStroke.getKeyStroke( + 'Z', + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + + InputEvent.SHIFT_DOWN_MASK), + "redoAction"); + redo.getInputMap(WHEN_IN_FOCUSED_WINDOW) + .put( + KeyStroke.getKeyStroke( + 'Y', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), + "redoAction"); + redo.setAccelerator( + KeyStroke.getKeyStroke( + 'Z', + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + + InputEvent.SHIFT_DOWN_MASK)); + } else { + redo.getInputMap(WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke('Y', InputEvent.CTRL_DOWN_MASK), "redoAction"); + redo.getInputMap(WHEN_IN_FOCUSED_WINDOW) + .put( + KeyStroke.getKeyStroke( + 'Z', InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK), + "redoAction"); redo.getActionMap().put("redoAction", redoAction); // Button in menu will show CTRL-SHIFT-Z as primary keybind - redo.setAccelerator(KeyStroke.getKeyStroke('Z', InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)); + redo.setAccelerator( + KeyStroke.getKeyStroke( + 'Z', InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)); } edit.add(fitBoardToScreen); - fitBoardToScreen.addActionListener((ActionEvent) -> dynamicBoardView.fitBoardViewToScreen()); + fitBoardToScreen.addActionListener( + (ActionEvent) -> dynamicBoardView.fitBoardViewToScreen()); edit.add(fitTreeToScreen); fitTreeToScreen.addActionListener((ActionEvent) -> this.fitTreeViewToScreen()); @@ -343,25 +475,31 @@ public void actionPerformed(ActionEvent e) { mBar.add(proof); about.add(aboutLegup); - aboutLegup.addActionListener(l -> { - JOptionPane.showMessageDialog(null, "Version: 5.1.0"); - }); + aboutLegup.addActionListener( + l -> { + JOptionPane.showMessageDialog(null, "Version: 5.1.0"); + }); about.add(helpLegup); - helpLegup.addActionListener(l -> { - try { - java.awt.Desktop.getDesktop().browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki")); - } - catch (IOException e) { - LOGGER.error("Can't open web page"); - } - }); + helpLegup.addActionListener( + l -> { + try { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki")); + } catch (IOException e) { + LOGGER.error("Can't open web page"); + } + }); mBar.add(about); return mBar; } + /** + * Clears the current puzzle, resets the UI to display the initial panel, + * and nullifies the references to the tree panel and board view. + */ public void exitEditor() { // Wipes the puzzle entirely as if LEGUP just started GameBoardFacade.getInstance().clearPuzzle(); @@ -370,7 +508,13 @@ public void exitEditor() { boardView = null; } - // File opener + /** + * Opens a file chooser dialog allowing the user to select a directory. It uses the user's + * preferred directory or the last saved path if available. The selected directory is used + * to set the new working directory. + * + * @return an array containing the file name and the selected file, or {@code null} if the operation was canceled + */ public Object[] promptPuzzle() { GameBoardFacade facade = GameBoardFacade.getInstance(); if (facade.getBoard() != null) { @@ -402,18 +546,24 @@ public Object[] promptPuzzle() { if (puzzlePath != null) { fileName = puzzlePath.getAbsolutePath(); - String lastDirectoryPath = fileName.substring(0, fileName.lastIndexOf(File.separator)); + String lastDirectoryPath = fileName.substring(0, fileName.lastIndexOf(File.separator)); preferences.setSavedPath(lastDirectoryPath); puzzleFile = puzzlePath; - } - else { + } else { // The attempt to prompt a puzzle ended gracefully (cancel) return null; } - return new Object[]{fileName, puzzleFile}; + System.out.println(preferences.getSavedPath()); + return new Object[] {fileName, puzzleFile}; } + /** + * Calls {@link #promptPuzzle()} to get the file information and then loads the puzzle using + * the provided file name and file object. Updates the frame title to reflect the puzzle name. + * If the file is not valid or an error occurs, an error message is shown, and the user is + * prompted to try loading another puzzle. + */ public void loadPuzzle() { Object[] items = promptPuzzle(); // Return if items == null (cancel) @@ -425,23 +575,47 @@ public void loadPuzzle() { loadPuzzle(fileName, puzzleFile); } + /** + * Attempts to load a puzzle from the given file. If successful, it updates the + * UI to display the puzzle and changes the frame title to include the puzzle name. If the + * file is invalid or cannot be read, it shows an appropriate error message and prompts the + * user to try loading another puzzle. + * + * @param fileName the name of the file to load + * @param puzzleFile the file object representing the puzzle file + */ public void loadPuzzle(String fileName, File puzzleFile) { + if (puzzleFile == null && fileName.equals("")) { + legupUI.displayPanel(1); + } if (puzzleFile != null && puzzleFile.exists()) { try { legupUI.displayPanel(1); GameBoardFacade.getInstance().loadPuzzle(fileName); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); frame.setTitle(puzzleName + " - " + puzzleFile.getName()); - } - catch (InvalidFileFormatException e) { + } catch (InvalidFileFormatException e) { legupUI.displayPanel(0); LOGGER.error(e.getMessage()); - if (e.getMessage().contains("Proof Tree construction error: could not find rule by ID")) { // TO DO: make error message not hardcoded - JOptionPane.showMessageDialog(null, "This file runs on an outdated version of Legup\nand is not compatible with the current version.", "Error", JOptionPane.ERROR_MESSAGE); + if (e.getMessage() + .contains( + "Proof Tree construction error: could not find rule by ID")) { // TO + // DO: make error + // message not + // hardcoded + JOptionPane.showMessageDialog( + null, + "This file runs on an outdated version of Legup\n" + + "and is not compatible with the current version.", + "Error", + JOptionPane.ERROR_MESSAGE); loadPuzzle(); - } - else { - JOptionPane.showMessageDialog(null, "File does not exist or it cannot be read", "Error", JOptionPane.ERROR_MESSAGE); + } else { + JOptionPane.showMessageDialog( + null, + "File does not exist or it cannot be read", + "Error", + JOptionPane.ERROR_MESSAGE); loadPuzzle(); } } @@ -449,7 +623,9 @@ public void loadPuzzle(String fileName, File puzzleFile) { } /** - * save the proof in the current file + * Uses the current puzzle and its associated exporter to save the puzzle data + * to the file currently being used. If the puzzle or exporter is null, or if an error occurs + * during export, the method will catch the exception and print the stack trace. */ private void direct_save() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); @@ -464,15 +640,16 @@ private void direct_save() { throw new ExportFileException("Puzzle exporter null"); } exporter.exportPuzzle(fileName); - } - catch (ExportFileException e) { + } catch (ExportFileException e) { e.printStackTrace(); } } } /** - * Create a new file and save proof to it + * Opens a file chooser dialog for the user to select a directory. The chosen directory is used + * to determine where the puzzle file will be saved. If an exporter is available, it will be used + * to export the puzzle data to the selected path. */ private void saveProofAs() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); @@ -480,40 +657,44 @@ private void saveProofAs() { return; } - fileDialog.setMode(FileDialog.SAVE); - fileDialog.setTitle("Save As"); - String curFileName = GameBoardFacade.getInstance().getCurFileName(); - if (curFileName == null) { - fileDialog.setDirectory(LegupPreferences.getInstance().getUserPref(LegupPreferences.WORK_DIRECTORY)); - } - else { - File curFile = new File(curFileName); - fileDialog.setDirectory(curFile.getParent()); + LegupPreferences preferences = LegupPreferences.getInstance(); + File preferredDirectory = + new File(preferences.getUserPref(LegupPreferences.WORK_DIRECTORY)); + if (preferences.getSavedPath() != "") { + preferredDirectory = new File(preferences.getSavedPath()); } - fileDialog.setVisible(true); + folderBrowser = new JFileChooser(preferredDirectory); - String fileName = null; - if (fileDialog.getDirectory() != null && fileDialog.getFile() != null) { - fileName = fileDialog.getDirectory() + File.separator + fileDialog.getFile(); - } + folderBrowser.showSaveDialog(this); + folderBrowser.setVisible(true); + folderBrowser.setCurrentDirectory(new File(LegupPreferences.WORK_DIRECTORY)); + folderBrowser.setDialogTitle("Select Directory"); + folderBrowser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + folderBrowser.setAcceptAllFileFilterUsed(false); - if (fileName != null) { + String path = folderBrowser.getSelectedFile().getAbsolutePath(); + + if (path != null) { try { PuzzleExporter exporter = puzzle.getExporter(); if (exporter == null) { throw new ExportFileException("Puzzle exporter null"); } - exporter.exportPuzzle(fileName); - } - catch (ExportFileException e) { + exporter.exportPuzzle(path); + } catch (ExportFileException e) { e.printStackTrace(); } } } // Hyperlink for help button; links to wiki page for tutorials + /** + * Opens the default web browser to a help page related to the type of puzzle currently being used. + * The URL is chosen based on the name of the puzzle. If the puzzle type is not recognized, a general + * tutorial page is opened. + */ private void helpTutorial() { - //redirecting to certain help link in wiki + // redirecting to certain help link in wiki Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); if (puzzle == null) { return; @@ -539,35 +720,35 @@ private void helpTutorial() { default: url = "https://github.com/Bram-Hub/Legup/wiki/LEGUP-Tutorial"; } - Runtime rt = Runtime.getRuntime(); try { - //rt.exec("rundll32 url.dll,FileProtocolHandler "+url); java.awt.Desktop.getDesktop().browse(java.net.URI.create(url)); - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); } } - //add the new function need to implement + // unfinished public void add_drop() { // add the mouse event then we can use the new listener to implement and // we should create a need jbuttom for it to ship the rule we select. JPanel panel = new JPanel(); JButton moveing_buttom = new JButton(); moveing_buttom.setFocusPainted(false); - moveing_buttom.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - //get the selected rule - } - }); + moveing_buttom.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // get the selected rule + } + }); panel.add(moveing_buttom); - } - - // Quick save proof to the current file with a pop window to show "successfully saved" + /** + * Saves the puzzle using the current file name and shows a message dialog to + * confirm that the save operation was successful. If the puzzle or exporter is null, or if + * an error occurs during export, the method will catch the exception and print the stack trace. + */ private void saveProofChange() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); if (puzzle == null) { @@ -582,27 +763,32 @@ private void saveProofChange() { } exporter.exportPuzzle(fileName); // Save confirmation - JOptionPane.showMessageDialog(null, "Successfully Saved", "Confirm", JOptionPane.INFORMATION_MESSAGE); - } - catch (ExportFileException e) { + JOptionPane.showMessageDialog( + null, "Successfully Saved", "Confirm", JOptionPane.INFORMATION_MESSAGE); + } catch (ExportFileException e) { e.printStackTrace(); } } - } - - //ask to edu.rpi.legup.save current proof + /** + * Displays a confirmation dialog with a specified message. Returns {@code true} if the user + * selects "No" or cancels the action, and {@code false} if the user selects "Yes". + * + * @param instr the message to display in the confirmation dialog + * @return {@code true} if the user chooses not to quit, {@code false} otherwise + */ public boolean noquit(String instr) { int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION); return n != JOptionPane.YES_OPTION; } /** - * Sets the main content for the edu.rpi.legup.user interface + * Configures the layout and components for the main user interface. This includes setting up + * panels, split panes, and borders, and adding them to the main content pane. */ protected void setupContent() { -// JPanel consoleBox = new JPanel(new BorderLayout()); + // JPanel consoleBox = new JPanel(new BorderLayout()); JPanel treeBox = new JPanel(new BorderLayout()); JPanel ruleBox = new JPanel(new BorderLayout()); @@ -612,13 +798,15 @@ protected void setupContent() { treePanel = new TreePanel(); - dynamicBoardView = new DynamicView(new ScrollView(new BoardController()), DynamicViewType.BOARD); + dynamicBoardView = + new DynamicView(new ScrollView(new BoardController()), DynamicViewType.BOARD); TitledBorder titleBoard = BorderFactory.createTitledBorder("Board"); titleBoard.setTitleJustification(TitledBorder.CENTER); dynamicBoardView.setBorder(titleBoard); JPanel boardPanel = new JPanel(new BorderLayout()); - topHalfPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, ruleFrame, dynamicBoardView); + topHalfPanel = + new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, ruleFrame, dynamicBoardView); mainPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, topHalfPanel, treePanel); topHalfPanel.setPreferredSize(new Dimension(600, 400)); mainPanel.setPreferredSize(new Dimension(600, 600)); @@ -631,107 +819,197 @@ protected void setupContent() { ruleBox.add(boardPanel); treeBox.add(ruleBox); this.add(treeBox); -// consoleBox.add(treeBox); -// -// getContentPane().add(consoleBox); - -// JPopupPanel popupPanel = new JPopupPanel(); -// setGlassPane(popupPanel); -// popupPanel.setVisible(true); mainPanel.setDividerLocation(mainPanel.getMaximumDividerLocation() + 100); -// frame.pack(); + revalidate(); } - private void setupToolBar() { - setToolBarButtons(new JButton[ToolbarName.values().length]); - for (int i = 0; i < ToolbarName.values().length; i++) { - String toolBarName = ToolbarName.values()[i].toString(); - URL resourceLocation = ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/" + toolBarName + ".png"); + /** + * Initializes the first toolbar, configures its appearance, and adds an 'Open' button + * with an associated icon. An action listener is attached to the button to trigger the loading of + * a puzzle when clicked. + */ + private void setupToolBar1() { + toolBar1 = new JToolBar(); + toolBar1.setFloatable(false); + toolBar1.setRollover(true); + setToolBar2Buttons(new JButton[1]); + + URL open_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Open.png"); + + // Scale the image icons down to make the buttons smaller + ImageIcon OpenImageIcon = new ImageIcon(open_url); + Image OpenImage = OpenImageIcon.getImage(); + OpenImageIcon = + new ImageIcon( + OpenImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton open = new JButton("Open", OpenImageIcon); + open.setFocusPainted(false); + + open.addActionListener((ActionEvent) -> loadPuzzle()); + + getToolBar2Buttons()[0] = open; + toolBar1.add(getToolBar2Buttons()[0]); + + this.add(toolBar1, BorderLayout.NORTH); + } - // Scale the image icons down to make the buttons smaller - ImageIcon imageIcon = new ImageIcon(resourceLocation); - Image image = imageIcon.getImage(); - imageIcon = new ImageIcon(image.getScaledInstance(this.TOOLBAR_ICON_SCALE, this.TOOLBAR_ICON_SCALE, Image.SCALE_SMOOTH)); + /** + * Initializes the second toolbar, configures its appearance, and adds four buttons each + * with associated icons. Action listeners are attached to each button to trigger their respective + * actions when clicked: + *

    + *
  • 'Directions' button triggers the `directionsToolButton` method.
  • + *
  • 'Undo' button triggers the undo action in the puzzle's history.
  • + *
  • 'Redo' button triggers the redo action in the puzzle's history.
  • + *
  • 'Check' button triggers the `checkProof` method.
  • + *
+ */ + private void setupToolBar2() { + toolBar2 = new JToolBar(); + toolBar2.setFloatable(false); + toolBar2.setRollover(true); + setToolBar2Buttons(new JButton[4]); + + URL directions_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Directions.png"); + + ImageIcon DirectionsImageIcon = new ImageIcon(directions_url); + Image DirectionsImage = DirectionsImageIcon.getImage(); + DirectionsImageIcon = + new ImageIcon( + DirectionsImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton directions = new JButton("Directions", DirectionsImageIcon); + directions.setFocusPainted(false); + directions.addActionListener((ActionEvent) -> directionsToolButton()); + + getToolBar2Buttons()[0] = directions; + toolBar2.add(getToolBar2Buttons()[0]); + + URL undo_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Undo.png"); + + ImageIcon UndoImageIcon = new ImageIcon(undo_url); + Image UndoImage = UndoImageIcon.getImage(); + UndoImageIcon = + new ImageIcon( + UndoImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton undo = new JButton("Undo", UndoImageIcon); + undo.setFocusPainted(false); + undo.addActionListener((ActionEvent) -> GameBoardFacade.getInstance().getHistory().undo()); + + getToolBar2Buttons()[1] = undo; + toolBar2.add(getToolBar2Buttons()[1]); + + URL redo_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Redo.png"); + + ImageIcon RedoImageIcon = new ImageIcon(redo_url); + Image RedoImage = RedoImageIcon.getImage(); + RedoImageIcon = + new ImageIcon( + RedoImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton redo = new JButton("Redo", RedoImageIcon); + redo.setFocusPainted(false); + redo.addActionListener((ActionEvent) -> { + GameBoardFacade.getInstance().getHistory().redo(); + }); - JButton button = new JButton(toolBarName, imageIcon); - button.setFocusPainted(false); - getToolBarButtons()[i] = button; - } + getToolBar2Buttons()[2] = redo; + toolBar2.add(getToolBar2Buttons()[2]); - toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); + URL check_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Check.png"); - for (int i = 0; i < getToolBarButtons().length; i++) { - for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) { - if (i == TOOLBAR_SEPARATOR_BEFORE[s]) { - toolBar.addSeparator(); - } - } - String toolBarName = ToolbarName.values()[i].toString(); + ImageIcon CheckImageIcon = new ImageIcon(check_url); + Image CheckImage = CheckImageIcon.getImage(); + CheckImageIcon = + new ImageIcon( + CheckImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); - toolBar.add(getToolBarButtons()[i]); - getToolBarButtons()[i].setToolTipText(toolBarName); + JButton check = new JButton("Check", CheckImageIcon); + check.setFocusPainted(false); + check.addActionListener((ActionEvent) -> checkProof()); - getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM); - getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER); - } + getToolBar2Buttons()[3] = check; + toolBar2.add(getToolBar2Buttons()[3]); -// toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent e) -> promptPuzzle()); -// toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) -> saveProof()); -// toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) -> GameBoardFacade.getInstance().getHistory().undo()); -// toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> GameBoardFacade.getInstance().getHistory().redo()); - toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> { - }); - toolBarButtons[ToolbarName.CHECK.ordinal()].addActionListener((ActionEvent e) -> checkProof()); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> { - }); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> { - }); - toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].addActionListener((ActionEvent e) -> checkProofAll()); + this.add(toolBar2, BorderLayout.NORTH); + } -// toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); -// toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); -// toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.CHECK_ALL.ordinal()].setEnabled(true); + /** + * Sets the toolbar1 buttons + * + * @param toolBar1Buttons toolbar buttons + */ + public void setToolBar1Buttons(JButton[] toolBar1Buttons) { + this.toolBar1Buttons = toolBar1Buttons; + } - this.add(toolBar, BorderLayout.NORTH); + /** + * Sets the toolbar2 buttons + * + * @param toolBar2Buttons toolbar buttons + */ + public void setToolBar2Buttons(JButton[] toolBar2Buttons) { + this.toolBar2Buttons = toolBar2Buttons; } /** - * Sets the toolbar buttons + * Gets the toolbar1 buttons * - * @param toolBarButtons toolbar buttons + * @return toolbar1 buttons */ - public void setToolBarButtons(JButton[] toolBarButtons) { - this.toolBarButtons = toolBarButtons; + public JButton[] getToolBar1Buttons() { + return toolBar1Buttons; } /** - * Gets the toolbar buttons + * Gets the toolbar2 buttons * - * @return toolbar buttons + * @return toolbar2 buttons */ - public JButton[] getToolBarButtons() { - return toolBarButtons; + public JButton[] getToolBar2Buttons() { + return toolBar2Buttons; } /** - * Checks the proof for correctness + * Uses the {@link GameBoardFacade} to obtain the current puzzle and board. If the puzzle is complete, + * it notifies the user of a correct proof. If not, it alerts the user that the board is not solved. */ private void checkProof() { GameBoardFacade facade = GameBoardFacade.getInstance(); Tree tree = GameBoardFacade.getInstance().getTree(); Board board = facade.getBoard(); Board finalBoard = null; - boolean delayStatus = true; //board.evalDelayStatus(); + boolean delayStatus = true; // board.evalDelayStatus(); repaintAll(); @@ -745,21 +1023,65 @@ private void checkProof() { submission.submit(); }*/ JOptionPane.showMessageDialog(null, "Congratulations! Your proof is correct."); - } - else { + } else { String message = "\nThe game board is not solved."; - JOptionPane.showMessageDialog(null, message, "Invalid proof.", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog( + null, message, "Invalid proof.", JOptionPane.ERROR_MESSAGE); + } + } + + /** + * Retrieves the puzzle name from the `GameBoardFacade` and opens a corresponding rules page in the default web browser. + * + * @throws IOException if an error occurs while trying to open the web page + */ + private void directionsToolButton() { + String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); + //System.out.println(puzzleName); + try { + if (puzzleName.equals("Fillapix")) { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Fill-a-pix-rules")); + } + else if (puzzleName.equals("LightUp")) { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Light-up-rules")); + } + else if (puzzleName.equals("TreeTent")) { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Tree-tent-rules")); + } + else if (puzzleName.equals("ShortTruthTables")) { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/Short-truth-table-rules")); + } + else { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki/" + puzzleName + "-rules")); + } + } catch (IOException e) { + LOGGER.error("Can't open web page"); } } + /** + * Repaints the board view and tree panel + */ private void repaintAll() { boardView.repaint(); treePanel.repaint(); } + /** + * Initializes the dynamic board view, updates the tree panel, and sets rules and search panels + * based on the provided puzzle. It also updates toolbars and reloads the GUI. + * + * @param puzzle the puzzle to be displayed + */ public void setPuzzleView(Puzzle puzzle) { this.boardView = puzzle.getBoardView(); + dynamicBoardView = new DynamicView(boardView, DynamicViewType.BOARD); this.topHalfPanel.setRightComponent(dynamicBoardView); this.topHalfPanel.setVisible(true); @@ -780,24 +1102,25 @@ public void setPuzzleView(Puzzle puzzle) { ruleFrame.getContradictionPanel().setRules(puzzle.getContradictionRules()); ruleFrame.getSearchPanel().setSearchBar(puzzle); - - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); -// toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true); - + toolBar1.setVisible(false); + setupToolBar2(); reloadGui(); } + /** + * Calls {@code repaintTree()} to refresh the tree view. + */ public void reloadGui() { repaintTree(); } - + /** + * Updates the tree view displayed in the tree panel to reflect the current state of the tree. + */ public void repaintTree() { treePanel.repaintTreeView(GameBoardFacade.getInstance().getTree()); } - /** - * Checks the proof for all files - */ + /** Checks the proof for all files */ private void checkProofAll() { GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -812,7 +1135,8 @@ private void checkProofAll() { */ LegupPreferences preferences = LegupPreferences.getInstance(); - File preferredDirectory = new File(preferences.getUserPref(LegupPreferences.WORK_DIRECTORY)); + File preferredDirectory = + new File(preferences.getUserPref(LegupPreferences.WORK_DIRECTORY)); folderBrowser = new JFileChooser(preferredDirectory); folderBrowser.showOpenDialog(this); @@ -830,13 +1154,13 @@ private void checkProofAll() { writer.append("Name,File Name,Puzzle Type,Score,Solved?\n"); // Go through student folders - for (final File folderEntry : Objects.requireNonNull(folder.listFiles(File::isDirectory))) { + for (final File folderEntry : + Objects.requireNonNull(folder.listFiles(File::isDirectory))) { // Write path String path = folderEntry.getName(); traverseDir(folderEntry, writer, path); } - } - catch (IOException ex) { + } catch (IOException ex) { LOGGER.error(ex.getMessage()); } JOptionPane.showMessageDialog(null, "Batch grading complete."); @@ -846,6 +1170,15 @@ private boolean basicCheckProof(int[][] origCells) { return false; } + /** + * Traverses a given directory, grades the proofs found in the directory, and writes the results + * to the specified CSV writer. + * + * @param folder the folder to traverse + * @param writer the CSV writer + * @param path the current path in the directory traversal + * @throws IOException if an error occurs while writing to the CSV file + */ private void traverseDir(File folder, BufferedWriter writer, String path) throws IOException { // Recursively traverse directory GameBoardFacade facade = GameBoardFacade.getInstance(); @@ -888,35 +1221,48 @@ private void traverseDir(File folder, BufferedWriter writer, String path) throws writer.append(puzzle.getName()).append(","); if (puzzle.isPuzzleComplete()) { writer.append("1,Solved\n"); - } - else { + } else { writer.append("0,Unsolved\n"); } - } - catch (InvalidFileFormatException e) { + } catch (InvalidFileFormatException e) { writer.append(fName).append(",Invalid,,Ungradeable\n"); } - } - else { + } else { LOGGER.debug("Failed to run sim"); } } } + /** + * Returns the current board view. + * + * @return the current {@link BoardView} + */ public BoardView getBoardView() { return boardView; } + + /** + * Returns the current dynamic board view. + * + * @return the current {@link DynamicView} + */ public DynamicView getDynamicBoardView() { return dynamicBoardView; } + /** + * Returns the current tree panel. + * + * @return the current {@link TreePanel} + */ public TreePanel getTreePanel() { return treePanel; } /** - * Called when a action is pushed onto the edu.rpi.legup.history stack + * Called when an action is pushed onto the edu.rpi.legup.history stack * * @param command action to push onto the stack */ @@ -924,9 +1270,7 @@ public TreePanel getTreePanel() { public void onPushChange(ICommand command) { LOGGER.info("Pushing " + command.getClass().getSimpleName() + " to stack."); undo.setEnabled(true); -// toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(true); redo.setEnabled(false); -// toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); @@ -934,34 +1278,28 @@ public void onPushChange(ICommand command) { } /** - * Called when the history is cleared + * Updates the state of the undo and redo buttons to reflect that there are no actions + * available to undo or redo. It disables both buttons when the history is cleared. */ @Override public void onClearHistory() { - //undo.setEnabled(false); -// toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); - //redo.setEnabled(false); -// toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); } /** * Called when an action is redone * * @param isBottom true if there are no more actions to undo, false otherwise - * @param isTop true if there are no more changes to redo, false otherwise + * @param isTop true if there are no more changes to redo, false otherwise */ @Override public void onRedo(boolean isBottom, boolean isTop) { undo.setEnabled(!isBottom); -// toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(!isBottom); redo.setEnabled(!isTop); -// toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(!isTop); if (isBottom) { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); frame.setTitle(puzzleName + " - " + puzzleFile.getName()); - } - else { + } else { String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); frame.setTitle(puzzleName + " - " + puzzleFile.getName() + " *"); @@ -972,44 +1310,47 @@ public void onRedo(boolean isBottom, boolean isTop) { * Called when an action is undone * * @param isBottom true if there are no more actions to undo, false otherwise - * @param isTop true if there are no more changes to redo, false otherwise + * @param isTop true if there are no more changes to redo, false otherwise */ @Override public void onUndo(boolean isBottom, boolean isTop) { undo.setEnabled(!isBottom); -// toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(!isBottom); redo.setEnabled(!isTop); -// toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(!isTop); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); File puzzleFile = new File(GameBoardFacade.getInstance().getCurFileName()); if (isBottom) { frame.setTitle(puzzleName + " - " + puzzleFile.getName()); - } - else { + } else { frame.setTitle(puzzleName + " - " + puzzleFile.getName() + " *"); } } - /** - * Submits the proof file - */ + /** Submits the proof file */ private void submit() { GameBoardFacade facade = GameBoardFacade.getInstance(); Board board = facade.getBoard(); - boolean delayStatus = true; //board.evalDelayStatus(); + boolean delayStatus = true; // board.evalDelayStatus(); repaintAll(); Puzzle pm = facade.getPuzzleModule(); if (pm.isPuzzleComplete() && delayStatus) { // 0 means yes, 1 means no (Java's fault...) - int confirm = JOptionPane.showConfirmDialog(null, "Are you sure you wish to submit?", "Proof Submission", JOptionPane.YES_NO_OPTION); + int confirm = + JOptionPane.showConfirmDialog( + null, + "Are you sure you wish to submit?", + "Proof Submission", + JOptionPane.YES_NO_OPTION); if (confirm == 0) { Submission submission = new Submission(board); submission.submit(); } - } - else { - JOptionPane.showConfirmDialog(null, "Your proof is incorrect! Are you sure you wish to submit?", "Proof Submission", JOptionPane.YES_NO_OPTION); + } else { + JOptionPane.showConfirmDialog( + null, + "Your proof is incorrect! Are you sure you wish to submit?", + "Proof Submission", + JOptionPane.YES_NO_OPTION); Submission submit = new Submission(board); } } @@ -1018,6 +1359,10 @@ public void showStatus(String status, boolean error, int timer) { // TODO: implement } + + /** + * Zooms the tree view to fit within the available screen space + */ protected void fitTreeViewToScreen() { this.treePanel.getTreeView().zoomFit(); } diff --git a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java index 2c4f37c85..2f3c16eac 100644 --- a/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java +++ b/src/main/java/edu/rpi/legup/ui/PuzzleEditorPanel.java @@ -1,27 +1,24 @@ package edu.rpi.legup.ui; +import static java.lang.System.exit; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.controller.BoardController; import edu.rpi.legup.controller.EditorElementController; -import edu.rpi.legup.controller.ElementController; import edu.rpi.legup.history.ICommand; import edu.rpi.legup.history.IHistoryListener; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.PuzzleExporter; -import edu.rpi.legup.model.gameboard.PuzzleElement; -import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentType; +import edu.rpi.legup.model.tree.Tree; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.save.ExportFileException; import edu.rpi.legup.save.InvalidFileFormatException; +import edu.rpi.legup.ui.HomePanel; import edu.rpi.legup.ui.boardview.BoardView; +import edu.rpi.legup.ui.proofeditorui.treeview.TreeViewSelection; import edu.rpi.legup.ui.puzzleeditorui.elementsview.ElementFrame; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.swing.*; -import javax.swing.border.TitledBorder; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -32,33 +29,54 @@ import java.net.URL; import java.util.List; import java.util.Objects; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; -import static java.lang.System.exit; - +/** + * Represents the panel used for puzzle editor in the LEGUP. + * This panel includes a variety of UI components such as toolbars, menus, and split panes. + * It handles puzzle file operations, including creating and editing puzzles. + */ public class PuzzleEditorPanel extends LegupPanel implements IHistoryListener { - private final static Logger LOGGER = LogManager.getLogger(PuzzleEditorPanel.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(PuzzleEditorPanel.class.getName()); private JMenu[] menus; private JMenuItem helpLegup, aboutLegup; private JMenuBar menuBar; - private JToolBar toolBar; + private JToolBar toolBar1; + private JToolBar toolBar2; + private JFileChooser folderBrowser; private JFrame frame; private JButton[] buttons; JSplitPane splitPanel; - private JButton[] toolBarButtons; + private JButton[] toolBar1Buttons; + private JButton[] toolBar2Buttons; private JPanel elementPanel; private DynamicView dynamicBoardView; private BoardView boardView; private TitledBorder boardBorder; - //private JSplitPane splitPanel, topHalfPanel; + // private JSplitPane splitPanel, topHalfPanel; private FileDialog fileDialog; private JMenuItem undo, redo, fitBoardToScreen; private ElementFrame elementFrame; private JPanel treePanel; private LegupUI legupUI; private EditorElementController editorElementController; - final static int[] TOOLBAR_SEPARATOR_BEFORE = {2, 4, 8}; + private CreatePuzzleDialog cpd; + private HomePanel hp; + private boolean existingPuzzle; + private String fileName; + private File puzzleFile; + /** + * Constructs a {@code PuzzleEditorPanel} with the specified file dialog, frame, and Legup UI instance + * + * @param fileDialog the file dialog used for file operations + * @param frame the main application frame + * @param legupUI the Legup UI instance + */ public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { this.fileDialog = fileDialog; this.frame = frame; @@ -67,6 +85,10 @@ public PuzzleEditorPanel(FileDialog fileDialog, JFrame frame, LegupUI legupUI) { setPreferredSize(new Dimension(800, 700)); } + /** + * Sets up the content of the panel, including the layout and UI components. + * Initializes and configures the {@code DynamicView} and {@code ElementFrame}, and adds them to the panel. + */ protected void setupContent() { JSplitPane splitPanel; JPanel elementBox = new JPanel(new BorderLayout()); @@ -75,13 +97,15 @@ protected void setupContent() { elementFrame = new ElementFrame(editorElementController); elementBox.add(elementFrame, BorderLayout.WEST); - dynamicBoardView = new DynamicView(new ScrollView(new BoardController()), DynamicViewType.BOARD); + dynamicBoardView = + new DynamicView(new ScrollView(new BoardController()), DynamicViewType.BOARD); TitledBorder titleBoard = BorderFactory.createTitledBorder("Board"); titleBoard.setTitleJustification(TitledBorder.CENTER); dynamicBoardView.setBorder(titleBoard); JPanel boardPanel = new JPanel(new BorderLayout()); - splitPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, elementFrame, dynamicBoardView); + splitPanel = + new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, elementFrame, dynamicBoardView); splitPanel.setPreferredSize(new Dimension(600, 400)); boardPanel.add(splitPanel); @@ -96,6 +120,11 @@ protected void setupContent() { revalidate(); } + /** + * Configures the menu bar with menus and menu items for the application. + * Adds actions for opening, creating, and exiting puzzles. + * Also sets up help and about menu items. + */ public void setMenuBar() { String os = LegupUI.getOS(); menuBar = new JMenuBar(); @@ -107,37 +136,45 @@ public void setMenuBar() { menus[0] = new JMenu("File"); // file>new - JMenuItem newPuzzle = new JMenuItem("New"); - newPuzzle.addActionListener((ActionEvent) -> loadPuzzle()); + JMenuItem openPuzzle = new JMenuItem("Open"); + openPuzzle.addActionListener((ActionEvent) -> loadPuzzle()); if (os.equals("mac")) { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('N', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('N', InputEvent.CTRL_DOWN_MASK)); - } - // file>save - JMenuItem savePuzzle = new JMenuItem("Save As"); - savePuzzle.addActionListener((ActionEvent) -> savePuzzle()); - JMenuItem directSavePuzzle = new JMenuItem("Direct Save Proof "); - directSavePuzzle.addActionListener((ActionEvent) -> direct_save()); + openPuzzle.setAccelerator( + KeyStroke.getKeyStroke( + 'O', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { + openPuzzle.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.CTRL_DOWN_MASK)); + } + // file>create + JMenuItem createPuzzle = new JMenuItem("Create"); + createPuzzle.addActionListener((ActionEvent) -> { + hp = new HomePanel(this.frame, this.legupUI); + cpd = new CreatePuzzleDialog(this.frame, hp); + cpd.setLocationRelativeTo(null); + cpd.setVisible(true); + existingPuzzle = false; + }); if (os.equals("mac")) { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('D', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { - newPuzzle.setAccelerator(KeyStroke.getKeyStroke('D', InputEvent.CTRL_DOWN_MASK)); + createPuzzle.setAccelerator( + KeyStroke.getKeyStroke( + 'C', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { + createPuzzle.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_DOWN_MASK)); } + JMenuItem exit = new JMenuItem("Exit"); exit.addActionListener((ActionEvent) -> exitEditor()); if (os.equals("mac")) { - exit.setAccelerator(KeyStroke.getKeyStroke('Q', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + exit.setAccelerator( + KeyStroke.getKeyStroke( + 'Q', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { exit.setAccelerator(KeyStroke.getKeyStroke('Q', InputEvent.CTRL_DOWN_MASK)); } - menus[0].add(newPuzzle); - menus[0].add(savePuzzle); - menus[0].add(directSavePuzzle); + menus[0].add(openPuzzle); + menus[0].add(createPuzzle); + //menus[0].add(directSavePuzzle); menus[0].add(exit); // EDIT @@ -148,44 +185,64 @@ public void setMenuBar() { redo = new JMenuItem("Redo"); fitBoardToScreen = new JMenuItem("Fit Board to Screen"); - menus[1].add(undo); - undo.addActionListener((ActionEvent) -> - GameBoardFacade.getInstance().getHistory().undo()); + // TODO: Undo operation currently does not get updated correctly in history + //menus[1].add(undo); + undo.addActionListener((ActionEvent) -> GameBoardFacade.getInstance().getHistory().undo()); if (os.equals("mac")) { - undo.setAccelerator(KeyStroke.getKeyStroke('Z', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - } - else { + undo.setAccelerator( + KeyStroke.getKeyStroke( + 'Z', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + } else { undo.setAccelerator(KeyStroke.getKeyStroke('Z', InputEvent.CTRL_DOWN_MASK)); } - menus[1].add(redo); - + // TODO: Redo operation currently does not get updated correctly in history + //menus[1].add(redo); // Created action to support two keybinds (CTRL-SHIFT-Z, CTRL-Y) - Action redoAction = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - GameBoardFacade.getInstance().getHistory().redo(); - } - }; + Action redoAction = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + GameBoardFacade.getInstance().getHistory().redo(); + } + }; if (os.equals("mac")) { - redo.getInputMap(WHEN_IN_FOCUSED_WINDOW).put( - KeyStroke.getKeyStroke('Z', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + InputEvent.SHIFT_DOWN_MASK), "redoAction"); - redo.getInputMap(WHEN_IN_FOCUSED_WINDOW).put( - KeyStroke.getKeyStroke('Y', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "redoAction"); - redo.setAccelerator(KeyStroke.getKeyStroke('Z', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + InputEvent.SHIFT_DOWN_MASK)); - } - else { - redo.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('Y', InputEvent.CTRL_DOWN_MASK), "redoAction"); - redo.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('Z', InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK), "redoAction"); + redo.getInputMap(WHEN_IN_FOCUSED_WINDOW) + .put( + KeyStroke.getKeyStroke( + 'Z', + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + + InputEvent.SHIFT_DOWN_MASK), + "redoAction"); + redo.getInputMap(WHEN_IN_FOCUSED_WINDOW) + .put( + KeyStroke.getKeyStroke( + 'Y', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), + "redoAction"); + redo.setAccelerator( + KeyStroke.getKeyStroke( + 'Z', + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + + InputEvent.SHIFT_DOWN_MASK)); + } else { + redo.getInputMap(WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke('Y', InputEvent.CTRL_DOWN_MASK), "redoAction"); + redo.getInputMap(WHEN_IN_FOCUSED_WINDOW) + .put( + KeyStroke.getKeyStroke( + 'Z', InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK), + "redoAction"); redo.getActionMap().put("redoAction", redoAction); // Button in menu will show CTRL-SHIFT-Z as primary keybind - redo.setAccelerator(KeyStroke.getKeyStroke('Z', InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)); + redo.setAccelerator( + KeyStroke.getKeyStroke( + 'Z', InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)); } - menus[1].add(fitBoardToScreen); - fitBoardToScreen.addActionListener((ActionEvent) -> dynamicBoardView.fitBoardViewToScreen()); + fitBoardToScreen.addActionListener( + (ActionEvent) -> dynamicBoardView.fitBoardViewToScreen()); // HELP menus[2] = new JMenu("Help"); @@ -193,18 +250,20 @@ public void actionPerformed(ActionEvent e) { aboutLegup = new JMenuItem("About Legup"); menus[2].add(helpLegup); menus[2].add(aboutLegup); - helpLegup.addActionListener(l -> { - try { - java.awt.Desktop.getDesktop().browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki")); - } - catch (IOException e) { - LOGGER.error("Can't open web page"); - } - }); + helpLegup.addActionListener( + l -> { + try { + java.awt.Desktop.getDesktop() + .browse(URI.create("https://github.com/Bram-Hub/LEGUP/wiki")); + } catch (IOException e) { + LOGGER.error("Can't open web page"); + } + }); menus[2].add(aboutLegup); - aboutLegup.addActionListener(l -> { - JOptionPane.showMessageDialog(null, "Version: 5.1.0"); - }); + aboutLegup.addActionListener( + l -> { + JOptionPane.showMessageDialog(null, "Version: 5.1.0"); + }); // add menus to menubar for (JMenu menu : menus) { menuBar.add(menu); @@ -212,6 +271,12 @@ public void actionPerformed(ActionEvent e) { frame.setJMenuBar(menuBar); } + /** + * Exits the puzzle editor and resets the application state to its initial condition. + * This method clears the current puzzle from the {@code GameBoardFacade}, + * resets the display to the initial panel, and nullifies references to the + * tree panel and board view. + */ public void exitEditor() { // Wipes the puzzle entirely as if LEGUP just started GameBoardFacade.getInstance().clearPuzzle(); @@ -220,160 +285,273 @@ public void exitEditor() { boardView = null; } + /** + * Makes the panel visible by setting up the toolbar, content, and menu bar. + * This method is called to refresh the panel's user interface. + */ @Override public void makeVisible() { this.removeAll(); - - setupToolBar(); + setupToolBar1(); setupContent(); setMenuBar(); } - private void setupToolBar() { - setToolBarButtons(new JButton[ToolbarName.values().length + 1]); - int lastone = 0; - for (int i = 0; i < ToolbarName.values().length - 1; i++) { - String toolBarName = ToolbarName.values()[i].toString(); - URL resourceLocation = ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/" + toolBarName + ".png"); - - // Scale the image icons down to make the buttons smaller - ImageIcon imageIcon = new ImageIcon(resourceLocation); - Image image = imageIcon.getImage(); - imageIcon = new ImageIcon(image.getScaledInstance(this.TOOLBAR_ICON_SCALE, this.TOOLBAR_ICON_SCALE, Image.SCALE_SMOOTH)); - - JButton button = new JButton(toolBarName, imageIcon); - button.setFocusPainted(false); - getToolBarButtons()[i] = button; - lastone = i; - } - - - URL check_and_save = ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/Check.png"); - ImageIcon imageIcon = new ImageIcon(check_and_save); - Image image = imageIcon.getImage(); - imageIcon = new ImageIcon(image.getScaledInstance(this.TOOLBAR_ICON_SCALE, this.TOOLBAR_ICON_SCALE, Image.SCALE_SMOOTH)); - - JButton checkandsave = new JButton("check and Save", imageIcon); - checkandsave.setFocusPainted(false); - checkandsave.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - //savePuzzle(); - String filename = savePuzzle(); - File puzzlename = new File(filename); - System.out.println(filename); - - - GameBoardFacade.getInstance().getLegupUI().displayPanel(1); - GameBoardFacade.getInstance().getLegupUI().getProofEditor().loadPuzzle(filename, new File(filename)); - String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); - frame.setTitle(puzzleName + " - " + puzzlename.getName()); - } + /** + * Sets up the first toolbar with buttons for opening and creating puzzles. + * This method initializes the toolbar buttons with their icons and actions. + */ + private void setupToolBar1() { + setToolBar1Buttons(new JButton[2]); + + URL open_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Open.png"); + ImageIcon OpenImageIcon = new ImageIcon(open_url); + Image OpenImage = OpenImageIcon.getImage(); + OpenImageIcon = + new ImageIcon( + OpenImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton open = new JButton("Open", OpenImageIcon); + open.setFocusPainted(false); + open.addActionListener((ActionEvent) -> loadPuzzle()); + + getToolBar1Buttons()[0] = open; + + toolBar1 = new JToolBar(); + toolBar1.setFloatable(false); + toolBar1.setRollover(true); + toolBar1.add(getToolBar1Buttons()[0]); + + URL create_url = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Open Puzzle.png"); + ImageIcon CreateImageIcon = new ImageIcon(create_url); + Image CreateImage = CreateImageIcon.getImage(); + CreateImageIcon = + new ImageIcon( + CreateImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton create = new JButton("Create", CreateImageIcon); + create.setFocusPainted(false); + create.addActionListener((ActionEvent) -> { + hp = new HomePanel(this.frame, this.legupUI); + cpd = new CreatePuzzleDialog(this.frame, hp); + cpd.setLocationRelativeTo(null); + cpd.setVisible(true); + existingPuzzle = false; }); - getToolBarButtons()[lastone + 1] = checkandsave; - System.out.println("it is create new file"); + getToolBar1Buttons()[1] = create; + toolBar1.setFloatable(false); + toolBar1.setRollover(true); + toolBar1.add(getToolBar1Buttons()[1]); - toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); + this.add(toolBar1, BorderLayout.NORTH); + } - for (int i = 0; i < getToolBarButtons().length - 1; i++) { - for (int s = 0; s < TOOLBAR_SEPARATOR_BEFORE.length; s++) { - if (i == TOOLBAR_SEPARATOR_BEFORE[s]) { - toolBar.addSeparator(); + /** + * Sets up the second toolbar with buttons for resetting, saving, and saving & solving puzzles. + * This method initializes the toolbar buttons with their icons and actions. + */ + private void setupToolBar2() { + toolBar2 = new JToolBar(); + toolBar2.setFloatable(false); + toolBar2.setRollover(true); + setToolBar2Buttons(new JButton[3]); + + URL reset = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Reset.png"); + ImageIcon ResetImageIcon = new ImageIcon(reset); + Image ResetImage = ResetImageIcon.getImage(); + ResetImageIcon = + new ImageIcon( + ResetImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton resetButton = new JButton("Reset", ResetImageIcon); + resetButton.setFocusPainted(false); + + resetButton.addActionListener( + a -> { + if (existingPuzzle) { + legupUI.getPuzzleEditor().loadPuzzle(fileName, puzzleFile); } - } - String toolBarName = ToolbarName.values()[i].toString(); - - toolBar.add(getToolBarButtons()[i]); - getToolBarButtons()[i].setToolTipText(toolBarName); - - getToolBarButtons()[i].setVerticalTextPosition(SwingConstants.BOTTOM); - getToolBarButtons()[i].setHorizontalTextPosition(SwingConstants.CENTER); - } - -// toolBarButtons[ToolbarName.OPEN_PUZZLE.ordinal()].addActionListener((ActionEvent e) -> promptPuzzle()); -// toolBarButtons[ToolbarName.SAVE.ordinal()].addActionListener((ActionEvent e) -> saveProof()); -// toolBarButtons[ToolbarName.UNDO.ordinal()].addActionListener((ActionEvent e) -> GameBoardFacade.getInstance().getHistory().undo()); -// toolBarButtons[ToolbarName.REDO.ordinal()].addActionListener((ActionEvent e) -> GameBoardFacade.getInstance().getHistory().redo()); - toolBarButtons[ToolbarName.HINT.ordinal()].addActionListener((ActionEvent e) -> { - }); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].addActionListener((ActionEvent e) -> { - }); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].addActionListener((ActionEvent e) -> { - }); - -// toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(false); -// toolBarButtons[ToolbarName.UNDO.ordinal()].setEnabled(false); -// toolBarButtons[ToolbarName.REDO.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.HINT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.SUBMIT.ordinal()].setEnabled(false); - toolBarButtons[ToolbarName.DIRECTIONS.ordinal()].setEnabled(false); - - this.add(toolBar, BorderLayout.NORTH); + else { + if (cpd.getGame().equals("ShortTruthTable")) { + GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), cpd.getTextArea()); + } + else { + GameBoardFacade.getInstance().loadPuzzle(cpd.getGame(), Integer.valueOf(cpd.getRows()), Integer.valueOf(cpd.getColumns())); + } + } + }); + + getToolBar2Buttons()[0] = resetButton; + toolBar2.add(getToolBar2Buttons()[0]); + + URL save_as = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Save.png"); + ImageIcon SaveAsImageIcon = new ImageIcon(save_as); + Image SaveAsImage = SaveAsImageIcon.getImage(); + SaveAsImageIcon = + new ImageIcon( + SaveAsImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton saveas = new JButton("Save As", SaveAsImageIcon); + saveas.setFocusPainted(false); + saveas.addActionListener((ActionEvent) -> savePuzzle()); + + getToolBar2Buttons()[1] = saveas; + toolBar2.add(getToolBar2Buttons()[1]); + + URL save_and_solve = + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Check.png"); + ImageIcon SaveSolveImageIcon = new ImageIcon(save_and_solve); + Image SaveSolveImage = SaveSolveImageIcon.getImage(); + SaveSolveImageIcon = + new ImageIcon( + SaveSolveImage.getScaledInstance( + this.TOOLBAR_ICON_SCALE, + this.TOOLBAR_ICON_SCALE, + Image.SCALE_SMOOTH)); + + JButton saveandsolve = new JButton("Save & Solve", SaveSolveImageIcon); + saveandsolve.setFocusPainted(false); + saveandsolve.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (GameBoardFacade.getInstance().getPuzzleModule() != null) { + String filename = savePuzzle(); + File puzzlename = new File(filename); + System.out.println(filename); + + GameBoardFacade.getInstance().getLegupUI().displayPanel(1); + GameBoardFacade.getInstance() + .getLegupUI() + .getProofEditor() + .loadPuzzle(filename, new File(filename)); + String puzzleName = + GameBoardFacade.getInstance().getPuzzleModule().getName(); + frame.setTitle(puzzleName + " - " + puzzlename.getName()); + } + } + }); + getToolBar2Buttons()[2] = saveandsolve; + toolBar2.add(getToolBar2Buttons()[2]); + + this.add(toolBar2, BorderLayout.NORTH); } - public void loadPuzzleFromHome(String game, int rows, int columns) throws IllegalArgumentException { + /** + * Initializes a puzzle based on the provided game name, rows, and columns. + * + * @param game the name of the game or puzzle to load + * @param rows the number of rows in the puzzle + * @param columns the number of columns in the puzzle + * @throws IllegalArgumentException if the provided arguments are invalid + */ + public void loadPuzzleFromHome(String game, int rows, int columns) + throws IllegalArgumentException { GameBoardFacade facade = GameBoardFacade.getInstance(); try { facade.loadPuzzle(game, rows, columns); - } - catch (IllegalArgumentException exception) { + } catch (IllegalArgumentException exception) { throw new IllegalArgumentException(exception.getMessage()); - } - catch (RuntimeException e) { + } catch (RuntimeException e) { e.printStackTrace(); LOGGER.error(e.getMessage()); } } + /** + * Initializes a puzzle based on the provided game name and an array of statements. + * + * @param game the name of the game or puzzle to load + * @param statements an array of statements to initialize the puzzle + * @throws IllegalArgumentException if the provided arguments are invalid + */ public void loadPuzzleFromHome(String game, String[] statements) { GameBoardFacade facade = GameBoardFacade.getInstance(); try { facade.loadPuzzle(game, statements); - } - catch (IllegalArgumentException exception) { + } catch (IllegalArgumentException exception) { throw new IllegalArgumentException(exception.getMessage()); - } - catch (RuntimeException e) { + } catch (RuntimeException e) { e.printStackTrace(); LOGGER.error(e.getMessage()); } } - // File opener + /** + * Prompts the user to select a puzzle file to open. + * Opens a file chooser dialog and returns the selected file's name and file object. + * If a puzzle is currently loaded, prompts the user to confirm if they want to open a new puzzle. + * + * @return an array containing the selected file name and file object, or null if the operation was canceled + */ public Object[] promptPuzzle() { GameBoardFacade facade = GameBoardFacade.getInstance(); if (facade.getBoard() != null) { - if (noQuit("Opening a new puzzle to edit?")) { + if (noQuit("Open an existing puzzle?")) { return new Object[0]; } } - if (fileDialog == null) { - fileDialog = new FileDialog(this.frame); - } + LegupPreferences preferences = LegupPreferences.getInstance(); String preferredDirectory = preferences.getUserPref(LegupPreferences.WORK_DIRECTORY); + if (preferences.getSavedPath() != "") { + preferredDirectory = preferences.getSavedPath(); + } - fileDialog.setMode(FileDialog.LOAD); - fileDialog.setTitle("Select Puzzle"); - fileDialog.setDirectory(preferredDirectory); - fileDialog.setVisible(true); + File preferredDirectoryFile = new File(preferredDirectory); + JFileChooser fileBrowser = new JFileChooser(preferredDirectoryFile); String fileName = null; File puzzleFile = null; - if (fileDialog.getDirectory() != null && fileDialog.getFile() != null) { - fileName = fileDialog.getDirectory() + File.separator + fileDialog.getFile(); - puzzleFile = new File(fileName); - } - else { + + fileBrowser.showOpenDialog(this); + fileBrowser.setVisible(true); + fileBrowser.setCurrentDirectory(new File(preferredDirectory)); + fileBrowser.setDialogTitle("Select Proof File"); + fileBrowser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + fileBrowser.setAcceptAllFileFilterUsed(false); + + File puzzlePath = fileBrowser.getSelectedFile(); + + if (puzzlePath != null) { + fileName = puzzlePath.getAbsolutePath(); + String lastDirectoryPath = fileName.substring(0, fileName.lastIndexOf(File.separator)); + preferences.setSavedPath(lastDirectoryPath); + puzzleFile = puzzlePath; + } else { // The attempt to prompt a puzzle ended gracefully (cancel) return null; } - return new Object[]{fileName, puzzleFile}; + return new Object[] {fileName, puzzleFile}; } + /** + * Loads a puzzle by prompting the user to select a puzzle file. + * If the user cancels the operation, no action is taken. If a puzzle file is selected, + * it will be loaded using the file name and file object. + */ public void loadPuzzle() { Object[] items = promptPuzzle(); // Return if items == null (cancel) @@ -385,6 +563,14 @@ public void loadPuzzle() { loadPuzzle(fileName, puzzleFile); } + /** + * Loads a puzzle from the specified file. + * If the puzzle file is valid and exists, it loads the puzzle and updates the UI. + * If the file format is invalid, an error message is displayed. + * + * @param fileName the name of the puzzle file + * @param puzzleFile the file object representing the puzzle file + */ public void loadPuzzle(String fileName, File puzzleFile) { if (puzzleFile != null && puzzleFile.exists()) { try { @@ -392,58 +578,119 @@ public void loadPuzzle(String fileName, File puzzleFile) { GameBoardFacade.getInstance().loadPuzzleEditor(fileName); String puzzleName = GameBoardFacade.getInstance().getPuzzleModule().getName(); frame.setTitle(puzzleName + " - " + puzzleFile.getName()); - } - catch (InvalidFileFormatException e) { + existingPuzzle = true; + this.fileName = fileName; + this.puzzleFile = puzzleFile; + } catch (InvalidFileFormatException e) { legupUI.displayPanel(0); LOGGER.error(e.getMessage()); - JOptionPane.showMessageDialog(null, "File does not exist, cannot be read, or cannot be edited", "Error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog( + null, + "File does not exist, cannot be read, or cannot be edited", + "Error", + JOptionPane.ERROR_MESSAGE); loadPuzzle(); } } } + /** + * Displays a confirmation dialog with the given instruction message. + * The method returns true if the user selected "No" or cancelled the dialog, + * and false if the user selected "Yes". + * + * @param instr the instruction message to display in the confirmation dialog + * @return true if the user selected "No" or canceled; false if the user selected "Yes" + */ public boolean noQuit(String instr) { int n = JOptionPane.showConfirmDialog(null, instr, "Confirm", JOptionPane.YES_NO_OPTION); return n != JOptionPane.YES_OPTION; } + /** + * {@inheritDoc} + */ @Override - public void onPushChange(ICommand command) { - - } + public void onPushChange(ICommand command) {} + /** + * {@inheritDoc} + */ @Override - public void onUndo(boolean isBottom, boolean isTop) { - - } + public void onUndo(boolean isBottom, boolean isTop) {} + /** + * {@inheritDoc} + */ @Override - public void onRedo(boolean isBottom, boolean isTop) { - - } + public void onRedo(boolean isBottom, boolean isTop) {} + /** + * {@inheritDoc} + */ @Override public void onClearHistory() { - //undo.setEnabled(false); - //redo.setEnabled(false); } + + /** + * Returns the current board view + * + * @return the board view + */ public BoardView getBoardView() { return boardView; } - public JButton[] getToolBarButtons() { - return toolBarButtons; + /** + * Returns the array of buttons for the first toolbar + * + * @return the array of toolbar1 buttons + */ + public JButton[] getToolBar1Buttons() { + return toolBar1Buttons; } - public void setToolBarButtons(JButton[] toolBarButtons) { - this.toolBarButtons = toolBarButtons; + /** + * Sets the array of buttons for the first toolbar + * + * @param toolBar1Buttons the array of toolbar1 buttons + */ + public void setToolBar1Buttons(JButton[] toolBar1Buttons) { + this.toolBar1Buttons = toolBar1Buttons; } + /** + * Returns the array of buttons for the second toolbar + * + * @return the array of toolbar2 buttons + */ + public JButton[] getToolBar2Buttons() { + return toolBar2Buttons; + } + + /** + * Sets the array of buttons for the second toolbar + * + * @param toolBar2Buttons the array of toolbar2 buttons + */ + public void setToolBar2Buttons(JButton[] toolBar2Buttons) { + this.toolBar2Buttons = toolBar2Buttons; + } + + /** + * Repaints the current board view + */ private void repaintAll() { boardView.repaint(); } + /** + * Sets the puzzle view based on the provided puzzle object. + * Updates the UI components to display the new puzzle. + * + * @param puzzle the puzzle object to display + */ public void setPuzzleView(Puzzle puzzle) { this.boardView = puzzle.getBoardView(); editorElementController.setElementController(boardView.getElementController()); @@ -453,24 +700,20 @@ public void setPuzzleView(Puzzle puzzle) { this.splitPanel.setVisible(true); } - TitledBorder titleBoard = BorderFactory.createTitledBorder(boardView.getClass().getSimpleName()); + TitledBorder titleBoard = + BorderFactory.createTitledBorder(boardView.getClass().getSimpleName()); titleBoard.setTitleJustification(TitledBorder.CENTER); dynamicBoardView.setBorder(titleBoard); puzzle.addBoardListener(puzzle.getBoardView()); - System.out.println("Setting elements"); if (this.elementFrame != null) { elementFrame.setElements(puzzle); } - - toolBarButtons[ToolbarName.CHECK.ordinal()].setEnabled(true); -// toolBarButtons[ToolbarName.SAVE.ordinal()].setEnabled(true); + toolBar1.setVisible(false); + setupToolBar2(); } - /** - * Saves a puzzle - */ - + /** Saves a puzzle */ private void direct_save() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); if (puzzle == null) { @@ -484,13 +727,19 @@ private void direct_save() { throw new ExportFileException("Puzzle exporter null"); } exporter.exportPuzzle(fileName); - } - catch (ExportFileException e) { + } catch (ExportFileException e) { e.printStackTrace(); } } } + /** + * Saves the current puzzle to a user-selected directory. + * Prompts the user to select a directory and saves the puzzle to that directory. + * Returns the path where the puzzle was saved. + * + * @return the path where the puzzle was saved, or an empty string if the save operation was canceled + */ private String savePuzzle() { Puzzle puzzle = GameBoardFacade.getInstance().getPuzzleModule(); if (puzzle == null) { @@ -500,54 +749,54 @@ private String savePuzzle() { // for TreeTent, need to check validity before saving if (Objects.equals(puzzle.getName(), "TreeTent")) { if (!puzzle.checkValidity()) { - int input = JOptionPane.showConfirmDialog(null, "The puzzle you edited is not " + - "valid, would you still like to save? "); + int input = + JOptionPane.showConfirmDialog( + null, + "The puzzle you edited is not " + + "valid, would you still like to save? "); if (input != 0) { return ""; } } } - if (fileDialog == null) { - fileDialog = new FileDialog(this.frame); - } - - fileDialog.setMode(FileDialog.SAVE); - fileDialog.setTitle("Save Proof"); - String curFileName = GameBoardFacade.getInstance().getCurFileName(); - if (curFileName == null) { - fileDialog.setDirectory(LegupPreferences.getInstance().getUserPref(LegupPreferences.WORK_DIRECTORY)); - } - else { - File curFile = new File(curFileName); - fileDialog.setDirectory(curFile.getParent()); - } - fileDialog.setVisible(true); - - String fileName = null; - if (fileDialog.getDirectory() != null && fileDialog.getFile() != null) { - fileName = fileDialog.getDirectory() + File.separator + fileDialog.getFile(); - } - - if (fileName != null) { + LegupPreferences preferences = LegupPreferences.getInstance(); + File preferredDirectory = + new File(preferences.getUserPref(LegupPreferences.WORK_DIRECTORY)); + if (preferences.getSavedPath() != "") { + preferredDirectory = new File(preferences.getSavedPath()); + } + folderBrowser = new JFileChooser(preferredDirectory); + + folderBrowser.showSaveDialog(this); + folderBrowser.setVisible(true); + folderBrowser.setCurrentDirectory(new File(LegupPreferences.WORK_DIRECTORY)); + folderBrowser.setDialogTitle("Select Directory"); + folderBrowser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + folderBrowser.setAcceptAllFileFilterUsed(false); + + String path = folderBrowser.getSelectedFile().getAbsolutePath(); + preferences.setSavedPath(path); + if (path != null) { try { PuzzleExporter exporter = puzzle.getExporter(); if (exporter == null) { throw new ExportFileException("Puzzle exporter null"); } - exporter.exportPuzzle(fileName); - } - catch (ExportFileException e) { + exporter.exportPuzzle(path); + } catch (ExportFileException e) { e.printStackTrace(); } } - return fileName; + return path; } - + /** + * Returns the current dynamic board view + * + * @return the dynamic board view + */ public DynamicView getDynamicBoardView() { return dynamicBoardView; } - - } diff --git a/src/main/java/edu/rpi/legup/ui/ScrollView.java b/src/main/java/edu/rpi/legup/ui/ScrollView.java index 8f9144fda..18aff4d1c 100644 --- a/src/main/java/edu/rpi/legup/ui/ScrollView.java +++ b/src/main/java/edu/rpi/legup/ui/ScrollView.java @@ -1,17 +1,17 @@ package edu.rpi.legup.ui; import edu.rpi.legup.controller.Controller; - import java.awt.*; -import java.lang.Double; - import java.util.TreeSet; import java.util.logging.Logger; - import javax.swing.*; +/** + * ScrollView extends {@link JScrollPane} to provide a customizable view with zoom and scroll capabilities. + * It uses a {@link ZoomablePane} as the canvas and allows for zooming and scrolling with respect to the canvas content. + */ public class ScrollView extends JScrollPane { - private final static Logger LOGGER = Logger.getLogger(ScrollView.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ScrollView.class.getName()); private static final double minScale = 0.25; private static final double maxScale = 4.0; @@ -28,8 +28,8 @@ public class ScrollView extends JScrollPane { private ZoomWidget widget; /** - * ScrollView Constructor - creates a ScrollView object using - * the controller handle the ui events + * ScrollView Constructor - creates a ScrollView object using the controller handle the ui + * events * * @param controller controller that handles the ui events */ @@ -107,9 +107,7 @@ public void layoutContainer(Container parent) { }; } - /** - * Updates zoomSize and view viewSize with the new scale - */ + /** Updates zoomSize and view viewSize with the new scale */ private void updateSize() { zoomSize.setSize((int) (viewSize.width * scale), (int) (viewSize.height * scale)); viewport.setViewSize(zoomSize); @@ -118,7 +116,7 @@ private void updateSize() { /** * Updates the viewport position * - * @param point point to set the viewport to + * @param point point to set the viewport to * @param magnification magnification to set the viewport to */ public void updatePosition(Point point, double magnification) { @@ -131,13 +129,16 @@ public void updatePosition(Point point, double magnification) { /** * Zooms in or out on a position within the dynamicView * - * @param n level of zoom - n less than 0 is zoom in, n greater than 0 is zoom out + * @param n level of zoom - n less than 0 is zoom in, n greater than 0 is zoom out * @param point position to zoom in on */ public void zoom(int n, Point point) { // if no Point is given, keep current center if (point == null) { - point = new Point(viewport.getWidth() / 2 + viewport.getX(), viewport.getHeight() / 2 + viewport.getY()); + point = + new Point( + viewport.getWidth() / 2 + viewport.getX(), + viewport.getHeight() / 2 + viewport.getY()); } // magnification level double mag = (double) n * 1.05; @@ -153,8 +154,7 @@ public void zoom(int n, Point point) { updateSize(); updatePosition(point, mag); // zoom out - } - else { + } else { mag = 1 / mag; // check zoom bounds if (scale * mag < minScale) { @@ -169,6 +169,11 @@ public void zoom(int n, Point point) { revalidate(); } + /** + * Adjusts the zoom level to the given scale and centers the viewport on the current center point + * + * @param newScale the new scale to set + */ public void zoomTo(double newScale) { // check zoom bounds if (newScale < minScale) { @@ -182,8 +187,10 @@ public void zoomTo(double newScale) { } // calculate the newScale and center point double mag = newScale / scale; - Point p = new Point(viewport.getWidth() / 2 + viewport.getX(), - viewport.getHeight() / 2 + viewport.getY()); + Point p = + new Point( + viewport.getWidth() / 2 + viewport.getX(), + viewport.getHeight() / 2 + viewport.getY()); // set scale directly scale = newScale; @@ -192,8 +199,7 @@ public void zoomTo(double newScale) { updateSize(); updatePosition(p, mag); // zoom out - } - else { + } else { updatePosition(p, mag); updateSize(); } @@ -201,9 +207,7 @@ public void zoomTo(double newScale) { revalidate(); } - /** - * Get the ideal zoom based on the viewSize - */ + /** Get the ideal zoom based on the viewSize */ public void zoomFit() { if (viewport.getWidth() != 0 && viewport.getHeight() != 0) { double fitWidth = (viewport.getWidth() - 8.0) / viewSize.width; @@ -213,9 +217,7 @@ public void zoomFit() { } } - /** - * Zooms in to the next zoom level - */ + /** Zooms in to the next zoom level */ public void zoomIn() { // find the next valid zoom level Double newScale = zoomLevels.higher(scale); @@ -224,9 +226,7 @@ public void zoomIn() { } } - /** - * Zooms out to the previous zoom level - */ + /** Zooms out to the previous zoom level */ public void zoomOut() { // find the next valid zoom level Double newScale = zoomLevels.lower(scale); @@ -291,6 +291,11 @@ public void setSize(Dimension size) { updateSize(); } + /** + * Gets the canvas for this {@code ScrollView} + * + * @return the ZoomablePane instance used as the canvas + */ public ZoomablePane getCanvas() { return canvas; } @@ -301,17 +306,18 @@ public ZoomablePane getCanvas() { * @param graphics2D Graphics2D object used for drawing */ protected void draw(Graphics2D graphics2D) { - graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - graphics2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + graphics2D.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.setRenderingHint( + RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); canvas.paint(graphics2D); } /** * Scroll up or down on the ScrollView * - * @param mag The magnitude for scroll up - * positive is scroll up, negative is scroll down, - * recommend to use getWheelRotation() as the mag + * @param mag The magnitude for scroll up positive is scroll up, negative is scroll down, + * recommend to use getWheelRotation() as the mag */ public void scroll(int mag) { Point point = super.viewport.getViewPosition(); diff --git a/src/main/java/edu/rpi/legup/ui/ToolbarName.java b/src/main/java/edu/rpi/legup/ui/ToolbarName.java index 3df635b05..53936a141 100644 --- a/src/main/java/edu/rpi/legup/ui/ToolbarName.java +++ b/src/main/java/edu/rpi/legup/ui/ToolbarName.java @@ -1,7 +1,12 @@ package edu.rpi.legup.ui; +/** + * This enum defines constants for toolbar names used in the user interface. + * Each represents a specific toolbar action. + */ public enum ToolbarName { - HINT, CHECK, SUBMIT, DIRECTIONS, CHECK_ALL; + DIRECTIONS, + CHECK; /** * Gets the String representation of the ToolbarName enum @@ -15,12 +20,12 @@ public String toString() { str = str.substring(0, 1).toUpperCase() + str.substring(1); for (int i = 0; i < str.length(); i++) { if (str.charAt(i) == ' ') { - str = str.substring(0, i + 1) + - str.substring(i + 1, i + 2).toUpperCase() + - str.substring(i + 2); + str = + str.substring(0, i + 1) + + str.substring(i + 1, i + 2).toUpperCase() + + str.substring(i + 2); } } return str; } - } diff --git a/src/main/java/edu/rpi/legup/ui/WrapLayout.java b/src/main/java/edu/rpi/legup/ui/WrapLayout.java index c37eb02f4..1e25b36d2 100644 --- a/src/main/java/edu/rpi/legup/ui/WrapLayout.java +++ b/src/main/java/edu/rpi/legup/ui/WrapLayout.java @@ -1,29 +1,25 @@ package edu.rpi.legup.ui; +import java.awt.*; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; -import java.awt.*; -/** - * FlowLayout subclass that fully supports wrapping of components. - */ +/** FlowLayout subclass that fully supports wrapping of components. */ public class WrapLayout extends FlowLayout { private Dimension preferredLayoutSize; /** - * Constructs a new WrapLayout with a left - * alignment and a default 5-unit horizontal and vertical gap. + * Constructs a new WrapLayout with a left alignment and a default 5-unit + * horizontal and vertical gap. */ public WrapLayout() { super(LEFT); } /** - * Constructs a new FlowLayout with the specified - * alignment and a default 5-unit horizontal and vertical gap. - * The value of the alignment argument must be one of - * WrapLayout, WrapLayout, - * or WrapLayout. + * Constructs a new FlowLayout with the specified alignment and a default 5-unit + * horizontal and vertical gap. The value of the alignment argument must be one of + * WrapLayout, WrapLayout, or WrapLayout. * * @param align the alignment value */ @@ -32,28 +28,27 @@ public WrapLayout(int align) { } /** - * Creates a new flow layout manager with the indicated alignment - * and the indicated horizontal and vertical gaps. - *

- * The value of the alignment argument must be one of - * WrapLayout, WrapLayout, - * or WrapLayout. + * Creates a new flow layout manager with the indicated alignment and the indicated horizontal + * and vertical gaps. + * + *

The value of the alignment argument must be one of WrapLayout, + * WrapLayout + * , or WrapLayout. * * @param align the alignment value - * @param hgap the horizontal gap between components - * @param vgap the vertical gap between components + * @param hgap the horizontal gap between components + * @param vgap the vertical gap between components */ public WrapLayout(int align, int hgap, int vgap) { super(align, hgap, vgap); } /** - * Returns the preferred dimensions for this layout given the - * visible components in the specified target container. + * Returns the preferred dimensions for this layout given the visible components in the + * specified target container. * * @param target the component which needs to be laid out - * @return the preferred dimensions to lay out the - * subcomponents of the specified container + * @return the preferred dimensions to lay out the subcomponents of the specified container */ @Override public Dimension preferredLayoutSize(Container target) { @@ -61,12 +56,11 @@ public Dimension preferredLayoutSize(Container target) { } /** - * Returns the minimum dimensions needed to layout the visible - * components contained in the specified target container. + * Returns the minimum dimensions needed to layout the visible components contained in the + * specified target container. * * @param target the component which needs to be laid out - * @return the minimum dimensions to lay out the - * subcomponents of the specified container + * @return the minimum dimensions to lay out the subcomponents of the specified container */ @Override public Dimension minimumLayoutSize(Container target) { @@ -76,10 +70,9 @@ public Dimension minimumLayoutSize(Container target) { } /** - * Returns the minimum or preferred dimension needed to layout the target - * container. + * Returns the minimum or preferred dimension needed to layout the target container. * - * @param target target to get layout dimension for + * @param target target to get layout dimension for * @param preferred should preferred dimension be calculated * @return the dimension to layout the target container */ @@ -155,11 +148,11 @@ private Dimension layoutSize(Container target, boolean preferred) { } /** - * A new row has been completed. Use the dimensions of this row - * to update the preferred dimension for the container. + * A new row has been completed. Use the dimensions of this row to update the preferred + * dimension for the container. * - * @param dim update the width and height when appropriate - * @param rowWidth the width of the row to add + * @param dim update the width and height when appropriate + * @param rowWidth the width of the row to add * @param rowHeight the height of the row to add */ private void addRow(Dimension dim, int rowWidth, int rowHeight) { @@ -171,4 +164,4 @@ private void addRow(Dimension dim, int rowWidth, int rowHeight) { dim.height += rowHeight; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java index 1e423c346..34e828250 100644 --- a/src/main/java/edu/rpi/legup/ui/ZoomWidget.java +++ b/src/main/java/edu/rpi/legup/ui/ZoomWidget.java @@ -2,25 +2,28 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; - +import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPopupMenu; import javax.swing.JSlider; import javax.swing.SwingConstants; -import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; -import javax.swing.ImageIcon; - +import javax.swing.event.ChangeListener; +/** + * The {@code ZoomWidget} displays a zoom icon that, when clicked, shows a popup slider to adjust + * the zoom level of the associated {@code ScrollView}. + */ public class ZoomWidget extends JLabel { private ScrollView parent; private PopupSlider palette = new PopupSlider(); - private MouseAdapter open = new MouseAdapter() { - public void mouseClicked(MouseEvent e) { - palette.slider.setValue(parent.getZoom()); - palette.show(e.getComponent(), 0, 0); - } - }; + private MouseAdapter open = + new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + palette.slider.setValue(parent.getZoom()); + palette.show(e.getComponent(), 0, 0); + } + }; /** * ZoomWidget Constructor creates a zoom widget for a ScrollView object @@ -34,13 +37,16 @@ public ZoomWidget(ScrollView parent) { } /** - * + * A {@code JPopupMenu} subclass that contains a vertical slider for adjusting zoom level. */ private class PopupSlider extends JPopupMenu implements ChangeListener { private static final long serialVersionUID = 8225019381200459814L; private JSlider slider; + /** + * Constructs a {@code PopupSlider} with a vertical slider + */ public PopupSlider() { slider = new JSlider(SwingConstants.VERTICAL, 0, 400, 200); slider.setMajorTickSpacing(25); @@ -50,6 +56,11 @@ public PopupSlider() { slider.addChangeListener(this); } + /** + * Handles state changes in the slider by adjusting the zoom level of the {@code ScrollView} + * + * @param e the {@code ChangeEvent} indicating that the slider's state has changed + */ public void stateChanged(ChangeEvent e) { if (slider.getValueIsAdjusting()) { parent.zoomTo((double) slider.getValue() / 100.0); diff --git a/src/main/java/edu/rpi/legup/ui/ZoomablePane.java b/src/main/java/edu/rpi/legup/ui/ZoomablePane.java index 86cfd866f..66af90abd 100644 --- a/src/main/java/edu/rpi/legup/ui/ZoomablePane.java +++ b/src/main/java/edu/rpi/legup/ui/ZoomablePane.java @@ -1,10 +1,14 @@ package edu.rpi.legup.ui; -import javax.swing.*; +import java.awt.AWTEvent; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.AWTEvent; +import javax.swing.*; +/** + * The {@code ZoomablePane} class is used to display components in a zoomable and scalable manner. + * It uses {@code ScrollView} to handle scaling and drawing of the content. + */ public class ZoomablePane extends JLayeredPane { private ScrollView viewer; diff --git a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java index 602672a9e..fa3ec70b7 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/BoardView.java @@ -8,10 +8,13 @@ import edu.rpi.legup.model.observer.IBoardListener; import edu.rpi.legup.model.tree.TreeElement; import edu.rpi.legup.ui.ScrollView; - import java.awt.*; import java.util.ArrayList; +/** + * An abstract class representing a view for a board in the puzzle game. + * It handles the visual representation and user interactions with the board elements. + */ public abstract class BoardView extends ScrollView implements IBoardListener { protected TreeElement treeElement; protected Board board; @@ -19,9 +22,9 @@ public abstract class BoardView extends ScrollView implements IBoardListener { protected ElementController elementController; protected ElementSelection selection; - /** - * BoardView Constructor creates a view for the board object using the controller handle the ui events + * BoardView Constructor creates a view for the board object using the controller handle the ui + * events * * @param boardController controller that handles the ui events * @param elementController controller that handles the ui events @@ -40,9 +43,7 @@ public BoardView(BoardController boardController, ElementController elementContr addKeyListener(elementController); } - /** - * Initializes the initial dimension of the viewport for the BoardView - */ + /** Initializes the initial dimension of the viewport for the BoardView */ public abstract void initSize(); /** @@ -70,13 +71,17 @@ public void setElementViews(ArrayList elements) { } /** - * Gets the ElementView from the location specified or null if one does not exists at that location + * Gets the ElementView from the location specified or null if one does not exists at that + * location * * @param point location on the viewport * @return ElementView at the specified location */ public ElementView getElement(Point point) { - Point scaledPoint = new Point((int) Math.round(point.x / getScale()), (int) Math.round(point.y / getScale())); + Point scaledPoint = + new Point( + (int) Math.round(point.x / getScale()), + (int) Math.round(point.y / getScale())); for (ElementView element : elementViews) { if (element.isWithinBounds(scaledPoint)) { return element; @@ -114,22 +119,26 @@ public void setBoard(Board board) { if (board instanceof CaseBoard) { setCasePickable(); - } - else { + } else { for (ElementView elementView : elementViews) { - elementView.setPuzzleElement(board.getPuzzleElement(elementView.getPuzzleElement())); + elementView.setPuzzleElement( + board.getPuzzleElement(elementView.getPuzzleElement())); elementView.setShowCasePicker(false); } } } } + /** + * Configures the view to handle case interactions + */ protected void setCasePickable() { CaseBoard caseBoard = (CaseBoard) board; Board baseBoard = caseBoard.getBaseBoard(); for (ElementView elementView : elementViews) { - PuzzleElement puzzleElement = baseBoard.getPuzzleElement(elementView.getPuzzleElement()); + PuzzleElement puzzleElement = + baseBoard.getPuzzleElement(elementView.getPuzzleElement()); elementView.setPuzzleElement(puzzleElement); elementView.setShowCasePicker(true); elementView.setCaseRulePickable(caseBoard.isPickable(puzzleElement, null)); @@ -181,15 +190,26 @@ public ArrayList getElementViews() { return elementViews; } + /** + * Gets the ElementController associated with this board view. + * + * @return the ElementController + */ public ElementController getElementController() { return elementController; } + @Override public void draw(Graphics2D graphics2D) { drawBoard(graphics2D); } + /** + * Draws the board and its elements. + * + * @param graphics2D the Graphics2D context used for drawing + */ public void drawBoard(Graphics2D graphics2D) { for (ElementView element : elementViews) { element.draw(graphics2D); @@ -206,5 +226,10 @@ public void onBoardDataChanged(PuzzleElement puzzleElement) { repaint(); } + /** + * Gets the selection popup menu for this board view. + * + * @return the DataSelectionView associated with this view + */ public abstract DataSelectionView getSelectionPopupMenu(); } diff --git a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java index 8257fd47c..a3d82b461 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/DataSelectionView.java @@ -1,13 +1,21 @@ package edu.rpi.legup.ui.boardview; import edu.rpi.legup.controller.ElementController; - +import java.awt.*; import javax.swing.*; import javax.swing.border.BevelBorder; -import java.awt.*; +/** + * DataSelectionView is a popup menu used for selecting data elements. + * It extends JPopupMenu and is styled with a gray background and a raised bevel border. + */ public class DataSelectionView extends JPopupMenu { + /** + * Constructs a DataSelectionView with the given controller. + * + * @param controller The ElementController to handle UI events. + */ public DataSelectionView(ElementController controller) { setBackground(Color.GRAY); setBorder(new BevelBorder(BevelBorder.RAISED)); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java index d8f88f979..9ad4132d6 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementSelection.java @@ -3,42 +3,72 @@ import java.awt.*; import java.util.ArrayList; +/** + * ElementSelection manages the selection and hover states of ElementViews. + * It maintains a list of selected elements, the currently hovered element, and the mouse point location. + */ public class ElementSelection { private ArrayList selection; private ElementView hover; private Point mousePoint; + /** + * Constructs an ElementSelection instance with an empty selection and no hover or mouse point + */ public ElementSelection() { this.selection = new ArrayList<>(); this.hover = null; this.mousePoint = null; } + /** + * Gets the list of currently selected ElementViews. + * + * @return the list of selected ElementViews + */ public ArrayList getSelection() { return selection; } + /** + * Gets the first ElementView in the selection, or null if the selection is empty. + * + * @return the first selected ElementView, or null if there are no selections + */ public ElementView getFirstSelection() { return selection.size() == 0 ? null : selection.get(0); } + /** + * Toggles the selection state of an ElementView. + * If the ElementView is currently selected, it is deselected. Otherwise, it is selected. + * + * @param elementView the ElementView to toggle + */ public void toggleSelection(ElementView elementView) { if (selection.contains(elementView)) { selection.remove(elementView); elementView.setSelected(false); - } - else { + } else { selection.add(elementView); elementView.setSelected(true); } } + /** + * Sets a new selection, clearing the previous selection and selecting the specified ElementView. + * + * @param elementView the ElementView to select + */ public void newSelection(ElementView elementView) { clearSelection(); selection.add(elementView); elementView.setSelected(true); } + /** + * Clears the selection and deselects all ElementViews + */ public void clearSelection() { for (ElementView elementView : selection) { elementView.setSelected(false); @@ -46,10 +76,20 @@ public void clearSelection() { selection.clear(); } + /** + * Gets the currently hovered ElementView. + * + * @return the currently hovered ElementView, or null if no element is hovered + */ public ElementView getHover() { return hover; } + /** + * Sets a new hovered ElementView, updating the hover state of the previous and new elements. + * + * @param newHovered the new ElementView to be hovered + */ public void newHover(ElementView newHovered) { newHovered.setHover(true); if (hover != null) { @@ -58,6 +98,9 @@ public void newHover(ElementView newHovered) { hover = newHovered; } + /** + * Clears the current hover state if there exists one + */ public void clearHover() { if (hover != null) { hover.setHover(false); @@ -65,10 +108,20 @@ public void clearHover() { } } + /** + * Gets the current mouse point location. + * + * @return the current mouse point location + */ public Point getMousePoint() { return mousePoint; } + /** + * Sets the mouse point location. + * + * @param point the new mouse point location + */ public void setMousePoint(Point point) { this.mousePoint = point; } diff --git a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java index 008c1a5f5..ad6cd3d3f 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/ElementView.java @@ -1,15 +1,18 @@ package edu.rpi.legup.ui.boardview; import edu.rpi.legup.model.gameboard.PuzzleElement; - -import javax.swing.*; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import javax.swing.*; +/** + * ElementView represents a visual representation of a PuzzleElement. + * It handles drawing, selection, hover states, and interaction with the PuzzleElement. + */ public abstract class ElementView implements Shape { protected int index; protected Point location; @@ -47,8 +50,10 @@ public ElementView(PuzzleElement puzzleElement) { * @return true if the point is within the ElementView, false otherwise */ public boolean isWithinBounds(Point point) { - return point.x >= location.x && point.x <= location.x + size.width && - point.y >= location.y && point.y <= location.y + size.height; + return point.x >= location.x + && point.x <= location.x + size.width + && point.y >= location.y + && point.y <= location.y + size.height; } /** @@ -72,9 +77,16 @@ public void draw(Graphics2D graphics2D) { } } + /** + * Draws the basic element representation (e.g., border, text) on the provided Graphics2D context. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawElement(Graphics2D graphics2D) { graphics2D.setStroke(new BasicStroke(1)); - graphics2D.draw(new Rectangle2D.Double(location.x + 0.5f, location.y + 0.5f, size.width - 2, size.height - 2)); + graphics2D.draw( + new Rectangle2D.Double( + location.x + 0.5f, location.y + 0.5f, size.width - 2, size.height - 2)); graphics2D.setColor(Color.BLACK); FontMetrics metrics = graphics2D.getFontMetrics(graphics2D.getFont()); @@ -84,29 +96,60 @@ public void drawElement(Graphics2D graphics2D) { graphics2D.drawString(String.valueOf(puzzleElement.getData()), xText, yText); } - public void drawGiven(Graphics2D graphics2D) { - - } + /** + * Draws additional elements for given PuzzleElements (default implementation does nothing). + * Overriden in some puzzle element views. + * + * @param graphics2D the Graphics2D context to use for drawing + */ + public void drawGiven(Graphics2D graphics2D) {} + /** + * Draws a hover effect on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawHover(Graphics2D graphics2D) { graphics2D.setColor(hoverColor); graphics2D.setStroke(new BasicStroke(2)); - graphics2D.draw(new Rectangle2D.Double(location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); + graphics2D.draw( + new Rectangle2D.Double( + location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Draws a modified effect on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawModified(Graphics2D graphics2D) { graphics2D.setColor(puzzleElement.isValid() ? modifiedColor : invalidColor); graphics2D.setStroke(new BasicStroke(2)); - graphics2D.draw(new Rectangle2D.Double(location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); + graphics2D.draw( + new Rectangle2D.Double( + location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Draws a case rule picker on the ElementView. + * + * @param graphics2D the Graphics2D context to use for drawing + */ public void drawCase(Graphics2D graphics2D) { graphics2D.setColor(caseColor); - graphics2D.fill(new Rectangle2D.Double(location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); + graphics2D.fill( + new Rectangle2D.Double( + location.x + 1.5f, location.y + 1.5f, size.width - 3, size.height - 3)); } + /** + * Creates an image representation of the ElementView. + * + * @return a BufferedImage of the ElementView + */ public BufferedImage getImage() { - BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB); + BufferedImage image = + new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB); Graphics2D graphics2D = image.createGraphics(); drawElement(graphics2D); graphics2D.dispose(); @@ -185,18 +228,27 @@ public void setPuzzleElement(PuzzleElement data) { this.puzzleElement = data; } + /** + * Checks if the case picker should be shown for this ElementView + * + * @return true if the case picker should be shown, false otherwise + */ public boolean isShowCasePicker() { return showCasePicker; } + /** + * Sets whether the case picker should be shown for this ElementView + * + * @param showCasePicker true if the case picker should be shown, false otherwise + */ public void setShowCasePicker(boolean showCasePicker) { this.showCasePicker = showCasePicker; } /** - * Gets the isCaseRulePickable field to determine if this ElementView - * should be highlighted in some way to indicate if it can be chosen by - * the CaseRule + * Gets the isCaseRulePickable field to determine if this ElementView should be highlighted in + * some way to indicate if it can be chosen by the CaseRule * * @return true if the ElementView can be chosen for the CaseRule, false otherwise */ @@ -205,11 +257,11 @@ public boolean isCaseRulePickable() { } /** - * Sets the isCaseRulePickable field to determine if this ElementView - * should be highlighted in some way to indicate if it can be chosen by - * the CaseRule + * Sets the isCaseRulePickable field to determine if this ElementView should be highlighted in + * some way to indicate if it can be chosen by the CaseRule * - * @param isCaseRulePickable true if the ElementView can be chosen for the CaseRule, false otherwise + * @param isCaseRulePickable true if the ElementView can be chosen for the CaseRule, false + * otherwise */ public void setCaseRulePickable(boolean isCaseRulePickable) { this.isCaseRulePickable = isCaseRulePickable; @@ -274,54 +326,134 @@ public JMenuItem getSelectionMenuItem() { return item; } + /** + * Determines if the specified point (x, y) is within the bounds of this ElementView + * + * @param x the x-coordinate of the point to check + * @param y the y-coordinate of the point to check + * @return {@code true} if the point is within the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean contains(double x, double y) { - return x >= location.x && x <= location.x + size.width && - y >= location.y && y <= location.y + size.height; + return x >= location.x + && x <= location.x + size.width + && y >= location.y + && y <= location.y + size.height; } + /** + * Determines if the specified Point2D object is within the bounds of this ElementView + * + * @param point the Point2D object representing the point to check + * @return {@code true} if the point is within the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean contains(Point2D point) { return contains(point.getX(), point.getY()); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this ElementView. + * + * @param x The x-coordinate of the rectangle to check + * @param y The y-coordinate of the rectangle to check + * @param width The width of the rectangle to check + * @param height The height of the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean intersects(double x, double y, double width, double height) { - return (x + width >= location.x && x <= location.x + size.width) || - (y + height >= location.y && y <= location.y + size.height); + return (x + width >= location.x && x <= location.x + size.width) + || (y + height >= location.y && y <= location.y + size.height); } + /** + * Determines if the specified Rectangle2D object intersects with the bounds of this ElementView. + * + * @param rectangle2D the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean intersects(Rectangle2D rectangle2D) { - return intersects(rectangle2D.getX(), rectangle2D.getY(), rectangle2D.getWidth(), rectangle2D.getHeight()); + return intersects( + rectangle2D.getX(), + rectangle2D.getY(), + rectangle2D.getWidth(), + rectangle2D.getHeight()); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this ElementView + * + * @param x the x-coordinate of the rectangle to check + * @param y the y-coordinate of the rectangle to check + * @param width the width of the rectangle to check + * @param height the height of the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean contains(double x, double y, double width, double height) { - return (x + width >= location.x && x <= location.x + size.width) && - (y + height >= location.y && y <= location.y + size.height); + return (x + width >= location.x && x <= location.x + size.width) + && (y + height >= location.y && y <= location.y + size.height); } + /** + * Determines if the specified Rectangle2D object is entirely contained within the bounds of this ElementView. + * + * @param rectangle2D the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this ElementView; {@code false} otherwise + */ @Override public boolean contains(Rectangle2D rectangle2D) { - return contains(rectangle2D.getX(), rectangle2D.getY(), rectangle2D.getWidth(), rectangle2D.getHeight()); + return contains( + rectangle2D.getX(), + rectangle2D.getY(), + rectangle2D.getWidth(), + rectangle2D.getHeight()); } + + /** + * Returns an iterator over the path geometry of this ElementView. The iterator provides access to the path's + * segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @return a PathIterator that iterates over the path geometry of this ElementView + */ @Override public PathIterator getPathIterator(AffineTransform at) { return new Rectangle(location.x, location.y, size.width, size.height).getPathIterator(at); } + /** + * Returns an iterator over the path geometry of this ElementView with the specified flatness. The iterator provides + * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @param flatness the maximum distance that the line segments can deviate from the true path + * @return a PathIterator that iterates over the path geometry of this ElementView + */ @Override public PathIterator getPathIterator(AffineTransform at, double flatness) { - return new Rectangle(location.x, location.y, size.width, size.height).getPathIterator(at, flatness); + return new Rectangle(location.x, location.y, size.width, size.height) + .getPathIterator(at, flatness); } + /** + * Returns the bounding rectangle of this ElementView + * + * @return a Rectangle representing the bounding box of this ElementView + */ @Override public Rectangle getBounds() { return new Rectangle(location.x, location.y, size.width, size.height); } + /** + * Returns the bounding rectangle of this ElementView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this ElementView + */ @Override public Rectangle2D getBounds2D() { return new Rectangle(location.x, location.y, size.width, size.height); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java index 5fdacc6b0..1baa34b3a 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/GridBoardView.java @@ -2,22 +2,30 @@ import edu.rpi.legup.controller.BoardController; import edu.rpi.legup.controller.ElementController; - import java.awt.Color; import java.awt.Dimension; +/** + * A view class for a grid-based board that displays elements in a grid layout. + * This class extends BoardView and is responsible for managing and rendering + * grid-based elements. + */ public class GridBoardView extends BoardView { protected Dimension gridSize; protected Dimension elementSize; /** - * GridBoardView Constructor creates a GridBoardView object using the controller handle the ui events + * GridBoardView Constructor creates a GridBoardView object using the controller handle the ui + * events * * @param boardController controller that handles the ui events * @param gridSize dimension of the grid * @param elementController controller that handles the ui events */ - public GridBoardView(BoardController boardController, ElementController elementController, Dimension gridSize) { + public GridBoardView( + BoardController boardController, + ElementController elementController, + Dimension gridSize) { this(boardController, elementController); this.gridSize = gridSize; this.elementSize = new Dimension(30, 30); @@ -25,7 +33,8 @@ public GridBoardView(BoardController boardController, ElementController elementC } /** - * GridBoardView Constructor creates a GridBoardView object using the controller handle the ui events + * GridBoardView Constructor creates a GridBoardView object using the controller handle the ui + * events * * @param boardController controller that handles the ui events */ @@ -35,8 +44,7 @@ private GridBoardView(BoardController boardController, ElementController element } /** - * Gets the GridElementView from the puzzleElement index or - * null if out of bounds + * Gets the GridElementView from the puzzleElement index or null if out of bounds * * @param index index of the ElementView * @return GridElementView at the specified index @@ -48,6 +56,14 @@ public GridElementView getElement(int index) { return null; } + /** + * Retrieves the GridElementView at the specified grid coordinates (xIndex, yIndex). + * Returns null if the coordinates are out of bounds. + * + * @param xIndex the x-coordinate (column) of the element view to retrieve + * @param yIndex the y-coordinate (row) of the element view to retrieve + * @return the GridElementView at the specified coordinates, or null if out of bounds + */ public GridElementView getElement(int xIndex, int yIndex) { if (xIndex < gridSize.width && yIndex < gridSize.height) { return (GridElementView) elementViews.get(yIndex * gridSize.width + xIndex); @@ -56,7 +72,8 @@ public GridElementView getElement(int xIndex, int yIndex) { } /** - * Initializes the initial dimension of the viewport for the GridBoardView + * Initializes the initial dimension of the viewport for the GridBoardView. + * Sets the size of the board view and adjusts the zoom to fit. */ @Override public void initSize() { @@ -65,9 +82,9 @@ public void initSize() { } /** - * Helper method to determine the proper dimension of the grid view + * Determines the proper dimension of the grid view based on grid size and element size. * - * @return proper dimension of the grid view + * @return the dimension of the grid view */ protected Dimension getProperSize() { Dimension boardViewSize = new Dimension(); @@ -76,13 +93,22 @@ protected Dimension getProperSize() { return boardViewSize; } + /** + * Retrieves the selection popup menu for data selection. + * Currently returns null as there is no implementation. + * + * @return null + */ public DataSelectionView getSelectionPopupMenu() { return null; } + /** + * Gets the size of each element in the grid + * + * @return the dimension of each element in the grid + */ public Dimension getElementSize() { return this.elementSize; } - } - diff --git a/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java b/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java index 440b3a693..31e8fcd6c 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/GridElementView.java @@ -2,6 +2,11 @@ import edu.rpi.legup.model.gameboard.GridCell; +/** + * A view class for a grid cell element in the board. + * This class extends ElementView and represents a specific type of element view + * associated with a GridCell. + */ public class GridElementView extends ElementView { public GridElementView(GridCell cell) { super(cell); diff --git a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java index 1ce5033c7..15deb86d1 100644 --- a/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java +++ b/src/main/java/edu/rpi/legup/ui/boardview/SelectionItemView.java @@ -1,31 +1,70 @@ package edu.rpi.legup.ui.boardview; import edu.rpi.legup.model.gameboard.PuzzleElement; - import javax.swing.*; +/** + * A menu item view class that represents a selectable item in a menu, associated with a PuzzleElement. + * This class extends JMenuItem and provides additional functionality to + * handle PuzzleElement data. + */ public class SelectionItemView extends JMenuItem { private PuzzleElement data; + /** + * Constructs a SelectionItemView with the specified PuzzleElement and icon. + * Initializes the menu item with the given icon and associates it with the + * provided PuzzleElement. + * + * @param data the PuzzleElement associated with this menu item + * @param icon the icon to be displayed on the menu item + */ public SelectionItemView(PuzzleElement data, Icon icon) { super(icon); this.data = data; } + /** + * Constructs a SelectionItemView with the specified PuzzleElement and display text. + * Initializes the menu item with the given display text and associates it with the + * provided PuzzleElement. + * + * @param data the PuzzleElement associated with this menu item + * @param display the text to be displayed on the menu item + */ public SelectionItemView(PuzzleElement data, String display) { super(display); this.data = data; } + /** + * Constructs a SelectionItemView with the specified PuzzleElement and display integer. + * Initializes the menu item with the integer converted to a string and associates it with + * the provided PuzzleElement. + * + * @param data the PuzzleElement associated with this menu item + * @param display the integer to be displayed on the menu item + */ public SelectionItemView(PuzzleElement data, int display) { super(String.valueOf(display)); this.data = data; } + /** + * Constructs a SelectionItemView with the specified PuzzleElement. + * Initializes the menu item with the data's integer representation as display text. + * + * @param data the PuzzleElement associated with this menu item + */ public SelectionItemView(PuzzleElement data) { this(data, (Integer) data.getData()); } + /** + * Gets the PuzzleElement associated with this menu item + * + * @return the PuzzleElement associated with this menu item + */ public PuzzleElement getData() { return data; } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/LegupLookAndFeel.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/LegupLookAndFeel.java index 84804e1a0..8469343f3 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/LegupLookAndFeel.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/LegupLookAndFeel.java @@ -5,20 +5,17 @@ import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialFonts; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialImages; - +import java.awt.*; import javax.swing.*; import javax.swing.plaf.basic.BasicLookAndFeel; -import java.awt.*; public class LegupLookAndFeel extends BasicLookAndFeel { /** - * Return a short string that identifies this look and feel, e.g. - * "CDE/Motif". This string should be appropriate for a menu item. - * Distinct look and feels should have different names, e.g. - * a subclass of MotifLookAndFeel that changes the way a few components - * are rendered should be called "CDE/Motif My Way"; something - * that would be useful to a user trying to select a L&F from a list - * of names. + * Return a short string that identifies this look and feel, e.g. "CDE/Motif". This string + * should be appropriate for a menu item. Distinct look and feels should have different names, + * e.g. a subclass of MotifLookAndFeel that changes the way a few components are rendered should + * be called "CDE/Motif My Way"; something that would be useful to a user trying to select a + * L&F from a list of names. * * @return short identifier for the look and feel */ @@ -28,13 +25,11 @@ public String getName() { } /** - * Return a string that identifies this look and feel. This string - * will be used by applications/services that want to recognize - * well known look and feel implementations. Presently - * the well known names are "Motif", "Windows", "Mac", "Metal". Note - * that a LookAndFeel derived from a well known superclass - * that doesn't make any fundamental changes to the look or feel - * shouldn't override this method. + * Return a string that identifies this look and feel. This string will be used by + * applications/services that want to recognize well known look and feel implementations. + * Presently the well known names are "Motif", "Windows", "Mac", "Metal". Note that a + * LookAndFeel derived from a well known superclass that doesn't make any fundamental changes to + * the look or feel shouldn't override this method. * * @return identifier for the look and feel */ @@ -44,9 +39,9 @@ public String getID() { } /** - * Return a one line description of this look and feel implementation, - * e.g. "The CDE/Motif Look and Feel". This string is intended for - * the user, e.g. in the title of a window or in a ToolTip message. + * Return a one line description of this look and feel implementation, e.g. "The CDE/Motif Look + * and Feel". This string is intended for the user, e.g. in the title of a window or in a + * ToolTip message. * * @return short description for the look and feel */ @@ -56,14 +51,11 @@ public String getDescription() { } /** - * If the underlying platform has a "native" look and feel, and - * this is an implementation of it, return {@code true}. For - * example, when the underlying platform is Solaris running CDE - * a CDE/Motif look and feel implementation would return {@code - * true}. + * If the underlying platform has a "native" look and feel, and this is an implementation of it, + * return {@code true}. For example, when the underlying platform is Solaris running CDE a + * CDE/Motif look and feel implementation would return {@code true}. * - * @return {@code true} if this look and feel represents the underlying - * platform look and feel + * @return {@code true} if this look and feel represents the underlying platform look and feel */ @Override public boolean isNativeLookAndFeel() { @@ -71,10 +63,9 @@ public boolean isNativeLookAndFeel() { } /** - * Return {@code true} if the underlying platform supports and or permits - * this look and feel. This method returns {@code false} if the look - * and feel depends on special resources or legal agreements that - * aren't defined for the current platform. + * Return {@code true} if the underlying platform supports and or permits this look and feel. + * This method returns {@code false} if the look and feel depends on special resources or legal + * agreements that aren't defined for the current platform. * * @return {@code true} if this is a supported look and feel * @see UIManager#setLookAndFeel @@ -85,16 +76,12 @@ public boolean isSupportedLookAndFeel() { } /** - * Initializes the look and feel. While this method is public, - * it should only be invoked by the {@code UIManager} when a - * look and feel is installed as the current look and feel. This - * method is invoked before the {@code UIManager} invokes - * {@code getDefaults}. This method is intended to perform any - * initialization for the look and feel. Subclasses - * should do any one-time setup they need here, rather than - * in a static initializer, because look and feel class objects - * may be loaded just to discover that {@code isSupportedLookAndFeel()} - * returns {@code false}. + * Initializes the look and feel. While this method is public, it should only be invoked by the + * {@code UIManager} when a look and feel is installed as the current look and feel. This method + * is invoked before the {@code UIManager} invokes {@code getDefaults}. This method is intended + * to perform any initialization for the look and feel. Subclasses should do any one-time setup + * they need here, rather than in a static initializer, because look and feel class objects may + * be loaded just to discover that {@code isSupportedLookAndFeel()} returns {@code false}. * * @see #uninitialize * @see UIManager#setLookAndFeel @@ -105,15 +92,12 @@ public void initialize() { } /** - * Populates {@code table} with mappings from {@code uiClassID} to the - * fully qualified name of the ui class. The value for a - * particular {@code uiClassID} is {@code - * "javax.swing.plaf.basic.Basic + uiClassID"}. For example, the - * value for the {@code uiClassID} {@code TreeUI} is {@code - * "javax.swing.plaf.basic.BasicTreeUI"}. + * Populates {@code table} with mappings from {@code uiClassID} to the fully qualified name of + * the ui class. The value for a particular {@code uiClassID} is {@code + * "javax.swing.plaf.basic.Basic + uiClassID"}. For example, the value for the {@code uiClassID} + * {@code TreeUI} is {@code "javax.swing.plaf.basic.BasicTreeUI"}. * - * @param table the {@code UIDefaults} instance the entries are - * added to + * @param table the {@code UIDefaults} instance the entries are added to * @throws NullPointerException if {@code table} is {@code null} * @see LookAndFeel * @see #getDefaults @@ -132,7 +116,7 @@ protected void initClassDefaults(UIDefaults table) { table.put("PanelUI", MaterialPanelUI.class.getCanonicalName()); table.put("LabelUI", MaterialLabelUI.class.getCanonicalName()); table.put("MenuItemUI", MaterialMenuItemUI.class.getCanonicalName()); -// table.put ("MenuBarUI", .class.getCanonicalName()); + // table.put ("MenuBarUI", .class.getCanonicalName()); table.put("MenuUI", MaterialMenuUI.class.getCanonicalName()); table.put("CheckBoxUI", MaterialCheckBoxUI.class.getCanonicalName()); table.put("RadioButtonUI", MaterialRadioButtonUI.class.getCanonicalName()); @@ -152,7 +136,7 @@ protected void initClassDefaults(UIDefaults table) { table.put("FileChooserUI", MaterialFileChooserUI.class.getCanonicalName()); table.put("ToolTipUI", MaterialToolTipUI.class.getCanonicalName()); table.put("SplitPaneUI", MaterialSplitPaneUI.class.getCanonicalName()); -// table.put ("ColorChooserUI", ); + // table.put ("ColorChooserUI", ); } @Override @@ -175,7 +159,11 @@ protected void initComponentDefaults(UIDefaults table) { table.put("ComboBox.font", MaterialFonts.REGULAR); table.put("ComboBox.background", Color.WHITE); table.put("ComboBox.foreground", Color.BLACK); - table.put("ComboBox.border", BorderFactory.createCompoundBorder(MaterialBorders.LIGHT_LINE_BORDER, BorderFactory.createEmptyBorder(0, 5, 0, 0))); + table.put( + "ComboBox.border", + BorderFactory.createCompoundBorder( + MaterialBorders.LIGHT_LINE_BORDER, + BorderFactory.createEmptyBorder(0, 5, 0, 0))); table.put("ComboBox.buttonBackground", MaterialColors.GRAY_300); table.put("ComboBox.selectionBackground", Color.WHITE); table.put("ComboBox.selectionForeground", Color.BLACK); @@ -251,7 +239,9 @@ protected void initComponentDefaults(UIDefaults table) { table.put("Slider.background", Color.WHITE); table.put("Slider.foreground", MaterialColors.GRAY_700); table.put("Slider.trackColor", Color.BLACK); -// table.put ("Slider.border", BorderFactory.createCompoundBorder(MaterialBorders.LIGHT_LINE_BORDER, BorderFactory.createEmptyBorder (5, 5, 5, 5))); + // table.put ("Slider.border", + // BorderFactory.createCompoundBorder(MaterialBorders.LIGHT_LINE_BORDER, + // BorderFactory.createEmptyBorder (5, 5, 5, 5))); table.put("SplitPane.border", MaterialBorders.LIGHT_LINE_BORDER); table.put("SplitPane.background", Color.WHITE); @@ -275,7 +265,11 @@ protected void initComponentDefaults(UIDefaults table) { table.put("Table.gridColor", MaterialColors.GRAY_200); table.put("TableHeader.background", MaterialColors.GRAY_200); table.put("TableHeader.font", MaterialFonts.BOLD); - table.put("TableHeader.cellBorder", BorderFactory.createCompoundBorder(MaterialBorders.LIGHT_LINE_BORDER, BorderFactory.createEmptyBorder(5, 5, 5, 5))); + table.put( + "TableHeader.cellBorder", + BorderFactory.createCompoundBorder( + MaterialBorders.LIGHT_LINE_BORDER, + BorderFactory.createEmptyBorder(5, 5, 5, 5))); table.put("TextArea.background", MaterialColors.GRAY_200); table.put("TextArea.border", BorderFactory.createEmptyBorder()); @@ -306,21 +300,27 @@ protected void initComponentDefaults(UIDefaults table) { table.put("RadioButtonMenuItem.foreground", Color.BLACK); table.put("RadioButtonMenuItem.selectionForeground", Color.BLACK); - //If it changes the background of the menuitem it must change this too, irrespective of its setting + // If it changes the background of the menuitem it must change this too, irrespective of its + // setting table.put("RadioButtonMenuItem.background", UIManager.getColor("MenuItem.background")); table.put("RadioButtonMenuItem.selectionBackground", MaterialColors.GRAY_200); table.put("RadioButtonMenuItem.border", BorderFactory.createEmptyBorder(5, 5, 5, 5)); table.put("RadioButtonMenuItem.checkIcon", new ImageIcon(MaterialImages.RADIO_BUTTON_OFF)); - table.put("RadioButtonMenuItem.selectedCheckIcon", new ImageIcon(MaterialImages.RADIO_BUTTON_ON)); + table.put( + "RadioButtonMenuItem.selectedCheckIcon", + new ImageIcon(MaterialImages.RADIO_BUTTON_ON)); - //If it changes the background of the menuitem it must change this too, irrespective of its setting + // If it changes the background of the menuitem it must change this too, irrespective of its + // setting table.put("CheckBoxMenuItem.background", UIManager.getColor("MenuItem.background")); table.put("CheckBoxMenuItem.selectionBackground", MaterialColors.GRAY_200); table.put("CheckBoxMenuItem.foreground", Color.BLACK); table.put("CheckBoxMenuItem.selectionForeground", Color.BLACK); table.put("CheckBoxMenuItem.border", BorderFactory.createEmptyBorder(5, 5, 5, 5)); table.put("CheckBoxMenuItem.checkIcon", new ImageIcon(MaterialImages.UNCHECKED_BOX)); - table.put("CheckBoxMenuItem.selectedCheckIcon", new ImageIcon(MaterialImages.PAINTED_CHECKED_BOX)); + table.put( + "CheckBoxMenuItem.selectedCheckIcon", + new ImageIcon(MaterialImages.PAINTED_CHECKED_BOX)); table.put("TextPane.border", MaterialBorders.LIGHT_LINE_BORDER); table.put("TextPane.background", MaterialColors.GRAY_50); diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/animation/MaterialUIMovement.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/animation/MaterialUIMovement.java index fe82238ab..db7d604a0 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/animation/MaterialUIMovement.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/animation/MaterialUIMovement.java @@ -1,12 +1,11 @@ package edu.rpi.legup.ui.lookandfeel.animation; -import javax.swing.JComponent; import java.awt.Color; +import javax.swing.JComponent; public class MaterialUIMovement { - private MaterialUIMovement() { - } + private MaterialUIMovement() {} public static void add(JComponent c, Color fadeTo, int steps, int interval) { new MaterialUITimer(c, fadeTo, steps, interval); diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/animation/MaterialUITimer.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/animation/MaterialUITimer.java index b5b3bbd76..f989185c7 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/animation/MaterialUITimer.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/animation/MaterialUITimer.java @@ -1,12 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.animation; -import javax.swing.JComponent; -import javax.swing.Timer; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import javax.swing.JComponent; +import javax.swing.Timer; public class MaterialUITimer implements MouseListener, ActionListener { @@ -72,14 +72,10 @@ public void mousePressed(MouseEvent me) { } @Override - public void mouseReleased(MouseEvent me) { - - } + public void mouseReleased(MouseEvent me) {} @Override - public void mouseClicked(MouseEvent me) { - - } + public void mouseClicked(MouseEvent me) {} @Override public void mouseExited(MouseEvent me) { @@ -100,8 +96,7 @@ public void actionPerformed(ActionEvent ae) { if (forward) { component.setBackground(nextColor()); ++alpha; - } - else { + } else { component.setBackground(previousColor()); --alpha; } @@ -110,4 +105,4 @@ public void actionPerformed(ActionEvent ae) { timer.stop(); } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialButtonUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialButtonUI.java index fe23536d3..debe6e215 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialButtonUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialButtonUI.java @@ -3,13 +3,12 @@ import edu.rpi.legup.ui.lookandfeel.animation.MaterialUIMovement; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.AbstractButton; import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicButtonUI; -import java.awt.Graphics; public class MaterialButtonUI extends BasicButtonUI { @@ -42,4 +41,4 @@ private void paintBackground(Graphics g, JComponent c) { g.setColor(c.getBackground()); g.fillRoundRect(0, 0, c.getWidth(), c.getHeight(), 7, 7); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialCheckBoxMenuItemUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialCheckBoxMenuItemUI.java index e5068a8ed..8f0df3604 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialCheckBoxMenuItemUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialCheckBoxMenuItemUI.java @@ -1,20 +1,18 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Color; +import java.awt.Graphics; import javax.swing.Icon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI; -import java.awt.Color; -import java.awt.Graphics; /** * @author https://github.com/vincenzopalazzo */ - public class MaterialCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { public static ComponentUI createUI(JComponent c) { @@ -32,12 +30,33 @@ public void paint(Graphics g, JComponent c) { } @Override - protected void paintMenuItem(Graphics g, JComponent c, Icon checkIcon, Icon arrowIcon, Color background, Color foreground, int defaultTextIconGap) { + protected void paintMenuItem( + Graphics g, + JComponent c, + Icon checkIcon, + Icon arrowIcon, + Color background, + Color foreground, + int defaultTextIconGap) { JCheckBoxMenuItem checkBoxMenuItem = (JCheckBoxMenuItem) c; if (checkBoxMenuItem.isSelected()) { - super.paintMenuItem(MaterialDrawingUtils.getAliasedGraphics(g), checkBoxMenuItem, UIManager.getIcon("CheckBoxMenuItem.selectedCheckIcon"), arrowIcon, background, foreground, defaultTextIconGap); + super.paintMenuItem( + MaterialDrawingUtils.getAliasedGraphics(g), + checkBoxMenuItem, + UIManager.getIcon("CheckBoxMenuItem.selectedCheckIcon"), + arrowIcon, + background, + foreground, + defaultTextIconGap); return; } - super.paintMenuItem(MaterialDrawingUtils.getAliasedGraphics(g), checkBoxMenuItem, UIManager.getIcon("CheckBoxMenuItem.checkIcon"), arrowIcon, background, foreground, defaultTextIconGap); + super.paintMenuItem( + MaterialDrawingUtils.getAliasedGraphics(g), + checkBoxMenuItem, + UIManager.getIcon("CheckBoxMenuItem.checkIcon"), + arrowIcon, + background, + foreground, + defaultTextIconGap); } } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialCheckBoxUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialCheckBoxUI.java index a85e9079e..4a9725d52 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialCheckBoxUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialCheckBoxUI.java @@ -1,15 +1,14 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicCheckBoxUI; -import java.awt.Graphics; -//TODO cambio colore icone combo box +// TODO cambio colore icone combo box public class MaterialCheckBoxUI extends BasicCheckBoxUI { public static ComponentUI createUI(JComponent c) { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialComboBoxRenderer.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialComboBoxRenderer.java index d6df89d44..73573d8f8 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialComboBoxRenderer.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialComboBoxRenderer.java @@ -1,23 +1,28 @@ package edu.rpi.legup.ui.lookandfeel.components; +import java.awt.Component; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicComboBoxRenderer; -import java.awt.Component; public class MaterialComboBoxRenderer extends BasicComboBoxRenderer { @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - JComponent component = (JComponent) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + public Component getListCellRendererComponent( + JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + JComponent component = + (JComponent) + super.getListCellRendererComponent( + list, value, index, isSelected, cellHasFocus); component.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); component.setForeground(UIManager.getColor("ComboBox.foreground")); - component.setBackground(isSelected || cellHasFocus ? - UIManager.getColor("ComboBox.selectedInDropDownBackground") : - UIManager.getColor("ComboBox.background")); + component.setBackground( + isSelected || cellHasFocus + ? UIManager.getColor("ComboBox.selectedInDropDownBackground") + : UIManager.getColor("ComboBox.background")); return component; } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialComboBoxUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialComboBoxUI.java index f9d6fa090..8cd52995b 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialComboBoxUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialComboBoxUI.java @@ -1,7 +1,7 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JButton; @@ -12,7 +12,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicArrowButton; import javax.swing.plaf.basic.BasicComboBoxUI; -import java.awt.Graphics; public class MaterialComboBoxUI extends BasicComboBoxUI { @@ -39,8 +38,7 @@ protected JButton createArrowButton() { JButton button; if (icon != null) { button = new JButton(icon); - } - else { + } else { button = new BasicArrowButton(SwingConstants.SOUTH); } button.setFocusPainted(false); diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialEditorPaneUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialEditorPaneUI.java index 92d6770e0..786f289bb 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialEditorPaneUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialEditorPaneUI.java @@ -7,7 +7,6 @@ /** * @author https://github.com/vincenzopalazzo */ - public class MaterialEditorPaneUI extends BasicEditorPaneUI { public static ComponentUI createUI(JComponent c) { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialFileChooserUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialFileChooserUI.java index 9a4ffc9d4..b8046c569 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialFileChooserUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialFileChooserUI.java @@ -2,13 +2,12 @@ import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialImages; - +import java.awt.Graphics; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.metal.MetalFileChooserUI; -import java.awt.Graphics; public class MaterialFileChooserUI extends MetalFileChooserUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialLabelUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialLabelUI.java index e06509a82..e19fc1fed 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialLabelUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialLabelUI.java @@ -1,13 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicLabelUI; -import java.awt.Graphics; public class MaterialLabelUI extends BasicLabelUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuBarUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuBarUI.java index 8d5625559..011d61862 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuBarUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuBarUI.java @@ -1,13 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JMenuBar; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicMenuBarUI; -import java.awt.Graphics; public class MaterialMenuBarUI extends BasicMenuBarUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuItemUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuItemUI.java index d7a23d1a3..a8c572b62 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuItemUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuItemUI.java @@ -1,14 +1,13 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicMenuItemUI; -import java.awt.Graphics; public class MaterialMenuItemUI extends BasicMenuItemUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuUI.java index 7461cbea0..16c1b9270 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialMenuUI.java @@ -1,13 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicMenuUI; -import java.awt.Graphics; public class MaterialMenuUI extends BasicMenuUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPanelUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPanelUI.java index cf786be3f..ae7a9be6b 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPanelUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPanelUI.java @@ -1,13 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicPanelUI; -import java.awt.Graphics; public class MaterialPanelUI extends BasicPanelUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPasswordFieldUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPasswordFieldUI.java index 61aa84fc7..d4778402b 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPasswordFieldUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPasswordFieldUI.java @@ -2,18 +2,6 @@ import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.BorderFactory; -import javax.swing.JComponent; -import javax.swing.JPasswordField; -import javax.swing.KeyStroke; -import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.basic.BasicPasswordFieldUI; -import javax.swing.text.Element; -import javax.swing.text.PasswordView; -import javax.swing.text.View; import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; @@ -26,8 +14,20 @@ import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPasswordField; +import javax.swing.KeyStroke; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicPasswordFieldUI; +import javax.swing.text.Element; +import javax.swing.text.PasswordView; +import javax.swing.text.View; -public class MaterialPasswordFieldUI extends BasicPasswordFieldUI implements FocusListener, PropertyChangeListener { +public class MaterialPasswordFieldUI extends BasicPasswordFieldUI + implements FocusListener, PropertyChangeListener { private Color focusedBackground; private Color unfocusedBackground; @@ -64,47 +64,65 @@ protected void installListeners() { protected void installKeyboardActions() { super.installKeyboardActions(); - Action selectAll = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - getComponent().selectAll(); - } - }; - - Action delete = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - if (getComponent().getSelectedText() == null) { - int pos = getComponent().getCaretPosition() - 1; - - if (pos >= 0) { - getComponent().select(pos, pos + 1); - getComponent().replaceSelection(""); + Action selectAll = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + getComponent().selectAll(); } - } - else { - getComponent().replaceSelection(""); - } - } - }; - - Action left = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - getComponent().setCaretPosition(Math.max(0, getComponent().getCaretPosition() - 1)); - } - }; - - Action right = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - getComponent().setCaretPosition(Math.min(getComponent().getText().length(), getComponent().getCaretPosition() + 1)); - } - }; - - // note getMenuShortcutKeyMask() is deprecated in Java 10 - change to getMenuShortcutKeyMaskEx() - getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "selectAll"); - getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), "delete"); + }; + + Action delete = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (getComponent().getSelectedText() == null) { + int pos = getComponent().getCaretPosition() - 1; + + if (pos >= 0) { + getComponent().select(pos, pos + 1); + getComponent().replaceSelection(""); + } + } else { + getComponent().replaceSelection(""); + } + } + }; + + Action left = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + getComponent() + .setCaretPosition( + Math.max(0, getComponent().getCaretPosition() - 1)); + } + }; + + Action right = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + getComponent() + .setCaretPosition( + Math.min( + getComponent().getText().length(), + getComponent().getCaretPosition() + 1)); + } + }; + + // note getMenuShortcutKeyMask() is deprecated in Java 10 - change to + // getMenuShortcutKeyMaskEx() + getComponent() + .getInputMap() + .put( + KeyStroke.getKeyStroke( + KeyEvent.VK_A, + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), + "selectAll"); + getComponent() + .getInputMap() + .put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), "delete"); getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left"); getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right"); @@ -122,15 +140,17 @@ public void paintSafely(Graphics g) { if (getComponent().hasFocus()) { c.setBackground(focusedBackground); c.setSelectionColor(focusedSelectionBackground); - } - else { + } else { c.setBackground(unfocusedBackground); c.setSelectionColor(unfocusedSelectionBackground); } int x = getComponent().getInsets().left; int y = getComponent().getInsets().top; - int w = getComponent().getWidth() - getComponent().getInsets().left - getComponent().getInsets().right; + int w = + getComponent().getWidth() + - getComponent().getInsets().left + - getComponent().getInsets().right; g.setColor(c.getBackground()); g.fillRect(x, c.getHeight() - y, w, 2); @@ -160,7 +180,8 @@ public void propertyChange(PropertyChangeEvent pce) { if (!newColor.equals(focusedBackground) && !newColor.equals(unfocusedBackground)) { this.focusedBackground = (Color) pce.getNewValue(); - this.focusedSelectionBackground = MaterialColors.bleach(this.focusedBackground, 0.3f); + this.focusedSelectionBackground = + MaterialColors.bleach(this.focusedBackground, 0.3f); } } } @@ -176,7 +197,9 @@ private MaterialPasswordView(Element elem) { super(elem); } - // depreciated in Java 9 and above - replace method with float drawEchoCharacter(Graphics2D g, float x, float y, char c) + // depreciated in Java 9 and above - replace method with float drawEchoCharacter(Graphics2D + // g, + // float x, float y, char c) @Override protected int drawEchoCharacter(Graphics g, int x, int y, char c) { Graphics2D g2 = (Graphics2D) g.create(); @@ -192,4 +215,4 @@ protected int drawEchoCharacter(Graphics g, int x, int y, char c) { return x + fm.charWidth(c); } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPopupMenuUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPopupMenuUI.java index 3fdb79961..d7baaf5df 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPopupMenuUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialPopupMenuUI.java @@ -1,13 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JPopupMenu; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicPopupMenuUI; -import java.awt.Graphics; public class MaterialPopupMenuUI extends BasicPopupMenuUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialProgressBarUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialProgressBarUI.java index 111b7ef92..7f91a779f 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialProgressBarUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialProgressBarUI.java @@ -3,17 +3,15 @@ import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialBorders; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JProgressBar; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicProgressBarUI; -import java.awt.Graphics; /** * @author https://github.com/vincenzopalazzo */ - public class MaterialProgressBarUI extends BasicProgressBarUI { public static ComponentUI createUI(JComponent c) { @@ -34,5 +32,4 @@ public void installUI(JComponent c) { public void paint(Graphics g, JComponent c) { super.paint(MaterialDrawingUtils.getAliasedGraphics(g), c); } - } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialRadioButtonMenuItemUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialRadioButtonMenuItemUI.java index d08e52f05..69a9cae53 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialRadioButtonMenuItemUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialRadioButtonMenuItemUI.java @@ -1,20 +1,18 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Color; +import java.awt.Graphics; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JRadioButtonMenuItem; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI; -import java.awt.Color; -import java.awt.Graphics; /** * @author https://github.com/vincenzopalazzo */ - public class MaterialRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI { public static ComponentUI createUI(JComponent c) { @@ -25,7 +23,7 @@ public static ComponentUI createUI(JComponent c) { public void installUI(JComponent c) { super.installUI(c); JRadioButtonMenuItem j = (JRadioButtonMenuItem) c; - //j.setBackground(MaterialColors.WHITE); + // j.setBackground(MaterialColors.WHITE); j.setBorder(UIManager.getBorder("MenuItem.border")); } @@ -35,12 +33,33 @@ public void paint(Graphics g, JComponent c) { } @Override - protected void paintMenuItem(Graphics g, JComponent c, Icon checkIcon, Icon arrowIcon, Color background, Color foreground, int defaultTextIconGap) { + protected void paintMenuItem( + Graphics g, + JComponent c, + Icon checkIcon, + Icon arrowIcon, + Color background, + Color foreground, + int defaultTextIconGap) { JRadioButtonMenuItem j = (JRadioButtonMenuItem) c; if (j.isSelected()) { - super.paintMenuItem(MaterialDrawingUtils.getAliasedGraphics(g), c, UIManager.getIcon("RadioButtonMenuItem.selectedCheckIcon"), arrowIcon, background, foreground, defaultTextIconGap); + super.paintMenuItem( + MaterialDrawingUtils.getAliasedGraphics(g), + c, + UIManager.getIcon("RadioButtonMenuItem.selectedCheckIcon"), + arrowIcon, + background, + foreground, + defaultTextIconGap); return; } - super.paintMenuItem(MaterialDrawingUtils.getAliasedGraphics(g), c, UIManager.getIcon("RadioButtonMenuItem.checkIcon"), arrowIcon, background, foreground, defaultTextIconGap); + super.paintMenuItem( + MaterialDrawingUtils.getAliasedGraphics(g), + c, + UIManager.getIcon("RadioButtonMenuItem.checkIcon"), + arrowIcon, + background, + foreground, + defaultTextIconGap); } } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialRadioButtonUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialRadioButtonUI.java index 047270369..6418d4f17 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialRadioButtonUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialRadioButtonUI.java @@ -1,18 +1,17 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JRadioButton; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicRadioButtonUI; -import java.awt.Graphics; /* * Contributed by https://github.com/downToHell * */ -//TODO cambio colore del radio button. +// TODO cambio colore del radio button. public class MaterialRadioButtonUI extends BasicRadioButtonUI { public static ComponentUI createUI(JComponent c) { @@ -35,4 +34,4 @@ public void installUI(JComponent c) { public void paint(Graphics g, JComponent c) { super.paint(MaterialDrawingUtils.getAliasedGraphics(g), c); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialScrollBarUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialScrollBarUI.java index 4bf5bbb0f..164209b3f 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialScrollBarUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialScrollBarUI.java @@ -1,7 +1,7 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JScrollBar; @@ -9,7 +9,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicArrowButton; import javax.swing.plaf.basic.BasicScrollBarUI; -import java.awt.Graphics; /* * Contributed by https://github.com/downToHell @@ -62,4 +61,4 @@ protected JButton createIncreaseButton(int orientation) { return button; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSeparatorUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSeparatorUI.java index 05cd5b60e..042b53d1b 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSeparatorUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSeparatorUI.java @@ -1,11 +1,10 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSeparatorUI; -import java.awt.Graphics; public class MaterialSeparatorUI extends BasicSeparatorUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSliderUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSliderUI.java index ab9d75484..7ac2fe350 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSliderUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSliderUI.java @@ -2,21 +2,21 @@ import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Dimension; +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JSlider; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSliderUI; -import java.awt.Dimension; -import java.awt.Graphics; -//TODO cambio grafica slider +// TODO cambio grafica slider public class MaterialSliderUI extends BasicSliderUI { private static final int NORMAL_THUMB_RADIUS = 6; private static final int DRAG_THUMB_RADIUS = 10; - private static final Dimension THUMB_SIZE = new Dimension(DRAG_THUMB_RADIUS * 2, DRAG_THUMB_RADIUS * 2); + private static final Dimension THUMB_SIZE = + new Dimension(DRAG_THUMB_RADIUS * 2, DRAG_THUMB_RADIUS * 2); public MaterialSliderUI(JSlider slider) { super(slider); @@ -81,33 +81,48 @@ public void paintTrack(Graphics g) { private Line getTrack(boolean loaded) { if (slider.getOrientation() == JSlider.HORIZONTAL) { - Line left = new Line(trackRect.x, thumbRect.y + thumbRect.height / 2, thumbRect.x + thumbRect.width / 2, thumbRect.y + thumbRect.height / 2); - Line right = new Line(thumbRect.x + thumbRect.width / 2, thumbRect.y + thumbRect.height / 2, trackRect.x + trackRect.width, thumbRect.y + thumbRect.height / 2); + Line left = + new Line( + trackRect.x, + thumbRect.y + thumbRect.height / 2, + thumbRect.x + thumbRect.width / 2, + thumbRect.y + thumbRect.height / 2); + Line right = + new Line( + thumbRect.x + thumbRect.width / 2, + thumbRect.y + thumbRect.height / 2, + trackRect.x + trackRect.width, + thumbRect.y + thumbRect.height / 2); if (loaded) { return slider.getInverted() ? right : left; - } - else { + } else { return slider.getInverted() ? left : right; } - } - else { - Line top = new Line(thumbRect.x + thumbRect.width / 2, trackRect.y, thumbRect.x + thumbRect.width / 2, thumbRect.y + thumbRect.height / 2); - Line bottom = new Line(thumbRect.x + thumbRect.width / 2, thumbRect.y + thumbRect.height / 2, thumbRect.x + thumbRect.width / 2, trackRect.y + trackRect.height); + } else { + Line top = + new Line( + thumbRect.x + thumbRect.width / 2, + trackRect.y, + thumbRect.x + thumbRect.width / 2, + thumbRect.y + thumbRect.height / 2); + Line bottom = + new Line( + thumbRect.x + thumbRect.width / 2, + thumbRect.y + thumbRect.height / 2, + thumbRect.x + thumbRect.width / 2, + trackRect.y + trackRect.height); if (loaded) { return slider.getInverted() ? top : bottom; - } - else { + } else { return slider.getInverted() ? bottom : top; } } } @Override - public void paintFocus(Graphics g) { - - } + public void paintFocus(Graphics g) {} @Override public void paint(Graphics g, JComponent c) { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSpinnerUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSpinnerUI.java index 0a74c9d99..ecfcbab17 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSpinnerUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSpinnerUI.java @@ -1,7 +1,8 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Component; +import java.awt.Graphics; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; @@ -11,8 +12,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicArrowButton; import javax.swing.plaf.basic.BasicSpinnerUI; -import java.awt.Component; -import java.awt.Graphics; public class MaterialSpinnerUI extends BasicSpinnerUI { @@ -51,8 +50,7 @@ protected Component createNextButton() { JButton button; if (icon != null) { button = new JButton(icon); - } - else { + } else { button = new BasicArrowButton(SwingConstants.NORTH); } button.setFocusPainted(false); @@ -70,8 +68,7 @@ protected Component createPreviousButton() { JButton button; if (icon != null) { button = new JButton(icon); - } - else { + } else { button = new BasicArrowButton(SwingConstants.SOUTH); } button.setFocusPainted(false); diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSplitPaneDivider.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSplitPaneDivider.java index 23d798644..0ec5db987 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSplitPaneDivider.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSplitPaneDivider.java @@ -6,18 +6,18 @@ public class MaterialSplitPaneDivider extends BasicSplitPaneDivider { public MaterialSplitPaneDivider(BasicSplitPaneUI ui) { super(ui); -// oneTouchSize = DefaultLookup.getInt(ui.getSplitPane(), ui, -// "SplitPane.oneTouchButtonSize", ONE_TOUCH_SIZE); -// oneTouchOffset = DefaultLookup.getInt(ui.getSplitPane(), ui, -// "SplitPane.oneTouchButtonOffset", ONE_TOUCH_OFFSET); -// centerOneTouchButtons = DefaultLookup.getBoolean(ui.getSplitPane(), -// ui, "SplitPane.centerOneTouchButtons", true); -// setLayout(new DividerLayout()); -// setBasicSplitPaneUI(ui); -// orientation = splitPane.getOrientation(); -// setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ? -// Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) : -// Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)); -// setBackground(UIManager.getColor("SplitPane.background")); + // oneTouchSize = DefaultLookup.getInt(ui.getSplitPane(), ui, + // "SplitPane.oneTouchButtonSize", ONE_TOUCH_SIZE); + // oneTouchOffset = DefaultLookup.getInt(ui.getSplitPane(), ui, + // "SplitPane.oneTouchButtonOffset", ONE_TOUCH_OFFSET); + // centerOneTouchButtons = DefaultLookup.getBoolean(ui.getSplitPane(), + // ui, "SplitPane.centerOneTouchButtons", true); + // setLayout(new DividerLayout()); + // setBasicSplitPaneUI(ui); + // orientation = splitPane.getOrientation(); + // setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ? + // Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) : + // Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)); + // setBackground(UIManager.getColor("SplitPane.background")); } } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSplitPaneUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSplitPaneUI.java index 90bd79b5e..33cee1316 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSplitPaneUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialSplitPaneUI.java @@ -15,13 +15,13 @@ public void installUI(JComponent c) { splitPane.setDividerSize(UIManager.getInt("SplitPane.dividerSize")); } -// /** -// * Creates the default divider. -// * -// * @return the default divider -// */ -// @Override -// public BasicSplitPaneDivider createDefaultDivider() { -// return new MaterialSplitPaneDivider(this); -// } + // /** + // * Creates the default divider. + // * + // * @return the default divider + // */ + // @Override + // public BasicSplitPaneDivider createDefaultDivider() { + // return new MaterialSplitPaneDivider(this); + // } } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTabbedPaneUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTabbedPaneUI.java index 0441cca35..878ed8479 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTabbedPaneUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTabbedPaneUI.java @@ -1,14 +1,13 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; +import java.awt.Rectangle; import javax.swing.JComponent; import javax.swing.JTabbedPane; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTabbedPaneUI; -import java.awt.Graphics; -import java.awt.Rectangle; public class MaterialTabbedPaneUI extends BasicTabbedPaneUI { @@ -38,25 +37,60 @@ public void paint(Graphics g, JComponent c) { } @Override - protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { + protected void paintTabBackground( + Graphics g, + int tabPlacement, + int tabIndex, + int x, + int y, + int w, + int h, + boolean isSelected) { g.setColor(isSelected ? lightHighlight : tabPane.getBackground()); g.fillRect(x, y, w, h); } @Override - protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { + protected void paintTabBorder( + Graphics g, + int tabPlacement, + int tabIndex, + int x, + int y, + int w, + int h, + boolean isSelected) { g.setColor(UIManager.getColor("TabbedPane.borderHighlightColor")); g.drawRect(x, y, w, h); } @Override - protected void paintFocusIndicator(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, boolean isSelected) { + protected void paintFocusIndicator( + Graphics g, + int tabPlacement, + Rectangle[] rects, + int tabIndex, + Rectangle iconRect, + Rectangle textRect, + boolean isSelected) { // do nothing } @Override - protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect) { + protected void paintTab( + Graphics g, + int tabPlacement, + Rectangle[] rects, + int tabIndex, + Rectangle iconRect, + Rectangle textRect) { // for some reason tabs aren't painted properly by paint() - super.paintTab(MaterialDrawingUtils.getAliasedGraphics(g), tabPlacement, rects, tabIndex, iconRect, textRect); + super.paintTab( + MaterialDrawingUtils.getAliasedGraphics(g), + tabPlacement, + rects, + tabIndex, + iconRect, + textRect); } } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableCellEditor.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableCellEditor.java index 329102fbe..b4e07e95f 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableCellEditor.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableCellEditor.java @@ -1,9 +1,9 @@ package edu.rpi.legup.ui.lookandfeel.components; +import java.awt.Component; import javax.swing.DefaultCellEditor; import javax.swing.JTable; import javax.swing.JTextField; -import java.awt.Component; public class MaterialTableCellEditor extends DefaultCellEditor { @@ -19,8 +19,12 @@ private static JTextField init() { } @Override - public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int rowIndex, int vColIndex) { - JTextField textField = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, rowIndex, vColIndex); + public Component getTableCellEditorComponent( + JTable table, Object value, boolean isSelected, int rowIndex, int vColIndex) { + JTextField textField = + (JTextField) + super.getTableCellEditorComponent( + table, value, isSelected, rowIndex, vColIndex); textField.setText(value.toString()); return textField; diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableCellRenderer.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableCellRenderer.java index 86c76e005..8fe0438e8 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableCellRenderer.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableCellRenderer.java @@ -1,17 +1,21 @@ package edu.rpi.legup.ui.lookandfeel.components; +import java.awt.Component; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JTable; import javax.swing.SwingConstants; import javax.swing.table.DefaultTableCellRenderer; -import java.awt.Component; public class MaterialTableCellRenderer extends DefaultTableCellRenderer { @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - JComponent component = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + public Component getTableCellRendererComponent( + JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JComponent component = + (JComponent) + super.getTableCellRendererComponent( + table, value, isSelected, hasFocus, row, column); // hides yellow selection highlight component.setBorder(BorderFactory.createEmptyBorder()); diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableHeaderCellRenderer.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableHeaderCellRenderer.java index 2cdfb0fa9..01f4db191 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableHeaderCellRenderer.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableHeaderCellRenderer.java @@ -1,17 +1,21 @@ package edu.rpi.legup.ui.lookandfeel.components; +import java.awt.Component; import javax.swing.JComponent; import javax.swing.JTable; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.table.DefaultTableCellRenderer; -import java.awt.Component; public class MaterialTableHeaderCellRenderer extends DefaultTableCellRenderer { @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - JComponent component = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + public Component getTableCellRendererComponent( + JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JComponent component = + (JComponent) + super.getTableCellRendererComponent( + table, value, isSelected, hasFocus, row, column); component.setBorder(UIManager.getBorder("TableHeader.cellBorder")); component.setFont(UIManager.getFont("TableHeader.font")); component.setBackground(UIManager.getColor("TableHeader.background")); diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableHeaderUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableHeaderUI.java index 82144615b..7a1eadb92 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableHeaderUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableHeaderUI.java @@ -1,12 +1,11 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTableHeaderUI; import javax.swing.table.JTableHeader; -import java.awt.Graphics; public class MaterialTableHeaderUI extends BasicTableHeaderUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableUI.java index dc0b82a34..91c68c973 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTableUI.java @@ -1,13 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTableUI; -import java.awt.Graphics; public class MaterialTableUI extends BasicTableUI { @@ -32,8 +31,7 @@ public void installUI(JComponent c) { int rowHeight = UIManager.getInt("Table.rowHeight"); if (rowHeight > 0) { table.setRowHeight(rowHeight); - } - else { + } else { table.setRowHeight(table.getRowHeight() + 25); } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTextFieldUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTextFieldUI.java index 019c4b047..5cfd2fc88 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTextFieldUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTextFieldUI.java @@ -3,15 +3,6 @@ import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialColors; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialFonts; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.BorderFactory; -import javax.swing.JComponent; -import javax.swing.JTextField; -import javax.swing.KeyStroke; -import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.basic.BasicTextFieldUI; import java.awt.Color; import java.awt.Graphics; import java.awt.Toolkit; @@ -21,9 +12,17 @@ import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTextFieldUI; - -public class MaterialTextFieldUI extends BasicTextFieldUI implements FocusListener, PropertyChangeListener { +public class MaterialTextFieldUI extends BasicTextFieldUI + implements FocusListener, PropertyChangeListener { private Color focusedBackground; private Color unfocusedBackground; @@ -50,9 +49,10 @@ public void installUI(JComponent c) { JTextField textField = (JTextField) c; textField.setOpaque(false); - textField.setBorder(drawLine ? - BorderFactory.createEmptyBorder(5, 2, 10, 0) : - BorderFactory.createEmptyBorder(2, 2, 2, 2)); + textField.setBorder( + drawLine + ? BorderFactory.createEmptyBorder(5, 2, 10, 0) + : BorderFactory.createEmptyBorder(2, 2, 2, 2)); textField.setBackground(MaterialColors.LIGHT_BLUE_400); textField.setFont(MaterialFonts.REGULAR); @@ -75,54 +75,73 @@ protected void installListeners() { protected void installKeyboardActions() { super.installKeyboardActions(); - Action selectAll = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - getComponent().selectAll(); - } - }; - - Action delete = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - if (getComponent().getSelectedText() == null) { - int pos = getComponent().getCaretPosition() - 1; - - if (pos >= 0) { - getComponent().select(pos, pos + 1); - getComponent().replaceSelection(""); + Action selectAll = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + getComponent().selectAll(); } - } - else { - getComponent().replaceSelection(""); - } - } - }; - - Action left = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - getComponent().setCaretPosition(Math.max(0, getComponent().getCaretPosition() - 1)); - } - }; - - Action right = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - getComponent().setCaretPosition(Math.min(getComponent().getText().length(), getComponent().getCaretPosition() + 1)); - } - }; - - Action enter = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - ((JTextField) getComponent()).postActionEvent(); - } - }; + }; + + Action delete = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (getComponent().getSelectedText() == null) { + int pos = getComponent().getCaretPosition() - 1; + + if (pos >= 0) { + getComponent().select(pos, pos + 1); + getComponent().replaceSelection(""); + } + } else { + getComponent().replaceSelection(""); + } + } + }; + + Action left = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + getComponent() + .setCaretPosition( + Math.max(0, getComponent().getCaretPosition() - 1)); + } + }; + + Action right = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + getComponent() + .setCaretPosition( + Math.min( + getComponent().getText().length(), + getComponent().getCaretPosition() + 1)); + } + }; - // note getMenuShortcutKeyMask() is deprecated in Java 10 - change to getMenuShortcutKeyMaskEx() - getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "selectAll"); - getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), "delete"); + Action enter = + new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + ((JTextField) getComponent()).postActionEvent(); + } + }; + + // note getMenuShortcutKeyMask() is deprecated in Java 10 - change to + // getMenuShortcutKeyMaskEx() + getComponent() + .getInputMap() + .put( + KeyStroke.getKeyStroke( + KeyEvent.VK_A, + Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), + "selectAll"); + getComponent() + .getInputMap() + .put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), "delete"); getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left"); getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right"); getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enter"); @@ -144,8 +163,7 @@ public void paintSafely(Graphics g) { if (getComponent().hasFocus()) { lineColor = focusedBackground; c.setSelectionColor(focusedSelectionBackground); - } - else { + } else { lineColor = unfocusedBackground; c.setSelectionColor(unfocusedSelectionBackground); } @@ -156,7 +174,10 @@ public void paintSafely(Graphics g) { if (drawLine) { int x = getComponent().getInsets().left; int y = getComponent().getInsets().top; - int w = getComponent().getWidth() - getComponent().getInsets().left - getComponent().getInsets().right; + int w = + getComponent().getWidth() + - getComponent().getInsets().left + - getComponent().getInsets().right; g.fillRect(x, c.getHeight() - y, w, 2); } @@ -188,8 +209,9 @@ public void propertyChange(PropertyChangeEvent pce) { if (!newColor.equals(focusedBackground) && !newColor.equals(unfocusedBackground)) { this.focusedBackground = (Color) pce.getNewValue(); - this.focusedSelectionBackground = MaterialColors.bleach(this.focusedBackground, 0.3f); + this.focusedSelectionBackground = + MaterialColors.bleach(this.focusedBackground, 0.3f); } } } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTextPaneUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTextPaneUI.java index 2adea67b2..f70048468 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTextPaneUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTextPaneUI.java @@ -7,7 +7,6 @@ /** * @author https://github.com/vincenzopalazzo */ - public class MaterialTextPaneUI extends BasicTextPaneUI { public static ComponentUI createUI(JComponent c) { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToggleButtonUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToggleButtonUI.java index 928b2e688..3749366e9 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToggleButtonUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToggleButtonUI.java @@ -1,13 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JToggleButton; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicToggleButtonUI; -import java.awt.Graphics; public class MaterialToggleButtonUI extends BasicToggleButtonUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToolBarUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToolBarUI.java index d95d52455..10251eb73 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToolBarUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToolBarUI.java @@ -1,13 +1,12 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JToolBar; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicToolBarUI; -import java.awt.Graphics; public class MaterialToolBarUI extends BasicToolBarUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToolTipUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToolTipUI.java index adbd78925..87e415e4c 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToolTipUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialToolTipUI.java @@ -1,11 +1,10 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.*; import javax.swing.*; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicToolTipUI; -import java.awt.*; public class MaterialToolTipUI extends BasicToolTipUI { diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeCellEditor.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeCellEditor.java index 6ac2230f4..ee9b0fcff 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeCellEditor.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeCellEditor.java @@ -1,13 +1,13 @@ package edu.rpi.legup.ui.lookandfeel.components; +import java.awt.Component; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.tree.DefaultTreeCellEditor; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeCellEditor; -import java.awt.Component; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; public class MaterialTreeCellEditor extends DefaultTreeCellEditor { @@ -18,7 +18,8 @@ public MaterialTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) { init(); } - public MaterialTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer, TreeCellEditor editor) { + public MaterialTreeCellEditor( + JTree tree, DefaultTreeCellRenderer renderer, TreeCellEditor editor) { super(tree, renderer, editor); init(); } @@ -27,18 +28,20 @@ private void init() { textField = new JTextField(); textField.setUI(new MaterialTextFieldUI()); - textField.addKeyListener(new KeyAdapter() { - @Override - public void keyTyped(KeyEvent e) { - if (e.getKeyChar() == KeyEvent.VK_ENTER) { - stopCellEditing(); - } - } - }); + textField.addKeyListener( + new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + stopCellEditing(); + } + } + }); } @Override - public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) { + public Component getTreeCellEditorComponent( + JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) { textField.setText(value.toString()); return textField; } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeCellRenderer.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeCellRenderer.java index f9ddcbf45..6ac5acabb 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeCellRenderer.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeCellRenderer.java @@ -1,11 +1,11 @@ package edu.rpi.legup.ui.lookandfeel.components; +import java.awt.Component; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JTree; import javax.swing.UIManager; import javax.swing.tree.DefaultTreeCellRenderer; -import java.awt.Component; public class MaterialTreeCellRenderer extends DefaultTreeCellRenderer { @@ -22,13 +22,22 @@ public MaterialTreeCellRenderer() { setOpenIcon(UIManager.getIcon("Tree.openIcon")); setLeafIcon(null); - setFont(UIManager.getFont("Tree.font")); } @Override - public Component getTreeCellRendererComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row, boolean hasFocus) { - JComponent component = (JComponent) super.getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, hasFocus); + public Component getTreeCellRendererComponent( + JTree tree, + Object value, + boolean isSelected, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { + JComponent component = + (JComponent) + super.getTreeCellRendererComponent( + tree, value, isSelected, expanded, leaf, row, hasFocus); component.setBorder(BorderFactory.createEmptyBorder(5, 2, 5, 2)); return component; diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeUI.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeUI.java index b1b9839bd..7d38c62f3 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeUI.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/components/MaterialTreeUI.java @@ -1,7 +1,7 @@ package edu.rpi.legup.ui.lookandfeel.components; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialDrawingUtils; - +import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JTree; import javax.swing.UIManager; @@ -9,7 +9,6 @@ import javax.swing.plaf.basic.BasicTreeUI; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeCellEditor; -import java.awt.Graphics; public class MaterialTreeUI extends BasicTreeUI { @@ -42,4 +41,4 @@ public void paint(Graphics g, JComponent c) { g = MaterialDrawingUtils.getAliasedGraphics(g); super.paint(g, c); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/DropShadowBorder.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/DropShadowBorder.java index 2543b8664..ce3244d4d 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/DropShadowBorder.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/DropShadowBorder.java @@ -1,8 +1,5 @@ package edu.rpi.legup.ui.lookandfeel.materialdesign; -import javax.swing.UIManager; -import javax.swing.border.AbstractBorder; -import javax.swing.border.Border; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; @@ -18,19 +15,22 @@ import java.awt.image.Kernel; import java.util.HashMap; import java.util.Map; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.border.Border; /** - * Implements a DropShadow for components. In general, the mdlaf.shadows.DropShadowBorder will - * work with any rectangular components that do not have a default border installed - * as part of the look and feel, or otherwise. For example, mdlaf.shadows.DropShadowBorder works - * wonderfully with JPanel, but horribly with JComboBox. + * Implements a DropShadow for components. In general, the mdlaf.shadows.DropShadowBorder will work + * with any rectangular components that do not have a default border installed as part of the look + * and feel, or otherwise. For example, mdlaf.shadows.DropShadowBorder works wonderfully with + * JPanel, but horribly with JComboBox. * * @author rbair */ public class DropShadowBorder extends AbstractBorder implements Border { - private static final Map> CACHE - = new HashMap>(); + private static final Map> CACHE = + new HashMap>(); private Color lineColor; private int lineWidth; private int shadowSize; @@ -53,9 +53,16 @@ public DropShadowBorder(Color lineColor, int lineWidth, boolean showLeftShadow) this(lineColor, lineWidth, 5, .5f, 12, false, showLeftShadow, true, true); } - public DropShadowBorder(Color lineColor, int lineWidth, int shadowSize, - float shadowOpacity, int cornerSize, boolean showTopShadow, - boolean showLeftShadow, boolean showBottomShadow, boolean showRightShadow) { + public DropShadowBorder( + Color lineColor, + int lineWidth, + int shadowSize, + float shadowOpacity, + int cornerSize, + boolean showTopShadow, + boolean showLeftShadow, + boolean showBottomShadow, + boolean showRightShadow) { this.lineColor = lineColor; this.lineWidth = lineWidth; this.shadowSize = shadowSize; @@ -67,9 +74,7 @@ public DropShadowBorder(Color lineColor, int lineWidth, int shadowSize, this.showRightShadow = showRightShadow; } - /** - * - */ + /** */ public void paintBorder(Component c, Graphics graphics, int x, int y, int width, int height) { /* * 1) Get images for this border @@ -77,8 +82,8 @@ public void paintBorder(Component c, Graphics graphics, int x, int y, int width, */ Map images = getImages(null); - //compute the edges of the components -- not including the border - //Insets borderInsets = getBorderInsets (c); + // compute the edges of the components -- not including the border + // Insets borderInsets = getBorderInsets (c); // int leftEdge = x + borderInsets.left - lineWidth; // int rightEdge = x + width - borderInsets.right; // int topEdge = y + borderInsets.top - lineWidth; @@ -86,24 +91,22 @@ public void paintBorder(Component c, Graphics graphics, int x, int y, int width, Graphics2D g2 = (Graphics2D) graphics; g2.setColor(lineColor); - //The location and size of the shadows depends on which shadows are being - //drawn. For instance, if the left & bottom shadows are being drawn, then - //the left shadows extends all the way down to the corner, a corner is drawn, - //and then the bottom shadows begins at the corner. If, however, only the - //bottom shadows is drawn, then the bottom-left corner is drawn to the - //right of the corner, and the bottom shadows is somewhat shorter than before. + // The location and size of the shadows depends on which shadows are being + // drawn. For instance, if the left & bottom shadows are being drawn, then + // the left shadows extends all the way down to the corner, a corner is drawn, + // and then the bottom shadows begins at the corner. If, however, only the + // bottom shadows is drawn, then the bottom-left corner is drawn to the + // right of the corner, and the bottom shadows is somewhat shorter than before. Point topLeftShadowPoint = null; if (showLeftShadow || showTopShadow) { topLeftShadowPoint = new Point(); if (showLeftShadow && !showTopShadow) { topLeftShadowPoint.setLocation(x, y + shadowSize); - } - else { + } else { if (showLeftShadow && showTopShadow) { topLeftShadowPoint.setLocation(x, y); - } - else { + } else { if (!showLeftShadow && showTopShadow) { topLeftShadowPoint.setLocation(x + shadowSize, y); } @@ -116,12 +119,10 @@ public void paintBorder(Component c, Graphics graphics, int x, int y, int width, bottomLeftShadowPoint = new Point(); if (showLeftShadow && !showBottomShadow) { bottomLeftShadowPoint.setLocation(x, y + height - shadowSize - shadowSize); - } - else { + } else { if (showLeftShadow && showBottomShadow) { bottomLeftShadowPoint.setLocation(x, y + height - shadowSize); - } - else { + } else { if (!showLeftShadow && showBottomShadow) { bottomLeftShadowPoint.setLocation(x + shadowSize, y + height - shadowSize); } @@ -133,15 +134,16 @@ public void paintBorder(Component c, Graphics graphics, int x, int y, int width, if (showRightShadow || showBottomShadow) { bottomRightShadowPoint = new Point(); if (showRightShadow && !showBottomShadow) { - bottomRightShadowPoint.setLocation(x + width - shadowSize, y + height - shadowSize - shadowSize); - } - else { + bottomRightShadowPoint.setLocation( + x + width - shadowSize, y + height - shadowSize - shadowSize); + } else { if (showRightShadow && showBottomShadow) { - bottomRightShadowPoint.setLocation(x + width - shadowSize, y + height - shadowSize); - } - else { + bottomRightShadowPoint.setLocation( + x + width - shadowSize, y + height - shadowSize); + } else { if (!showRightShadow && showBottomShadow) { - bottomRightShadowPoint.setLocation(x + width - shadowSize - shadowSize, y + height - shadowSize); + bottomRightShadowPoint.setLocation( + x + width - shadowSize - shadowSize, y + height - shadowSize); } } } @@ -152,12 +154,10 @@ public void paintBorder(Component c, Graphics graphics, int x, int y, int width, topRightShadowPoint = new Point(); if (showRightShadow && !showTopShadow) { topRightShadowPoint.setLocation(x + width - shadowSize, y + shadowSize); - } - else { + } else { if (showRightShadow && showTopShadow) { topRightShadowPoint.setLocation(x + width - shadowSize, y); - } - else { + } else { if (!showRightShadow && showTopShadow) { topRightShadowPoint.setLocation(x + width - shadowSize - shadowSize, y); } @@ -166,42 +166,118 @@ public void paintBorder(Component c, Graphics graphics, int x, int y, int width, } if (showLeftShadow) { - Rectangle leftShadowRect = new Rectangle(x, (int) (topLeftShadowPoint.getY() + shadowSize), shadowSize, (int) (bottomLeftShadowPoint.getY() - topLeftShadowPoint.getY() - shadowSize)); - g2.drawImage(images.get(Position.LEFT).getScaledInstance(leftShadowRect.width, leftShadowRect.height, Image.SCALE_FAST), leftShadowRect.x, leftShadowRect.y, null); + Rectangle leftShadowRect = + new Rectangle( + x, + (int) (topLeftShadowPoint.getY() + shadowSize), + shadowSize, + (int) + (bottomLeftShadowPoint.getY() + - topLeftShadowPoint.getY() + - shadowSize)); + g2.drawImage( + images.get(Position.LEFT) + .getScaledInstance( + leftShadowRect.width, leftShadowRect.height, Image.SCALE_FAST), + leftShadowRect.x, + leftShadowRect.y, + null); } if (showBottomShadow) { - Rectangle bottomShadowRect = new Rectangle((int) (bottomLeftShadowPoint.getX() + shadowSize), y + height - shadowSize, (int) (bottomRightShadowPoint.getX() - bottomLeftShadowPoint.getX() - shadowSize), shadowSize); - g2.drawImage(images.get(Position.BOTTOM).getScaledInstance(bottomShadowRect.width, bottomShadowRect.height, Image.SCALE_FAST), bottomShadowRect.x, bottomShadowRect.y, null); + Rectangle bottomShadowRect = + new Rectangle( + (int) (bottomLeftShadowPoint.getX() + shadowSize), + y + height - shadowSize, + (int) + (bottomRightShadowPoint.getX() + - bottomLeftShadowPoint.getX() + - shadowSize), + shadowSize); + g2.drawImage( + images.get(Position.BOTTOM) + .getScaledInstance( + bottomShadowRect.width, + bottomShadowRect.height, + Image.SCALE_FAST), + bottomShadowRect.x, + bottomShadowRect.y, + null); } if (showRightShadow) { - Rectangle rightShadowRect = new Rectangle(x + width - shadowSize, (int) (topRightShadowPoint.getY() + shadowSize), shadowSize, (int) (bottomRightShadowPoint.getY() - topRightShadowPoint.getY() - shadowSize)); - g2.drawImage(images.get(Position.RIGHT).getScaledInstance(rightShadowRect.width, rightShadowRect.height, Image.SCALE_FAST), rightShadowRect.x, rightShadowRect.y, null); + Rectangle rightShadowRect = + new Rectangle( + x + width - shadowSize, + (int) (topRightShadowPoint.getY() + shadowSize), + shadowSize, + (int) + (bottomRightShadowPoint.getY() + - topRightShadowPoint.getY() + - shadowSize)); + g2.drawImage( + images.get(Position.RIGHT) + .getScaledInstance( + rightShadowRect.width, + rightShadowRect.height, + Image.SCALE_FAST), + rightShadowRect.x, + rightShadowRect.y, + null); } if (showTopShadow) { - Rectangle topShadowRect = new Rectangle((int) topLeftShadowPoint.getX() + shadowSize, y, (int) (topRightShadowPoint.getX() - topLeftShadowPoint.getX() - shadowSize), shadowSize); - g2.drawImage(images.get(Position.TOP).getScaledInstance(topShadowRect.width, topShadowRect.height, Image.SCALE_FAST), topShadowRect.x, topShadowRect.y, null); + Rectangle topShadowRect = + new Rectangle( + (int) topLeftShadowPoint.getX() + shadowSize, + y, + (int) + (topRightShadowPoint.getX() + - topLeftShadowPoint.getX() + - shadowSize), + shadowSize); + g2.drawImage( + images.get(Position.TOP) + .getScaledInstance( + topShadowRect.width, topShadowRect.height, Image.SCALE_FAST), + topShadowRect.x, + topShadowRect.y, + null); } if (showLeftShadow || showTopShadow) { - g2.drawImage(images.get(Position.TOP_LEFT), null, (int) topLeftShadowPoint.getX(), (int) topLeftShadowPoint.getY()); + g2.drawImage( + images.get(Position.TOP_LEFT), + null, + (int) topLeftShadowPoint.getX(), + (int) topLeftShadowPoint.getY()); } if (showLeftShadow || showBottomShadow) { - g2.drawImage(images.get(Position.BOTTOM_LEFT), null, (int) bottomLeftShadowPoint.getX(), (int) bottomLeftShadowPoint.getY()); + g2.drawImage( + images.get(Position.BOTTOM_LEFT), + null, + (int) bottomLeftShadowPoint.getX(), + (int) bottomLeftShadowPoint.getY()); } if (showRightShadow || showBottomShadow) { - g2.drawImage(images.get(Position.BOTTOM_RIGHT), null, (int) bottomRightShadowPoint.getX(), (int) bottomRightShadowPoint.getY()); + g2.drawImage( + images.get(Position.BOTTOM_RIGHT), + null, + (int) bottomRightShadowPoint.getX(), + (int) bottomRightShadowPoint.getY()); } if (showRightShadow || showTopShadow) { - g2.drawImage(images.get(Position.TOP_RIGHT), null, (int) topRightShadowPoint.getX(), (int) topRightShadowPoint.getY()); + g2.drawImage( + images.get(Position.TOP_RIGHT), + null, + (int) topRightShadowPoint.getX(), + (int) topRightShadowPoint.getY()); } } private Map getImages(Graphics2D g2) { - //first, check to see if an image for this size has already been rendered - //if so, use the cache. Else, draw and save + // first, check to see if an image for this size has already been rendered + // if so, use the cache. Else, draw and save Map images = CACHE.get(shadowSize); if (images == null) { images = new HashMap(); @@ -221,25 +297,35 @@ private Map getImages(Graphics2D g2) { * drawing the Border */ int rectWidth = cornerSize + 1; - RoundRectangle2D rect = new RoundRectangle2D.Double(0, 0, rectWidth, rectWidth, cornerSize, cornerSize); + RoundRectangle2D rect = + new RoundRectangle2D.Double(0, 0, rectWidth, rectWidth, cornerSize, cornerSize); int imageWidth = rectWidth + shadowSize * 2; - BufferedImage image = new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB); + BufferedImage image = + new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB); Graphics2D buffer = (Graphics2D) image.getGraphics(); - buffer.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - buffer.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - buffer.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - buffer.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); + buffer.setRenderingHint( + RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + buffer.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + buffer.setRenderingHint( + RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + buffer.setRenderingHint( + RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); buffer.setColor(new Color(0.0f, 0.0f, 0.0f, shadowOpacity)); buffer.translate(shadowSize, shadowSize); buffer.fill(rect); - float blurry = 1.0f / (float) (shadowSize * shadowSize);//1.0f / (float)(shadowSize * shadowSize); + float blurry = 1.0f / (float) (shadowSize * shadowSize); // 1.0f / (float)(shadowSize * + // shadowSize); float[] blurKernel = new float[shadowSize * shadowSize]; for (int i = 0; i < blurKernel.length; i++) { blurKernel[i] = blurry; } ConvolveOp blur = new ConvolveOp(new Kernel(shadowSize, shadowSize, blurKernel)); - BufferedImage targetImage = new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB); - ((Graphics2D) targetImage.getGraphics()).drawImage(image, blur, -(shadowSize / 2), -(shadowSize / 2)); + BufferedImage targetImage = + new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB); + ((Graphics2D) targetImage.getGraphics()) + .drawImage(image, blur, -(shadowSize / 2), -(shadowSize / 2)); int x = 1; int y = 1; @@ -288,9 +374,7 @@ private Map getImages(Graphics2D g2) { return images; } - /** - * - */ + /** */ public Insets getBorderInsets(Component c) { int top = 4 + (showTopShadow ? lineWidth + shadowSize : lineWidth); int left = 4 + (showLeftShadow ? lineWidth + shadowSize : lineWidth); @@ -300,9 +384,7 @@ public Insets getBorderInsets(Component c) { return new Insets(top, left, bottom, right); } - /** - * - */ + /** */ public boolean isBorderOpaque() { return true; } @@ -344,7 +426,13 @@ public int getCornerSize() { } private enum Position { - TOP, TOP_LEFT, LEFT, BOTTOM_LEFT, - BOTTOM, BOTTOM_RIGHT, RIGHT, TOP_RIGHT + TOP, + TOP_LEFT, + LEFT, + BOTTOM_LEFT, + BOTTOM, + BOTTOM_RIGHT, + RIGHT, + TOP_RIGHT } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialBorders.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialBorders.java index c78d20e34..8c2e3eeec 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialBorders.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialBorders.java @@ -1,17 +1,20 @@ package edu.rpi.legup.ui.lookandfeel.materialdesign; +import java.awt.Color; import javax.swing.BorderFactory; import javax.swing.border.Border; -import java.awt.Color; public class MaterialBorders { - public static final Border LIGHT_LINE_BORDER = BorderFactory.createLineBorder(MaterialColors.GRAY_200, 1); - public static final Border THICK_LINE_BORDER = BorderFactory.createLineBorder(MaterialColors.GRAY_200, 2); + public static final Border LIGHT_LINE_BORDER = + BorderFactory.createLineBorder(MaterialColors.GRAY_200, 1); + public static final Border THICK_LINE_BORDER = + BorderFactory.createLineBorder(MaterialColors.GRAY_200, 2); - public static final Border LIGHT_SHADOW_BORDER = new DropShadowBorder(Color.BLACK, 0, 4, 0.3f, 12, true, true, true, true); - public static final Border DEFAULT_SHADOW_BORDER = new DropShadowBorder(Color.BLACK, 5, 5, 0.3f, 12, true, true, true, true); + public static final Border LIGHT_SHADOW_BORDER = + new DropShadowBorder(Color.BLACK, 0, 4, 0.3f, 12, true, true, true, true); + public static final Border DEFAULT_SHADOW_BORDER = + new DropShadowBorder(Color.BLACK, 5, 5, 0.3f, 12, true, true, true, true); - private MaterialBorders() { - } -} \ No newline at end of file + private MaterialBorders() {} +} diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialColors.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialColors.java index 30229b936..00cb0720a 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialColors.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialColors.java @@ -261,8 +261,7 @@ public class MaterialColors { public static final Color WHITE = new Color(255, 255, 255); public static final Color TRANSPARENT = new Color(0, 0, 0, 255); - private MaterialColors() { - } + private MaterialColors() {} public static Color bleach(Color color, float amount) { int red = (int) ((color.getRed() * (1 - amount) / 255 + amount) * 255); diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialDrawingUtils.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialDrawingUtils.java index fbc330faf..f5e209b0d 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialDrawingUtils.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialDrawingUtils.java @@ -15,17 +15,19 @@ public class MaterialDrawingUtils { } public static Graphics getAliasedGraphics(Graphics g) { - Map hints = (Map) Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"); + Map hints = + (Map) + Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"); if (hints != null) { hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Graphics2D g2d = (Graphics2D) g; g2d.addRenderingHints(hints); - //g2d.addRenderingHints (new RenderingHints (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)); + // g2d.addRenderingHints (new RenderingHints (RenderingHints.KEY_ANTIALIASING, + // RenderingHints.VALUE_ANTIALIAS_ON)); return g2d; - } - else { + } else { // Desktop hints not supported on this platform return g; } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialFonts.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialFonts.java index 9bbc4e884..e5d1de56c 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialFonts.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialFonts.java @@ -1,6 +1,5 @@ package edu.rpi.legup.ui.lookandfeel.materialdesign; - import java.awt.*; import java.awt.font.TextAttribute; import java.io.IOException; @@ -13,17 +12,22 @@ public class MaterialFonts { private static final Map fontSettings = new HashMap<>(); public static final Font BLACK = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-Black.ttf"); - public static final Font BLACK_ITALIC = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-BlackItalic.ttf"); + public static final Font BLACK_ITALIC = + loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-BlackItalic.ttf"); public static final Font BOLD = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-Bold.ttf"); - public static final Font BOLD_ITALIC = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-BoldItalic.ttf"); + public static final Font BOLD_ITALIC = + loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-BoldItalic.ttf"); public static final Font ITALIC = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-Italic.ttf"); public static final Font LIGHT = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-Light.ttf"); - public static final Font LIGHT_ITALIC = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-LightItalic.ttf"); + public static final Font LIGHT_ITALIC = + loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-LightItalic.ttf"); public static final Font MEDIUM = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-Medium.ttf"); - public static final Font MEDIUM_ITALIC = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-MediumItalic.ttf"); + public static final Font MEDIUM_ITALIC = + loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-MediumItalic.ttf"); public static final Font REGULAR = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-Regular.ttf"); public static final Font THIN = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-Thin.ttf"); - public static final Font THIN_ITALIC = loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-ThinItalic.ttf"); + public static final Font THIN_ITALIC = + loadFont("/edu/rpi/legup/fonts/Roboto/Roboto-ThinItalic.ttf"); private static Font loadFont(String fontPath) { if (fontSettings.isEmpty()) { @@ -33,8 +37,7 @@ private static Font loadFont(String fontPath) { try (InputStream inputStream = MaterialFonts.class.getResourceAsStream(fontPath)) { return Font.createFont(Font.TRUETYPE_FONT, inputStream).deriveFont(fontSettings); - } - catch (IOException | FontFormatException e) { + } catch (IOException | FontFormatException e) { e.printStackTrace(); throw new RuntimeException("Font " + fontPath + " wasn't loaded"); } @@ -45,10 +48,11 @@ public static Font getRegularFont(float size) { map.put(TextAttribute.SIZE, size); map.put(TextAttribute.KERNING, TextAttribute.KERNING_ON); - try (InputStream inputStream = MaterialFonts.class.getResourceAsStream("/edu/rpi/legup/fonts/Roboto/Roboto-Regular.ttf")) { + try (InputStream inputStream = + MaterialFonts.class.getResourceAsStream( + "/edu/rpi/legup/fonts/Roboto/Roboto-Regular.ttf")) { return Font.createFont(Font.TRUETYPE_FONT, inputStream).deriveFont(map); - } - catch (IOException | FontFormatException e) { + } catch (IOException | FontFormatException e) { e.printStackTrace(); throw new RuntimeException("Font regular wasn't loaded"); } diff --git a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialImages.java b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialImages.java index dabf2139d..a1a716c76 100644 --- a/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialImages.java +++ b/src/main/java/edu/rpi/legup/ui/lookandfeel/materialdesign/MaterialImages.java @@ -1,26 +1,34 @@ package edu.rpi.legup.ui.lookandfeel.materialdesign; -import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; +import javax.imageio.ImageIO; public class MaterialImages { public static final BufferedImage RIGHT_ARROW = loadImg("/edu/rpi/legup/imgs/right_arrow.png"); public static final BufferedImage DOWN_ARROW = loadImg("/edu/rpi/legup/imgs/down_arrow.png"); public static final BufferedImage UP_ARROW = loadImg("/edu/rpi/legup/imgs/up_arrow.png"); - public static final BufferedImage PAINTED_CHECKED_BOX = loadImg("/edu/rpi/legup/imgs/painted_checked_box.png"); - public static final BufferedImage OUTLINED_CHECKED_BOX = loadImg("/edu/rpi/legup/imgs/outlined_checked_box.png"); - public static final BufferedImage UNCHECKED_BOX = loadImg("/edu/rpi/legup/imgs/unchecked_box.png"); - public static final BufferedImage RADIO_BUTTON_ON = loadImg("/edu/rpi/legup/imgs/radio_button_on.png"); - public static final BufferedImage RADIO_BUTTON_OFF = loadImg("/edu/rpi/legup/imgs/radio_button_off.png"); - public static final BufferedImage TOGGLE_BUTTON_ON = loadImg("/edu/rpi/legup/imgs/toggle_on.png"); - public static final BufferedImage TOGGLE_BUTTON_OFF = loadImg("/edu/rpi/legup/imgs/toggle_off.png"); + public static final BufferedImage PAINTED_CHECKED_BOX = + loadImg("/edu/rpi/legup/imgs/painted_checked_box.png"); + public static final BufferedImage OUTLINED_CHECKED_BOX = + loadImg("/edu/rpi/legup/imgs/outlined_checked_box.png"); + public static final BufferedImage UNCHECKED_BOX = + loadImg("/edu/rpi/legup/imgs/unchecked_box.png"); + public static final BufferedImage RADIO_BUTTON_ON = + loadImg("/edu/rpi/legup/imgs/radio_button_on.png"); + public static final BufferedImage RADIO_BUTTON_OFF = + loadImg("/edu/rpi/legup/imgs/radio_button_off.png"); + public static final BufferedImage TOGGLE_BUTTON_ON = + loadImg("/edu/rpi/legup/imgs/toggle_on.png"); + public static final BufferedImage TOGGLE_BUTTON_OFF = + loadImg("/edu/rpi/legup/imgs/toggle_off.png"); public static final BufferedImage BACK_ARROW = loadImg("/edu/rpi/legup/imgs/back_arrow.png"); public static final BufferedImage COMPUTER = loadImg("/edu/rpi/legup/imgs/computer.png"); public static final BufferedImage FILE = loadImg("/edu/rpi/legup/imgs/file.png"); - public static final BufferedImage FLOPPY_DRIVE = loadImg("/edu/rpi/legup/imgs/floppy_drive.png"); + public static final BufferedImage FLOPPY_DRIVE = + loadImg("/edu/rpi/legup/imgs/floppy_drive.png"); public static final BufferedImage FOLDER = loadImg("/edu/rpi/legup/imgs/folder.png"); public static final BufferedImage HARD_DRIVE = loadImg("/edu/rpi/legup/imgs/hard_drive.png"); public static final BufferedImage HOME = loadImg("/edu/rpi/legup/imgs/home.png"); @@ -28,14 +36,12 @@ public class MaterialImages { public static final BufferedImage NEW_FOLDER = loadImg("/edu/rpi/legup/imgs/new_folder.png"); public static final BufferedImage DETAILS = loadImg("/edu/rpi/legup/imgs/details.png"); - private MaterialImages() { - } + private MaterialImages() {} private static BufferedImage loadImg(String imgPath) { try (InputStream inputStream = MaterialImages.class.getResourceAsStream(imgPath)) { return ImageIO.read(inputStream); - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("Image " + imgPath + " wasn't loaded"); } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java index 5f22ac62c..849c5c145 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRulePanel.java @@ -2,6 +2,12 @@ import javax.swing.ImageIcon; +/** + * The {@code CaseRulePanel} class is a specialized panel that represents case rules + * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides + * specific functionality and UI components related to case rules. + * This class initializes with an icon and name that are specific to case rules. + */ public class CaseRulePanel extends RulePanel { /** * CaseRulePanel Constructor creates a CaseRulePanel @@ -10,8 +16,11 @@ public class CaseRulePanel extends RulePanel { */ CaseRulePanel(RuleFrame ruleFrame) { super(ruleFrame); - this.icon = new ImageIcon(ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/Case Rules.gif")); + this.icon = + new ImageIcon( + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Case Rules.gif")); this.name = "Case Rules"; this.toolTip = "Case Rules"; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRuleSelectionView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRuleSelectionView.java index 276583a99..ae9444db2 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRuleSelectionView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/CaseRuleSelectionView.java @@ -1,9 +1,8 @@ package edu.rpi.legup.ui.proofeditorui.rulesview; import edu.rpi.legup.ui.WrapLayout; - -import javax.swing.*; import java.awt.*; +import javax.swing.*; public class CaseRuleSelectionView extends JPanel { diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java index 908ffc49b..5bed7e17d 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/ContradictionRulePanel.java @@ -2,7 +2,14 @@ import javax.swing.*; -public class ContradictionRulePanel extends RulePanel { +/** + * The {@code ContradictionRulePanel} class is a specialized panel that represents contradiction rules + * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides + * specific functionality and UI components related to contradiction rules. + * This class initializes with an icon and name that are specific to contradiction rules. + */ + + public class ContradictionRulePanel extends RulePanel { /** * ContradictionRulePanel Constructor creates a ContradictionRulePanel * @@ -10,7 +17,10 @@ public class ContradictionRulePanel extends RulePanel { */ ContradictionRulePanel(RuleFrame ruleFrame) { super(ruleFrame); - this.icon = new ImageIcon(ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/Contradictions.gif")); + this.icon = + new ImageIcon( + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Contradictions.gif")); this.name = "Contradiction Rules"; this.toolTip = "Contradiction Rules"; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java index 3d0672525..c1562eb70 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/DirectRulePanel.java @@ -1,22 +1,30 @@ -package edu.rpi.legup.ui.proofeditorui.rulesview; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.swing.ImageIcon; - -public class DirectRulePanel extends RulePanel { - private static final Logger LOGGER = LogManager.getLogger(DirectRulePanel.class.getName()); - - /** - * DirectRulePanel Constructor creates a basic rule panel - * - * @param ruleFrame rule frame that this basic rule panel is contained in - */ - DirectRulePanel(RuleFrame ruleFrame) { - super(ruleFrame); - this.icon = new ImageIcon(ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/Direct Rules.gif")); - this.name = "Direct Rules"; - this.toolTip = "Direct Rules"; - } -} \ No newline at end of file +package edu.rpi.legup.ui.proofeditorui.rulesview; + +import javax.swing.ImageIcon; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * The {@code DirectRulePanel} class is a specialized panel that represents direct rules + * within a {@link RuleFrame}. It extends the {@link RulePanel} and provides + * specific functionality and UI components related to direct rules. + * This class initializes with an icon and name that are specific to direct rules. + */ + public class DirectRulePanel extends RulePanel { + private static final Logger LOGGER = LogManager.getLogger(DirectRulePanel.class.getName()); + + /** + * DirectRulePanel Constructor creates a basic rule panel + * + * @param ruleFrame rule frame that this basic rule panel is contained in + */ + DirectRulePanel(RuleFrame ruleFrame) { + super(ruleFrame); + this.icon = + new ImageIcon( + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Direct Rules.gif")); + this.name = "Direct Rules"; + this.toolTip = "Direct Rules"; + } +} diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java index 30545f413..7222603bc 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleButton.java @@ -1,9 +1,13 @@ package edu.rpi.legup.ui.proofeditorui.rulesview; import edu.rpi.legup.model.rules.Rule; - import javax.swing.*; +/** + * The {@code RuleButton} class is a custom button that represents a rule in the user interface. + * It extends {@link JButton} and is designed to display a rule's name and icon. + * The button is initialized with a {@link Rule} object, which provides the name and icon for the button. + */ public class RuleButton extends JButton { private Rule rule; @@ -13,7 +17,9 @@ public class RuleButton extends JButton { * @param rule rule to create the button */ RuleButton(Rule rule) { - super(rule.getRuleName(), rule.getImageIcon()); // display rules' name under rule when load the icon + super( + rule.getRuleName(), + rule.getImageIcon()); // display rules' name under rule when load the icon this.rule = rule; this.setFocusPainted(false); } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java index 0fe03d476..3131f474d 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RuleFrame.java @@ -5,14 +5,18 @@ import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.ui.lookandfeel.components.MaterialTabbedPaneUI; - import java.awt.BorderLayout; import java.awt.Dimension; - import javax.swing.*; - import javax.swing.border.TitledBorder; +/** + * The {@code RuleFrame} class is a panel that contains and manages multiple rule-related panels + * within a tabbed interface. It extends {@link JPanel} and organizes the display of various rule types + * such as direct rules, contradiction rules, and case rules. + * The frame uses a {@link JTabbedPane} to allow users to switch between different rule panels. + * It also includes a search bar panel and a status label for displaying additional information. + */ public class RuleFrame extends JPanel { private static final String checkBox = " \u2714 "; private static final String xBox = " \u2718 "; @@ -31,15 +35,22 @@ public class RuleFrame extends JPanel { private RuleController controller; + /** + * Constructs a new {@code RuleFrame} instance. + * Initializes the frame with tabs for the different rule panels, a search bar panel, and a status label. + * + * @param controller the {@link RuleController} instance that manages the rules for this frame + */ public RuleFrame(RuleController controller) { - MaterialTabbedPaneUI tabOverride = new MaterialTabbedPaneUI() { - //this prevents the tabs from moving around when you select them - @Override - protected boolean shouldRotateTabRuns(int i) { - return false; - } - }; + MaterialTabbedPaneUI tabOverride = + new MaterialTabbedPaneUI() { + // this prevents the tabs from moving around when you select them + @Override + protected boolean shouldRotateTabRuns(int i) { + return false; + } + }; this.controller = controller; @@ -51,7 +62,11 @@ protected boolean shouldRotateTabRuns(int i) { DirectRulePanel = new DirectRulePanel(this); JScrollPane newbrp = new JScrollPane(DirectRulePanel); newbrp.getVerticalScrollBar().setUnitIncrement(16); - tabbedPane.addTab(DirectRulePanel.getName(), DirectRulePanel.getIcon(), newbrp, DirectRulePanel.getToolTip()); + tabbedPane.addTab( + DirectRulePanel.getName(), + DirectRulePanel.getIcon(), + newbrp, + DirectRulePanel.getToolTip()); casePanel = new CaseRulePanel(this); JScrollPane newcp = new JScrollPane(casePanel); @@ -61,7 +76,8 @@ protected boolean shouldRotateTabRuns(int i) { contradictionPanel = new ContradictionRulePanel(this); JScrollPane newp = new JScrollPane(contradictionPanel); newp.getVerticalScrollBar().setUnitIncrement(16); - tabbedPane.addTab(contradictionPanel.name, contradictionPanel.icon, newp, contradictionPanel.toolTip); + tabbedPane.addTab( + contradictionPanel.name, contradictionPanel.icon, newp, contradictionPanel.toolTip); searchPanel = new SearchBarPanel(this); JScrollPane newsp = new JScrollPane(searchPanel); @@ -95,38 +111,33 @@ public void setSelectionByRule(Rule rule) { contradictionPanel.setSelectionByRule(rule); } - /** - * Reset the rules button and status string - */ + /** Reset the rules button and status string */ public void resetRuleButtons() { resetStatus(); } - /** - * Reset the status label to the empty string - */ + /** Reset the status label to the empty string */ public void resetStatus() { - //((GridUI)GameBoardFacade.getInstance().getLegupUI()).getTreePanel().updateStatus(); + // ((GridUI)GameBoardFacade.getInstance().getLegupUI()).getTreePanel().updateStatus(); } - /** - * Resets the dimension of the rule frame - */ + /** Resets the dimension of the rule frame */ public void resetSize() { - int buttonWidth = ((RulePanel) tabbedPane.getSelectedComponent()).getRuleButtons()[0].getWidth(); + int buttonWidth = + ((RulePanel) tabbedPane.getSelectedComponent()).getRuleButtons()[0].getWidth(); this.setMinimumSize(new Dimension(2 * buttonWidth + 64, this.getHeight())); } /** * Set the status label to a value. Use resetStatus to clear it. * - * @param check true iff we want a check box, if false we'll have a red x box - * @param text the text we're setting the label to display + * @param check true if we want a checkbox, if false we'll have a red x box + * @param text the text we're setting the label to display */ public void setStatus(boolean check, String text) { String box = (check ? checkBox : xBox); - //status.setText(htmlHead + box + text + htmlTail); - //((GridUI)GameBoardFacade.getInstance().getLegupUI()).getTreePanel().getStatus().setText(htmlHead + box + text + htmlTail); + // status.setText(htmlHead + box + text + htmlTail); + // ((GridUI)GameBoardFacade.getInstance().getLegupUI()).getTreePanel().getStatus().setText(htmlHead + box + text + htmlTail); } /** @@ -158,22 +169,47 @@ public RuleController getController() { return controller; } + /** + * Gets the JTabbedPane used in this frame + * + * @return the JTabbedPane instance + */ public JTabbedPane getTabbedPane() { return tabbedPane; } + /** + * Gets the {@code DirectRulePanel} contained in this frame + * + * @return the {@link DirectRulePanel} instance + */ public DirectRulePanel getDirectRulePanel() { return DirectRulePanel; } + /** + * Gets the {@code CaseRulePanel} contained in this frame + * + * @return the {@link CaseRulePanel} instance + */ public CaseRulePanel getCasePanel() { return casePanel; } + /** + * Gets the {@code ContradictionRulePanel} contained in this frame + * + * @return the {@link ContradictionRulePanel} instance + */ public ContradictionRulePanel getContradictionPanel() { return contradictionPanel; } + /** + * Gets the {@code SearchBarPanel} contained in this frame + * + * @return the {@link SearchBarPanel} instance + */ public SearchBarPanel getSearchPanel() { return searchPanel; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java index f11fee5b4..4c9ebf882 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/RulePanel.java @@ -3,13 +3,16 @@ import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.model.rules.Rule; import edu.rpi.legup.ui.WrapLayout; - -import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; import java.util.List; +import javax.swing.*; +/** + * Abstract base class for panels displaying rules. Each subclass will represent a specific type + * of rule panel (e.g., DirectRulePanel, CaseRulePanel). + */ public abstract class RulePanel extends JPanel { protected ImageIcon icon; protected String name; @@ -33,7 +36,7 @@ public RulePanel(RuleFrame ruleFrame) { } /** - * Gets the rule rule buttons + * Gets the array of rule buttons * * @return rule ruleButtons */ @@ -56,7 +59,16 @@ public void setRules(List rules) { Rule rule = rules.get(i); ruleButtons[i] = new RuleButton(rule); - ruleButtons[i].setPreferredSize(new Dimension(150, 150));// adjust the size of each RuleButton + ruleButtons[i].setPreferredSize(new Dimension(150, 150)); // adjust the size of each RuleButton + + if (rule.getRuleName().length() > 18) { + ruleButtons[i].setFont(new Font("Segoe UI", Font.PLAIN, 11)); + } + if (rule.getRuleName().length() > 20) { + ruleButtons[i].setFont(new Font("Segoe UI", Font.PLAIN, 10)); + } + System.out.println(ruleButtons[i].getFont().getName()); + ruleButtons[i].setHorizontalTextPosition(JButton.CENTER); ruleButtons[i].setVerticalTextPosition(JButton.BOTTOM); @@ -64,30 +76,30 @@ public void setRules(List rules) { ruleButtons[i].setToolTipText(rule.getRuleName() + ": " + rule.getDescription()); // showing description ruleButtons[i].addActionListener(ruleFrame.getController()); add(ruleButtons[i]); - } revalidate(); } + /** + * Updates the rules displayed by reloading images and setting the rules again. + */ public void updateRules() { - for (Rule rule : rules){ + for (Rule rule : rules) { rule.loadImage(); } setRules(rules); } - /** * Search a certain rule in all the puzzles and set it for the searchBarPanel * * @param puzzle puzzle where the rule is being searched for * @param ruleName rule that is being compared to each puzzle - * - * This function is the searching algorithm for "public void setSearchBar(Puzzle allPuzzle)" (below) - * - * It takes two param Puzzle puzzle and String ruleName - * puzzle contains rules, this function will compare each rule of puzzle with ruleName, - * to find exact same, similar rules, or all the rules with same start letter (if input is a signal letter) + *

This function is the searching algorithm for "public void setSearchBar(Puzzle + * allPuzzle)" (below) + *

It takes two param Puzzle puzzle and String ruleName puzzle contains rules, this + * function will compare each rule of puzzle with ruleName, to find exact same, similar + * rules, or all the rules with same start letter (if input is a signal letter) */ public void searchForRule(Puzzle puzzle, String ruleName) { @@ -99,7 +111,6 @@ public void searchForRule(Puzzle puzzle, String ruleName) { ruleButtons = new RuleButton[100]; int similarfound = 0; - for (int i = 0; i < allrules.size(); i++) { for (int j = 0; j < allrules.get(i).size(); j++) { Rule rule = allrules.get(i).get(j); @@ -108,42 +119,46 @@ public void searchForRule(Puzzle puzzle, String ruleName) { ruleButtons[0] = new RuleButton(rule); ruleFrame.getButtonGroup().add(ruleButtons[0]); - ruleButtons[0].setPreferredSize(new Dimension(150, 150));// adjust the size of each RuleButton + ruleButtons[0].setPreferredSize( + new Dimension(150, 150)); // adjust the size of each RuleButton ruleButtons[0].setHorizontalTextPosition(JButton.CENTER); ruleButtons[0].setVerticalTextPosition(JButton.BOTTOM); - ruleButtons[0].setToolTipText(rule.getRuleName() + ": " + rule.getDescription()); + ruleButtons[0].setToolTipText( + rule.getRuleName() + ": " + rule.getDescription()); ruleButtons[0].addActionListener(ruleFrame.getController()); add(ruleButtons[0]); revalidate(); return; - } - else { + } else { if (similarityCheck(ruleName, rule.getRuleName().toUpperCase()) > 0.2) { ruleButtons[similarfound] = new RuleButton(rule); ruleFrame.getButtonGroup().add(ruleButtons[similarfound]); - ruleButtons[similarfound].setPreferredSize(new Dimension(150, 150));// adjust the size of each RuleButton + ruleButtons[similarfound].setPreferredSize( + new Dimension(150, 150)); // adjust the size of each RuleButton ruleButtons[similarfound].setHorizontalTextPosition(JButton.CENTER); ruleButtons[similarfound].setVerticalTextPosition(JButton.BOTTOM); - ruleButtons[similarfound].setToolTipText(rule.getRuleName() + ": " + rule.getDescription()); + ruleButtons[similarfound].setToolTipText( + rule.getRuleName() + ": " + rule.getDescription()); ruleButtons[similarfound].addActionListener(ruleFrame.getController()); add(ruleButtons[similarfound]); similarfound += 1; revalidate(); - } - else { + } else { if ((ruleName.charAt(0)) == (rule.getRuleName().toUpperCase()).charAt(0)) { ruleButtons[similarfound] = new RuleButton(rule); ruleFrame.getButtonGroup().add(ruleButtons[similarfound]); - ruleButtons[similarfound].setPreferredSize(new Dimension(150, 150));// adjust the size of each RuleButton + ruleButtons[similarfound].setPreferredSize( + new Dimension(150, 150)); // adjust the size of each RuleButton ruleButtons[similarfound].setHorizontalTextPosition(JButton.CENTER); ruleButtons[similarfound].setVerticalTextPosition(JButton.BOTTOM); - ruleButtons[similarfound].setToolTipText(rule.getRuleName() + ": " + rule.getDescription()); + ruleButtons[similarfound].setToolTipText( + rule.getRuleName() + ": " + rule.getDescription()); ruleButtons[similarfound].addActionListener(ruleFrame.getController()); add(ruleButtons[similarfound]); similarfound += 1; @@ -155,19 +170,24 @@ public void searchForRule(Puzzle puzzle, String ruleName) { } if (ruleButtons[0] == null) { - JOptionPane.showMessageDialog(null, "Please input the correct rule name", "Confirm", JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog( + null, + "Please input the correct rule name", + "Confirm", + JOptionPane.INFORMATION_MESSAGE); } } /** - * Calculates the similarity (a number within 0 and 1) between two strings. - * This function will take two para String s1 and String s2, which s1 is the user's input - * and s2 is the compared really rule name + * Calculates the similarity (a number within 0 and 1) between two strings. This function will + * take two para String s1 and String s2, which s1 is the user's input and s2 is the compared + * really rule name + * * @param s1 user's input * @param s2 the compared really rule name - * @return a similarity degree between 0 and 1 - * similarityCheck will use a helper function to calculate a similarity degree(from 0 to 1). - * closer to 0 means less similar, and closer to 1 means more similar. + * @return a similarity degree between 0 and 1 similarityCheck will use a helper function to + * calculate a similarity degree(from 0 to 1). closer to 0 means less similar, and closer to + * 1 means more similar. */ public static double similarityCheck(String s1, String s2) { String longer = s1, shorter = s2; @@ -184,6 +204,7 @@ public static double similarityCheck(String s1, String s2) { /** * Help function for similarityCheck(); + * * @param s1 user's input * @param s2 the compared really rule name * @return a similarity degree between 0 and 1 @@ -198,8 +219,7 @@ public static int editDistance(String s1, String s2) { for (int j = 0; j <= s2.length(); j++) { if (i == 0) { costs[j] = j; - } - else { + } else { if (j > 0) { int newValue = costs[j - 1]; if (s1.charAt(i - 1) != s2.charAt(j - 1)) { @@ -218,23 +238,24 @@ public static int editDistance(String s1, String s2) { } /** - * Sets the search bar for SearchBarPanel - * search bar allows user to input a name to get relative rules - * once a name is entered and click ok will load (a/several) rule icon, - * which has all the functions just as other rule icons. + * Sets the search bar for SearchBarPanel search bar allows user to input a name to get relative + * rules once a name is entered and click ok will load (a/several) rule icon, which has all the + * functions just as other rule icons. + * * @param allPuzzle name of rule input */ public void setSearchBar(Puzzle allPuzzle) { searchBarPanel = new JPanel(new FlowLayout(SwingConstants.LEADING, 6, 6)); - textField=new JTextField(); - ruleFrame.addComponentListener(new ComponentAdapter() { - public void componentResized(ComponentEvent componentEvent) { - Component c= componentEvent.getComponent(); - textField.setColumns((8+(c.getWidth()-250)/10)-1); - } - }); + textField = new JTextField(); + ruleFrame.addComponentListener( + new ComponentAdapter() { + public void componentResized(ComponentEvent componentEvent) { + Component c = componentEvent.getComponent(); + textField.setColumns((8 + (c.getWidth() - 250) / 10) - 1); + } + }); add(searchBarPanel); JLabel findLabel = new JLabel("Search:"); @@ -243,37 +264,40 @@ public void componentResized(ComponentEvent componentEvent) { searchBarPanel.add(textField); searchBarPanel.add(Box.createRigidArea(new Dimension(1, 0))); JButton findButton = new JButton("Go"); - ActionListener action = new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (ruleButtons != null) { - for (int i = 0; i != ruleButtons.length; i++) { - if (ruleButtons[i] == null) { - continue; + ActionListener action = + new ActionListener() { + @Override + public void actionPerformed(ActionEvent event) { + if (ruleButtons != null) { + for (int i = 0; i != ruleButtons.length; i++) { + if (ruleButtons[i] == null) { + continue; + } + ruleButtons[i].removeActionListener(ruleFrame.getController()); + } } - ruleButtons[i].removeActionListener(ruleFrame.getController()); - } - } - String inputRule = textField.getText().toUpperCase().trim(); + String inputRule = textField.getText().toUpperCase().trim(); - if (!inputRule.isEmpty()) { - if (ruleButtons != null) { + if (!inputRule.isEmpty()) { + if (ruleButtons != null) { - for (int x = 0; x < ruleButtons.length; ++x) { - if (ruleButtons[x] == null) { - continue; + for (int x = 0; x < ruleButtons.length; ++x) { + if (ruleButtons[x] == null) { + continue; + } + remove(ruleButtons[x]); + } } - remove(ruleButtons[x]); + searchForRule(allPuzzle, inputRule); + } else { + JOptionPane.showMessageDialog( + null, + "Please give a name", + "Confirm", + JOptionPane.INFORMATION_MESSAGE); } } - searchForRule(allPuzzle, inputRule); - } - else { - JOptionPane.showMessageDialog(null, "Please give a name", "Confirm", JOptionPane.INFORMATION_MESSAGE); - } - - } - }; + }; textField.addActionListener(action); findButton.addActionListener(action); searchBarPanel.add(findButton); @@ -295,9 +319,7 @@ public void setSelectionByRule(Rule rule) { } } - /** - * Clears the rule buttons off this panel - */ + /** Clears the rule buttons off this panel */ protected void clearButtons() { if (ruleButtons != null) { removeAll(); @@ -316,29 +338,59 @@ public List getRules() { return rules; } + /** + * Gets the icon associated with this panel + * + * @return The ImageIcon associated with this panel + */ public ImageIcon getIcon() { return icon; } + /** + * Sets the icon for this panel + * + * @return the ImageIcon associated with this panel + */ public void setIcon(ImageIcon icon) { this.icon = icon; } + /** + * Gets the name of this panel + * + * @return the name of this panel in a String + */ @Override public String getName() { return name; } + /** + * Sets the name of this panel + * + * @param name the name to set for this panel + */ @Override public void setName(String name) { this.name = name; } + /** + * Gets the tooltip text associated with this panel + * + * @return the tooltip text of this panel + */ public String getToolTip() { return toolTip; } + /** + * Sets the tooltip text for this panel + * + * @param toolTip the tooltip text to set for this panel + */ public void setToolTip(String toolTip) { this.toolTip = toolTip; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java index ff8a5d259..842859ce2 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java @@ -2,17 +2,24 @@ import javax.swing.*; + +/** + * The {@code SearchBarPanel} class creates a panel that allows users to search for rules within the rule frame. + * This panel provides a search bar for entering rule names and finding corresponding rules. + */ public class SearchBarPanel extends RulePanel { /** * SearchBarPanel Constructor creates a SearchBarPanel * * @param ruleFrame rule frame that this SearchBarPanel is contained in - *

- * This class is used to create a panel named "search bar" + *

This class is used to create a panel named "search bar" */ SearchBarPanel(RuleFrame ruleFrame) { super(ruleFrame); - this.icon = new ImageIcon(ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/Zoom In.png")); + this.icon = + new ImageIcon( + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Zoom In.png")); this.name = "Search Rules"; this.toolTip = "Search Rules"; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java index 676992654..228e69950 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeElementView.java @@ -2,9 +2,14 @@ import edu.rpi.legup.model.tree.TreeElement; import edu.rpi.legup.model.tree.TreeElementType; - import java.awt.*; +/** + * Abstract base class for views of tree elements in the tree structure. + * This class implements the Shape interface to support custom drawing and interaction + * with tree elements. + * It holds properties for rendering, interaction, and layout of the tree elements. + */ public abstract class TreeElementView implements Shape { protected TreeElement treeElement; protected double span; @@ -18,7 +23,7 @@ public abstract class TreeElementView implements Shape { /** * TreeElementView Constructor creates a tree puzzleElement view * - * @param type tree puzzleElement type + * @param type tree puzzleElement type * @param treeElement tree puzzleElement puzzleElement associated with this view */ protected TreeElementView(TreeElementType type, TreeElement treeElement) { @@ -37,7 +42,7 @@ protected TreeElementView(TreeElementType type, TreeElement treeElement) { public abstract void draw(Graphics2D graphics2D); /** - * Gets the span for the sub tree rooted at this view + * Gets the span for the subtree rooted at this view * * @return span bounded y span */ @@ -46,7 +51,7 @@ public double getSpan() { } /** - * Sets the span for the sub tree rooted at this view. + * Sets the span for the subtree rooted at this view. * * @param span bounded y span */ @@ -136,8 +141,8 @@ public void setHover(boolean isHovered) { } /** - * Gets the visibility of the tree puzzleElement. - * Tells the TreeView whether or not to draw the tree puzzleElement + * Gets the visibility of the tree puzzleElement. Tells the TreeView whether or not to draw the + * tree puzzleElement * * @return visibility of the tree puzzleElement */ diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java index 2fce4d2d1..0e2a31bbf 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeNodeView.java @@ -3,11 +3,16 @@ import edu.rpi.legup.model.rules.RuleType; import edu.rpi.legup.model.tree.TreeElementType; import edu.rpi.legup.model.tree.TreeNode; - import java.awt.*; import java.awt.geom.*; import java.util.ArrayList; +/** + * Represents a view of a tree node in the tree structure. + * This class extends {@link TreeElementView} and provides specific rendering and interaction + * functionality for tree nodes. It includes visual properties and methods to manage the + * node's appearance, location, and its relationships with other nodes. + */ public class TreeNodeView extends TreeElementView { static final int RADIUS = 25; static final int DIAMETER = 2 * RADIUS; @@ -31,7 +36,6 @@ public class TreeNodeView extends TreeElementView { private static final Color HOVER_COLOR = new Color(0x90CAF9); private static final Color OUTLINE_HOVER_COLOR = new Color(0xBDBDBD); - private Point location; private TreeTransitionView parentView; @@ -63,48 +67,69 @@ public TreeNodeView(TreeNode treeNode) { */ public void draw(Graphics2D graphics2D) { if (isVisible() && treeElement != null) { - if (getTreeElement().getParent() != null && - getTreeElement().getParent().isJustified() && - getTreeElement().getParent().getRule().getRuleType() == RuleType.CONTRADICTION) { + if (getTreeElement().getParent() != null + && getTreeElement().getParent().isJustified() + && getTreeElement().getParent().getRule().getRuleType() + == RuleType.CONTRADICTION) { isContradictoryState = true; graphics2D.setColor(NODE_COLOR_CONTRADICTION); - graphics2D.drawLine(location.x - RADIUS, location.y - RADIUS, location.x + RADIUS, location.y + RADIUS); - graphics2D.drawLine(location.x + RADIUS, location.y - RADIUS, location.x - RADIUS, location.y + RADIUS); - } - else { + graphics2D.drawLine( + location.x - RADIUS, + location.y - RADIUS, + location.x + RADIUS, + location.y + RADIUS); + graphics2D.drawLine( + location.x + RADIUS, + location.y - RADIUS, + location.x - RADIUS, + location.y + RADIUS); + } else { isContradictoryState = false; graphics2D.setStroke(MAIN_STROKE); boolean isContraBranch = getTreeElement().isContradictoryBranch(); if (isSelected) { graphics2D.setColor(SELECTION_COLOR); - graphics2D.fillOval(location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); + graphics2D.fillOval( + location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); graphics2D.setColor(OUTLINE_COLOR); - graphics2D.drawOval(location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); + graphics2D.drawOval( + location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); graphics2D.setStroke(SELECTION_STROKE); graphics2D.setColor(OUTLINE_SELECTION_COLOR); - graphics2D.drawOval(location.x - RADIUS - 4, location.y - RADIUS - 4, DIAMETER + 8, DIAMETER + 8); - } - else { + graphics2D.drawOval( + location.x - RADIUS - 4, + location.y - RADIUS - 4, + DIAMETER + 8, + DIAMETER + 8); + } else { if (isHover) { graphics2D.setColor(HOVER_COLOR); - graphics2D.fillOval(location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); + graphics2D.fillOval( + location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); graphics2D.setColor(OUTLINE_COLOR); - graphics2D.drawOval(location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); + graphics2D.drawOval( + location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); graphics2D.setStroke(SELECTION_STROKE); graphics2D.setColor(OUTLINE_HOVER_COLOR); - graphics2D.drawOval(location.x - RADIUS - 4, location.y - RADIUS - 4, DIAMETER + 8, DIAMETER + 8); - } - else { - graphics2D.setColor(isContraBranch ? NODE_COLOR_CONTRADICTION : NODE_COLOR_DEFAULT); - graphics2D.fillOval(location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); + graphics2D.drawOval( + location.x - RADIUS - 4, + location.y - RADIUS - 4, + DIAMETER + 8, + DIAMETER + 8); + } else { + graphics2D.setColor( + isContraBranch ? NODE_COLOR_CONTRADICTION : NODE_COLOR_DEFAULT); + graphics2D.fillOval( + location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); graphics2D.setColor(OUTLINE_COLOR); - graphics2D.drawOval(location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); + graphics2D.drawOval( + location.x - RADIUS, location.y - RADIUS, DIAMETER, DIAMETER); } } } @@ -241,53 +266,121 @@ public int getRadius() { return RADIUS; } + /** + * Returns the bounding rectangle of this TreeNodeView + * + * @return a Rectangle representing the bounding box of this TreeNodeView + */ @Override public Rectangle getBounds() { return new Rectangle(location.x, location.y, DIAMETER, DIAMETER); } + /** + * Returns the bounding rectangle of this TreeNodeView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this TreeNodeView + */ @Override public Rectangle2D getBounds2D() { return new Rectangle(location.x, location.y, DIAMETER, DIAMETER); } + /** + * Determines if the specified point (x, y) is within the bounds of this TreeNodeView + * + * @param x the x-coordinate of the point to check + * @param y the y-coordinate of the point to check + * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean contains(double x, double y) { return Math.sqrt(Math.pow(x - location.x, 2) + Math.pow(y - location.y, 2)) <= RADIUS; } + /** + * Determines if the specified Point2D object is within the bounds of this TreeNodeView + * + * @param p the Point2D object representing the point to check + * @return {@code true} if the point is within the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean contains(Point2D p) { return contains(p.getX(), p.getY()); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this TreeNodeView. + * + * @param x The x-coordinate of the rectangle to check + * @param y The y-coordinate of the rectangle to check + * @param w The width of the rectangle to check + * @param h The height of the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean intersects(double x, double y, double w, double h) { return false; } + /** + * Determines if the specified Rectangle2D object intersects with the bounds of this TreeNodeView. + * + * @param r the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean intersects(Rectangle2D r) { return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this TreeNodeView + * + * @param x the x-coordinate of the rectangle to check + * @param y the y-coordinate of the rectangle to check + * @param w the width of the rectangle to check + * @param h the height of the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean contains(double x, double y, double w, double h) { return false; } + /** + * Determines if the specified Rectangle2D object is entirely contained within the bounds of this TreeNodeView. + * + * @param r the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeNodeView; {@code false} otherwise + */ @Override public boolean contains(Rectangle2D r) { return false; } + /** + * Returns an iterator over the path geometry of this TreeNodeView. The iterator provides access to the path's + * segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @return a PathIterator that iterates over the path geometry of this TreeNodeView + */ @Override public PathIterator getPathIterator(AffineTransform at) { return null; } + /** + * Returns an iterator over the path geometry of this TreeNodeView with the specified flatness. The iterator provides + * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @param flatness the maximum distance that the line segments can deviate from the true path + * @return a PathIterator that iterates over the path geometry of this TreeNodeView + */ @Override public PathIterator getPathIterator(AffineTransform at, double flatness) { return null; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java index ac7accaee..4bef664bd 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreePanel.java @@ -10,17 +10,19 @@ import edu.rpi.legup.model.tree.Tree; import edu.rpi.legup.ui.DynamicView; import edu.rpi.legup.ui.DynamicViewType; -import edu.rpi.legup.ui.LegupUI; import edu.rpi.legup.ui.lookandfeel.materialdesign.MaterialFonts; - import java.awt.*; - +import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; - -import javax.swing.BorderFactory; import javax.swing.border.TitledBorder; + +/** + * {@code TreePanel} is a JPanel that manages and displays a tree view with associated toolbar and status information. + * It provides methods to interact with the tree view, such as adding, deleting, and merging tree elements, + * and updating the status based on actions performed. + */ public class TreePanel extends JPanel { public boolean modifiedSinceSave = false; public boolean modifiedSinceUndoPush = false; @@ -33,8 +35,11 @@ public class TreePanel extends JPanel { private JLabel status; - public TreePanel(/*LegupUI legupUI*/) { - //this.legupUI = legupUI; + /** + * Constructs a {@code TreePanel} and initializes the UI components. + */ + public TreePanel(/*LegupUI legupUI*/ ) { + // this.legupUI = legupUI; main = new JPanel(); @@ -64,17 +69,32 @@ public TreePanel(/*LegupUI legupUI*/) { updateStatusTimer = 0; } + /** + * Repaints the tree view with the provided {@link Tree} object + * + * @param tree the {@link Tree} object to update the view with + */ public void repaintTreeView(Tree tree) { treeView.updateTreeView(tree); } + /** + * Updates the status of the panel based on changes to the {@link Board} + * + * @param board the {@link Board} object representing the current board state + */ public void boardDataChanged(Board board) { modifiedSinceSave = true; modifiedSinceUndoPush = true; updateStatus(); - //colorTransitions(); + // colorTransitions(); } + /** + * Updates the status display based on the status timer. + * If the timer is greater than 0, the status will not be updated. + * Otherwise, it clears the status text. + */ public void updateStatus() { updateStatusTimer = ((updateStatusTimer - 1) > 0) ? (updateStatusTimer - 1) : 0; if (updateStatusTimer > 0) { @@ -83,22 +103,41 @@ public void updateStatus() { this.status.setText(""); } + /** + * Updates the status display with the given status string + * + * @param statusString the status string to display + */ public void updateStatus(String statusString) { status.setForeground(Color.BLACK); status.setFont(MaterialFonts.REGULAR); status.setText(statusString); } + /** + * Updates the status display as an error with an error message + * + * @param error the error message to display + */ public void updateError(String error) { status.setForeground(Color.RED); status.setFont(MaterialFonts.ITALIC); status.setText(error); } + /** + * Gets the {@link TreeView} instance associated with this panel + * + * @return the {@link TreeView} instance + */ public TreeView getTreeView() { return treeView; } + /** + * Adds a new tree element by executing an {@link AddTreeElementCommand}. + * If the command cannot be executed, it updates the status display with an error and error message. + */ public void add() { TreeViewSelection selection = treeView.getSelection(); @@ -106,12 +145,15 @@ public void add() { if (add.canExecute()) { add.execute(); GameBoardFacade.getInstance().getHistory().pushChange(add); - } - else { + } else { updateError(add.getError()); } } + /** + * Deletes the selected tree element by executing a {@link DeleteTreeElementCommand}. + * If the command cannot be executed, it updates the status display with an error and an error message. + */ public void delete() { TreeViewSelection selection = treeView.getSelection(); @@ -119,12 +161,15 @@ public void delete() { if (del.canExecute()) { del.execute(); GameBoardFacade.getInstance().getHistory().pushChange(del); - } - else { + } else { updateError(del.getError()); } } + /** + * Merges selected tree elements by executing a {@link MergeCommand}. + * If the command cannot be executed, it updates the status display with an error and an error message. + */ public void merge() { TreeViewSelection selection = treeView.getSelection(); @@ -132,12 +177,15 @@ public void merge() { if (merge.canExecute()) { merge.execute(); GameBoardFacade.getInstance().getHistory().pushChange(merge); - } - else { + } else { updateError(merge.getError()); } } + /** + * Toggles the collapsed state of the selected tree elements. + * If an element is collapsed, it will be expanded, and vice versa. + */ public void collapse() { TreeViewSelection selection = treeView.getSelection(); for (TreeElementView view : selection.getSelectedViews()) { diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java index c2f40e21a..214c735df 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarButton.java @@ -1,13 +1,22 @@ package edu.rpi.legup.ui.proofeditorui.treeview; -import javax.swing.*; import java.awt.Dimension; +import javax.swing.*; +/** + * {@code TreeToolBarButton} is a JButton that represents a button in the tree toolbar. + */ public class TreeToolBarButton extends JButton { private TreeToolBarName name; private final Dimension MINIMUM_DIMENSION = new Dimension(60, 60); + /** + * Constructs a {@code TreeToolBarButton} with the specified icon and name. + * + * @param imageIcon the {@link ImageIcon} to be displayed on the button + * @param name the {@link TreeToolBarName} associated with this button + */ public TreeToolBarButton(ImageIcon imageIcon, TreeToolBarName name) { super(imageIcon); this.name = name; @@ -16,6 +25,11 @@ public TreeToolBarButton(ImageIcon imageIcon, TreeToolBarName name) { this.setFocusPainted(false); } + /** + * Gets the {@link TreeToolBarName} associated with this button + * + * @return the {@link TreeToolBarName} associated with this button + */ public TreeToolBarName getToolBarName() { return name; } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java index dd8a37c15..3aec664be 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolBarName.java @@ -1,5 +1,12 @@ package edu.rpi.legup.ui.proofeditorui.treeview; +/** + * {@code TreeToolBarName} defines the names of actions represented by buttons in the tree toolbar. + * These actions are used for managing tree elements within the UI. + */ public enum TreeToolBarName { - ADD_CHILD, DEL_CHILD, MERGE, COLLAPSE + ADD_CHILD, + DEL_CHILD, + MERGE, + COLLAPSE } diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java index 332fd64a0..500ed29c5 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeToolbarPanel.java @@ -1,25 +1,50 @@ package edu.rpi.legup.ui.proofeditorui.treeview; -import javax.swing.*; import java.awt.*; +import javax.swing.*; + +/** + * {@code TreeToolbarPanel} is a JPanel that provides a toolbar for managing tree elements in the tree view. + * It includes buttons for adding, deleting, merging, and collapsing nodes. + */ public class TreeToolbarPanel extends JPanel { private TreePanel treePanel; private TreeToolBarButton addChild, delChild, merge, collapse; /** * TreeToolbarPanel Constructor - creates the tree tool mBar panel + * * @param treePanel treePanel input */ public TreeToolbarPanel(TreePanel treePanel) { this.treePanel = treePanel; this.setLayout(new GridLayout(4, 1, 0, 2)); - - addChild = new TreeToolBarButton(new ImageIcon(ClassLoader.getSystemResource("edu/rpi/legup/images/Legup/AddChild.png")), TreeToolBarName.ADD_CHILD); - delChild = new TreeToolBarButton(new ImageIcon(ClassLoader.getSystemResource("edu/rpi/legup/images/Legup/DelChild.png")), TreeToolBarName.DEL_CHILD); - merge = new TreeToolBarButton(new ImageIcon(ClassLoader.getSystemResource("edu/rpi/legup/images/Legup/Merge.png")), TreeToolBarName.MERGE); - collapse = new TreeToolBarButton(new ImageIcon(ClassLoader.getSystemResource("edu/rpi/legup/images/Legup/Collapse.png")), TreeToolBarName.COLLAPSE); + addChild = + new TreeToolBarButton( + new ImageIcon( + ClassLoader.getSystemResource( + "edu/rpi/legup/images/Legup/AddChild.png")), + TreeToolBarName.ADD_CHILD); + delChild = + new TreeToolBarButton( + new ImageIcon( + ClassLoader.getSystemResource( + "edu/rpi/legup/images/Legup/DelChild.png")), + TreeToolBarName.DEL_CHILD); + merge = + new TreeToolBarButton( + new ImageIcon( + ClassLoader.getSystemResource( + "edu/rpi/legup/images/Legup/Merge.png")), + TreeToolBarName.MERGE); + collapse = + new TreeToolBarButton( + new ImageIcon( + ClassLoader.getSystemResource( + "edu/rpi/legup/images/Legup/Collapse.png")), + TreeToolBarName.COLLAPSE); add(addChild); addChild.addActionListener(a -> treePanel.add()); @@ -38,4 +63,4 @@ public TreeToolbarPanel(TreePanel treePanel) { collapse.setToolTipText("Collapse nodes"); collapse.setEnabled(false); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java index 749af0c79..25c67bb5a 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeTransitionView.java @@ -1,16 +1,20 @@ package edu.rpi.legup.ui.proofeditorui.treeview; +import static java.lang.Math.*; + +import edu.rpi.legup.app.LegupPreferences; import edu.rpi.legup.model.tree.TreeElementType; import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.app.LegupPreferences; - import java.awt.*; import java.awt.geom.*; -import java.util.List; import java.util.ArrayList; +import java.util.List; -import static java.lang.Math.*; - +/** + * {@code TreeTransitionView} is a visual representation of a tree transition in the tree view. + * It extends TreeElementView and displays a transition arrow between tree nodes and handles various + * visual states such as selection, hover, and correctness. + */ public class TreeTransitionView extends TreeElementView { static final int RADIUS = 25; static final int DIAMETER = 2 * RADIUS; @@ -86,8 +90,15 @@ public void draw(Graphics2D graphics2D) { double ctrlx2 = lineEndPoint.x - 25; double ctrly2 = lineEndPoint.y; - c.setCurve(lineStartPoint.x, lineStartPoint.y, ctrlx1, - ctrly1, ctrlx2, ctrly2, lineEndPoint.x, lineEndPoint.y); + c.setCurve( + lineStartPoint.x, + lineStartPoint.y, + ctrlx1, + ctrly1, + ctrlx2, + ctrly2, + lineEndPoint.x, + lineEndPoint.y); graphics2D.draw(c); } @@ -100,16 +111,13 @@ public void draw(Graphics2D graphics2D) { if (getTreeElement().isCorrect()) { if (colorBlind) { c = CORRECT_COLOR_COLORBLIND; - } - else { + } else { c = CORRECT_COLOR; } - } - else { + } else { if (colorBlind) { c = INCORRECT_COLOR_COLORBLIND; - } - else { + } else { c = INCORRECT_COLOR; } } @@ -127,8 +135,7 @@ public void draw(Graphics2D graphics2D) { graphics2D.setStroke(SELECTION_STROKE); graphics2D.setColor(OUTLINE_SELECTION_COLOR); graphics2D.drawPolygon(selection_triangle); - } - else { + } else { if (isHover) { graphics2D.setColor(HOVER_COLOR); graphics2D.fillPolygon(arrowhead); @@ -142,23 +149,19 @@ public void draw(Graphics2D graphics2D) { graphics2D.setStroke(SELECTION_STROKE); graphics2D.setColor(OUTLINE_HOVER_COLOR); graphics2D.drawPolygon(selection_triangle); - } - else { + } else { Color c = DEFAULT_COLOR; if (getTreeElement().isJustified()) { if (getTreeElement().isCorrect()) { if (colorBlind) { c = CORRECT_COLOR_COLORBLIND; - } - else { + } else { c = CORRECT_COLOR; } - } - else { + } else { if (colorBlind) { c = INCORRECT_COLOR_COLORBLIND; - } - else { + } else { c = INCORRECT_COLOR; } } @@ -172,9 +175,7 @@ public void draw(Graphics2D graphics2D) { } } - /** - * Constructs the arrowhead shape from the start and end points - */ + /** Constructs the arrowhead shape from the start and end points */ private Polygon createTransitionTriangle(int radius) { double thetaArrow = Math.toRadians(30); @@ -270,87 +271,165 @@ public void removeParentView(TreeNodeView nodeView) { } } - public Point getEndPoint() { - return endPoint; - } - - public void setEndPoint(Point endPoint) { - this.endPoint = endPoint; - } - + /** + * Gets the x-coordinate of the end point of the transition arrow + * + * @return the x-coordinate of the end point + */ public int getEndX() { return endPoint.x; } + /** + * Sets the x-coordinate of the end point of the transition arrow + * + * @param x the new x-coordinate of the end point + */ public void setEndX(int x) { this.endPoint.x = x; } + /** + * Gets the y-coordinate of the end point of the transition arrow + * + * @return the y-coordinate of the end point + */ public int getEndY() { return endPoint.y; } + /** + * Sets the y-coordinate of the end point of the transition arrow + * + * @param y the new y-coordinate of the end point + */ public void setEndY(int y) { this.endPoint.y = y; } - public List getLineStartPoints() { - return lineStartPoints; - } - - public void setLineStartPoints(List lineStartPoints) { - this.lineStartPoints = lineStartPoints; - } - + /** + * Gets the start point at the specified index from the list of start points + * + * @param index the index of the start point to retrieve + * @return the start point at the specified index, or null if the index is out of range + */ public Point getLineStartPoint(int index) { return index < lineStartPoints.size() ? lineStartPoints.get(index) : null; } + /** + * Returns the bounding rectangle of this TreeTransitionView + * + * @return a Rectangle representing the bounding box of this TreeTransitionView + */ @Override public Rectangle getBounds() { return arrowhead.getBounds(); } + /** + * Returns the bounding rectangle of this TreeTransitionView as a Rectangle2D + * + * @return a Rectangle2D representing the bounding box of this TreeTransitionView + */ @Override public Rectangle2D getBounds2D() { return arrowhead.getBounds2D(); } + /** + * Determines if the specified point (x, y) is within the bounds of this TreeTransitionView + * + * @param x the x-coordinate of the point to check + * @param y the y-coordinate of the point to check + * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean contains(double x, double y) { return arrowhead.contains(x, y); } + /** + * Determines if the specified Point2D object is within the bounds of this TreeTransitionView + * + * @param p the Point2D object representing the point to check + * @return {@code true} if the point is within the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean contains(Point2D p) { return arrowhead != null && arrowhead.contains(p); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) intersects with the bounds of this TreeTransitionView. + * + * @param x The x-coordinate of the rectangle to check + * @param y The y-coordinate of the rectangle to check + * @param w The width of the rectangle to check + * @param h The height of the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean intersects(double x, double y, double w, double h) { return arrowhead.intersects(x, y, w, h); } + /** + * Determines if the specified Rectangle2D object intersects with the bounds of this TreeTransitionView. + * + * @param r the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle intersects with the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean intersects(Rectangle2D r) { return arrowhead.intersects(r); } + /** + * Determines if the specified rectangle defined by (x, y, width, height) is entirely contained within the bounds of this TreeTransitionView + * + * @param x the x-coordinate of the rectangle to check + * @param y the y-coordinate of the rectangle to check + * @param w the width of the rectangle to check + * @param h the height of the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean contains(double x, double y, double w, double h) { return arrowhead.contains(x, y, w, h); } + /** + * Determines if the specified Rectangle2D object is entirely contained within the bounds of this TreeTransitionView. + * + * @param r the Rectangle2D object representing the rectangle to check + * @return {@code true} if the rectangle is entirely contained within the bounds of this TreeTransitionView; {@code false} otherwise + */ @Override public boolean contains(Rectangle2D r) { return arrowhead.contains(r); } + /** + * Returns an iterator over the path geometry of this TreeTransitionView. The iterator provides access to the path's + * segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @return a PathIterator that iterates over the path geometry of this TreeTransitionView + */ @Override public PathIterator getPathIterator(AffineTransform at) { return arrowhead.getPathIterator(at); } + /** + * Returns an iterator over the path geometry of this TreeTransitionView with the specified flatness. The iterator provides + * access to the path's segments and their coordinates, which can be used for rendering or hit testing. + * + * @param at the AffineTransform to apply to the path geometry + * @param flatness the maximum distance that the line segments can deviate from the true path + * @return a PathIterator that iterates over the path geometry of this TreeTransitionView + */ @Override public PathIterator getPathIterator(AffineTransform at, double flatness) { return arrowhead.getPathIterator(at, flatness); diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java index 9bfffe60a..490cf1480 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeView.java @@ -1,9 +1,13 @@ package edu.rpi.legup.ui.proofeditorui.treeview; +import static edu.rpi.legup.model.tree.TreeElementType.NODE; +import static edu.rpi.legup.model.tree.TreeElementType.TRANSITION; +import static edu.rpi.legup.ui.proofeditorui.treeview.TreeNodeView.DIAMETER; +import static edu.rpi.legup.ui.proofeditorui.treeview.TreeNodeView.RADIUS; + import edu.rpi.legup.app.GameBoardFacade; import edu.rpi.legup.controller.TreeController; import edu.rpi.legup.model.gameboard.Board; -import edu.rpi.legup.model.gameboard.GridCell; import edu.rpi.legup.model.gameboard.PuzzleElement; import edu.rpi.legup.model.observer.ITreeListener; import edu.rpi.legup.model.rules.CaseRule; @@ -14,23 +18,22 @@ import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.ui.ScrollView; import edu.rpi.legup.utility.DisjointSets; - -import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.util.*; import java.util.List; - +import javax.swing.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import static edu.rpi.legup.model.tree.TreeElementType.NODE; -import static edu.rpi.legup.model.tree.TreeElementType.TRANSITION; -import static edu.rpi.legup.ui.proofeditorui.treeview.TreeNodeView.DIAMETER; -import static edu.rpi.legup.ui.proofeditorui.treeview.TreeNodeView.RADIUS; - +/** + * The {@code TreeView} class provides a graphical representation of a {@code Tree} structure, + * allowing interaction and visualization of tree elements, transitions, and selections. + * It extends {@code ScrollView} and implements {@code ITreeListener} to respond to updates + * in the tree structure. + */ public class TreeView extends ScrollView implements ITreeListener { - private final static Logger LOGGER = LogManager.getLogger(TreeView.class.getName()); + private static final Logger LOGGER = LogManager.getLogger(TreeView.class.getName()); private static final int TRANS_GAP = 5; @@ -54,6 +57,11 @@ public class TreeView extends ScrollView implements ITreeListener { private TreeViewSelection selection; + /** + * Constructs a {@code TreeView} with the specified {@code TreeController}. + * + * @param treeController the {@code TreeController} used to manage tree operations + */ public TreeView(TreeController treeController) { super(treeController); currentStateBoxes = new ArrayList<>(); @@ -65,6 +73,11 @@ public TreeView(TreeController treeController) { selection = new TreeViewSelection(); } + /** + * Gets the current tree view selection + * + * @return the {@code TreeViewSelection} object representing the current selection + */ public TreeViewSelection getSelection() { return selection; } @@ -88,7 +101,8 @@ public void setNodeHover(TreeNodeView nodeHover) { } /** - * Gets the TreeElementView by the specified point or null if no view exists at the specified point + * Gets the TreeElementView by the specified point or null if no view exists at the specified + * point * * @param point location to query for a view * @return TreeElementView at the point specified, otherwise null @@ -98,25 +112,24 @@ public TreeElementView getTreeElementView(Point point) { } /** - * Recursively gets the TreeElementView by the specified point or null if no view exists at the specified point or - * the view specified is null + * Recursively gets the TreeElementView by the specified point or null if no view exists at the + * specified point or the view specified is null * - * @param point location to query for a view + * @param point location to query for a view * @param elementView view to determine if the point is contained within it * @return TreeElementView at the point specified, otherwise null */ private TreeElementView getTreeElementView(Point point, TreeElementView elementView) { if (elementView == null) { return null; - } - else { + } else { if (elementView.contains(point) && elementView.isVisible()) { - if (elementView.getType() == NODE && ((TreeNodeView) elementView).isContradictoryState()) { + if (elementView.getType() == NODE + && ((TreeNodeView) elementView).isContradictoryState()) { return null; } return elementView; - } - else { + } else { if (elementView.getType() == NODE) { TreeNodeView nodeView = (TreeNodeView) elementView; for (TreeTransitionView transitionView : nodeView.getChildrenViews()) { @@ -125,8 +138,7 @@ private TreeElementView getTreeElementView(Point point, TreeElementView elementV return view; } } - } - else { + } else { TreeTransitionView transitionView = (TreeTransitionView) elementView; return getTreeElementView(point, transitionView.getChildView()); } @@ -135,6 +147,11 @@ private TreeElementView getTreeElementView(Point point, TreeElementView elementV return null; } + /** + * Updates the tree view with the specified {@code Tree} + * + * @param tree the {@code Tree} to display in the view + */ public void updateTreeView(Tree tree) { this.tree = tree; if (selection.getSelectedViews().size() == 0) { @@ -152,6 +169,9 @@ public void setTree(Tree tree) { this.tree = tree; } + /** + * Updates the size of the tree view based on the bounds of its tree + */ public void updateTreeSize() { if (GameBoardFacade.getInstance().getTree() == null) { return; @@ -159,15 +179,23 @@ public void updateTreeSize() { setSize(bounds.getSize()); } + /** + * Resets the view if the tree bounds have been modified + */ public void reset() { if (bounds.x != 0 || bounds.y != 0) { updateTreeSize(); } } + /** + * Adjusts the zoom level to fit the entire tree within the viewport when + * the Resize Proof button is selected + */ public void zoomFit() { - double fitWidth = (viewport.getWidth() - 8.0) / (getSize().width - 200); - double fitHeight = (viewport.getHeight() - 8.0) / (getSize().height - 120); + final int MIN_HEIGHT = 200; + double fitWidth = (viewport.getWidth() - 7.0) / (getSize().width - 75); + double fitHeight = (viewport.getHeight()) / Math.max((getSize().height - 115), MIN_HEIGHT); zoomTo(Math.min(fitWidth, fitHeight)); viewport.setViewPosition(new Point(0, viewport.getHeight() / 2)); } @@ -216,19 +244,26 @@ public void layoutContainer(Container parent) { }; } + /** + * Draws the tree view on the provided {@code Graphics2D} context + * + * @param graphics2D the {@code Graphics2D} context to draw on + */ public void draw(Graphics2D graphics2D) { currentStateBoxes.clear(); Tree tree = GameBoardFacade.getInstance().getTree(); if (tree != null) { - //setSize(bounds.getDimension()); - graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + // setSize(bounds.getDimension()); + graphics2D.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.setRenderingHint( + RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); drawTree(graphics2D); dimension.width += BORDER_SPACING; setSize(dimension); -// graphics2D.drawRect(0,0, dimension.width, dimension.height); + // graphics2D.drawRect(0,0, dimension.width, dimension.height); if (selection.getHover() != null) { drawMouseOver(graphics2D); @@ -236,11 +271,20 @@ public void draw(Graphics2D graphics2D) { } } + /** + * Resets the zoom level to its default state and positions the viewport from the top-left corner + */ public void zoomReset() { zoomTo(1.0); viewport.setViewPosition(new Point(0, 0)); } + /** + * Recursively redraws the tree starting from the specified node view + * + * @param graphics2D the {@code Graphics2D} context to draw on + * @param nodeView the {@code TreeNodeView} to start drawing from + */ private void redrawTree(Graphics2D graphics2D, TreeNodeView nodeView) { if (nodeView != null) { nodeView.draw(graphics2D); @@ -251,14 +295,20 @@ private void redrawTree(Graphics2D graphics2D, TreeNodeView nodeView) { } } + /** + * Removes the specified {@code TreeElementView} from the tree view + * + * @param view the {@code TreeElementView} to remove + */ public void removeTreeElement(TreeElementView view) { if (view.getType() == NODE) { TreeNodeView nodeView = (TreeNodeView) view; nodeView.getParentView().setChildView(null); - } - else { + } else { TreeTransitionView transitionView = (TreeTransitionView) view; - transitionView.getParentViews().forEach((TreeNodeView n) -> n.removeChildrenView(transitionView)); + transitionView + .getParentViews() + .forEach((TreeNodeView n) -> n.removeChildrenView(transitionView)); } } @@ -268,18 +318,24 @@ public void removeTreeElement(TreeElementView view) { * @param g the graphics to use to draw */ public void drawMouseOver(Graphics2D g) { - if (selection.getHover().getType() == TRANSITION && ((TreeTransitionView) selection.getHover()).getTreeElement().isJustified()) { + if (selection.getHover().getType() == TRANSITION + && ((TreeTransitionView) selection.getHover()).getTreeElement().isJustified()) { TreeTransition transition = (TreeTransition) selection.getHover().treeElement; int imgWidth = 100; int imgHeight = 100; - BufferedImage image = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_ARGB); - image.createGraphics().drawImage(transition.getRule().getImageIcon().getImage(), 0, 0, null); + BufferedImage image = + new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_ARGB); + image.createGraphics() + .drawImage(transition.getRule().getImageIcon().getImage(), 0, 0, null); Point mousePoint = selection.getMousePoint(); g.drawImage(image, mousePoint.x, mousePoint.y - 50, imgWidth, imgHeight, null); } } + /** + * Resets the view by clearing the current tree, root node view, and selection + */ public void resetView() { this.tree = null; this.rootNodeView = null; @@ -296,8 +352,7 @@ public void resetView() { public void onTreeElementAdded(TreeElement treeElement) { if (treeElement.getType() == NODE) { addTreeNode((TreeNode) treeElement); - } - else { + } else { addTreeTransition((TreeTransition) treeElement); } repaint(); @@ -316,8 +371,7 @@ public void onTreeElementRemoved(TreeElement element) { nodeView.getParentView().setChildView(null); removeTreeNode(node); - } - else { + } else { TreeTransition trans = (TreeTransition) element; TreeTransitionView transView = (TreeTransitionView) viewMap.get(trans); @@ -330,7 +384,7 @@ public void onTreeElementRemoved(TreeElement element) { continue; } - CaseRule caseRule = (CaseRule)rule; + CaseRule caseRule = (CaseRule) rule; // set dependent elements to be modifiable by ancestors (if not dependent on others) List ancestors = node.getAncestors(); for (TreeNode ancestor : ancestors) { @@ -339,22 +393,29 @@ public void onTreeElementRemoved(TreeElement element) { continue; } - for (PuzzleElement pelement : caseRule.dependentElements(node.getBoard(), trans.getSelection())) { + for (PuzzleElement pelement : + caseRule.dependentElements(node.getBoard(), trans.getSelection())) { // decrement, unlock if 0 cases depended - PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(pelement); + PuzzleElement oldElement = + ancestor.getParent().getBoard().getPuzzleElement(pelement); oldElement.setCasesDepended(oldElement.getCasesDepended() - 1); if (oldElement.getCasesDepended() != 0) { - continue; + continue; } // set modifiable if started modifiable - boolean modifiable = tree.getRootNode().getBoard().getPuzzleElement(oldElement).isModifiable(); + boolean modifiable = + tree.getRootNode() + .getBoard() + .getPuzzleElement(oldElement) + .isModifiable(); // unmodifiable if already modified TreeNode modNode = ancestor.getParent().getParents().get(0); - while (modNode.getParent()!=null) { + while (modNode.getParent() != null) { Board modBoard = modNode.getParent().getBoard(); - if (modBoard.getModifiedData().contains(modBoard.getPuzzleElement(oldElement))) { + if (modBoard.getModifiedData() + .contains(modBoard.getPuzzleElement(oldElement))) { modifiable = false; break; } @@ -364,7 +425,7 @@ public void onTreeElementRemoved(TreeElement element) { } } } - + transView.getParentViews().forEach(n -> n.removeChildrenView(transView)); removeTreeTransition(trans); } @@ -384,9 +445,7 @@ public void onTreeSelectionChanged(TreeViewSelection selection) { repaint(); } - /** - * Called when the model has finished updating the tree. - */ + /** Called when the model has finished updating the tree. */ @Override public void onUpdateTree() { repaint(); @@ -402,15 +461,24 @@ public TreeElementView getElementView(TreeElement element) { return viewMap.get(element); } - private void removeTreeNode(TreeNode node) { + /** + * Removes the specified {@link TreeNode} and its associated views + * + * @param node the {@link TreeNode} to be removed + */ + public void removeTreeNode(TreeNode node) { viewMap.remove(node); + if (node.getChildren() != null) { + node.getChildren().forEach(t -> removeTreeTransition(t)); + } + List children = node.getChildren(); // if child is a case rule, unlock ancestor elements if (!children.isEmpty()) { Rule rule = children.get(0).getRule(); if (rule instanceof CaseRule) { - CaseRule caseRule = (CaseRule)rule; + CaseRule caseRule = (CaseRule) rule; // set dependent elements to be modifiable by ancestors (if not dependent on others) List ancestors = node.getAncestors(); for (TreeNode ancestor : ancestors) { @@ -418,22 +486,32 @@ private void removeTreeNode(TreeNode node) { if (ancestor.getParent() == null) { continue; } - for (PuzzleElement pelement : caseRule.dependentElements(node.getBoard(), children.get(0).getSelection())) { + for (PuzzleElement pelement : + caseRule.dependentElements( + node.getBoard(), children.get(0).getSelection())) { // decrement, unlock if 0 cases depended - PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(pelement); + PuzzleElement oldElement = + ancestor.getParent().getBoard().getPuzzleElement(pelement); oldElement.setCasesDepended(oldElement.getCasesDepended() - 1); if (oldElement.getCasesDepended() == 0) { continue; } // set modifiable if started modifiable - boolean modifiable = tree.getRootNode().getBoard().getPuzzleElement(oldElement).isModifiable(); + boolean modifiable = false; + if (tree != null) { + tree.getRootNode() + .getBoard() + .getPuzzleElement(oldElement) + .isModifiable(); + } // unmodifiable if already modified TreeNode modNode = ancestor.getParent().getParents().get(0); while (modNode.getParent() != null) { Board modBoard = modNode.getParent().getBoard(); - if (modBoard.getModifiedData().contains(modBoard.getPuzzleElement(oldElement))) { + if (modBoard.getModifiedData() + .contains(modBoard.getPuzzleElement(oldElement))) { modifiable = false; break; } @@ -444,33 +522,69 @@ private void removeTreeNode(TreeNode node) { } } } - node.getChildren().forEach(t -> removeTreeTransition(t)); } - private void removeTreeTransition(TreeTransition trans) { + /** + * Removes the specified {@link TreeTransition} and its associated views + * + * @param trans the {@link TreeTransition} to be removed + */ + public void removeTreeTransition(TreeTransition trans) { viewMap.remove(trans); if (trans.getChildNode() != null) { removeTreeNode(trans.getChildNode()); } + + // Update transition modifiability if removing a case rule + List parents = trans.getParents(); + for (TreeNode parent : parents) { + // if transition is a case rule, unlock ancestor elements up until latest case rule or root node + boolean nextAncestorIsCaseRule = false; + Rule rule = trans.getRule(); + if (rule instanceof CaseRule) { + List ancestors = parent.getAncestors(); + for (int i = 0; i < ancestors.size(); i++) { + if (ancestors.get(i).getParent() == null) { + continue; + } + if (nextAncestorIsCaseRule) { + break; + } + for (PuzzleElement element : parent.getBoard().getPuzzleElements()) { + PuzzleElement curElement = ancestors.get(i).getParent().getBoard().getPuzzleElement(element); + if (!curElement.isModifiableCaseRule()) { + curElement.setModifiableCaseRule(true); + } + } + if (ancestors.get(i).getParent().getRule() instanceof CaseRule) { + nextAncestorIsCaseRule = true; + } + } + } + } } + /** + * Adds the specified {@link TreeNode} and its associated views + * + * @param node the {@link TreeNode} to be added + */ private void addTreeNode(TreeNode node) { TreeTransition parent = node.getParent(); - TreeNodeView nodeView = new TreeNodeView(node); - TreeTransitionView parentView = (TreeTransitionView) viewMap.get(parent); + TreeTransitionView parentView = (TreeTransitionView) viewMap.get(parent); nodeView.setParentView(parentView); parentView.setChildView(nodeView); viewMap.put(node, nodeView); if (!node.getChildren().isEmpty()) { - + // if adding a case rule, lock dependent ancestor elements Rule rule = node.getChildren().get(0).getRule(); if (rule instanceof CaseRule) { - CaseRule caseRule = (CaseRule)rule; + CaseRule caseRule = (CaseRule) rule; List ancestors = node.getAncestors(); for (TreeNode ancestor : ancestors) { @@ -478,63 +592,69 @@ private void addTreeNode(TreeNode node) { if (ancestor.getParent() == null) { continue; } - for (PuzzleElement element : caseRule.dependentElements(node.getBoard(), node.getChildren().get(0).getSelection())) { + for (PuzzleElement element : + caseRule.dependentElements(node.getBoard(), node.getChildren().get(0).getSelection())) { // increment and lock - PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(element); - oldElement.setCasesDepended(oldElement.getCasesDepended()+1); + PuzzleElement oldElement = + ancestor.getParent().getBoard().getPuzzleElement(element); + oldElement.setCasesDepended(oldElement.getCasesDepended() + 1); oldElement.setModifiable(false); } } } - + node.getChildren().forEach(t -> addTreeTransition(t)); } } + /** + * Adds the specified {@link TreeTransition} and its associated views + * + * @param trans The {@link TreeTransition} to be added + */ private void addTreeTransition(TreeTransition trans) { List parents = trans.getParents(); - TreeTransitionView transView = new TreeTransitionView(trans); + for (TreeNode parent : parents) { TreeNodeView parentNodeView = (TreeNodeView) viewMap.get(parent); transView.addParentView(parentNodeView); parentNodeView.addChildrenView(transView); - + + viewMap.put(trans, transView); + // if transition is a new case rule, lock dependent ancestor elements Rule rule = trans.getRule(); - if (rule instanceof CaseRule && parent.getChildren().size()==1) { - CaseRule caseRule = (CaseRule)rule; - + if (rule instanceof CaseRule && parent.getChildren().size() == 1) { List ancestors = parent.getAncestors(); for (TreeNode ancestor : ancestors) { // for all ancestors but root if (ancestor.getParent() == null) { continue; } - for (PuzzleElement element : caseRule.dependentElements(parent.getBoard(), trans.getSelection())) { - // increment and lock - PuzzleElement oldElement = ancestor.getParent().getBoard().getPuzzleElement(element); - oldElement.setCasesDepended(oldElement.getCasesDepended()+1); - oldElement.setModifiable(false); + + for (PuzzleElement element : parent.getBoard().getPuzzleElements()) { + PuzzleElement curElement = ancestor.getParent().getBoard().getPuzzleElement(element); + curElement.setModifiableCaseRule(false); } } } } - viewMap.put(trans, transView); - if (trans.getChildNode() != null) { addTreeNode(trans.getChildNode()); } } - ///New Draw Methods - + /** + * Draws the tree using the provided {@link Graphics2D} object + * + * @param graphics2D the {@link Graphics2D} object used for drawing the tree + */ public void drawTree(Graphics2D graphics2D) { if (tree == null) { LOGGER.error("Unable to draw tree."); - } - else { + } else { if (rootNodeView == null) { rootNodeView = new TreeNodeView(tree.getRootNode()); @@ -556,6 +676,11 @@ public void drawTree(Graphics2D graphics2D) { } } + /** + * Creates views for the given {@link TreeNodeView} and its children + * + * @param nodeView the {@link TreeNodeView} for which to create views + */ public void createViews(TreeNodeView nodeView) { if (nodeView != null) { viewMap.put(nodeView.getTreeElement(), nodeView); @@ -589,6 +714,14 @@ public void createViews(TreeNodeView nodeView) { } } + /** + * Calculates the layout locations (x and y coordinates) of the nodes in the tree. + * This method recursively traverses the tree and updates the positions of + * nodes and transitions based on their depth and parent relationships. + * + * @param nodeView the node view to calculate the positions for + * @param depth the depth of the node in the tree, used to calculate its x-coordinate + */ public void calculateViewLocations(TreeNodeView nodeView, int depth) { nodeView.setDepth(depth); int xLoc = (NODE_GAP_WIDTH + DIAMETER) * depth + DIAMETER; @@ -596,52 +729,29 @@ public void calculateViewLocations(TreeNodeView nodeView, int depth) { dimension.width = Math.max(dimension.width, xLoc); TreeTransitionView parentTransView = nodeView.getParentView(); - int yLoc = parentTransView == null ? (int) nodeView.getSpan() / 2 : parentTransView.getEndY(); + int yLoc = + parentTransView == null ? (int) nodeView.getSpan() / 2 : parentTransView.getEndY(); nodeView.setY(yLoc); ArrayList children = nodeView.getChildrenViews(); switch (children.size()) { case 0: break; - case 1: { - TreeTransitionView childView = children.get(0); - - List parentsViews = childView.getParentViews(); - if (parentsViews.size() == 1) { - childView.setEndY(yLoc); - - childView.setDepth(depth); - - Point lineStartPoint = childView.getLineStartPoint(0); - lineStartPoint.x = xLoc + RADIUS + TRANS_GAP / 2; - lineStartPoint.y = yLoc; - childView.setEndX((NODE_GAP_WIDTH + DIAMETER) * (depth + 1) + RADIUS - TRANS_GAP / 2); - - dimension.width = Math.max(dimension.width, childView.getEndX()); + case 1: + { + TreeTransitionView childView = children.get(0); - TreeNodeView childNodeView = childView.getChildView(); - if (childNodeView != null) { - calculateViewLocations(childNodeView, depth + 1); - } - } - else { - if (parentsViews.size() > 1 && parentsViews.get(parentsViews.size() - 1) == nodeView) { - int yAvg = 0; - for (int i = 0; i < parentsViews.size(); i++) { - TreeNodeView parentNodeView = parentsViews.get(i); - depth = Math.max(depth, parentNodeView.getDepth()); - yAvg += parentNodeView.getY(); - - Point lineStartPoint = childView.getLineStartPoint(i); - lineStartPoint.x = parentNodeView.getX() + RADIUS + TRANS_GAP / 2; - lineStartPoint.y = parentNodeView.getY(); - } - yAvg /= parentsViews.size(); - childView.setEndY(yAvg); + List parentsViews = childView.getParentViews(); + if (parentsViews.size() == 1) { + childView.setEndY(yLoc); childView.setDepth(depth); - childView.setEndX((NODE_GAP_WIDTH + DIAMETER) * (depth + 1) + RADIUS - TRANS_GAP / 2); + Point lineStartPoint = childView.getLineStartPoint(0); + lineStartPoint.x = xLoc + RADIUS + TRANS_GAP / 2; + lineStartPoint.y = yLoc; + childView.setEndX( + (NODE_GAP_WIDTH + DIAMETER) * (depth + 1) + RADIUS - TRANS_GAP / 2); dimension.width = Math.max(dimension.width, childView.getEndX()); @@ -649,58 +759,97 @@ public void calculateViewLocations(TreeNodeView nodeView, int depth) { if (childNodeView != null) { calculateViewLocations(childNodeView, depth + 1); } + } else { + if (parentsViews.size() > 1 + && parentsViews.get(parentsViews.size() - 1) == nodeView) { + int yAvg = 0; + for (int i = 0; i < parentsViews.size(); i++) { + TreeNodeView parentNodeView = parentsViews.get(i); + depth = Math.max(depth, parentNodeView.getDepth()); + yAvg += parentNodeView.getY(); + + Point lineStartPoint = childView.getLineStartPoint(i); + lineStartPoint.x = parentNodeView.getX() + RADIUS + TRANS_GAP / 2; + lineStartPoint.y = parentNodeView.getY(); + } + yAvg /= parentsViews.size(); + childView.setEndY(yAvg); + + childView.setDepth(depth); + + childView.setEndX( + (NODE_GAP_WIDTH + DIAMETER) * (depth + 1) + + RADIUS + - TRANS_GAP / 2); + + dimension.width = Math.max(dimension.width, childView.getEndX()); + + TreeNodeView childNodeView = childView.getChildView(); + if (childNodeView != null) { + calculateViewLocations(childNodeView, depth + 1); + } + } } + break; } - break; - } - default: { - int span = 0; - for (TreeTransitionView childView : children) { - span += childView.getSpan(); - } - - span = (int) ((nodeView.getSpan() - span) / 2); - for (int i = 0; i < children.size(); i++) { - TreeTransitionView childView = children.get(i); + default: + { + int span = 0; + for (TreeTransitionView childView : children) { + span += childView.getSpan(); + } - childView.setDepth(depth); + span = (int) ((nodeView.getSpan() - span) / 2); + for (int i = 0; i < children.size(); i++) { + TreeTransitionView childView = children.get(i); - Point lineStartPoint = childView.getLineStartPoint(0); - lineStartPoint.x = xLoc + RADIUS + TRANS_GAP / 2; - lineStartPoint.y = yLoc; - childView.setEndX((NODE_GAP_WIDTH + DIAMETER) * (depth + 1) + RADIUS - TRANS_GAP / 2); - childView.setEndY(yLoc - (int) (nodeView.getSpan() / 2) + span + (int) (childView.getSpan() / 2)); + childView.setDepth(depth); - span += childView.getSpan(); - TreeNodeView childNodeView = childView.getChildView(); - if (childNodeView != null) { - calculateViewLocations(childNodeView, depth + 1); + Point lineStartPoint = childView.getLineStartPoint(0); + lineStartPoint.x = xLoc + RADIUS + TRANS_GAP / 2; + lineStartPoint.y = yLoc; + childView.setEndX( + (NODE_GAP_WIDTH + DIAMETER) * (depth + 1) + RADIUS - TRANS_GAP / 2); + childView.setEndY( + yLoc + - (int) (nodeView.getSpan() / 2) + + span + + (int) (childView.getSpan() / 2)); + + span += childView.getSpan(); + TreeNodeView childNodeView = childView.getChildView(); + if (childNodeView != null) { + calculateViewLocations(childNodeView, depth + 1); + } } + break; } - break; - } } } + /** + * Calculates the span (height) required for the given view, including its children. + * This method recursively determines the span for nodes and transitions based on their + * children and the merging branches they belong to. + * + * @param view the view whose span is to be calculated + */ public void calcSpan(TreeElementView view) { if (view.getType() == NODE) { TreeNodeView nodeView = (TreeNodeView) view; TreeNode node = nodeView.getTreeElement(); if (nodeView.getChildrenViews().size() == 0) { nodeView.setSpan(DIAMETER + NODE_GAP_HEIGHT); - } - else { + } else { if (nodeView.getChildrenViews().size() == 1) { TreeTransitionView childView = nodeView.getChildrenViews().get(0); calcSpan(childView); if (childView.getParentViews().size() > 1) { nodeView.setSpan(DIAMETER + NODE_GAP_HEIGHT); - } - else { + } else { nodeView.setSpan(childView.getSpan()); } - } - else { + } else { DisjointSets branches = node.findMergingBranches(); List children = node.getChildren(); @@ -719,17 +868,18 @@ public void calcSpan(TreeElementView view) { for (Set mergeSet : mergingSets) { if (mergeSet.size() > 1) { TreeTransition mergePoint = TreeNode.findMergingPoint(mergeSet); - TreeTransitionView mergePointView = (TreeTransitionView) viewMap.get(mergePoint); + TreeTransitionView mergePointView = + (TreeTransitionView) viewMap.get(mergePoint); double subSpan = 0.0; for (TreeTransition branch : mergeSet) { - TreeTransitionView branchView = (TreeTransitionView) viewMap.get(branch); + TreeTransitionView branchView = + (TreeTransitionView) viewMap.get(branch); subCalcSpan(branchView, mergePointView); subSpan += branchView.getSpan(); } calcSpan(mergePointView); span += Math.max(mergePointView.getSpan(), subSpan); - } - else { + } else { TreeTransition trans = mergeSet.iterator().next(); TreeTransitionView transView = (TreeTransitionView) viewMap.get(trans); calcSpan(transView); @@ -739,14 +889,12 @@ public void calcSpan(TreeElementView view) { nodeView.setSpan(span); } } - } - else { + } else { TreeTransitionView transView = (TreeTransitionView) view; TreeNodeView nodeView = transView.getChildView(); if (nodeView == null) { transView.setSpan(DIAMETER + NODE_GAP_HEIGHT); - } - else { + } else { calcSpan(nodeView); transView.setSpan(nodeView.getSpan()); } @@ -754,14 +902,15 @@ public void calcSpan(TreeElementView view) { } /** - * Calculates the sub span of a given sub tree rooted at the specified view and stops at the tree puzzleElement view - * specified as stop. Stop tree puzzleElement is NOT included in the span calculation + * Calculates the span of a subtree rooted at the specified view, stopping at the given + * stop view. The stop view is not included in the span calculation. * - * @param view - * @param stop + * @param view the root view of the subtree to calculate the span for + * @param stop the view at which to stop the span calculation. The stop view itself is + * not included in the span calculation */ private void subCalcSpan(TreeElementView view, TreeElementView stop) { - //safe-guard for infinite loop + // safe-guard for infinite loop if (view == stop) { return; } @@ -771,24 +920,20 @@ private void subCalcSpan(TreeElementView view, TreeElementView stop) { TreeNode node = nodeView.getTreeElement(); if (nodeView.getChildrenViews().size() == 0) { nodeView.setSpan(DIAMETER + NODE_GAP_HEIGHT); - } - else { + } else { if (nodeView.getChildrenViews().size() == 1) { TreeTransitionView childView = nodeView.getChildrenViews().get(0); if (childView == stop) { nodeView.setSpan(DIAMETER + NODE_GAP_HEIGHT); - } - else { + } else { subCalcSpan(childView, stop); if (childView.getParentViews().size() > 1) { nodeView.setSpan(DIAMETER + NODE_GAP_HEIGHT); - } - else { + } else { nodeView.setSpan(childView.getSpan()); } } - } - else { + } else { DisjointSets branches = node.findMergingBranches(); List children = node.getChildren(); @@ -802,17 +947,18 @@ private void subCalcSpan(TreeElementView view, TreeElementView stop) { for (Set mergeSet : mergingSets) { if (mergeSet.size() > 1) { TreeTransition mergePoint = TreeNode.findMergingPoint(mergeSet); - TreeTransitionView mergePointView = (TreeTransitionView) viewMap.get(mergePoint); + TreeTransitionView mergePointView = + (TreeTransitionView) viewMap.get(mergePoint); double subSpan = 0.0; for (TreeTransition branch : mergeSet) { - TreeTransitionView branchView = (TreeTransitionView) viewMap.get(branch); + TreeTransitionView branchView = + (TreeTransitionView) viewMap.get(branch); subCalcSpan(branchView, mergePointView); subSpan += branchView.getSpan(); } subCalcSpan(mergePointView, stop); span += Math.max(mergePointView.getSpan(), subSpan); - } - else { + } else { TreeTransition trans = mergeSet.iterator().next(); TreeTransitionView transView = (TreeTransitionView) viewMap.get(trans); subCalcSpan(transView, stop); @@ -823,14 +969,12 @@ private void subCalcSpan(TreeElementView view, TreeElementView stop) { nodeView.setSpan(span); } } - } - else { + } else { TreeTransitionView transView = (TreeTransitionView) view; TreeNodeView nodeView = transView.getChildView(); if (nodeView == null || nodeView == stop) { transView.setSpan(DIAMETER + NODE_GAP_HEIGHT); - } - else { + } else { calcSpan(nodeView); transView.setSpan(nodeView.getSpan()); } @@ -838,11 +982,14 @@ private void subCalcSpan(TreeElementView view, TreeElementView stop) { } /** - * Reorders branches such that merging branches are sequentially grouped together and transitions are kept in - * relative order in the list of child transitions of the specified node + * Reorders the branches of a given node such that branches that merge are grouped together sequentially. + * Transitions are kept in their relative order based on their original positions in the list of child transitions + * of the specified node. This ensures that the visual representation of the branches and transitions maintains + * a logical and readable structure. * - * @param node root node of the branches - * @param branches DisjointSets of the child branches of the specified node which determine which branches merge + * @param node the root node whose branches are to be reordered + * @param branches a DisjointSets structure representing the merging relationships of the child branches of the + * specified node. This determines which branches should be grouped together */ private void reorderBranches(TreeNode node, DisjointSets branches) { List children = node.getChildren(); @@ -852,35 +999,38 @@ private void reorderBranches(TreeNode node, DisjointSets branche for (Set set : mergingSets) { List mergeBranch = new ArrayList<>(); newOrder.add(mergeBranch); - children.forEach(t -> { - if (set.contains(t)) { - mergeBranch.add(t); - } - }); - mergeBranch.sort((TreeTransition t1, TreeTransition t2) -> - children.indexOf(t1) <= children.indexOf(t2) ? -1 : 1); + children.forEach( + t -> { + if (set.contains(t)) { + mergeBranch.add(t); + } + }); + mergeBranch.sort( + (TreeTransition t1, TreeTransition t2) -> + children.indexOf(t1) <= children.indexOf(t2) ? -1 : 1); } - newOrder.sort((List b1, List b2) -> { - int low1 = -1; - int low2 = -1; - for (TreeTransition t1 : b1) { - int curIndex = children.indexOf(t1); - if (low1 == -1 || curIndex < low1) { - low1 = curIndex; - } - } - for (TreeTransition t1 : b2) { - int curIndex = children.indexOf(t1); - if (low1 == -1 || curIndex < low1) { - low1 = curIndex; - } - } - return low1 < low2 ? -1 : 1; - }); + newOrder.sort( + (List b1, List b2) -> { + int low1 = -1; + int low2 = -1; + for (TreeTransition t1 : b1) { + int curIndex = children.indexOf(t1); + if (low1 == -1 || curIndex < low1) { + low1 = curIndex; + } + } + for (TreeTransition t1 : b2) { + int curIndex = children.indexOf(t1); + if (low1 == -1 || curIndex < low1) { + low1 = curIndex; + } + } + return low1 < low2 ? -1 : 1; + }); List newChildren = new ArrayList<>(); newOrder.forEach(l -> newChildren.addAll(l)); node.setChildren(newChildren); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java index 042eb8880..c7893b168 100644 --- a/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java +++ b/src/main/java/edu/rpi/legup/ui/proofeditorui/treeview/TreeViewSelection.java @@ -1,17 +1,20 @@ package edu.rpi.legup.ui.proofeditorui.treeview; import java.awt.*; -import java.util.List; import java.util.ArrayList; +import java.util.List; + +/** + * {@code TreeViewSelection} manages the selection and hover state of tree element views in a tree view. + * It maintains a list of selected views, tracks the currently hovered view, and manages the mouse position. + */ public class TreeViewSelection { private ArrayList selectedViews; private TreeElementView hover; private Point mousePoint; - /** - * TreeViewSelection Constructor creates a tree view selection - */ + /** TreeViewSelection Constructor creates a tree view selection */ public TreeViewSelection() { this.selectedViews = new ArrayList<>(); this.hover = null; @@ -38,7 +41,6 @@ public TreeViewSelection(List views) { this.selectedViews.addAll(views); } - /** * Gets the list of selected tree puzzleElement views * @@ -66,8 +68,7 @@ public void toggleSelection(TreeElementView treeElementView) { if (selectedViews.contains(treeElementView)) { selectedViews.remove(treeElementView); treeElementView.setSelected(false); - } - else { + } else { selectedViews.add(treeElementView); treeElementView.setSelected(true); } @@ -96,9 +97,7 @@ public void newSelection(TreeElementView treeElementView) { treeElementView.setSelected(true); } - /** - * Clears all selected views - */ + /** Clears all selected views */ public void clearSelection() { for (TreeElementView treeElementView : selectedViews) { treeElementView.setSelected(false); @@ -109,7 +108,8 @@ public void clearSelection() { /** * Gets tree puzzleElement view that the mouse is hovering over or null is no such view exists * - * @return tree puzzleElement view that the mouse is hovering over or null is no such view exists + * @return tree puzzleElement view that the mouse is hovering over or null is no such view + * exists */ public TreeElementView getHover() { return hover; @@ -128,9 +128,7 @@ public void newHover(TreeElementView newHovered) { hover = newHovered; } - /** - * Clears the current hover tree puzzleElement view - */ + /** Clears the current hover tree puzzleElement view */ public void clearHover() { if (hover != null) { hover.setHover(false); diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementButton.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementButton.java index de2281ad1..552d517b9 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementButton.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementButton.java @@ -1,11 +1,9 @@ package edu.rpi.legup.ui.puzzleeditorui.elementsview; import edu.rpi.legup.model.elements.Element; -import edu.rpi.legup.model.rules.Rule; - +import java.awt.*; import javax.swing.*; import javax.swing.border.Border; -import java.awt.*; public class ElementButton extends JButton { diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java index 1fc2b3792..97c76919e 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementFrame.java @@ -3,10 +3,9 @@ import edu.rpi.legup.controller.EditorElementController; import edu.rpi.legup.model.Puzzle; import edu.rpi.legup.ui.lookandfeel.components.MaterialTabbedPaneUI; - +import java.awt.*; import javax.swing.*; import javax.swing.border.TitledBorder; -import java.awt.*; public class ElementFrame extends JPanel { private static final String checkBox = " \u2714 "; @@ -15,44 +14,36 @@ public class ElementFrame extends JPanel { private static final String htmlTail = ""; private PlaceableElementPanel placeableElementPanel; - private NonPlaceableElementPanel nonPlaceableElementPanel; - private JTabbedPane tabbedPane; + //private JTabbedPane tabbedPane; private ButtonGroup buttonGroup; private EditorElementController controller; public ElementFrame(EditorElementController controller) { + this.controller = controller; - MaterialTabbedPaneUI tabOverride = new MaterialTabbedPaneUI() { - //this prevents the tabs from moving around when you select them - @Override - protected boolean shouldRotateTabRuns(int i) { - return false; - } - }; - - this.tabbedPane = new JTabbedPane(); - tabbedPane.setUI(tabOverride); + JLabel status = new JLabel("", SwingConstants.CENTER); this.buttonGroup = new ButtonGroup(); - nonPlaceableElementPanel = new NonPlaceableElementPanel(this); - //nonPlaceableElementPanel.setMinimumSize(new Dimension(100,200)); - tabbedPane.addTab(nonPlaceableElementPanel.getName(), nonPlaceableElementPanel.getIcon(), new JScrollPane(nonPlaceableElementPanel), nonPlaceableElementPanel.getToolTip()); + // Parent panel to hold all elements + JPanel elementPanel = new JPanel(); + elementPanel.setLayout(new BoxLayout(elementPanel, BoxLayout.Y_AXIS)); placeableElementPanel = new PlaceableElementPanel(this); - //placeableElementPanel.setMinimuSize(new Dimension(100,200)); - tabbedPane.addTab(placeableElementPanel.getName(), placeableElementPanel.getIcon(), new JScrollPane(placeableElementPanel), placeableElementPanel.getToolTip()); - tabbedPane.setTabPlacement(JTabbedPane.TOP); - + placeableElementPanel.setMinimumSize(new Dimension(100, 200)); + elementPanel.add(new JScrollPane(placeableElementPanel)); + // Set layout and dimensions for the main panel setLayout(new BorderLayout()); setMinimumSize(new Dimension(250, 256)); setPreferredSize(new Dimension(330, 256)); - add(tabbedPane); + // Add components to the main panel + add(elementPanel, BorderLayout.CENTER); add(status, BorderLayout.SOUTH); + // Center-align the titled border TitledBorder title = BorderFactory.createTitledBorder("Elements"); title.setTitleJustification(TitledBorder.CENTER); setBorder(title); @@ -62,28 +53,26 @@ public ButtonGroup getButtonGroup() { return buttonGroup; } - public void resetSize() { - int buttonWidth = ((ElementPanel) tabbedPane.getSelectedComponent()).getElementButtons()[0].getWidth(); - this.setMinimumSize(new Dimension(2 * buttonWidth + 64, this.getHeight())); - } +// public void resetSize() { +// int buttonWidth = +// ((ElementPanel) tabbedPane.getSelectedComponent()) +// .getElementButtons()[0].getWidth(); +// this.setMinimumSize(new Dimension(2 * buttonWidth + 64, this.getHeight())); +// } public void setElements(Puzzle puzzle) { - nonPlaceableElementPanel.setElements(puzzle.getNonPlaceableElements()); - placeableElementPanel.setElements(puzzle.getPlaceableElements()); - + if (puzzle != null) { + placeableElementPanel.setElements(puzzle.getPlaceableElements()); + } } public EditorElementController getController() { return controller; } - public JTabbedPane getTabbedPane() { - return tabbedPane; - } - - public NonPlaceableElementPanel getNonPlaceableElementPanel() { - return nonPlaceableElementPanel; - } +// public JTabbedPane getTabbedPane() { +// return tabbedPane; +// } public PlaceableElementPanel getPlaceableElementPanel() { return placeableElementPanel; diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java index 2b0c4c63e..70826d25c 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/ElementPanel.java @@ -1,13 +1,10 @@ package edu.rpi.legup.ui.puzzleeditorui.elementsview; -import edu.rpi.legup.model.rules.Rule; -import edu.rpi.legup.ui.WrapLayout; import edu.rpi.legup.model.elements.Element; -import edu.rpi.legup.ui.proofeditorui.rulesview.RuleButton; - -import javax.swing.*; +import edu.rpi.legup.ui.WrapLayout; import java.util.ArrayList; import java.util.List; +import javax.swing.*; public abstract class ElementPanel extends JPanel { protected ImageIcon icon; @@ -23,7 +20,7 @@ public ElementPanel(ElementFrame eFrame) { setLayout(new WrapLayout()); } - public void setElements(List elements) { + public int setElements(List elements) { this.elements = elements; clearButtons(); @@ -35,11 +32,13 @@ public void setElements(List elements) { elementFrame.getButtonGroup().add(elementButtons[i]); System.out.printf("added button: %d, element %s\n", i, element.getElementName()); - elementButtons[i].setToolTipText(element.getElementName() + ": " + element.getDescription()); + elementButtons[i].setToolTipText( + element.getElementName() + ": " + element.getDescription()); elementButtons[i].addActionListener(elementFrame.getController()); add(elementButtons[i]); } revalidate(); + return elements.size(); } protected void clearButtons() { @@ -81,4 +80,3 @@ public void setToolTip(String toolTip) { this.toolTip = toolTip; } } - diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java index 7920f564c..796d1ae68 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/NonPlaceableElementPanel.java @@ -1,12 +1,15 @@ -package edu.rpi.legup.ui.puzzleeditorui.elementsview; - -import javax.swing.*; - -public class NonPlaceableElementPanel extends ElementPanel { - public NonPlaceableElementPanel(ElementFrame elementFrame) { - super(elementFrame); - this.icon = new ImageIcon(ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/Direct Rules.gif")); - this.name = "Non-Placeable Elements"; - this.toolTip = "Non-Placeable Elements"; - } -} +//package edu.rpi.legup.ui.puzzleeditorui.elementsview; +// +//import javax.swing.*; +// +//public class NonPlaceableElementPanel extends ElementPanel { +// public NonPlaceableElementPanel(ElementFrame elementFrame) { +// super(elementFrame); +// this.icon = +// new ImageIcon( +// ClassLoader.getSystemClassLoader() +// .getResource("edu/rpi/legup/images/Legup/Direct Rules.gif")); +// this.name = "Non-Placeable Elements"; +// this.toolTip = "Non-Placeable Elements"; +// } +//} diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/PlaceableElementPanel.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/PlaceableElementPanel.java index 1fa8eabfb..088e18f8c 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/PlaceableElementPanel.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/elementsview/PlaceableElementPanel.java @@ -5,7 +5,10 @@ public class PlaceableElementPanel extends ElementPanel { public PlaceableElementPanel(ElementFrame elementFrame) { super(elementFrame); - this.icon = new ImageIcon(ClassLoader.getSystemClassLoader().getResource("edu/rpi/legup/images/Legup/Direct Rules.gif")); + this.icon = + new ImageIcon( + ClassLoader.getSystemClassLoader() + .getResource("edu/rpi/legup/images/Legup/Direct Rules.gif")); this.name = "Placeable Elements"; this.toolTip = "Placeable Elements"; } diff --git a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/resizeview/ResizePanel.java b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/resizeview/ResizePanel.java index 7cb7856e7..902d9dbd3 100644 --- a/src/main/java/edu/rpi/legup/ui/puzzleeditorui/resizeview/ResizePanel.java +++ b/src/main/java/edu/rpi/legup/ui/puzzleeditorui/resizeview/ResizePanel.java @@ -1,4 +1,3 @@ package edu.rpi.legup.ui.puzzleeditorui.resizeview; -public class ResizePanel { -} +public class ResizePanel {} diff --git a/src/main/java/edu/rpi/legup/user/Submission.java b/src/main/java/edu/rpi/legup/user/Submission.java index eb2b8446c..42373d2ec 100644 --- a/src/main/java/edu/rpi/legup/user/Submission.java +++ b/src/main/java/edu/rpi/legup/user/Submission.java @@ -3,11 +3,7 @@ import edu.rpi.legup.model.gameboard.Board; public class Submission { - public Submission(Board board) { + public Submission(Board board) {} - } - - public void submit() { - - } + public void submit() {} } diff --git a/src/main/java/edu/rpi/legup/user/UsageStatistics.java b/src/main/java/edu/rpi/legup/user/UsageStatistics.java index 192db593f..0bc5d1c62 100644 --- a/src/main/java/edu/rpi/legup/user/UsageStatistics.java +++ b/src/main/java/edu/rpi/legup/user/UsageStatistics.java @@ -1,27 +1,19 @@ package edu.rpi.legup.user; +import java.io.IOException; +import java.io.InputStream; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; public class UsageStatistics { private static final String url = "https://legup-3b4a5.firebaseio.com/databases/test.json"; - public UsageStatistics() { - - } + public UsageStatistics() {} public boolean sendErrorReport() { try { @@ -31,12 +23,12 @@ public boolean sendErrorReport() { // Request parameters and other properties. httppost.setEntity(new StringEntity("{\"test\": \"jeff\"}")); -// List params = new ArrayList<>(2); -// params.add(new BasicNameValuePair("param-1", "12345")); -// params.add(new BasicNameValuePair("param-2", "Hello!")); -// httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); + // List params = new ArrayList<>(2); + // params.add(new BasicNameValuePair("param-1", "12345")); + // params.add(new BasicNameValuePair("param-2", "Hello!")); + // httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); - //Execute and get the response. + // Execute and get the response. HttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); @@ -44,14 +36,12 @@ public boolean sendErrorReport() { InputStream instream = entity.getContent(); try { -// System.err.println(new String(instream.readAllBytes())); - } - finally { + // System.err.println(new String(instream.readAllBytes())); + } finally { instream.close(); } } - } - catch (IOException e) { + } catch (IOException e) { return false; } return false; diff --git a/src/main/java/edu/rpi/legup/user/User.java b/src/main/java/edu/rpi/legup/user/User.java index 2e542a96c..63280a72d 100644 --- a/src/main/java/edu/rpi/legup/user/User.java +++ b/src/main/java/edu/rpi/legup/user/User.java @@ -1,5 +1,3 @@ package edu.rpi.legup.user; -public class User { - -} +public class User {} diff --git a/src/main/java/edu/rpi/legup/utility/ConnectedRegions.java b/src/main/java/edu/rpi/legup/utility/ConnectedRegions.java index ce4b74bdc..14b68ba40 100644 --- a/src/main/java/edu/rpi/legup/utility/ConnectedRegions.java +++ b/src/main/java/edu/rpi/legup/utility/ConnectedRegions.java @@ -7,13 +7,15 @@ import java.util.Set; public final class ConnectedRegions { - public static List> getConnectedRegions(int boundaryCell, int[][] cells, int width, int height) { + public static List> getConnectedRegions( + int boundaryCell, int[][] cells, int width, int height) { Set boundaryCells = new HashSet<>(); boundaryCells.add(boundaryCell); return getConnectedRegions(boundaryCells, cells, width, height); } - public static List> getConnectedRegions(Set boundaryCells, int[][] cells, int width, int height) { + public static List> getConnectedRegions( + Set boundaryCells, int[][] cells, int width, int height) { boolean[][] visited = new boolean[height][width]; List> results = new ArrayList<>(); for (int y = 0; y < height; y++) { @@ -36,17 +38,26 @@ public static boolean regionContains(int toFind, int[][] cells, Set regio return false; } - public static Set getRegionAroundPoint(Point p, int boundaryCell, int[][] cells, int width, int height) { + public static Set getRegionAroundPoint( + Point p, int boundaryCell, int[][] cells, int width, int height) { Set boundaryCells = new HashSet<>(); boundaryCells.add(boundaryCell); return getRegionAroundPoint(p, boundaryCells, cells, width, height); } - public static Set getRegionAroundPoint(Point p, Set boundaryCells, int[][] cells, int width, int height) { + public static Set getRegionAroundPoint( + Point p, Set boundaryCells, int[][] cells, int width, int height) { return floodfill(boundaryCells, cells, new boolean[height][width], width, height, p.x, p.y); } - private static Set floodfill(Set boundaryCells, int[][] cells, boolean[][] visited, int w, int h, int x, int y) { + private static Set floodfill( + Set boundaryCells, + int[][] cells, + boolean[][] visited, + int w, + int h, + int x, + int y) { HashSet result = new HashSet<>(); if ((x < 0) || (x >= w)) { return result; @@ -64,4 +75,4 @@ private static Set floodfill(Set boundaryCells, int[][] cells, b } return result; } -} \ No newline at end of file +} diff --git a/src/main/java/edu/rpi/legup/utility/DisjointSets.java b/src/main/java/edu/rpi/legup/utility/DisjointSets.java index 1e2270318..f33b8993c 100644 --- a/src/main/java/edu/rpi/legup/utility/DisjointSets.java +++ b/src/main/java/edu/rpi/legup/utility/DisjointSets.java @@ -7,9 +7,7 @@ public class DisjointSets { private Map depths; private Map> sets; - /** - * DisjointSets Constructor creates an empty DisjointSets - */ + /** DisjointSets Constructor creates an empty DisjointSets */ public DisjointSets() { this.parents = new HashMap<>(); this.depths = new HashMap<>(); @@ -17,8 +15,9 @@ public DisjointSets() { } /** - * Creates a unique set that contains the specified puzzleElement. If the specified puzzleElement is null or another set already - * contains that puzzleElement, this method returns false, indicating that a set was not created + * Creates a unique set that contains the specified puzzleElement. If the specified + * puzzleElement is null or another set already contains that puzzleElement, this method returns + * false, indicating that a set was not created * * @param u puzzleElement to create the set from * @return true if the set was created, false otherwise @@ -26,8 +25,7 @@ public DisjointSets() { public boolean createSet(T u) { if (u == null || parents.containsKey(u)) { return false; - } - else { + } else { parents.put(u, u); depths.put(u, 0); Set newSet = new HashSet<>(); @@ -38,16 +36,17 @@ public boolean createSet(T u) { } /** - * Finds and returns the representative set puzzleElement of the set that the specified puzzleElement contains + * Finds and returns the representative set puzzleElement of the set that the specified + * puzzleElement contains * * @param p puzzleElement of the set of which to find - * @return representative set puzzleElement or null if the specified puzzleElement is null or is not in the DisjointSets + * @return representative set puzzleElement or null if the specified puzzleElement is null or is + * not in the DisjointSets */ public T find(T p) { if (p == null || parents.get(p) == null) { return null; - } - else { + } else { if (p != parents.get(p)) { parents.put(p, find(parents.get(p))); } @@ -56,7 +55,8 @@ public T find(T p) { } /** - * Unions two sets together. If the set are non-null and disjoint, then it returns true, false otherwise + * Unions two sets together. If the set are non-null and disjoint, then it returns true, false + * otherwise * * @param p set one * @param q set two @@ -67,14 +67,12 @@ public boolean union(T p, T q) { T qid = find(q); if (pid == null || qid == null || pid == qid) { return false; - } - else { + } else { if (depths.get(pid) > depths.get(qid)) { parents.put(qid, pid); sets.get(pid).addAll(sets.get(qid)); sets.remove(qid); - } - else { + } else { parents.put(pid, qid); sets.get(qid).addAll(sets.get(pid)); sets.remove(pid); @@ -87,8 +85,9 @@ public boolean union(T p, T q) { } /** - * Unions to elements together, if either puzzleElement is not already in the DisjointSets, it creates a set for the - * puzzleElement then unions the sets together. If either puzzleElement is null, no action is taken. + * Unions to elements together, if either puzzleElement is not already in the DisjointSets, it + * creates a set for the puzzleElement then unions the sets together. If either puzzleElement is + * null, no action is taken. * * @param p puzzleElement one * @param q puzzleElement two @@ -118,17 +117,18 @@ public boolean contains(T u) { } /** - * Gets the set of elements that the specified puzzleElement is contained in, or null if no such set exists. + * Gets the set of elements that the specified puzzleElement is contained in, or null if no such + * set exists. * * @param p puzzleElement to get the set of - * @return the set of elements that the specified puzzleElement if contained in, or null if no such set exists + * @return the set of elements that the specified puzzleElement if contained in, or null if no + * such set exists */ public Set getSet(T p) { T pid = find(p); if (pid != null) { return new HashSet<>(sets.get(pid)); - } - else { + } else { return null; } } diff --git a/src/main/java/edu/rpi/legup/utility/Entry.java b/src/main/java/edu/rpi/legup/utility/Entry.java index 1819f7eb0..0686f0dbf 100644 --- a/src/main/java/edu/rpi/legup/utility/Entry.java +++ b/src/main/java/edu/rpi/legup/utility/Entry.java @@ -7,7 +7,7 @@ public class Entry { /** * Entry Constructor creates a key value pair * - * @param key key + * @param key key * @param value value */ public Entry(K key, V value) { diff --git a/src/main/java/edu/rpi/legup/utility/LegupUtils.java b/src/main/java/edu/rpi/legup/utility/LegupUtils.java index dbdd24e7f..ce21a8d9a 100644 --- a/src/main/java/edu/rpi/legup/utility/LegupUtils.java +++ b/src/main/java/edu/rpi/legup/utility/LegupUtils.java @@ -17,7 +17,8 @@ public class LegupUtils { private static final Logger LOGGER = Logger.getLogger(LegupUtils.class.getName()); /** - * Scans all classes accessible from the context class loader which belong to the given package and subpackages. + * Scans all classes accessible from the context class loader which belong to the given package + * and subpackages. * * @param packageName The base package * @return The classes @@ -54,12 +55,13 @@ public static Class[] getClasses(String packageName) /** * Recursive method used to find all classes in a given directory and subdirs. * - * @param directory The base directory + * @param directory The base directory * @param packageName The package name for classes found inside the base directory * @return The classes * @throws ClassNotFoundException */ - private static List findClasses(File directory, String packageName) throws ClassNotFoundException { + private static List findClasses(File directory, String packageName) + throws ClassNotFoundException { List classes = new ArrayList<>(); if (!directory.exists()) { return classes; @@ -69,23 +71,36 @@ private static List findClasses(File directory, String packageName) throw if (file.isDirectory()) { assert !file.getName().contains("."); classes.addAll(findClasses(file, packageName + "." + file.getName())); - } - else { + } else { if (file.getName().endsWith(".class")) { - classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); + classes.add( + Class.forName( + packageName + + '.' + + file.getName() + .substring(0, file.getName().length() - 6))); } } } return classes; } - private static List findClassesZip(String path, String packageName) throws IOException, ClassNotFoundException { + private static List findClassesZip(String path, String packageName) + throws IOException, ClassNotFoundException { List classes = new ArrayList<>(); ZipInputStream zip = new ZipInputStream(new FileInputStream(path)); for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) { - if (!entry.isDirectory() && entry.getName().endsWith(".class") && entry.getName().startsWith(packageName)) { + if (!entry.isDirectory() + && entry.getName().endsWith(".class") + && entry.getName().startsWith(packageName)) { String className = entry.getName().replace('/', '.'); - classes.add(Class.forName(className.substring(0, className.length() - ".class".length()))); + String substr = className.substring(0, className.length() - ".class".length()); + try { + Class c = Class.forName(substr); + classes.add(c); + } catch (LinkageError | ClassNotFoundException e) { + System.out.println("Failed on " + substr); + } } } return classes; diff --git a/src/main/java/edu/rpi/legup/utility/Logger.java b/src/main/java/edu/rpi/legup/utility/Logger.java index 1feb56f04..67048e5b4 100644 --- a/src/main/java/edu/rpi/legup/utility/Logger.java +++ b/src/main/java/edu/rpi/legup/utility/Logger.java @@ -1,6 +1,6 @@ package edu.rpi.legup.utility; -import edu.rpi.legup.Legup; +import java.io.File; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.ConsoleAppender; @@ -10,27 +10,31 @@ import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.layout.PatternLayout; -import java.io.File; - public class Logger { - private static final String LEGUP_HOME = System.getProperty("user.home") + File.separator + ".legup" + File.separator; + private static final String LEGUP_HOME = + System.getProperty("user.home") + File.separator + ".legup" + File.separator; public static void initLogger() { LoggerContext context = (LoggerContext) LogManager.getContext(false); Configuration config = context.getConfiguration(); ConsoleAppender consoleAppender = config.getAppender("console"); PatternLayout consolePattern = (PatternLayout) consoleAppender.getLayout(); - TimeBasedTriggeringPolicy triggeringPolicy = TimeBasedTriggeringPolicy.newBuilder().withInterval(1).withModulate(true).build(); - PatternLayout patternLayout = PatternLayout.newBuilder().withPattern(consolePattern.getConversionPattern()).build(); - RollingFileAppender rollingFileAppender = RollingFileAppender.newBuilder() - .setName("fileLogger") - .withFileName(LEGUP_HOME + "legup.log") - .withFilePattern(LEGUP_HOME + "legup-%d{yyyy-MM-dd}.log.gz") - .withPolicy(triggeringPolicy) - .setLayout(patternLayout) - .setConfiguration(config) - .build(); + TimeBasedTriggeringPolicy triggeringPolicy = + TimeBasedTriggeringPolicy.newBuilder().withInterval(1).withModulate(true).build(); + PatternLayout patternLayout = + PatternLayout.newBuilder() + .withPattern(consolePattern.getConversionPattern()) + .build(); + RollingFileAppender rollingFileAppender = + RollingFileAppender.newBuilder() + .setName("fileLogger") + .withFileName(LEGUP_HOME + "legup.log") + .withFilePattern(LEGUP_HOME + "legup-%d{yyyy-MM-dd}.log.gz") + .withPolicy(triggeringPolicy) + .setLayout(patternLayout) + .setConfiguration(config) + .build(); rollingFileAppender.start(); config.addAppender(rollingFileAppender); LoggerConfig rootLogger = config.getRootLogger(); @@ -39,5 +43,4 @@ public static void initLogger() { System.setProperty("sun.java2d.noddraw", Boolean.TRUE.toString()); } - } diff --git a/src/main/resources/edu/rpi/legup/images/Legup/Reset.png b/src/main/resources/edu/rpi/legup/images/Legup/Reset.png new file mode 100644 index 000000000..fd6ffefa0 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/Legup/Reset.png differ diff --git a/src/main/resources/edu/rpi/legup/images/Legup/logo.ico b/src/main/resources/edu/rpi/legup/images/Legup/logo.ico new file mode 100644 index 000000000..746d1ba26 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/Legup/logo.ico differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png new file mode 100644 index 000000000..27ccec972 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/CompleteRowColumnDirectRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png new file mode 100644 index 000000000..ed0701f26 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/PreventTrioDirectRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png new file mode 100644 index 000000000..5cc030a76 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/RepeatedRowColumnContradictionRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png new file mode 100644 index 000000000..7695ae2da Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/SaveBlockerDirectRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/TrioContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/TrioContradictionRule.png new file mode 100644 index 000000000..e292ec9fa Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/TrioContradictionRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png new file mode 100644 index 000000000..bd66c16a7 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/UnbalancedRowColumnContradictionRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png new file mode 100644 index 000000000..7785d198c Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/UniqueRowColumnDirectRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png new file mode 100644 index 000000000..8813d7956 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/WastedBlockerContradictionRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png b/src/main/resources/edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png new file mode 100644 index 000000000..7394bff91 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/rules/ZeroOrOneCaseRule.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png b/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png new file mode 100644 index 000000000..41fb61dfa Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/tiles/NumberTile.png differ diff --git a/src/main/resources/edu/rpi/legup/images/binary/tiles/UnknownTile.png b/src/main/resources/edu/rpi/legup/images/binary/tiles/UnknownTile.png new file mode 100644 index 000000000..9ab9f7481 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/binary/tiles/UnknownTile.png differ diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg new file mode 100644 index 000000000..ce7c7418a Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/BombOrFilled.jpg differ diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyFlag.jpg b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyFlag.jpg new file mode 100644 index 000000000..ae575bd8c Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/SatisfyFlag.jpg differ diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png new file mode 100644 index 000000000..7272bbdb6 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/cases/Satisfy_Flag.png differ diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/Bomb_Surplus.jpg b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/Bomb_Surplus.jpg new file mode 100644 index 000000000..5e8c36662 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/contradictions/Bomb_Surplus.jpg differ diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg new file mode 100644 index 000000000..8214972ac Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/direct/Fill_Bombs.jpg differ diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Bomb.png b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Bomb.png new file mode 100644 index 000000000..dd6bad509 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Bomb.png differ diff --git a/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Empty.png b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Empty.png new file mode 100644 index 000000000..c553ce15a Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/minesweeper/tiles/Empty.png differ diff --git a/src/main/resources/edu/rpi/legup/images/nurikabe/cases/FinishRoom.png b/src/main/resources/edu/rpi/legup/images/nurikabe/cases/FinishRoom.png new file mode 100644 index 000000000..207d4c820 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/nurikabe/cases/FinishRoom.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/CellForNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/CellForNumber.png index 7ab0cdbef..e8cca03b4 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/CellForNumber.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/CellForNumber.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/NumberForCell.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/NumberForCell.png index fedbbbac8..307d0d754 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/NumberForCell.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/cases/NumberForCell.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png index 7ba489c2b..6ab3cd769 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png index ff999f4bc..2f5b5237d 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png index cfe04a503..285451ba1 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png index 6d330baa6..6c4a6e457 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png index 76947671d..ae78caf49 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png index 8862702f1..602f62702 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/FixedMax.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/FixedMax.png index 8a26bbfeb..86a4ee8a0 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/FixedMax.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/FixedMax.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png index 216a0f3a1..8db8a3bbf 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png index 1e0555648..dcf4cb2b8 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png index d3dd36bbc..b238b36aa 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png differ diff --git a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/OneEdge.png b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/OneEdge.png index 40d6ff65f..6841a8034 100644 Binary files a/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/OneEdge.png and b/src/main/resources/edu/rpi/legup/images/skyscrapers/rules/OneEdge.png differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png b/src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png deleted file mode 100644 index d51538baf..000000000 Binary files a/src/main/resources/edu/rpi/legup/images/sudoku/AdvancedDeduction.png and /dev/null differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png new file mode 100644 index 000000000..9dcade64b Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberColumn.png differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png new file mode 100644 index 000000000..000dc8b68 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRegion.png differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png new file mode 100644 index 000000000..f984f8365 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoCellForNumberRow.png differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/NoSolution.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/NoSolution.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/NoSolution.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/NoSolution.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/PossibleValues.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/PossibleValues.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/PossibleValues.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/PossibleValues.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/RepeatedNumber.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/RepeatedNumber.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/RepeatedNumber.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/forcedByDeduction.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/forcedByDeduction.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByDeduction.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/forcedByElimination.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByElimination.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/forcedByElimination.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/forcedByElimination.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/possible_cells_number.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png new file mode 100644 index 000000000..2ebdc5823 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_column.png differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png new file mode 100644 index 000000000..cc371e3e9 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_region.png differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png new file mode 100644 index 000000000..80476a428 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/sudoku/rules/possible_cells_number_row.png differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/tem.png b/src/main/resources/edu/rpi/legup/images/sudoku/rules/tem.png similarity index 100% rename from src/main/resources/edu/rpi/legup/images/sudoku/tem.png rename to src/main/resources/edu/rpi/legup/images/sudoku/rules/tem.png diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/tiles/NumberTile.png b/src/main/resources/edu/rpi/legup/images/sudoku/tiles/NumberTile.png new file mode 100644 index 000000000..5a8540d02 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/sudoku/tiles/NumberTile.png differ diff --git a/src/main/resources/edu/rpi/legup/images/sudoku/tiles/UnknownTile.png b/src/main/resources/edu/rpi/legup/images/sudoku/tiles/UnknownTile.png new file mode 100644 index 000000000..850fbf127 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/sudoku/tiles/UnknownTile.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Element Template.png b/src/main/resources/edu/rpi/legup/images/thermometer/Element Template.png new file mode 100644 index 000000000..52e3e36b7 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Element Template.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png new file mode 100644 index 000000000..238a301af Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png new file mode 100644 index 000000000..8f343a3ba Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png new file mode 100644 index 000000000..f95536076 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png new file mode 100644 index 000000000..b1bbd31be Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadBlockW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png new file mode 100644 index 000000000..852043171 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png new file mode 100644 index 000000000..78179a633 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png new file mode 100644 index 000000000..463b4308c Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png new file mode 100644 index 000000000..19240e5fc Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadEmpW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillE.png new file mode 100644 index 000000000..d577c25f5 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillN.png new file mode 100644 index 000000000..9905da3aa Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillS.png new file mode 100644 index 000000000..2e6c6d75d Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillW.png new file mode 100644 index 000000000..94ad0b2b4 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/HeadFillW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png new file mode 100644 index 000000000..d351674c5 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png new file mode 100644 index 000000000..505aa6ec9 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png new file mode 100644 index 000000000..91356f95e Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png new file mode 100644 index 000000000..6013fca19 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftBlockW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png new file mode 100644 index 000000000..b038ea65f Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png new file mode 100644 index 000000000..c59c1a930 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png new file mode 100644 index 000000000..f70a25cf1 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png new file mode 100644 index 000000000..48cde1b37 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftEmpW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png new file mode 100644 index 000000000..06a507b74 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png new file mode 100644 index 000000000..26c177a91 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png new file mode 100644 index 000000000..046b96e26 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillW.png new file mode 100644 index 000000000..3688bbe0a Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/ShaftFillW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockE.png new file mode 100644 index 000000000..d78a9723a Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockN.png new file mode 100644 index 000000000..eca516d89 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockS.png new file mode 100644 index 000000000..a207de1c4 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockW.png new file mode 100644 index 000000000..f48ff2b28 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipBlockW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpE.png new file mode 100644 index 000000000..660506aa7 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpN.png new file mode 100644 index 000000000..ae3ca519d Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpS.png new file mode 100644 index 000000000..62f60dfb4 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpW.png new file mode 100644 index 000000000..d67801d76 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipEmpW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillE.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillE.png new file mode 100644 index 000000000..1f24029e5 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillE.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillN.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillN.png new file mode 100644 index 000000000..e7abdb0bb Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillN.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillS.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillS.png new file mode 100644 index 000000000..bfb506b99 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillS.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillW.png b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillW.png new file mode 100644 index 000000000..e931a7555 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/Elements/TipFillW.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithBlocked.png b/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithBlocked.png new file mode 100644 index 000000000..0a36aa3ac Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithBlocked.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithMercury.png b/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithMercury.png new file mode 100644 index 000000000..6693e2d7b Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/FinishWithMercury.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/MercOrBlocked.png b/src/main/resources/edu/rpi/legup/images/thermometer/MercOrBlocked.png new file mode 100644 index 000000000..66c994de0 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/MercOrBlocked.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/MercuryInBody.png b/src/main/resources/edu/rpi/legup/images/thermometer/MercuryInBody.png new file mode 100644 index 000000000..06cb87e42 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/MercuryInBody.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/MinimumFill.png b/src/main/resources/edu/rpi/legup/images/thermometer/MinimumFill.png new file mode 100644 index 000000000..28719cf53 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/MinimumFill.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/NotEnoughMercury.png b/src/main/resources/edu/rpi/legup/images/thermometer/NotEnoughMercury.png new file mode 100644 index 000000000..d2277e8ef Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/NotEnoughMercury.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/PriorIsFilled.png b/src/main/resources/edu/rpi/legup/images/thermometer/PriorIsFilled.png new file mode 100644 index 000000000..9bda3a60b Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/PriorIsFilled.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/RestIsEmpty.png b/src/main/resources/edu/rpi/legup/images/thermometer/RestIsEmpty.png new file mode 100644 index 000000000..91374e062 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/RestIsEmpty.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/SatisfyMercury.png b/src/main/resources/edu/rpi/legup/images/thermometer/SatisfyMercury.png new file mode 100644 index 000000000..f450a205e Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/SatisfyMercury.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/ThermometerTooLarge.png b/src/main/resources/edu/rpi/legup/images/thermometer/ThermometerTooLarge.png new file mode 100644 index 000000000..eb61b4f1b Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/ThermometerTooLarge.png differ diff --git a/src/main/resources/edu/rpi/legup/images/thermometer/TooManyMercury.png b/src/main/resources/edu/rpi/legup/images/thermometer/TooManyMercury.png new file mode 100644 index 000000000..99a215b12 Binary files /dev/null and b/src/main/resources/edu/rpi/legup/images/thermometer/TooManyMercury.png differ diff --git a/src/main/resources/edu/rpi/legup/legup/config b/src/main/resources/edu/rpi/legup/legup/config index ccd4f5be3..e01767677 100644 --- a/src/main/resources/edu/rpi/legup/legup/config +++ b/src/main/resources/edu/rpi/legup/legup/config @@ -4,6 +4,10 @@ qualifiedClassName="edu.rpi.legup.puzzle.battleship.Battleship" fileType=".xml" fileCreationDisabled="true"/> + + fileCreationDisabled="false"/> - + + + diff --git a/src/test/java/legup/MockGameBoardFacade.java b/src/test/java/legup/MockGameBoardFacade.java index 7840b61b7..f4f1db938 100644 --- a/src/test/java/legup/MockGameBoardFacade.java +++ b/src/test/java/legup/MockGameBoardFacade.java @@ -11,8 +11,7 @@ protected MockGameBoardFacade() { Config config = null; try { config = new Config(); - } - catch (InvalidConfigException e) { + } catch (InvalidConfigException e) { System.exit(1); } setConfig(config); @@ -23,7 +22,7 @@ protected MockGameBoardFacade() { * * @return single instance of GameBoardFacade */ - public synchronized static GameBoardFacade getInstance() { + public static synchronized GameBoardFacade getInstance() { if (instance == null) { instance = new MockGameBoardFacade(); } @@ -31,9 +30,7 @@ public synchronized static GameBoardFacade getInstance() { } @Override - public void initializeUI() { - - } + public void initializeUI() {} @Override public void setPuzzle(Puzzle puzzle) { @@ -41,7 +38,5 @@ public void setPuzzle(Puzzle puzzle) { } @Override - public void setWindowTitle(String puzzleName, String fileName) { - - } + public void setWindowTitle(String puzzleName, String fileName) {} } diff --git a/src/test/java/legup/TestRunner.java b/src/test/java/legup/TestRunner.java index 3a74c4c61..5486a0353 100644 --- a/src/test/java/legup/TestRunner.java +++ b/src/test/java/legup/TestRunner.java @@ -1,17 +1,16 @@ package legup; - import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; -import puzzles.battleship.rules.*; +import puzzles.battleship.rules.AdjacentShipsContradictionRuleTest; +import puzzles.battleship.rules.FinishWithShipsDirectRuleTests; import puzzles.lightup.rules.*; +import puzzles.minesweeper.MinesweeperUtilitiesTest; import puzzles.nurikabe.rules.*; import puzzles.treetent.rules.*; -/** - * This class runs all of the tests for the project without needing to run build scripts. - */ +/** This class runs all of the tests for the project without needing to run build scripts. */ public class TestRunner { public static void main(String[] args) { // Battleship Tests @@ -20,7 +19,7 @@ public static void main(String[] args) { Result result2 = JUnitCore.runClasses(FinishWithShipsDirectRuleTests.class); printTestResults(result2); - // Lightup Tests + // LightUp Tests Result result3 = JUnitCore.runClasses(BulbsInPathContradictionRuleTest.class); printTestResults(result3); Result result4 = JUnitCore.runClasses(CannotLightACellContradictionRuleTest.class); @@ -31,68 +30,74 @@ public static void main(String[] args) { printTestResults(result6); Result result7 = JUnitCore.runClasses(FinishWithBulbsDirectRuleTest.class); printTestResults(result7); - Result result8 = JUnitCore.runClasses(LightOrEmptyCaseRuleTest.class); + Result result8 = JUnitCore.runClasses(FinishWithEmptyDirectRuleTest.class); printTestResults(result8); - Result result9 = JUnitCore.runClasses(MustLightDirectRuleTest.class); + Result result9 = JUnitCore.runClasses(LightOrEmptyCaseRuleTest.class); printTestResults(result9); - Result result10 = JUnitCore.runClasses(SatisfyNumberCaseRuleTest.class); + Result result10 = JUnitCore.runClasses(MustLightDirectRuleTest.class); printTestResults(result10); - Result result11 = JUnitCore.runClasses(TooFewBulbsContradictionRuleTest.class); + Result result11 = JUnitCore.runClasses(SatisfyNumberCaseRuleTest.class); printTestResults(result11); - Result result12 = JUnitCore.runClasses(TooManyBulbsContradictionRuleTest.class); + Result result12 = JUnitCore.runClasses(TooFewBulbsContradictionRuleTest.class); printTestResults(result12); - - //nurikabe tests - Result result13 = JUnitCore.runClasses(BlackBetweenRegionsDirectRuleTest.class); + Result result13 = JUnitCore.runClasses(TooManyBulbsContradictionRuleTest.class); printTestResults(result13); - Result result14 = JUnitCore.runClasses(BlackBottleNeckDirectRuleTest.class); + + // nurikabe tests + Result result14 = JUnitCore.runClasses(BlackBetweenRegionsDirectRuleTest.class); printTestResults(result14); - Result result15 = JUnitCore.runClasses(BlackOrWhiteCaseRuleTest.class); + Result result15 = JUnitCore.runClasses(BlackBottleNeckDirectRuleTest.class); printTestResults(result15); - Result result16 = JUnitCore.runClasses(BlackSquareContradictionRuleTest.class); + Result result16 = JUnitCore.runClasses(BlackOrWhiteCaseRuleTest.class); printTestResults(result16); - Result result17 = JUnitCore.runClasses(CornerBlackDirectRuleTest.class); + Result result17 = JUnitCore.runClasses(BlackSquareContradictionRuleTest.class); printTestResults(result17); - Result result18 = JUnitCore.runClasses(FillinBlackDirectRuleTest.class); + Result result18 = JUnitCore.runClasses(CornerBlackDirectRuleTest.class); printTestResults(result18); - Result result19 = JUnitCore.runClasses(FillinWhiteDirectRuleTest.class); + Result result19 = JUnitCore.runClasses(FillinBlackDirectRuleTest.class); printTestResults(result19); - Result result20 = JUnitCore.runClasses(IsolateBlackContradictionRuleTest.class); + Result result20 = JUnitCore.runClasses(FillinWhiteDirectRuleTest.class); printTestResults(result20); - Result result21 = JUnitCore.runClasses(MultipleNumbersContradictionRuleTest.class); + Result result21 = JUnitCore.runClasses(IsolateBlackContradictionRuleTest.class); printTestResults(result21); - Result result22 = JUnitCore.runClasses(NoNumbersContradictionRuleTest.class); + Result result22 = JUnitCore.runClasses(MultipleNumbersContradictionRuleTest.class); printTestResults(result22); - Result result23 = JUnitCore.runClasses(PreventBlackSquareDirectRuleTest.class); + Result result23 = JUnitCore.runClasses(NoNumbersContradictionRuleTest.class); printTestResults(result23); - Result result24 = JUnitCore.runClasses(SurroundRegionDirectRuleTest.class); + Result result24 = JUnitCore.runClasses(PreventBlackSquareDirectRuleTest.class); printTestResults(result24); - Result result25 = JUnitCore.runClasses(TooFewSpacesContradictionRuleTest.class); + Result result25 = JUnitCore.runClasses(SurroundRegionDirectRuleTest.class); printTestResults(result25); - Result result26 = JUnitCore.runClasses(TooManySpacesContradictionRuleTest.class); + Result result26 = JUnitCore.runClasses(TooFewSpacesContradictionRuleTest.class); printTestResults(result26); - Result result27 = JUnitCore.runClasses(WhiteBottleNeckDirectRuleTest.class); + Result result27 = JUnitCore.runClasses(TooManySpacesContradictionRuleTest.class); printTestResults(result27); + Result result28 = JUnitCore.runClasses(WhiteBottleNeckDirectRuleTest.class); + printTestResults(result28); // Treetent - Result result28 = JUnitCore.runClasses(EmptyFieldDirectRuleTest.class); - printTestResults(result28); - Result result29 = JUnitCore.runClasses(FinishWithGrassDirectRuleTest.class); + Result result29 = JUnitCore.runClasses(EmptyFieldDirectRuleTest.class); printTestResults(result29); - Result result30 = JUnitCore.runClasses(FinishWithTentsDirectRuleTest.class); + Result result30 = JUnitCore.runClasses(FinishWithGrassDirectRuleTest.class); printTestResults(result30); - Result result31 = JUnitCore.runClasses(LastCampingSpotDirectRuleTest.class); + Result result31 = JUnitCore.runClasses(FinishWithTentsDirectRuleTest.class); printTestResults(result31); - Result result32 = JUnitCore.runClasses(NoTentForTreeContradictionRuleTest.class); + Result result32 = JUnitCore.runClasses(LastCampingSpotDirectRuleTest.class); printTestResults(result32); - Result result33 = JUnitCore.runClasses(NoTreeForTentContradictionRuleTest.class); + Result result33 = JUnitCore.runClasses(NoTentForTreeContradictionRuleTest.class); printTestResults(result33); - Result result34 = JUnitCore.runClasses(SurroundTentWithGrassDirectRuleTest.class); + Result result34 = JUnitCore.runClasses(NoTreeForTentContradictionRuleTest.class); printTestResults(result34); - Result result35 = JUnitCore.runClasses(TreeForTentDirectRuleTest.class); + Result result35 = JUnitCore.runClasses(SurroundTentWithGrassDirectRuleTest.class); printTestResults(result35); - Result result36 = JUnitCore.runClasses(TentOrGrassCaseRuleTest.class); + Result result36 = JUnitCore.runClasses(TreeForTentDirectRuleTest.class); printTestResults(result36); + Result result37 = JUnitCore.runClasses(TentOrGrassCaseRuleTest.class); + printTestResults(result37); + + // Minesweeper + Result result38 = JUnitCore.runClasses(MinesweeperUtilitiesTest.class); + printTestResults(result38); } private static void printTestResults(Result result) { diff --git a/src/test/java/legup/TestUtilities.java b/src/test/java/legup/TestUtilities.java index 9f203b223..d48d648d7 100644 --- a/src/test/java/legup/TestUtilities.java +++ b/src/test/java/legup/TestUtilities.java @@ -7,9 +7,18 @@ import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.save.InvalidFileFormatException; +import java.io.InputStream; + public final class TestUtilities { - public static void importTestBoard(String fileName, Puzzle puzzle) throws InvalidFileFormatException { - puzzle.importPuzzle(ClassLoader.getSystemResourceAsStream(fileName)); + public static void importTestBoard(String fileName, Puzzle puzzle) + throws InvalidFileFormatException { + InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName); + + if (inputStream == null) { + throw new IllegalArgumentException("InputStream cannot be null. File not found: " + fileName); + } + + puzzle.importPuzzle(inputStream); Tree tree = puzzle.getTree(); TreeNode rootNode = tree.getRootNode(); Board board = rootNode.getBoard().copy(); diff --git a/src/test/java/puzzles/battleship/rules/AdjacentShipsContradictionRuleTest.java b/src/test/java/puzzles/battleship/rules/AdjacentShipsContradictionRuleTest.java index c9e65e9c1..08b6633db 100644 --- a/src/test/java/puzzles/battleship/rules/AdjacentShipsContradictionRuleTest.java +++ b/src/test/java/puzzles/battleship/rules/AdjacentShipsContradictionRuleTest.java @@ -1,24 +1,20 @@ package puzzles.battleship.rules; -import edu.rpi.legup.puzzle.battleship.BattleshipType; -import legup.MockGameBoardFacade; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; import edu.rpi.legup.puzzle.battleship.Battleship; import edu.rpi.legup.puzzle.battleship.BattleshipBoard; -import edu.rpi.legup.puzzle.battleship.BattleshipCell; import edu.rpi.legup.puzzle.battleship.rules.AdjacentShipsContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; - import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class AdjacentShipsContradictionRuleTest { - private static final AdjacentShipsContradictionRule RULE - = new AdjacentShipsContradictionRule(); + private static final AdjacentShipsContradictionRule RULE = new AdjacentShipsContradictionRule(); private static Battleship battleship; @@ -30,8 +26,9 @@ public static void setUp() { @Test public void OrthogonalAdjacentTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/battleship/rules" + - "/AdjacentShipsContradictionRule/OrthogonalAdjacentBoards", + TestUtilities.importTestBoard( + "puzzles/battleship/rules" + + "/AdjacentShipsContradictionRule/OrthogonalAdjacentBoards", battleship); TreeNode rootNode = battleship.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -39,37 +36,38 @@ public void OrthogonalAdjacentTest() throws InvalidFileFormatException { BattleshipBoard board = (BattleshipBoard) transition.getBoard(); - Assert.assertNotNull(RULE.checkContradiction( - board)); + Assert.assertNotNull(RULE.checkContradiction(board)); } @Test public void InvalidOrthogonalAdjacentTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/battleship/rules" + - "/AdjacentShipsContradictionRule" + - "/InvalidOrthogonalAdjacentBoards", battleship); + TestUtilities.importTestBoard( + "puzzles/battleship/rules" + + "/AdjacentShipsContradictionRule" + + "/InvalidOrthogonalAdjacentBoards", + battleship); TreeNode rootNode = battleship.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); BattleshipBoard board = (BattleshipBoard) transition.getBoard(); - Assert.assertNull(RULE.checkContradiction( - board)); + Assert.assertNull(RULE.checkContradiction(board)); } @Test public void DiagonalAdjacentTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/battleship/rules" + - "/AdjacentShipsContradictionRule" + - "/DiagonalAdjacentBoards", battleship); + TestUtilities.importTestBoard( + "puzzles/battleship/rules" + + "/AdjacentShipsContradictionRule" + + "/DiagonalAdjacentBoards", + battleship); TreeNode rootNode = battleship.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); BattleshipBoard board = (BattleshipBoard) transition.getBoard(); - Assert.assertNull(RULE.checkContradiction( - board)); + Assert.assertNull(RULE.checkContradiction(board)); } } diff --git a/src/test/java/puzzles/battleship/rules/FinishWithShipsDirectRuleTests.java b/src/test/java/puzzles/battleship/rules/FinishWithShipsDirectRuleTests.java index ac7e8cb8e..1548445fd 100644 --- a/src/test/java/puzzles/battleship/rules/FinishWithShipsDirectRuleTests.java +++ b/src/test/java/puzzles/battleship/rules/FinishWithShipsDirectRuleTests.java @@ -1,18 +1,16 @@ package puzzles.battleship.rules; -import org.junit.*; - -import legup.MockGameBoardFacade; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.battleship.*; import edu.rpi.legup.puzzle.battleship.rules.*; import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.*; public class FinishWithShipsDirectRuleTests { - private static final FinishWithShipsDirectRule RULE - = new FinishWithShipsDirectRule(); + private static final FinishWithShipsDirectRule RULE = new FinishWithShipsDirectRule(); private static Battleship battleship; @@ -22,10 +20,10 @@ public static void setUp() { battleship = new Battleship(); } - //@Test + // @Test public void HorizontalValidTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/battleship/rules" + - "/FinishWithShipsBasicRuleTests/HorizontalValidBoard", + TestUtilities.importTestBoard( + "puzzles/battleship/rules" + "/FinishWithShipsBasicRuleTests/HorizontalValidBoard", battleship); TreeNode rootNode = battleship.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -34,10 +32,10 @@ public void HorizontalValidTest() throws InvalidFileFormatException { Assert.assertNull(RULE.checkRule(transition)); } - //@Test + // @Test public void VerticaValidTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/battleship/rules" + - "/FinishWithShipsBasicRuleTests/VerticalValidBoard", + TestUtilities.importTestBoard( + "puzzles/battleship/rules" + "/FinishWithShipsBasicRuleTests/VerticalValidBoard", battleship); TreeNode rootNode = battleship.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -46,10 +44,11 @@ public void VerticaValidTest() throws InvalidFileFormatException { Assert.assertNull(RULE.checkRule(transition)); } - //@Test + // @Test public void HorizontalInvalidTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/battleship/rules" + - "/FinishWithShipsBasicRuleTests/HorizontalInvalidBoard", + TestUtilities.importTestBoard( + "puzzles/battleship/rules" + + "/FinishWithShipsBasicRuleTests/HorizontalInvalidBoard", battleship); TreeNode rootNode = battleship.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); @@ -58,10 +57,10 @@ public void HorizontalInvalidTest() throws InvalidFileFormatException { Assert.assertNotNull(RULE.checkRule(transition)); } - //@Test + // @Test public void VerticalInvalidTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/battleship/rules" + - "/FinishWithShipsBasicRuleTests/VerticalInvalidBoard", + TestUtilities.importTestBoard( + "puzzles/battleship/rules" + "/FinishWithShipsBasicRuleTests/VerticalInvalidBoard", battleship); TreeNode rootNode = battleship.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); diff --git a/src/test/java/puzzles/lightup/rules/BulbsInPathContradictionRuleTest.java b/src/test/java/puzzles/lightup/rules/BulbsInPathContradictionRuleTest.java index 0e7930751..316a86f43 100644 --- a/src/test/java/puzzles/lightup/rules/BulbsInPathContradictionRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/BulbsInPathContradictionRuleTest.java @@ -1,14 +1,13 @@ package puzzles.lightup.rules; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; import edu.rpi.legup.puzzle.lightup.LightUp; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.rules.BulbsInPathContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; - +import legup.TestUtilities; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -22,31 +21,35 @@ public static void setUp() { } @Test - public void BulbsInPathContradictionRule_LightInHorizontalPath() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/BulbsInPathContradictionRule/LightInHorizontalPath", lightUp); + public void BulbsInPathContradictionRule_LightInHorizontalPath() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/lightup/rules/BulbsInPathContradictionRule/LightInHorizontalPath", + lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm there is a contradiction somewhere on the board + // confirm there is a contradiction somewhere on the board Assert.assertNull(RULE.checkContradiction(board)); Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(2, 0))); - Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 1))); } @Test - public void BulbsInPathContradictionRule_LightInVerticalPath() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/BulbsInPathContradictionRule/LightInVerticalPath", lightUp); + public void BulbsInPathContradictionRule_LightInVerticalPath() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/lightup/rules/BulbsInPathContradictionRule/LightInVerticalPath", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm there is a contradiction somewhere on the board + // confirm there is a contradiction somewhere on the board Assert.assertNull(RULE.checkContradiction(board)); Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(0, 2))); @@ -55,8 +58,10 @@ public void BulbsInPathContradictionRule_LightInVerticalPath() throws InvalidFil } @Test - public void BulbsInPathContradictionRule_BlockInVerticalPath() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInVerticalPath", lightUp); + public void BulbsInPathContradictionRule_BlockInVerticalPath() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInVerticalPath", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -70,17 +75,19 @@ public void BulbsInPathContradictionRule_BlockInVerticalPath() throws InvalidFil } @Test - public void BulbsInPathContradictionRule_BlockInHorizontalPath() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInHorizontalPath", lightUp); + public void BulbsInPathContradictionRule_BlockInHorizontalPath() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/lightup/rules/BulbsInPathContradictionRule/BlockInHorizontalPath", + lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); Assert.assertNotNull(RULE.checkContradiction(board)); - Assert.assertNotNull(RULE.checkContradictionAt(board,board.getCell(0,0))); - Assert.assertNotNull(RULE.checkContradictionAt(board,board.getCell(2,0))); - Assert.assertNotNull(RULE.checkContradictionAt(board,board.getCell(1,1))); - + Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); + Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0))); + Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 1))); } } diff --git a/src/test/java/puzzles/lightup/rules/CannotLightACellContradictionRuleTest.java b/src/test/java/puzzles/lightup/rules/CannotLightACellContradictionRuleTest.java index 7b3ffd2b9..6db42d39b 100644 --- a/src/test/java/puzzles/lightup/rules/CannotLightACellContradictionRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/CannotLightACellContradictionRuleTest.java @@ -1,19 +1,19 @@ package puzzles.lightup.rules; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; import edu.rpi.legup.puzzle.lightup.LightUp; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.rules.CannotLightACellContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; - +import legup.TestUtilities; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; public class CannotLightACellContradictionRuleTest { - private static final CannotLightACellContradictionRule RULE = new CannotLightACellContradictionRule(); + private static final CannotLightACellContradictionRule RULE = + new CannotLightACellContradictionRule(); private static LightUp lightUp; @BeforeClass @@ -22,22 +22,23 @@ public static void setUp() { } @Test - //extensive full testing of null and non-null in a 5x5 board + // extensive full testing of null and non-null in a 5x5 board public void FullLightTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/CannotLightACellContradictionRule/FullLightTest", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/CannotLightACellContradictionRule/FullLightTest", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm there is a contradiction somewhere on the board + // confirm there is a contradiction somewhere on the board Assert.assertNull(RULE.checkContradiction(board)); - //confirm it is impossible to light up these squares + // confirm it is impossible to light up these squares Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 3))); Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(3, 3))); - //confirm these are not required to be lit because they are already lit or unable to be + // confirm these are not required to be lit because they are already lit or unable to be Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 1))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0))); @@ -45,21 +46,22 @@ public void FullLightTest() throws InvalidFileFormatException { } @Test - //simple contradiction testing for null and non-null in a 3x3 board + // simple contradiction testing for null and non-null in a 3x3 board public void CannotLightMiddleTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/CannotLightACellContradictionRule/CannotLight", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/CannotLightACellContradictionRule/CannotLight", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm there is a contradiction somewhere on the board + // confirm there is a contradiction somewhere on the board Assert.assertNull(RULE.checkContradiction(board)); - //confirm it is impossible to light up the center square + // confirm it is impossible to light up the center square Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1))); - //every square except the center + // every square except the center Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0))); @@ -71,16 +73,17 @@ public void CannotLightMiddleTest() throws InvalidFileFormatException { @Test public void CanLightTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/CannotLightACellContradictionRule/CanLightTest", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/CannotLightACellContradictionRule/CanLightTest", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm there is not a contradiction somewhere on the board + // confirm there is not a contradiction somewhere on the board Assert.assertNotNull(RULE.checkContradiction(board)); - //confirm that these cells can be lit, are already lit, or that they are just black blocks + // confirm that these cells can be lit, are already lit, or that they are just black blocks Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 3))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(3, 3))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); diff --git a/src/test/java/puzzles/lightup/rules/EmptyCellinLightDirectRuleTest.java b/src/test/java/puzzles/lightup/rules/EmptyCellinLightDirectRuleTest.java index b0a2d10ed..264cf928c 100644 --- a/src/test/java/puzzles/lightup/rules/EmptyCellinLightDirectRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/EmptyCellinLightDirectRuleTest.java @@ -1,17 +1,17 @@ package puzzles.lightup.rules; -import org.junit.BeforeClass; -import org.junit.Test; -import edu.rpi.legup.puzzle.lightup.LightUp; -import edu.rpi.legup.puzzle.lightup.rules.EmptyCellinLightDirectRule; -import edu.rpi.legup.save.InvalidFileFormatException; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUp; import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import edu.rpi.legup.puzzle.lightup.rules.EmptyCellinLightDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.TestUtilities; import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class EmptyCellinLightDirectRuleTest { private static final EmptyCellinLightDirectRule RULE = new EmptyCellinLightDirectRule(); @@ -23,72 +23,80 @@ public static void setUp() { } @Test - //tests a 3x3 board with with a 0 black tile in the center and lightbulbs in top left and bototm right - //confirms the rest of the tiles must be empty - public void EmptyCellinLightDirectRule() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/lightup/rules/EmptyCellinLightDirectRule/EmptyCells", lightUp); + // tests a 3x3 board with with a 0 black tile in the center and lightbulbs in top left and + // bototm + // right + // confirms the rest of the tiles must be empty + public void EmptyCellinLightDirectRule() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/lightup/rules/EmptyCellinLightDirectRule/EmptyCells", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - //get board state + transition.setRule(RULE); + + // get board state LightUpBoard board = (LightUpBoard) transition.getBoard(); - //change the board's cells considering the emptycellinlight rule - LightUpCell cell2 = board.getCell(1,0); + // change the board's cells considering the emptycellinlight rule + LightUpCell cell2 = board.getCell(1, 0); cell2.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell2); - LightUpCell cell3 = board.getCell(0,1); + LightUpCell cell3 = board.getCell(0, 1); cell3.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell3); - LightUpCell cell4 = board.getCell(2,0); + LightUpCell cell4 = board.getCell(2, 0); cell4.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell4); - LightUpCell cell5 = board.getCell(0,2); + LightUpCell cell5 = board.getCell(0, 2); cell5.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell5); - LightUpCell cell6 = board.getCell(1,2); + LightUpCell cell6 = board.getCell(1, 2); cell6.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell6); - LightUpCell cell7 = board.getCell(2,1); + LightUpCell cell7 = board.getCell(2, 1); cell7.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell7); - LightUpCell cell8 = board.getCell(3,0); + LightUpCell cell8 = board.getCell(3, 0); cell8.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell8); - LightUpCell cell9 = board.getCell(3,2); + LightUpCell cell9 = board.getCell(3, 2); cell9.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell9); - LightUpCell cell10 = board.getCell(2,3); + LightUpCell cell10 = board.getCell(2, 3); cell10.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell10); - LightUpCell cell11 = board.getCell(0,3); + LightUpCell cell11 = board.getCell(0, 3); cell11.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell11); - //confirm there is a logical following of the EmptyCellinLight rule + // confirm there is a logical following of the EmptyCellinLight rule Assert.assertNull(RULE.checkRule(transition)); - //cells (0,0) and (2,2) are not empty because they have lightbulbs, (1,1) - //because it is a black tile, and (1,3),(3,1),(3,3) because they are not lit. Confirm the rest are empty + // cells (0,0) and (2,2) are not empty because they have lightbulbs, (1,1) + // because it is a black tile, and (1,3),(3,1),(3,3) because they are not lit. Confirm the + // rest + // are empty LightUpCell c; for (int i = 0; i < board.getHeight(); i++) { for (int j = 0; j < board.getWidth(); j++) { c = board.getCell(j, i); - if ((i == 0 && j == 0) || (i == 2 && j == 2) || (i == 1 && j == 1) || (i == 1 && j == 3) || (i == 3 && j == 1) - || (i==3 && j==3)){ + if ((i == 0 && j == 0) + || (i == 2 && j == 2) + || (i == 1 && j == 1) + || (i == 1 && j == 3) + || (i == 3 && j == 1) + || (i == 3 && j == 3)) { Assert.assertNotNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { Assert.assertNull(RULE.checkRuleAt(transition, c)); } } diff --git a/src/test/java/puzzles/lightup/rules/EmptyCornersDirectRuleTest.java b/src/test/java/puzzles/lightup/rules/EmptyCornersDirectRuleTest.java index bea69b95f..a4f958860 100644 --- a/src/test/java/puzzles/lightup/rules/EmptyCornersDirectRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/EmptyCornersDirectRuleTest.java @@ -1,23 +1,22 @@ package puzzles.lightup.rules; -import org.junit.BeforeClass; -import org.junit.Test; -import edu.rpi.legup.puzzle.lightup.LightUp; -import edu.rpi.legup.puzzle.lightup.rules.EmptyCornersDirectRule; -import edu.rpi.legup.save.InvalidFileFormatException; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUp; import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import edu.rpi.legup.puzzle.lightup.rules.EmptyCornersDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.TestUtilities; import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class EmptyCornersDirectRuleTest { private static final EmptyCornersDirectRule RULE = new EmptyCornersDirectRule(); private static LightUp lightUp; - @BeforeClass public static void setUp() { lightUp = new LightUp(); @@ -25,55 +24,55 @@ public static void setUp() { @Test public void EmptyCornersTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/EmptyCornersDirectRule/EmptyCorners", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/EmptyCornersDirectRule/EmptyCorners", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - //get board state + // get board state LightUpBoard board = (LightUpBoard) transition.getBoard(); - //change the board's cells considering the EmptyCorners rule to empty - LightUpCell cell1 = board.getCell(2,2); + // change the board's cells considering the EmptyCorners rule to empty + LightUpCell cell1 = board.getCell(2, 2); cell1.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell1); - LightUpCell cell2 = board.getCell(0,2); + LightUpCell cell2 = board.getCell(0, 2); cell2.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell2); - LightUpCell cell3 = board.getCell(4,3); + LightUpCell cell3 = board.getCell(4, 3); cell3.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell3); - //confirm there is a logical following of the EmptyCorners rule + // confirm there is a logical following of the EmptyCorners rule Assert.assertNull(RULE.checkRule(transition)); - //this should not be accepted, the cell should remain unknown - LightUpCell cell4 = board.getCell(4,5); + // this should not be accepted, the cell should remain unknown + LightUpCell cell4 = board.getCell(4, 5); cell4.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell4); - //this should not be accepted, the cell should be empty but not because of this rule - LightUpCell cell5 = board.getCell(4,1); + // this should not be accepted, the cell should be empty but not because of this rule + LightUpCell cell5 = board.getCell(4, 1); cell5.setData(LightUpCellType.EMPTY.value); board.addModifiedData(cell5); Assert.assertNotNull(RULE.checkRule(transition)); - //confirm the two expected cells are emptied USING THE RULE + // confirm the two expected cells are emptied USING THE RULE // and none of the rest are (others can be empty just not by the same rule) LightUpCell c; for (int i = 0; i < board.getHeight(); i++) { for (int j = 0; j < board.getWidth(); j++) { c = board.getCell(j, i); - if ((i == 2 && j == 0) || (i == 2 && j == 2) || (i==3 && j==4)){ + if ((i == 2 && j == 0) || (i == 2 && j == 2) || (i == 3 && j == 4)) { Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/lightup/rules/FinishWithBulbsDirectRuleTest.java b/src/test/java/puzzles/lightup/rules/FinishWithBulbsDirectRuleTest.java index f98a48303..59cbfdbf9 100644 --- a/src/test/java/puzzles/lightup/rules/FinishWithBulbsDirectRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/FinishWithBulbsDirectRuleTest.java @@ -1,17 +1,17 @@ package puzzles.lightup.rules; -import org.junit.BeforeClass; -import org.junit.Test; -import edu.rpi.legup.puzzle.lightup.LightUp; -import edu.rpi.legup.puzzle.lightup.rules.FinishWithBulbsDirectRule; -import edu.rpi.legup.save.InvalidFileFormatException; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUp; import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import edu.rpi.legup.puzzle.lightup.rules.FinishWithBulbsDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.TestUtilities; import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class FinishWithBulbsDirectRuleTest { private static final FinishWithBulbsDirectRule RULE = new FinishWithBulbsDirectRule(); @@ -24,77 +24,79 @@ public static void setUp() { @Test public void FinishBulbTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/FinishWithBulbsDirectRule/FinishWithBulbs", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/FinishWithBulbsDirectRule/FinishWithBulbs", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - //get board state + transition.setRule(RULE); + + // get board state LightUpBoard board = (LightUpBoard) transition.getBoard(); - //change the board's cells considering the FinishWithBulbs rule to empty - LightUpCell cell1 = board.getCell(1,0); + // change the board's cells considering the FinishWithBulbs rule to empty + LightUpCell cell1 = board.getCell(1, 0); cell1.setData(LightUpCellType.BULB.value); board.addModifiedData(cell1); - //confirm there is a logical following of the FinishWithBulbs rule + // confirm there is a logical following of the FinishWithBulbs rule Assert.assertNull(RULE.checkRule(transition)); - //check every square except the top center (2,0) + // check every square except the top center (2,0) LightUpCell c; for (int i = 0; i < board.getHeight(); i++) { for (int j = 0; j < board.getWidth(); j++) { c = board.getCell(j, i); - if (i == 0 && j == 1){ - //logically follows + if (i == 0 && j == 1) { + // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { - //does not use the rule to logically follow + } else { + // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } } } - //even though this test isnt a completely filled board because it is unsolveable, it tests FinishBulbs properly + // even though this test isnt a completely filled board because it is unsolveable, it tests + // FinishBulbs properly @Test public void FinishBulbTestWithThree() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/FinishWithBulbsDirectRule/FinishWithBulbsWithThree", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/FinishWithBulbsDirectRule/FinishWithBulbsWithThree", + lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - //get board state + transition.setRule(RULE); + + // get board state LightUpBoard board = (LightUpBoard) transition.getBoard(); - //change the board's cells considering the FinishWithBulbs rule to empty - LightUpCell cell1 = board.getCell(1,2); + // change the board's cells considering the FinishWithBulbs rule to empty + LightUpCell cell1 = board.getCell(1, 2); cell1.setData(LightUpCellType.BULB.value); board.addModifiedData(cell1); - LightUpCell cell2 = board.getCell(0,1); + LightUpCell cell2 = board.getCell(0, 1); cell2.setData(LightUpCellType.BULB.value); board.addModifiedData(cell2); - LightUpCell cell3 = board.getCell(2,1); + LightUpCell cell3 = board.getCell(2, 1); cell3.setData(LightUpCellType.BULB.value); board.addModifiedData(cell3); - //confirm there is a logical following of the FinishWithBulbs rule + // confirm there is a logical following of the FinishWithBulbs rule Assert.assertNull(RULE.checkRule(transition)); - //check every square for logical following + // check every square for logical following LightUpCell c; for (int i = 0; i < board.getHeight(); i++) { for (int j = 0; j < board.getWidth(); j++) { c = board.getCell(j, i); - if ((i == 1 && j == 2) || (i == 2 && j == 1) || (i == 1 && j == 0)){ - //logically follows + if ((i == 1 && j == 2) || (i == 2 && j == 1) || (i == 1 && j == 0)) { + // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { - //does not use the rule to logically follow + } else { + // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } diff --git a/src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleTest.java b/src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleTest.java new file mode 100644 index 000000000..079641ee7 --- /dev/null +++ b/src/test/java/puzzles/lightup/rules/FinishWithEmptyDirectRuleTest.java @@ -0,0 +1,105 @@ +package puzzles.lightup.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUp; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; +import edu.rpi.legup.puzzle.lightup.LightUpCell; +import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import edu.rpi.legup.puzzle.lightup.rules.FinishWithEmptyDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class FinishWithEmptyDirectRuleTest { + private static final FinishWithEmptyDirectRule RULE = new FinishWithEmptyDirectRule(); + private static LightUp lightUp; + + @BeforeClass + public static void setUp() { + lightUp = new LightUp(); + } + + @Test + public void FinishEmptyTestWithOne() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/lightup/rules/FinishWithEmptyDirectRule/FinishWithEmptyWithOne", lightUp); + TreeNode rootNode = lightUp.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // get board state + LightUpBoard board = (LightUpBoard) transition.getBoard(); + // The board has a "1" clue at (1,1) with a bulb one space above at (1,0); + + // change the board's cells considering the FinishWithEmpty rule to empty + LightUpCell cell1 = board.getCell(0, 1); // left + cell1.setData(LightUpCellType.EMPTY.value); + board.addModifiedData(cell1); + + LightUpCell cell2 = board.getCell(2, 1); // right + cell2.setData(LightUpCellType.EMPTY.value); + board.addModifiedData(cell2); + + LightUpCell cell3 = board.getCell(1, 2); // below + cell3.setData(LightUpCellType.EMPTY.value); + board.addModifiedData(cell3); + + // confirm there is a logical following of the FinishWithEmpty rule + Assert.assertNull(RULE.checkRule(transition)); + + // check every square except the top center (2,0) + LightUpCell c; + for (int i = 0; i < board.getHeight(); i++) { + for (int j = 0; j < board.getWidth(); j++) { + c = board.getCell(j, i); + if ((i == 1 && j == 0) || (i == 1 && j == 2) || (i == 2 && j == 1)) { + // logically follows + Assert.assertNull(RULE.checkRuleAt(transition, c)); + } else { + // does not use the rule to logically follow + Assert.assertNotNull(RULE.checkRuleAt(transition, c)); + } + } + } + } + + @Test + public void FinishEmptyTestWithThree() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/lightup/rules/FinishWithEmptyDirectRule/FinishWithEmptyWithThree", + lightUp); + TreeNode rootNode = lightUp.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // get board state + LightUpBoard board = (LightUpBoard) transition.getBoard(); + // The board has a "3" clue at (1,1) with a bulbs at (0,1), (2,1), and (1,2) + + // change the board's cells considering the FinishWithBulbs rule to empty + LightUpCell cell1 = board.getCell(1, 0); + cell1.setData(LightUpCellType.EMPTY.value); + board.addModifiedData(cell1); + + // confirm there is a logical following of the FinishWithBulbs rule + Assert.assertNull(RULE.checkRule(transition)); + + // check every square for logical following + LightUpCell c; + for (int i = 0; i < board.getHeight(); i++) { + for (int j = 0; j < board.getWidth(); j++) { + c = board.getCell(j, i); + if (i == 0 && j == 1) { + // logically follows + Assert.assertNull(RULE.checkRuleAt(transition, c)); + } else { + // does not use the rule to logically follow + Assert.assertNotNull(RULE.checkRuleAt(transition, c)); + } + } + } + } +} diff --git a/src/test/java/puzzles/lightup/rules/LightOrEmptyCaseRuleTest.java b/src/test/java/puzzles/lightup/rules/LightOrEmptyCaseRuleTest.java index 2e6a1e879..fa0698edb 100644 --- a/src/test/java/puzzles/lightup/rules/LightOrEmptyCaseRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/LightOrEmptyCaseRuleTest.java @@ -1,19 +1,19 @@ package puzzles.lightup.rules; -import org.junit.BeforeClass; -import org.junit.Test; -import edu.rpi.legup.puzzle.lightup.LightUp; -import edu.rpi.legup.puzzle.lightup.rules.LightOrEmptyCaseRule; -import edu.rpi.legup.save.InvalidFileFormatException; -import legup.TestUtilities; +import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUp; import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; -import org.junit.Assert; +import edu.rpi.legup.puzzle.lightup.rules.LightOrEmptyCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; import java.util.ArrayList; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class LightOrEmptyCaseRuleTest { private static final LightOrEmptyCaseRule RULE = new LightOrEmptyCaseRule(); @@ -24,49 +24,52 @@ public static void setUp() { lightUp = new LightUp(); } - //creates boards for what is expected output, and checks that the getcases function produces the correct boards - //IT FAILS BECAUSE THE EXISTING GETCASES FUNCTION IS BUGGY/NOT COMPLETED (not my fault :| ) + // creates boards for what is expected output, and checks that the getcases function produces + // the + // correct boards + // IT FAILS BECAUSE THE EXISTING GETCASES FUNCTION IS BUGGY/NOT COMPLETED (not my fault :| ) @Test public void LightOrEmptyTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/LightOrEmptyCaseRule/LightOrEmpty", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/LightOrEmptyCaseRule/LightOrEmpty", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); + transition.setRule(RULE); - //get all new board states using caserule builtin function + // get all new board states using caserule builtin function LightUpBoard b = (LightUpBoard) transition.getBoard(); - LightUpCell numbered_cell = b.getCell(0,0); //the focus cell + LightUpCell numbered_cell = b.getCell(0, 0); // the focus cell ArrayList cases = RULE.getCases(b, numbered_cell); - //assert correct number of cases + // assert correct number of cases Assert.assertEquals(2, cases.size()); - //make a list of boards that I expect + // make a list of boards that I expect LightUpCell change_cell; LightUpBoard case1 = ((LightUpBoard) transition.getBoard()).copy(); LightUpBoard case2 = ((LightUpBoard) transition.getBoard()).copy(); - //change the cells of the first new case board - change_cell = case1.getCell(0,0); + // change the cells of the first new case board + change_cell = case1.getCell(0, 0); change_cell.setData(LightUpCellType.BULB.value); - //case1.addModifiedData(change_cell); + // case1.addModifiedData(change_cell); - change_cell = case1.getCell(1,1); + change_cell = case1.getCell(1, 1); change_cell.setData(LightUpCellType.BULB.value); - //case1.addModifiedData(change_cell); + // case1.addModifiedData(change_cell); - //change the cells of the second new case board - change_cell = case2.getCell(0,1); + // change the cells of the second new case board + change_cell = case2.getCell(0, 1); change_cell.setData(LightUpCellType.BULB.value); - //case2.addModifiedData(change_cell); + // case2.addModifiedData(change_cell); - change_cell = case2.getCell(1,0); + change_cell = case2.getCell(1, 0); change_cell.setData(LightUpCellType.BULB.value); - //case2.addModifiedData(change_cell); + // case2.addModifiedData(change_cell); - //check each board I expect and make sure it exists in returned board list - //currently cases is not made correctly, so the getCases function is flawed. - //Assert.assertTrue(cases.contains((Board) case1)); - //Assert.assertTrue(cases.contains((Board) case2)); + // check each board I expect and make sure it exists in returned board list + // currently cases is not made correctly, so the getCases function is flawed. + // Assert.assertTrue(cases.contains((Board) case1)); + // Assert.assertTrue(cases.contains((Board) case2)); } } diff --git a/src/test/java/puzzles/lightup/rules/MustLightDirectRuleTest.java b/src/test/java/puzzles/lightup/rules/MustLightDirectRuleTest.java index 07958895b..e0e1434c3 100644 --- a/src/test/java/puzzles/lightup/rules/MustLightDirectRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/MustLightDirectRuleTest.java @@ -1,17 +1,17 @@ package puzzles.lightup.rules; -import org.junit.BeforeClass; -import org.junit.Test; -import edu.rpi.legup.puzzle.lightup.LightUp; -import edu.rpi.legup.puzzle.lightup.rules.MustLightDirectRule; -import edu.rpi.legup.save.InvalidFileFormatException; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUp; import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; +import edu.rpi.legup.puzzle.lightup.rules.MustLightDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.TestUtilities; import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class MustLightDirectRuleTest { private static final MustLightDirectRule RULE = new MustLightDirectRule(); @@ -24,33 +24,33 @@ public static void setUp() { @Test public void MustLightTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/MustLightDirectRule/MustLight", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/MustLightDirectRule/MustLight", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - //get board state + transition.setRule(RULE); + + // get board state LightUpBoard board = (LightUpBoard) transition.getBoard(); - //change the board's cells considering the MustLight rule - LightUpCell cell1 = board.getCell(1,2); + // change the board's cells considering the MustLight rule + LightUpCell cell1 = board.getCell(1, 2); cell1.setData(LightUpCellType.BULB.value); board.addModifiedData(cell1); - //confirm there is a logical following of the FinishWithBulbs rule + // confirm there is a logical following of the FinishWithBulbs rule Assert.assertNull(RULE.checkRule(transition)); - //only the cell above should change following the rule + // only the cell above should change following the rule LightUpCell c; for (int i = 0; i < board.getHeight(); i++) { for (int j = 0; j < board.getWidth(); j++) { c = board.getCell(j, i); - if (i == 2 && j == 1){ - //logically follows + if (i == 2 && j == 1) { + // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { - //does not use the rule to logically follow + } else { + // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } diff --git a/src/test/java/puzzles/lightup/rules/SatisfyNumberCaseRuleTest.java b/src/test/java/puzzles/lightup/rules/SatisfyNumberCaseRuleTest.java index de3551778..a04f1c520 100644 --- a/src/test/java/puzzles/lightup/rules/SatisfyNumberCaseRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/SatisfyNumberCaseRuleTest.java @@ -1,19 +1,19 @@ package puzzles.lightup.rules; -import org.junit.BeforeClass; -import org.junit.Test; -import edu.rpi.legup.puzzle.lightup.LightUp; -import edu.rpi.legup.puzzle.lightup.rules.SatisfyNumberCaseRule; -import edu.rpi.legup.save.InvalidFileFormatException; -import legup.TestUtilities; +import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.lightup.LightUp; import edu.rpi.legup.puzzle.lightup.LightUpBoard; -import edu.rpi.legup.model.gameboard.Board; import edu.rpi.legup.puzzle.lightup.LightUpCell; import edu.rpi.legup.puzzle.lightup.LightUpCellType; -import org.junit.Assert; +import edu.rpi.legup.puzzle.lightup.rules.SatisfyNumberCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; import java.util.ArrayList; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class SatisfyNumberCaseRuleTest { private static final SatisfyNumberCaseRule RULE = new SatisfyNumberCaseRule(); @@ -23,69 +23,77 @@ public class SatisfyNumberCaseRuleTest { public static void setUp() { lightUp = new LightUp(); } - - //creates two boards for what is expected output, and checks that the getcases function produces the correct boards - //IT FAILS BECAUSE THE EXISTING GETCASES FUNCTION IS BUGGY/NOT COMPLETED (not my fault :| ) + + // creates two boards for what is expected output, and checks that the getcases function + // produces + // the correct boards + // IT FAILS BECAUSE THE EXISTING GETCASES FUNCTION IS BUGGY/NOT COMPLETED (not my fault :| ) @Test public void SatisfyNumberTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/SatisfyNumberCaseRule/SatisfyNumber", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/SatisfyNumberCaseRule/SatisfyNumber", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); + transition.setRule(RULE); - //get all new board states using caserule builtin function + // get all new board states using caserule builtin function LightUpBoard b = (LightUpBoard) transition.getBoard(); - LightUpCell numbered_cell = b.getCell(1,0); //the tile cell - ArrayList cases = RULE.getCases(b, numbered_cell);//C MUST BE THE NUMBERED TILE, NOT ANY RANDOM EMPTY ONE + LightUpCell numbered_cell = b.getCell(1, 0); // the tile cell + ArrayList cases = + RULE.getCases( + b, numbered_cell); // C MUST BE THE NUMBERED TILE, NOT ANY RANDOM EMPTY ONE - //assert correct number of cases + // assert correct number of cases Assert.assertEquals(2, cases.size()); - //make a list of boards that I expect + // make a list of boards that I expect LightUpCell change_cell; LightUpBoard case1 = ((LightUpBoard) transition.getBoard()).copy(); LightUpBoard case2 = ((LightUpBoard) transition.getBoard()).copy(); - //change the cells of the first new case board - change_cell = case1.getCell(0,0); + // change the cells of the first new case board + change_cell = case1.getCell(0, 0); change_cell.setData(LightUpCellType.BULB.value); - //case1.addModifiedData(change_cell); + // case1.addModifiedData(change_cell); - change_cell = case1.getCell(1,1); + change_cell = case1.getCell(1, 1); change_cell.setData(LightUpCellType.EMPTY.value); - //case1.addModifiedData(change_cell); + // case1.addModifiedData(change_cell); - //change the cells of the second new case board - change_cell = case2.getCell(0,0); + // change the cells of the second new case board + change_cell = case2.getCell(0, 0); change_cell.setData(LightUpCellType.EMPTY.value); - //case2.addModifiedData(change_cell); + // case2.addModifiedData(change_cell); - change_cell = case2.getCell(1,1); + change_cell = case2.getCell(1, 1); change_cell.setData(LightUpCellType.BULB.value); - //case2.addModifiedData(change_cell); + // case2.addModifiedData(change_cell); - //check each board I expect and make sure it exists in returned board list - //currently cases is not made correctly, so the getCases function is flawed. - //Assert.assertTrue(cases.contains((Board) case1)); - //Assert.assertTrue(cases.contains((Board) case2)); + // check each board I expect and make sure it exists in returned board list + // currently cases is not made correctly, so the getCases function is flawed. + // Assert.assertTrue(cases.contains((Board) case1)); + // Assert.assertTrue(cases.contains((Board) case2)); } @Test public void SatisfyNumberTestTwo() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/SatisfyNumberCaseRule/SatisfyNumberTwo", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/SatisfyNumberCaseRule/SatisfyNumberTwo", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); + transition.setRule(RULE); - //get all new board states using caserule builtin function + // get all new board states using caserule builtin function LightUpBoard b = (LightUpBoard) transition.getBoard(); - LightUpCell numbered_cell = b.getCell(1,1); //the tile cell - ArrayList cases = RULE.getCases(b, numbered_cell);//C MUST BE THE NUMBERED TILE, NOT ANY RANDOM EMPTY ONE + LightUpCell numbered_cell = b.getCell(1, 1); // the tile cell + ArrayList cases = + RULE.getCases( + b, numbered_cell); // C MUST BE THE NUMBERED TILE, NOT ANY RANDOM EMPTY ONE - //assert correct number of cases + // assert correct number of cases Assert.assertEquals(6, cases.size()); - //make a list of boards that I expect + // make a list of boards that I expect LightUpCell change_cell1; LightUpCell change_cell2; LightUpBoard case1 = ((LightUpBoard) transition.getBoard()).copy(); @@ -95,61 +103,61 @@ public void SatisfyNumberTestTwo() throws InvalidFileFormatException { LightUpBoard case5 = ((LightUpBoard) transition.getBoard()).copy(); LightUpBoard case6 = ((LightUpBoard) transition.getBoard()).copy(); - //case 1: lights in (1,0) and (0,1) - change_cell1 = case1.getCell(1,0); - change_cell2 = case1.getCell(0,1); + // case 1: lights in (1,0) and (0,1) + change_cell1 = case1.getCell(1, 0); + change_cell2 = case1.getCell(0, 1); change_cell1.setData(LightUpCellType.BULB.value); change_cell2.setData(LightUpCellType.BULB.value); case1.addModifiedData(change_cell1); case1.addModifiedData(change_cell2); - //case 2: lights in (1,0) and (1,2) - change_cell1 = case2.getCell(1,0); - change_cell2 = case2.getCell(1,2); + // case 2: lights in (1,0) and (1,2) + change_cell1 = case2.getCell(1, 0); + change_cell2 = case2.getCell(1, 2); change_cell1.setData(LightUpCellType.BULB.value); change_cell2.setData(LightUpCellType.BULB.value); case2.addModifiedData(change_cell1); case2.addModifiedData(change_cell2); - //case 3: lights in (1,0) and (2,1) - change_cell1 = case3.getCell(1,0); - change_cell2 = case3.getCell(2,1); + // case 3: lights in (1,0) and (2,1) + change_cell1 = case3.getCell(1, 0); + change_cell2 = case3.getCell(2, 1); change_cell1.setData(LightUpCellType.BULB.value); change_cell2.setData(LightUpCellType.BULB.value); case3.addModifiedData(change_cell1); case3.addModifiedData(change_cell2); - //case 4: lights in (0,1) and (2,1) - change_cell1 = case4.getCell(0,1); - change_cell2 = case4.getCell(2,1); + // case 4: lights in (0,1) and (2,1) + change_cell1 = case4.getCell(0, 1); + change_cell2 = case4.getCell(2, 1); change_cell1.setData(LightUpCellType.BULB.value); change_cell2.setData(LightUpCellType.BULB.value); case4.addModifiedData(change_cell1); case4.addModifiedData(change_cell2); - //case 5: lights in (0,1) and (1,2) - change_cell1 = case5.getCell(0,1); - change_cell2 = case5.getCell(1,2); + // case 5: lights in (0,1) and (1,2) + change_cell1 = case5.getCell(0, 1); + change_cell2 = case5.getCell(1, 2); change_cell1.setData(LightUpCellType.BULB.value); change_cell2.setData(LightUpCellType.BULB.value); case5.addModifiedData(change_cell1); case5.addModifiedData(change_cell2); - //case 6: lights in (1,2) and (2,1) - change_cell1 = case6.getCell(1,2); - change_cell2 = case6.getCell(2,1); + // case 6: lights in (1,2) and (2,1) + change_cell1 = case6.getCell(1, 2); + change_cell2 = case6.getCell(2, 1); change_cell1.setData(LightUpCellType.BULB.value); change_cell2.setData(LightUpCellType.BULB.value); case6.addModifiedData(change_cell1); case6.addModifiedData(change_cell2); - //check each board I expect and make sure it exists in returned board list - //currently the cases list is not made correctly, so the getCases function is flawed. - //Assert.assertTrue(cases.contains((Board) case1)); - //Assert.assertTrue(cases.contains((Board) case2)); - //Assert.assertTrue(cases.contains((Board) case3)); - //Assert.assertTrue(cases.contains((Board) case4)); - //Assert.assertTrue(cases.contains((Board) case5)); - //Assert.assertTrue(cases.contains((Board) case6)); + // check each board I expect and make sure it exists in returned board list + // currently the cases list is not made correctly, so the getCases function is flawed. + // Assert.assertTrue(cases.contains((Board) case1)); + // Assert.assertTrue(cases.contains((Board) case2)); + // Assert.assertTrue(cases.contains((Board) case3)); + // Assert.assertTrue(cases.contains((Board) case4)); + // Assert.assertTrue(cases.contains((Board) case5)); + // Assert.assertTrue(cases.contains((Board) case6)); } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/lightup/rules/TooFewBulbsContradictionRuleTest.java b/src/test/java/puzzles/lightup/rules/TooFewBulbsContradictionRuleTest.java index bab616198..fe994baa6 100644 --- a/src/test/java/puzzles/lightup/rules/TooFewBulbsContradictionRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/TooFewBulbsContradictionRuleTest.java @@ -1,15 +1,15 @@ package puzzles.lightup.rules; -import org.junit.BeforeClass; -import org.junit.Test; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.lightup.LightUp; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.rules.TooFewBulbsContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; import legup.TestUtilities; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class TooFewBulbsContradictionRuleTest { private static final TooFewBulbsContradictionRule RULE = new TooFewBulbsContradictionRule(); @@ -22,21 +22,22 @@ public static void setUp() { @Test public void TooFewBulbsContradictionRule() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/TooFewBulbsContradictionRule/FullTooFewTest", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/TooFewBulbsContradictionRule/FullTooFewTest", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); + transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm there is a contradiction somewhere on the board + // confirm there is a contradiction somewhere on the board Assert.assertNull(RULE.checkContradiction(board)); - //confirm that there arent enough bulbs around the black tiles + // confirm that there arent enough bulbs around the black tiles Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1))); Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(4, 1))); Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 4))); - //confirm there are no requirements for number of bulbs around non-black tiles or 0 tiles + // confirm there are no requirements for number of bulbs around non-black tiles or 0 tiles Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(4, 4))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(5, 5))); @@ -44,17 +45,18 @@ public void TooFewBulbsContradictionRule() throws InvalidFileFormatException { @Test public void TooFewSimpleTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/TooFewBulbsContradictionRule/TooFew", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/TooFewBulbsContradictionRule/TooFew", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); + transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm it is impossible to satisfy up the center square + // confirm it is impossible to satisfy up the center square Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1))); - //every square except the center + // every square except the center Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0))); diff --git a/src/test/java/puzzles/lightup/rules/TooManyBulbsContradictionRuleTest.java b/src/test/java/puzzles/lightup/rules/TooManyBulbsContradictionRuleTest.java index fe3dad2e0..e27fa3323 100644 --- a/src/test/java/puzzles/lightup/rules/TooManyBulbsContradictionRuleTest.java +++ b/src/test/java/puzzles/lightup/rules/TooManyBulbsContradictionRuleTest.java @@ -1,15 +1,15 @@ package puzzles.lightup.rules; -import org.junit.BeforeClass; -import org.junit.Test; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; import edu.rpi.legup.puzzle.lightup.LightUp; +import edu.rpi.legup.puzzle.lightup.LightUpBoard; import edu.rpi.legup.puzzle.lightup.rules.TooManyBulbsContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; import legup.TestUtilities; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import edu.rpi.legup.puzzle.lightup.LightUpBoard; import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class TooManyBulbsContradictionRuleTest { private static final TooManyBulbsContradictionRule RULE = new TooManyBulbsContradictionRule(); @@ -19,41 +19,44 @@ public class TooManyBulbsContradictionRuleTest { public static void setUp() { lightUp = new LightUp(); } + @Test - //complex extensive toofew test + // complex extensive toofew test public void TooFewBulbsContradictionRule() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/TooManyBulbsContradictionRule/FullTooManyTest", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/TooManyBulbsContradictionRule/FullTooManyTest", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); + transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm there is a contradiction somewhere on the board + // confirm there is a contradiction somewhere on the board Assert.assertNull(RULE.checkContradiction(board)); - //confirm that there are too many bulbs around the black tiles + // confirm that there are too many bulbs around the black tiles Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1))); Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 4))); - //confirm there are no requirements for number of bulbs around non-black tiles or 0 tiles + // confirm there are no requirements for number of bulbs around non-black tiles or 0 tiles Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(5, 5))); } @Test - //tests a 3x3 board with a 3 in the center and 4 surrounding lightbulbs + // tests a 3x3 board with a 3 in the center and 4 surrounding lightbulbs public void TooManySimpleTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/lightup/rules/TooManyBulbsContradictionRule/TooMany", lightUp); + TestUtilities.importTestBoard( + "puzzles/lightup/rules/TooManyBulbsContradictionRule/TooMany", lightUp); TreeNode rootNode = lightUp.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); + transition.setRule(RULE); LightUpBoard board = (LightUpBoard) transition.getBoard(); - //confirm it is impossible to satisfy up the center square + // confirm it is impossible to satisfy up the center square Assert.assertNull(RULE.checkContradictionAt(board, board.getCell(1, 1))); - //every square except the center + // every square except the center Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(0, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(1, 0))); Assert.assertNotNull(RULE.checkContradictionAt(board, board.getCell(2, 0))); diff --git a/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java b/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java new file mode 100644 index 000000000..0e0112040 --- /dev/null +++ b/src/test/java/puzzles/minesweeper/MinesweeperUtilitiesTest.java @@ -0,0 +1,69 @@ +package puzzles.minesweeper; + +import edu.rpi.legup.puzzle.minesweeper.Minesweeper; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperBoard; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperCell; +import edu.rpi.legup.puzzle.minesweeper.MinesweeperUtilities; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.stream.Stream; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class MinesweeperUtilitiesTest { + + private static Minesweeper minesweeper; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + minesweeper = new Minesweeper(); + } + + @Test + public void getSurroundingCellsSizeThreeByThreeAtOneXOneTest() + throws InvalidFileFormatException { + + TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); + + final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); + MinesweeperCell cell = board.getCell(1, 1); + + final Stream cells = MinesweeperUtilities.getSurroundingCells(board, cell); + + final long count = cells.count(); + Assert.assertEquals(count, 8); + } + + @Test + public void getSurroundingCellsSizeThreeByThreeAtZeroXZeroTest() + throws InvalidFileFormatException { + + TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); + + final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); + MinesweeperCell cell = board.getCell(0, 0); + + final Stream cells = MinesweeperUtilities.getSurroundingCells(board, cell); + + final long count = cells.count(); + Assert.assertEquals(count, 3); + } + + @Test + public void getSurroundingCellsSizeThreeByThreeAtZeroXOneTest() + throws InvalidFileFormatException { + + TestUtilities.importTestBoard("puzzles/minesweeper/utilities/3x3test", minesweeper); + + final MinesweeperBoard board = (MinesweeperBoard) minesweeper.getCurrentBoard(); + MinesweeperCell cell = board.getCell(0, 1); + + final Stream cells = MinesweeperUtilities.getSurroundingCells(board, cell); + + final long count = cells.count(); + Assert.assertEquals(count, 5); + } +} diff --git a/src/test/java/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRuleTest.java b/src/test/java/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRuleTest.java index 7e8b5eb83..d87398303 100644 --- a/src/test/java/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRuleTest.java +++ b/src/test/java/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRuleTest.java @@ -1,190 +1,204 @@ -package puzzles.nurikabe.rules; - -//import javafx.scene.layout.Pane; - -import legup.MockGameBoardFacade; -import legup.TestUtilities; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import edu.rpi.legup.puzzle.nurikabe.Nurikabe; -import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; -import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; -import edu.rpi.legup.puzzle.nurikabe.NurikabeType; -import edu.rpi.legup.puzzle.nurikabe.rules.BlackBetweenRegionsDirectRule; -import edu.rpi.legup.save.InvalidFileFormatException; - -import java.awt.*; - -public class BlackBetweenRegionsDirectRuleTest { - - private static final BlackBetweenRegionsDirectRule RULE = new BlackBetweenRegionsDirectRule(); - private static Nurikabe nurikabe; - - @BeforeClass - public static void setUp() { - MockGameBoardFacade.getInstance(); - nurikabe = new Nurikabe(); - } - - /** - * Tests the Black Between Regions direct rule for regions that are diagonal to each other (diagonal going from top left to bottom right) - */ - @Test - public void BlackBetweenRegionsDirectRule_DiagonalBlackBetweenRegions1Test() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/DiagonalBlackBetweenRegions1", nurikabe); - TreeNode rootNode = nurikabe.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - - NurikabeCell cell1 = board.getCell(2, 1); - cell1.setData(NurikabeType.BLACK.toValue()); - NurikabeCell cell2 = board.getCell(1, 2); - cell2.setData(NurikabeType.BLACK.toValue()); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - /** - * Tests the Black Between Regions direct rule for regions that are diagonal to each other (diagonal going from bottom left to top right) - */ - @Test - public void BlackBetweenRegionsDirectRule_DiagonalBlackBetweenRegions2Test() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/DiagonalBlackBetweenRegions2", nurikabe); - TreeNode rootNode = nurikabe.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - - NurikabeCell cell1 = board.getCell(1, 1); - cell1.setData(NurikabeType.BLACK.toValue()); - NurikabeCell cell2 = board.getCell(2, 2); - cell2.setData(NurikabeType.BLACK.toValue()); - - board.addModifiedData(cell1); - board.addModifiedData(cell2); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - /** - * Tests the Black Between Regions direct rule for regions that are horizontally opposite each other - */ - @Test - public void BlackBetweenRegionsDirectRule_HorizontalBlackBetweenRegionsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/HorizontalBlackBetweenRegions", nurikabe); - TreeNode rootNode = nurikabe.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - - NurikabeCell cell = board.getCell(1, 1); - cell.setData(NurikabeType.BLACK.toValue()); - - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Point point = new Point(k, i); - if (point.equals(cell.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - /** - * Tests the Black Between Regions direct rule for regions that are vertically opposite each other - */ - @Test - public void BlackBetweenRegionsDirectRule_VerticalBlackBetweenRegionsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/VerticalBlackBetweenRegions", nurikabe); - TreeNode rootNode = nurikabe.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - - NurikabeCell cell = board.getCell(1, 1); - cell.setData(NurikabeType.BLACK.toValue()); - - board.addModifiedData(cell); - - Assert.assertNull(RULE.checkRule(transition)); - - for (int i = 0; i < board.getHeight(); i++) { - for (int k = 0; k < board.getWidth(); k++) { - Point point = new Point(k, i); - if (point.equals(cell.getLocation())) { - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - } - } - } - - /** - * Tests the Black Between Regions direct rule for a false application of the rule, where a black tile is enclosed by one region - */ - @Test - public void BlackBetweenRegionsDirectRule_FalseBlackBetweenRegionsTest() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/FalseBlackBetweenRegions",nurikabe); - TreeNode rootNode = nurikabe.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - NurikabeCell cell = board.getCell(1,1); - cell.setData(NurikabeType.BLACK.toValue()); - board.addModifiedData(cell); - - Assert.assertNotNull(RULE.checkRule(transition)); - - for(int i=0; i cases = RULE.getCases(board,cell); + NurikabeCell cell = board.getCell(0, 0); + ArrayList cases = RULE.getCases(board, cell); - Assert.assertEquals(2,cases.size()); + Assert.assertEquals(2, cases.size()); NurikabeBoard caseBoard = (NurikabeBoard) cases.get(0); NurikabeBoard caseBoard2 = (NurikabeBoard) cases.get(1); - NurikabeType board1Type = caseBoard.getCell(0,0).getType(); - NurikabeType board2Type = caseBoard2.getCell(0,0).getType(); + NurikabeType board1Type = caseBoard.getCell(0, 0).getType(); + NurikabeType board2Type = caseBoard2.getCell(0, 0).getType(); - Assert.assertTrue((board1Type.equals(NurikabeType.BLACK) || board1Type.equals(NurikabeType.WHITE)) && - (board2Type.equals(NurikabeType.BLACK) || board2Type.equals(NurikabeType.WHITE))); + Assert.assertTrue( + (board1Type.equals(NurikabeType.BLACK) || board1Type.equals(NurikabeType.WHITE)) + && (board2Type.equals(NurikabeType.BLACK) + || board2Type.equals(NurikabeType.WHITE))); Assert.assertFalse(board1Type.equals(board2Type)); - Assert.assertEquals(caseBoard.getHeight(),caseBoard2.getHeight(), board.getHeight()); - Assert.assertEquals(caseBoard.getWidth(),caseBoard2.getWidth(), board.getWidth()); + Assert.assertEquals(caseBoard.getHeight(), caseBoard2.getHeight(), board.getHeight()); + Assert.assertEquals(caseBoard.getWidth(), caseBoard2.getWidth(), board.getWidth()); - for(int i=0; i cases = RULE.getCases(board, cell); + Assert.assertEquals(2, cases.size()); + + NurikabeBoard caseBoard = (NurikabeBoard) cases.get(0); + NurikabeBoard caseBoard2 = (NurikabeBoard) cases.get(1); + + NurikabeType board1Type = caseBoard.getCell(5, 5).getType(); + NurikabeType board2Type = caseBoard2.getCell(6, 6).getType(); + + Assert.assertTrue( + (board1Type.equals(NurikabeType.WHITE) && board2Type.equals(NurikabeType.WHITE))); + + Assert.assertEquals(caseBoard.getHeight(), caseBoard2.getHeight(), board.getHeight()); + Assert.assertEquals(caseBoard.getWidth(), caseBoard2.getWidth(), board.getWidth()); + + DisjointSets regions = + NurikabeUtilities.getNurikabeRegions(caseBoard); // gathers regions + Set disRow = regions.getSet(caseBoard.getCell(5, 5)); + Assert.assertEquals(disRow.size(), 3); + + DisjointSets regions2 = + NurikabeUtilities.getNurikabeRegions(caseBoard2); // gathers regions + Set disRow2 = regions2.getSet(caseBoard2.getCell(6, 6)); + Assert.assertEquals(disRow2.size(), 3); + + for (int i = 0; i < caseBoard.getHeight(); i++) { + for (int k = 0; k < caseBoard.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(caseBoard.getCell(k, i).getLocation())) { + continue; + } + Assert.assertTrue( + caseBoard.getCell(k, i).equals(caseBoard2.getCell(k, i)) + || caseBoard2.getCell(k, i).equals(caseBoard2.getCell(k, i))); + } + } + + NurikabeCell cell2 = board.getCell(4, 2); + ArrayList cases2 = RULE.getCases(board, cell2); + + Assert.assertEquals(9, cases2.size()); + } +} diff --git a/src/test/java/puzzles/nurikabe/rules/IsolateBlackContradictionRuleTest.java b/src/test/java/puzzles/nurikabe/rules/IsolateBlackContradictionRuleTest.java index 26216fde1..660542d79 100644 --- a/src/test/java/puzzles/nurikabe/rules/IsolateBlackContradictionRuleTest.java +++ b/src/test/java/puzzles/nurikabe/rules/IsolateBlackContradictionRuleTest.java @@ -1,19 +1,18 @@ package puzzles.nurikabe.rules; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.nurikabe.Nurikabe; import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +import edu.rpi.legup.puzzle.nurikabe.rules.IsolateBlackContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import legup.MockGameBoardFacade; import legup.TestUtilities; -import edu.rpi.legup.model.tree.TreeNode; -import edu.rpi.legup.model.tree.TreeTransition; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import edu.rpi.legup.puzzle.nurikabe.Nurikabe; -import edu.rpi.legup.puzzle.nurikabe.rules.IsolateBlackContradictionRule; -import edu.rpi.legup.save.InvalidFileFormatException; - -import java.awt.*; public class IsolateBlackContradictionRuleTest { @@ -27,71 +26,75 @@ public static void setUp() { } /** - * Tests the Isolate Black contradiction rule for a black square in the corner, separated by a diagonal of white squares + * Tests the Isolate Black contradiction rule for a black square in the corner, separated by a + * diagonal of white squares */ @Test - public void IsolateBlackContradictionRule_SimpleIsolateBlackTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/nurikabe/rules/IsolateBlackContradictionRule/SimpleIsolateBlack", nurikabe); + public void IsolateBlackContradictionRule_SimpleIsolateBlackTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/nurikabe/rules/IsolateBlackContradictionRule/SimpleIsolateBlack", + nurikabe); TreeNode rootNode = nurikabe.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); NurikabeBoard board = (NurikabeBoard) transition.getBoard(); - NurikabeCell cell1 = board.getCell(0,0); - NurikabeCell cell2 = board.getCell(2,2); - - Assert.assertNull(RULE.checkContradiction((NurikabeBoard)transition.getBoard())); - - for(int i=0; i cases = RULE.getCases(board, cell); // Make sure that the rule checks out @@ -63,60 +60,64 @@ private void falseAndTest(String fileName, // First assert the two cells are not equal, then verify that they are either // unknown or false. Assert.assertNotEquals(board1A, board1B); - Assert.assertTrue(board1A.equals(ShortTruthTableCellType.UNKNOWN) || board1A.equals(ShortTruthTableCellType.FALSE)); - Assert.assertTrue(board1B.equals(ShortTruthTableCellType.UNKNOWN) || board1B.equals(ShortTruthTableCellType.FALSE)); + Assert.assertTrue( + board1A.equals(ShortTruthTableCellType.UNKNOWN) + || board1A.equals(ShortTruthTableCellType.FALSE)); + Assert.assertTrue( + board1B.equals(ShortTruthTableCellType.UNKNOWN) + || board1B.equals(ShortTruthTableCellType.FALSE)); Assert.assertNotEquals(board2A, board2B); - Assert.assertTrue(board2A.equals(ShortTruthTableCellType.UNKNOWN) || board1A.equals(ShortTruthTableCellType.FALSE)); - Assert.assertTrue(board2B.equals(ShortTruthTableCellType.UNKNOWN) || board2B.equals(ShortTruthTableCellType.FALSE)); + Assert.assertTrue( + board2A.equals(ShortTruthTableCellType.UNKNOWN) + || board1A.equals(ShortTruthTableCellType.FALSE)); + Assert.assertTrue( + board2B.equals(ShortTruthTableCellType.UNKNOWN) + || board2B.equals(ShortTruthTableCellType.FALSE)); // Verify the board dimensions are unchanged Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); // Verify that everywhere else on the board is unchanged - for (int i = 0; i< caseBoard1.getWidth(); i++) { + for (int i = 0; i < caseBoard1.getWidth(); i++) { for (int j = 0; j < caseBoard1.getHeight(); j++) { // Make sure not to check the two cells that should be different if (!((i == aX && j == aY) || (i == bX && j == bY))) { - Assert.assertEquals(caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); + Assert.assertEquals( + caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); } } } } /** - * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that - * two branches are created: one where A is false and one where B is false. + * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that two branches + * are created: one where A is false and one where B is false. */ @Test public void SimpleStatement1FalseTest() throws InvalidFileFormatException { - falseAndTest("SimpleStatement1_False", 1, 0, 0, 0, - 2, 0); + falseAndTest("SimpleStatement1_False", 1, 0, 0, 0, 2, 0); } /** - * Given a statement ~(A|B)^(C^D) where the first ^ is false, tests this case rule - * by ensuring that two branches are created: one where ~ is false and one where - * the second ^ is false. + * Given a statement ~(A|B)^(C^D) where the first ^ is false, tests this case rule by ensuring + * that two branches are created: one where ~ is false and one where the second ^ is false. */ @Test public void ComplexStatement1FalseTest() throws InvalidFileFormatException { - falseAndTest("ComplexStatement1_False", 6, 0, 0, 0, - 9, 0); + falseAndTest("ComplexStatement1_False", 6, 0, 0, 0, 9, 0); } - private void trueAndTest(String fileName, - int andX, int andY, - int aX, int aY, - int bX, int bY) throws InvalidFileFormatException { + private void trueAndTest(String fileName, int andX, int andY, int aX, int aY, int bX, int bY) + throws InvalidFileFormatException { TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndCaseRule/" + fileName, stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); - ShortTruthTableCell cell = board.getCell(andX,andY); + ShortTruthTableCell cell = board.getCell(andX, andY); ArrayList cases = RULE.getCases(board, cell); // Make sure that the rule checks out @@ -139,22 +140,20 @@ private void trueAndTest(String fileName, } /** - * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that - * one branch is created where A and B are both true. + * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that one branch is + * created where A and B are both true. */ @Test public void SimpleStatement1AndTest() throws InvalidFileFormatException { - trueAndTest("SimpleStatement1_True", 1, 0, 0, 0, - 2, 0); + trueAndTest("SimpleStatement1_True", 1, 0, 0, 0, 2, 0); } /** - * Given a statement ~(A|B)^(C^D) where the first ^ is true, tests this case rule - * by ensuring that one branch is created where both ~ and the second ^ are true. + * Given a statement ~(A|B)^(C^D) where the first ^ is true, tests this case rule by ensuring + * that one branch is created where both ~ and the second ^ are true. */ @Test public void ComplexStatement1TrueTest() throws InvalidFileFormatException { - trueAndTest("ComplexStatement1_True", 6, 0, 0, 0, - 9, 0); + trueAndTest("ComplexStatement1_True", 6, 0, 0, 0, 9, 0); } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/AndContradictionRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/AndContradictionRuleTest.java new file mode 100644 index 000000000..618c03926 --- /dev/null +++ b/src/test/java/puzzles/shorttruthtable/rules/AndContradictionRuleTest.java @@ -0,0 +1,132 @@ +package puzzles.shorttruthtable.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleAnd; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class AndContradictionRuleTest { + + private static final ContradictionRuleAnd RULE = new ContradictionRuleAnd(); + private static ShortTruthTable stt; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + stt = new ShortTruthTable(); + } + + /** + * Given a statement: A ^ B where ^ is true + * + *

Asserts that this is a valid application of the rule if and only if A or B are set to + * false. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void trueAndTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/AndContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + trueAndTestHelper(path + first + "T" + second); + } + } + } + + private void trueAndTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(2, 0); + + if (a.getType() == ShortTruthTableCellType.FALSE + || b.getType() == ShortTruthTableCellType.FALSE) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } + + /** + * Given a statement: A ^ B where ^ is false + * + *

Asserts that this is a valid application of the rule if and only if A or B (or both) are + * set to true. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void falseAndTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/AndContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + falseAndTestHelper(path + first + "F" + second); + } + } + } + + private void falseAndTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(2, 0); + + if (a.getType() == ShortTruthTableCellType.TRUE + && b.getType() == ShortTruthTableCellType.TRUE) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } + + /** + * Given a statement: A ^ B where ^ is unknown + * + *

Asserts that this is not a valid application of this rule. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void unknownAndTest() throws InvalidFileFormatException { + // Getting the files that have or set to unknown from And Introduction + String path = "puzzles/shorttruthtable/rules/AndIntroductionDirectRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + unknownAndTestHelper(path + first + "U" + second); + } + } + } + + private void unknownAndTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/AndEliminationDirectRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/AndEliminationDirectRuleTest.java index 0d94eb672..61f29a669 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/AndEliminationDirectRuleTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/AndEliminationDirectRuleTest.java @@ -26,21 +26,26 @@ public static void setup() { /** * Given one statement: B^C where ^ is true - * - * Checks all possible combinations of true, false, and unknown for B and C - * except for where both B and C are true and asserts that each one of them - * is not a valid application of the rule. + * + *

Checks all possible combinations of true, false, and unknown for B and C except for where + * both B and C are true and asserts that each one of them is not a valid application of the + * rule. * * @throws InvalidFileFormatException */ @Test public void trueAndTest1() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -69,21 +74,23 @@ public void trueAndTest1() throws InvalidFileFormatException { /** * Given one statement: B^C where ^ is true - * - * Checks all possible combinations of true and unknown for B and C - * except for where both B and C are unknown and asserts that each one - * of them is a valid application of the rule. + * + *

Checks all possible combinations of true and unknown for B and C except for where both B + * and C are unknown and asserts that each one of them is a valid application of the rule. * * @throws InvalidFileFormatException */ @Test public void trueAndTest2() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/AndEliminationDirectRule/TrueAnd", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -112,20 +119,25 @@ public void trueAndTest2() throws InvalidFileFormatException { /** * Given one statement: B^C where ^ is false - * - * Checks all possible combinations of true, false, and unknown for B and C - * and asserts that each one of them is not a valid application of the rule. + * + *

Checks all possible combinations of true, false, and unknown for B and C and asserts that + * each one of them is not a valid application of the rule. * * @throws InvalidFileFormatException */ @Test public void falseAndWithUnknownsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAnd", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAnd", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -150,15 +162,17 @@ public void falseAndWithUnknownsTest() throws InvalidFileFormatException { /** * Given one statement: B^C where both B and ^ are false - * - * Asserts that this is not a valid application of the rule if C is set to - * either true or false. + * + *

Asserts that this is not a valid application of the rule if C is set to either true or + * false. * * @throws InvalidFileFormatException */ @Test public void falseAndWithKnownFalseTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownFalse", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownFalse", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -177,15 +191,16 @@ public void falseAndWithKnownFalseTest() throws InvalidFileFormatException { /** * Given one statement: B^C where B is true and ^ is false - * - * Asserts that this is a valid application of the rule if and only if C is - * set to false. + * + *

Asserts that this is a valid application of the rule if and only if C is set to false. * * @throws InvalidFileFormatException */ @Test public void falseAndWithKnownTrueTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownTrue", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/AndEliminationDirectRule/FalseAndWithKnownTrue", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -201,4 +216,4 @@ public void falseAndWithKnownTrueTest() throws InvalidFileFormatException { board.addModifiedData(clyde); Assert.assertNull(RULE.checkRule(transition)); } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/AndIntroductionDirectRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/AndIntroductionDirectRuleTest.java index 4d4e009b2..ec03919ae 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/AndIntroductionDirectRuleTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/AndIntroductionDirectRuleTest.java @@ -27,8 +27,8 @@ public static void setup() { /** * Given a statement: A ^ B * - * Asserts that if at least 1 of A or B is false, then this is a valid application - * of the rule if and only if ^ is false. + *

Asserts that if at least 1 of A or B is false, then this is a valid application of the + * rule if and only if ^ is false. * * @param filePath The file path for test board setup. * @throws InvalidFileFormatException @@ -64,8 +64,8 @@ private void falseAndTestHelper(String filePath) throws InvalidFileFormatExcepti /** * Given a statement: A ^ B * - * Asserts that setting ^ to true is a valid application of the rule if - * and only if both A and B are true. + *

Asserts that setting ^ to true is a valid application of the rule if and only if both A + * and B are true. * * @param filePath The file path for test board setup. * @throws InvalidFileFormatException @@ -95,11 +95,11 @@ private void trueAndTestHelper(String filePath) throws InvalidFileFormatExceptio and.setData(ShortTruthTableCellType.TRUE); board.addModifiedData(and); - if (a.getType() == ShortTruthTableCellType.TRUE && b.getType() == ShortTruthTableCellType.TRUE) { + if (a.getType() == ShortTruthTableCellType.TRUE + && b.getType() == ShortTruthTableCellType.TRUE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/AtomicContradictionRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/AtomicContradictionRuleTest.java new file mode 100644 index 000000000..a87035f42 --- /dev/null +++ b/src/test/java/puzzles/shorttruthtable/rules/AtomicContradictionRuleTest.java @@ -0,0 +1,66 @@ +package puzzles.shorttruthtable.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleAtomic; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class AtomicContradictionRuleTest { + + private static final ContradictionRuleAtomic RULE = new ContradictionRuleAtomic(); + private static ShortTruthTable stt; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + stt = new ShortTruthTable(); + } + + /** + * Given two statements: A, A + * + *

Asserts that this is a valid application of the rule if and only if both A and B are not + * unknown and different. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void mismatchTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/AtomicContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + mismatchHelper(path + first + second); + } + } + } + + private void mismatchHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(0, 2); + + if (a.getType() != ShortTruthTableCellType.UNKNOWN + && b.getType() != ShortTruthTableCellType.UNKNOWN + && a.getType() != b.getType()) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/AtomicDirectRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/AtomicDirectRuleTest.java index 51aa213c6..c631db613 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/AtomicDirectRuleTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/AtomicDirectRuleTest.java @@ -25,13 +25,10 @@ public static void setup() { } /** - * Given two statements: - * A - * A - * where the first A is set to false. - * - * This test sets the second A to false and then asserts that this - * is a valid application of the rule. + * Given two statements: A A where the first A is set to false. + * + *

This test sets the second A to false and then asserts that this is a valid application of + * the rule. * * @throws InvalidFileFormatException */ @@ -52,13 +49,10 @@ public void MatchingFalseTest() throws InvalidFileFormatException { } /** - * Given two statements: - * A - * A - * where the first A is set to false. - * - * This test sets the second A to true and then asserts that this - * is not a valid application of the rule. + * Given two statements: A A where the first A is set to false. + * + *

This test sets the second A to true and then asserts that this is not a valid application + * of the rule. * * @throws InvalidFileFormatException */ @@ -79,13 +73,10 @@ public void MismatchingFalseTest() throws InvalidFileFormatException { } /** - * Given two statements: - * B - * B - * where the first B is set to true. - * - * This test sets the second B to true and then asserts that this - * is a valid application of the rule. + * Given two statements: B B where the first B is set to true. + * + *

This test sets the second B to true and then asserts that this is a valid application of + * the rule. * * @throws InvalidFileFormatException */ @@ -106,13 +97,10 @@ public void MatchingTrueTest() throws InvalidFileFormatException { } /** - * Given two statements: - * B - * B - * where the first B is set to true. - * - * This test sets the second B to false and then asserts that this - * is not a valid application of the rule. + * Given two statements: B B where the first B is set to true. + * + *

This test sets the second B to false and then asserts that this is not a valid application + * of the rule. * * @throws InvalidFileFormatException */ @@ -133,13 +121,10 @@ public void MismatchingTrueTest() throws InvalidFileFormatException { } /** - * Given two statements: - * C - * C - * where neither statement is set to anything. - * - * This test sets the second C to false and then asserts that this - * is not a valid application of the rule. + * Given two statements: C C where neither statement is set to anything. + * + *

This test sets the second C to false and then asserts that this is not a valid application + * of the rule. * * @throws InvalidFileFormatException */ @@ -160,13 +145,10 @@ public void NothingPreviouslyMarkedTest() throws InvalidFileFormatException { } /** - * Given two statements: - * C - * C - * where neither statement is set to anything. - * - * This test sets the second C to true and then asserts that this - * is not a valid application of the rule. + * Given two statements: C C where neither statement is set to anything. + * + *

This test sets the second C to true and then asserts that this is not a valid application + * of the rule. * * @throws InvalidFileFormatException */ @@ -185,4 +167,4 @@ public void NothingPreviouslyMarkedTest2() throws InvalidFileFormatException { Assert.assertNotNull(RULE.checkRule(transition)); } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/BiconditionalCaseRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalCaseRuleTest.java new file mode 100644 index 000000000..527cba652 --- /dev/null +++ b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalCaseRuleTest.java @@ -0,0 +1,191 @@ +package puzzles.shorttruthtable.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.rules.caserule.CaseRuleBiconditional; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class BiconditionalCaseRuleTest { + + private static final CaseRuleBiconditional RULE = new CaseRuleBiconditional(); + private static ShortTruthTable stt; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + stt = new ShortTruthTable(); + } + + private void trueBiconditionalTest( + String fileName, int biconditionalX, int biconditionalY, int aX, int aY, int bX, int bY) + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalCaseRule/" + fileName, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell cell = board.getCell(biconditionalX, biconditionalY); + ArrayList cases = RULE.getCases(board, cell); + + // Make sure that the rule checks out + Assert.assertNull(RULE.checkRule(transition)); + + // Make sure there are two branches + Assert.assertEquals(2, cases.size()); + + ShortTruthTableBoard caseBoard1 = (ShortTruthTableBoard) cases.get(0); + ShortTruthTableCellType board1A = caseBoard1.getCell(aX, aY).getType(); + ShortTruthTableCellType board1B = caseBoard1.getCell(bX, bY).getType(); + + ShortTruthTableBoard caseBoard2 = (ShortTruthTableBoard) cases.get(1); + ShortTruthTableCellType board2A = caseBoard2.getCell(aX, aY).getType(); + ShortTruthTableCellType board2B = caseBoard2.getCell(bX, bY).getType(); + + // Assert that the corresponding cells for the different case rules do not + // match with each other + Assert.assertNotEquals(board1A, board2A); + Assert.assertNotEquals(board1B, board2B); + + // Assert that A and B are equal and either true or false in both branches + Assert.assertEquals(board1A, board1B); + Assert.assertTrue( + (board1A.equals(ShortTruthTableCellType.TRUE) + && board1B.equals(ShortTruthTableCellType.TRUE)) + || (board1A.equals(ShortTruthTableCellType.FALSE) + && board1B.equals(ShortTruthTableCellType.FALSE))); + + Assert.assertNotEquals(board1B, board2B); + Assert.assertTrue( + (board2A.equals(ShortTruthTableCellType.TRUE) + && board2B.equals(ShortTruthTableCellType.TRUE)) + || (board2A.equals(ShortTruthTableCellType.FALSE) + && board2B.equals(ShortTruthTableCellType.FALSE))); + + // Verify the board dimensions are unchanged + Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); + Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); + + // Verify that everywhere else on the board is unchanged + for (int i = 0; i < caseBoard1.getWidth(); i++) { + for (int j = 0; j < caseBoard1.getHeight(); j++) { + // Make sure not to check the two cells that should be different + if (!((i == aX && j == aY) || (i == bX && j == bY))) { + Assert.assertEquals( + caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); + } + } + } + } + + /** + * Given a statement A -> B where ^ is true, tests this case rule by ensuring that two branches + * are created: one where A is false and one where B is true. + */ + @Test + public void SimpleStatement1TrueTest() throws InvalidFileFormatException { + trueBiconditionalTest("TrueBiconditional", 1, 0, 0, 0, 2, 0); + } + + /** + * Given a statement ~(A|B) -> (C^D) where the -> is true, tests this case rule by ensuring that + * two branches are created: one where ~ is false and one where ^ is true. + */ + @Test + public void ComplexStatement1TrueTest() throws InvalidFileFormatException { + trueBiconditionalTest("ComplexStatement1_True", 6, 0, 0, 0, 9, 0); + } + + private void falseBiconditionalTest( + String fileName, int biconditionalX, int biconditionalY, int aX, int aY, int bX, int bY) + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalCaseRule/" + fileName, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell cell = board.getCell(biconditionalX, biconditionalY); + ArrayList cases = RULE.getCases(board, cell); + + // Make sure that the rule checks out + Assert.assertNull(RULE.checkRule(transition)); + + // Make sure there are two branches + Assert.assertEquals(2, cases.size()); + + ShortTruthTableBoard caseBoard1 = (ShortTruthTableBoard) cases.get(0); + ShortTruthTableCellType board1A = caseBoard1.getCell(aX, aY).getType(); + ShortTruthTableCellType board1B = caseBoard1.getCell(bX, bY).getType(); + + ShortTruthTableBoard caseBoard2 = (ShortTruthTableBoard) cases.get(1); + ShortTruthTableCellType board2A = caseBoard2.getCell(aX, aY).getType(); + ShortTruthTableCellType board2B = caseBoard2.getCell(bX, bY).getType(); + + // Assert that the corresponding cells for the different case rules do not + // match with each other + Assert.assertNotEquals(board1A, board2A); + Assert.assertNotEquals(board1B, board2B); + + // Assert that A and B are not equal and are both either true or false in both branches + Assert.assertNotEquals(board1A, board1B); + Assert.assertTrue( + (board1A.equals(ShortTruthTableCellType.TRUE) + && board1B.equals(ShortTruthTableCellType.FALSE)) + || (board1A.equals(ShortTruthTableCellType.FALSE) + && board1B.equals(ShortTruthTableCellType.TRUE))); + + Assert.assertNotEquals(board2A, board2B); + Assert.assertTrue( + (board2A.equals(ShortTruthTableCellType.TRUE) + && board2B.equals(ShortTruthTableCellType.FALSE)) + || (board2A.equals(ShortTruthTableCellType.FALSE) + && board2B.equals(ShortTruthTableCellType.TRUE))); + + // Verify the board dimensions are unchanged + Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); + Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); + + // Verify that everywhere else on the board is unchanged + for (int i = 0; i < caseBoard1.getWidth(); i++) { + for (int j = 0; j < caseBoard1.getHeight(); j++) { + // Make sure not to check the two cells that should be different + if (!((i == aX && j == aY) || (i == bX && j == bY))) { + Assert.assertEquals( + caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); + } + } + } + } + + /** + * Given a statement A -> B where -> is false, tests this case rule by ensuring that one branch + * is created where A is true and B is false. + */ + @Test + public void SimpleStatement1FalseTest() throws InvalidFileFormatException { + falseBiconditionalTest("FalseBiconditional", 1, 0, 0, 0, 2, 0); + } + + /** + * Given a statement ~(A|B) -> (C^D) where -> is true, tests this case rule by ensuring that one + * branch is created where ~ is true and ^ is false. + */ + @Test + public void ComplexStatement1FalseTest() throws InvalidFileFormatException { + falseBiconditionalTest("ComplexStatement1_False", 6, 0, 0, 0, 9, 0); + } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/BiconditionalContradictionRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalContradictionRuleTest.java new file mode 100644 index 000000000..af41a5b8c --- /dev/null +++ b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalContradictionRuleTest.java @@ -0,0 +1,134 @@ +package puzzles.shorttruthtable.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleBiconditional; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class BiconditionalContradictionRuleTest { + + private static final ContradictionRuleBiconditional RULE = new ContradictionRuleBiconditional(); + private static ShortTruthTable stt; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + stt = new ShortTruthTable(); + } + + /** + * Given a statement: A <-> B where <-> is true + * + *

Asserts that this is a valid application of the rule if and only if A and B are not + * unknown and A does not equal B + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void trueBiconditionalTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/BiconditionalContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + trueBiconditionalTestHelper(path + first + "T" + second); + } + } + } + + private void trueBiconditionalTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(2, 0); + + if (a.getType() != ShortTruthTableCellType.UNKNOWN + && b.getType() != ShortTruthTableCellType.UNKNOWN + && a.getType() != b.getType()) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } + + /** + * Given a statement: A <-> B where <-> is false + * + *

Asserts that this is a valid application of the rule if and only if A and B are not + * unknown and A equals B + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void falseConditionalTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/BiconditionalContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + falseBiconditionalTestHelper(path + first + "F" + second); + } + } + } + + private void falseBiconditionalTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(2, 0); + + if (a.getType() != ShortTruthTableCellType.UNKNOWN + && b.getType() != ShortTruthTableCellType.UNKNOWN + && a.getType() == b.getType()) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } + + /** + * Given a statement: A <-> B where <-> is unknown + * + *

Asserts that this is not a valid application of this rule. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void unknownBiconditionalTest() throws InvalidFileFormatException { + // Getting the files that have or set to unknown from Biconditional Introduction + String path = "puzzles/shorttruthtable/rules/BiconditionalIntroductionDirectRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + unknownBiconditionalTestHelper(path + first + "U" + second); + } + } + } + + private void unknownBiconditionalTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/BiconditionalEliminationTest.java b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalEliminationTest.java index 05faf87bb..987d194f9 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/BiconditionalEliminationTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalEliminationTest.java @@ -15,7 +15,8 @@ import org.junit.Test; public class BiconditionalEliminationTest { - private static final DirectRuleBiconditionalElimination RULE = new DirectRuleBiconditionalElimination(); + private static final DirectRuleBiconditionalElimination RULE = + new DirectRuleBiconditionalElimination(); private static ShortTruthTable stt; @BeforeClass @@ -27,13 +28,15 @@ public static void setup() { /** * Given one statement: A <-> B where both A and <-> are true * - * Asserts that this is a valid application of the rule if and only if B is true. + *

Asserts that this is a valid application of the rule if and only if B is true. * * @throws InvalidFileFormatException */ @Test public void TrueBiconditionalWithTrueATest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueA", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueA", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -60,13 +63,15 @@ public void TrueBiconditionalWithTrueATest() throws InvalidFileFormatException { /** * Given one statement: A <-> B where both B and <-> are true * - * Asserts that this is a valid application of the rule if and only if A is true. + *

Asserts that this is a valid application of the rule if and only if A is true. * * @throws InvalidFileFormatException */ @Test public void TrueBiconditionalWithTrueBTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueB", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithTrueB", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -90,17 +95,18 @@ public void TrueBiconditionalWithTrueBTest() throws InvalidFileFormatException { Assert.assertNotNull(RULE.checkRule(transition)); } - /** * Given one statement: A <-> B where A is false and <-> is true * - * Asserts that this is a valid application of the rule if and only if B is false. + *

Asserts that this is a valid application of the rule if and only if B is false. * * @throws InvalidFileFormatException */ @Test public void TrueBiconditionalWithFalseATest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseA", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseA", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -127,13 +133,15 @@ public void TrueBiconditionalWithFalseATest() throws InvalidFileFormatException /** * Given one statement: A <-> B where B is false and <-> is true * - * Asserts that this is a valid application of the rule if and only if A is false. + *

Asserts that this is a valid application of the rule if and only if A is false. * * @throws InvalidFileFormatException */ @Test public void TrueBiconditionalWithFalseBTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseB", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditionalWithFalseB", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -160,13 +168,15 @@ public void TrueBiconditionalWithFalseBTest() throws InvalidFileFormatException /** * Given one statement: A <-> B where A is true and <-> is false * - * Asserts that this is a valid application of the rule if and only if B is false. + *

Asserts that this is a valid application of the rule if and only if B is false. * * @throws InvalidFileFormatException */ @Test public void FalseBiconditionalWithTrueATest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueA", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueA", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -193,13 +203,15 @@ public void FalseBiconditionalWithTrueATest() throws InvalidFileFormatException /** * Given one statement: A <-> B where B is true and <-> is false * - * Asserts that this is a valid application of the rule if and only if A is false. + *

Asserts that this is a valid application of the rule if and only if A is false. * * @throws InvalidFileFormatException */ @Test public void FalseBiconditionalWithTrueBTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueB", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithTrueB", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -226,13 +238,15 @@ public void FalseBiconditionalWithTrueBTest() throws InvalidFileFormatException /** * Given one statement: A <-> B where A and <-> are false * - * Asserts that this is a valid application of the rule if and only if B is true. + *

Asserts that this is a valid application of the rule if and only if B is true. * * @throws InvalidFileFormatException */ @Test public void FalseBiconditionalWithFalseATest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseA", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseA", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -259,13 +273,15 @@ public void FalseBiconditionalWithFalseATest() throws InvalidFileFormatException /** * Given one statement: A <-> B where B and <-> are false * - * Asserts that this is a valid application of the rule if and only if A is true. + *

Asserts that this is a valid application of the rule if and only if A is true. * * @throws InvalidFileFormatException */ @Test public void FalseBiconditionalWithFalseBTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseB", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/FalseBiconditionalWithFalseB", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -292,19 +308,25 @@ public void FalseBiconditionalWithFalseBTest() throws InvalidFileFormatException /** * Given one statement: A <-> B where <-> is true * - * Asserts that setting any combination of A and B at the same time is not a valid + *

Asserts that setting any combination of A and B at the same time is not a valid * application of this rule * * @throws InvalidFileFormatException */ @Test public void TrueBiconditionalSetBothAtOnceTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditional", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/BiconditionalEliminationDirectRule/TrueBiconditional", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -324,8 +346,8 @@ public void TrueBiconditionalSetBothAtOnceTest() throws InvalidFileFormatExcepti } /** - * Asserts that setting any combination of A and B at the same time is not a valid - * application of this rule. This is tested on multiple files. + * Asserts that setting any combination of A and B at the same time is not a valid application + * of this rule. This is tested on multiple files. * * @throws InvalidFileFormatException */ @@ -352,7 +374,11 @@ private void setAandBBothAtOnceTest(String filePath) throws InvalidFileFormatExc TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -370,4 +396,4 @@ private void setAandBBothAtOnceTest(String filePath) throws InvalidFileFormatExc } } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/BiconditionalIntroductionTest.java b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalIntroductionTest.java index fe2574b5e..e1c5cf957 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/BiconditionalIntroductionTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/BiconditionalIntroductionTest.java @@ -15,7 +15,8 @@ import org.junit.Test; public class BiconditionalIntroductionTest { - private static final DirectRuleBiconditionalIntroduction RULE = new DirectRuleBiconditionalIntroduction(); + private static final DirectRuleBiconditionalIntroduction RULE = + new DirectRuleBiconditionalIntroduction(); private static ShortTruthTable stt; @BeforeClass @@ -27,8 +28,8 @@ public static void setup() { /** * Given a statement: A <-> B * - * Asserts that if setting <-> to false is a valid application of this rule if and - * only if A and B do not match. + *

Asserts that if setting <-> to false is a valid application of this rule if and only if A + * and B do not match. * * @throws InvalidFileFormatException */ @@ -61,14 +62,13 @@ private void falseConditionalHelper(String filePath) throws InvalidFileFormatExc ShortTruthTableCell b = board.getCell(2, 0); if (a.getType() != b.getType()) { // Not valid if they don't match but at least one of the values of A or B is unknown - if (a.getType() == ShortTruthTableCellType.UNKNOWN || b.getType() == ShortTruthTableCellType.UNKNOWN) { + if (a.getType() == ShortTruthTableCellType.UNKNOWN + || b.getType() == ShortTruthTableCellType.UNKNOWN) { Assert.assertNotNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNull(RULE.checkRule(transition)); } - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } @@ -76,8 +76,8 @@ private void falseConditionalHelper(String filePath) throws InvalidFileFormatExc /** * Given a statement: A <-> B * - * Asserts that if setting <-> to true is a valid application of this rule if and - * only if A and B match. + *

Asserts that if setting <-> to true is a valid application of this rule if and only if A + * and B match. * * @throws InvalidFileFormatException */ @@ -110,9 +110,8 @@ private void trueConditionalHelper(String filePath) throws InvalidFileFormatExce ShortTruthTableCell b = board.getCell(2, 0); if (a.getType() == b.getType() && a.getType() != ShortTruthTableCellType.UNKNOWN) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/ConditionalCaseRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/ConditionalCaseRuleTest.java new file mode 100644 index 000000000..891fd975d --- /dev/null +++ b/src/test/java/puzzles/shorttruthtable/rules/ConditionalCaseRuleTest.java @@ -0,0 +1,160 @@ +package puzzles.shorttruthtable.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.rules.caserule.CaseRuleConditional; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class ConditionalCaseRuleTest { + + private static final CaseRuleConditional RULE = new CaseRuleConditional(); + private static ShortTruthTable stt; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + stt = new ShortTruthTable(); + } + + private void trueConditionalTest( + String fileName, int conditionalX, int conditionalY, int aX, int aY, int bX, int bY) + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalCaseRule/" + fileName, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell cell = board.getCell(conditionalX, conditionalY); + ArrayList cases = RULE.getCases(board, cell); + + // Make sure that the rule checks out + Assert.assertNull(RULE.checkRule(transition)); + + // Make sure there are two branches + Assert.assertEquals(2, cases.size()); + + ShortTruthTableBoard caseBoard1 = (ShortTruthTableBoard) cases.get(0); + ShortTruthTableCellType board1A = caseBoard1.getCell(aX, aY).getType(); + ShortTruthTableCellType board1B = caseBoard1.getCell(bX, bY).getType(); + + ShortTruthTableBoard caseBoard2 = (ShortTruthTableBoard) cases.get(1); + ShortTruthTableCellType board2A = caseBoard2.getCell(aX, aY).getType(); + ShortTruthTableCellType board2B = caseBoard2.getCell(bX, bY).getType(); + + // Assert that the corresponding cells for the different case rules do not + // match with each other + Assert.assertNotEquals(board1A, board2A); + Assert.assertNotEquals(board1B, board2B); + + // Assert that A is unknown in one board and false in the other + Assert.assertNotEquals(board1A, board2A); + Assert.assertTrue( + (board1A.equals(ShortTruthTableCellType.UNKNOWN) + && board2A.equals(ShortTruthTableCellType.FALSE)) + || (board1A.equals(ShortTruthTableCellType.FALSE) + && board2A.equals(ShortTruthTableCellType.UNKNOWN))); + + // Assert that B is unknown in one board and true in the other + Assert.assertNotEquals(board1B, board2B); + Assert.assertTrue( + (board1B.equals(ShortTruthTableCellType.UNKNOWN) + && board2B.equals(ShortTruthTableCellType.TRUE)) + || (board1B.equals(ShortTruthTableCellType.TRUE) + && board2B.equals(ShortTruthTableCellType.UNKNOWN))); + + // Verify the board dimensions are unchanged + Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); + Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); + + // Verify that everywhere else on the board is unchanged + for (int i = 0; i < caseBoard1.getWidth(); i++) { + for (int j = 0; j < caseBoard1.getHeight(); j++) { + // Make sure not to check the two cells that should be different + if (!((i == aX && j == aY) || (i == bX && j == bY))) { + Assert.assertEquals( + caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); + } + } + } + } + + /** + * Given a statement A -> B where ^ is true, tests this case rule by ensuring that two branches + * are created: one where A is false and one where B is true. + */ + @Test + public void SimpleStatement1TrueTest() throws InvalidFileFormatException { + trueConditionalTest("TrueConditional", 1, 0, 0, 0, 2, 0); + } + + /** + * Given a statement ~(A|B) -> (C^D) where the -> is true, tests this case rule by ensuring that + * two branches are created: one where ~ is false and one where ^ is true. + */ + @Test + public void ComplexStatement1TrueTest() throws InvalidFileFormatException { + trueConditionalTest("ComplexStatement1_True", 6, 0, 0, 0, 9, 0); + } + + private void falseConditionalTest( + String fileName, int conditionalX, int conditionalY, int aX, int aY, int bX, int bY) + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalCaseRule/" + fileName, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell cell = board.getCell(conditionalX, conditionalY); + ArrayList cases = RULE.getCases(board, cell); + + // Make sure that the rule checks out + Assert.assertNull(RULE.checkRule(transition)); + + // There should only be 1 branch + Assert.assertEquals(1, cases.size()); + + ShortTruthTableBoard caseBoard = (ShortTruthTableBoard) cases.get(0); + ShortTruthTableCellType caseBoardAType = caseBoard.getCell(aX, aY).getType(); + ShortTruthTableCellType caseBoardBType = caseBoard.getCell(bX, bY).getType(); + + // A should be true and B should be false + Assert.assertEquals(caseBoardAType, ShortTruthTableCellType.TRUE); + Assert.assertEquals(caseBoardBType, ShortTruthTableCellType.FALSE); + + // Verify the board dimensions are unchanged + Assert.assertEquals(caseBoard.getHeight(), caseBoard.getHeight(), board.getHeight()); + } + + /** + * Given a statement A -> B where -> is false, tests this case rule by ensuring that one branch + * is created where A is true and B is false. + */ + @Test + public void SimpleStatement1FalseTest() throws InvalidFileFormatException { + falseConditionalTest("FalseConditional", 1, 0, 0, 0, 2, 0); + } + + /** + * Given a statement ~(A|B) -> (C^D) where -> is true, tests this case rule by ensuring that one + * branch is created where ~ is true and ^ is false. + */ + @Test + public void ComplexStatement1FalseTest() throws InvalidFileFormatException { + falseConditionalTest("ComplexStatement1_False", 6, 0, 0, 0, 9, 0); + } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/ConditionalContradictionRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/ConditionalContradictionRuleTest.java new file mode 100644 index 000000000..cfbc98b67 --- /dev/null +++ b/src/test/java/puzzles/shorttruthtable/rules/ConditionalContradictionRuleTest.java @@ -0,0 +1,132 @@ +package puzzles.shorttruthtable.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleConditional; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class ConditionalContradictionRuleTest { + + private static final ContradictionRuleConditional RULE = new ContradictionRuleConditional(); + private static ShortTruthTable stt; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + stt = new ShortTruthTable(); + } + + /** + * Given a statement: A -> B where -> is true + * + *

Asserts that this is a valid application of the rule if and only if both A is true and B + * is false + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void trueConditionalTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/ConditionalContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + trueConditionalTestHelper(path + first + "T" + second); + } + } + } + + private void trueConditionalTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(2, 0); + + if (a.getType() == ShortTruthTableCellType.TRUE + && b.getType() == ShortTruthTableCellType.FALSE) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } + + /** + * Given a statement: A -> B where -> is false + * + *

Asserts that this is a valid application of the rule if and only if A is false or B is + * true + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void falseConditionalTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/ConditionalContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + falseConditionalTestHelper(path + first + "F" + second); + } + } + } + + private void falseConditionalTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(2, 0); + + if (a.getType() == ShortTruthTableCellType.FALSE + || b.getType() == ShortTruthTableCellType.TRUE) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } + + /** + * Given a statement: A -> B where -> is unknown + * + *

Asserts that this is not a valid application of this rule. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void unknownConditionalTest() throws InvalidFileFormatException { + // Getting the files that have or set to unknown from Conditional Introduction + String path = "puzzles/shorttruthtable/rules/ConditionalIntroductionDirectRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + unknownConditionalTestHelper(path + first + "U" + second); + } + } + } + + private void unknownConditionalTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/ConditionalEliminationTest.java b/src/test/java/puzzles/shorttruthtable/rules/ConditionalEliminationTest.java index 8d0bb4e1a..0f95906f2 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/ConditionalEliminationTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/ConditionalEliminationTest.java @@ -15,7 +15,8 @@ import org.junit.Test; public class ConditionalEliminationTest { - private static final DirectRuleConditionalElimination RULE = new DirectRuleConditionalElimination(); + private static final DirectRuleConditionalElimination RULE = + new DirectRuleConditionalElimination(); private static ShortTruthTable stt; @BeforeClass @@ -27,19 +28,25 @@ public static void setup() { /** * Given one statement: A -> B where -> is false * - * Asserts that the only valid combination of A and B that is a valid application - * of this rule is when A is true and B is false + *

Asserts that the only valid combination of A and B that is a valid application of this + * rule is when A is true and B is false * * @throws InvalidFileFormatException */ @Test public void FalseConditionalTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -53,10 +60,10 @@ public void FalseConditionalTest() throws InvalidFileFormatException { board.addModifiedData(aubergine); board.addModifiedData(boniato); - if (cellType1 == ShortTruthTableCellType.TRUE && cellType2 == ShortTruthTableCellType.FALSE) { + if (cellType1 == ShortTruthTableCellType.TRUE + && cellType2 == ShortTruthTableCellType.FALSE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } @@ -66,14 +73,15 @@ public void FalseConditionalTest() throws InvalidFileFormatException { /** * Given one statement: A -> B where -> is false * - * Asserts that this is a valid application of the rule if and only if A - * is set to true. + *

Asserts that this is a valid application of the rule if and only if A is set to true. * * @throws InvalidFileFormatException */ @Test public void FalseConditionalTrueATest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -93,14 +101,15 @@ public void FalseConditionalTrueATest() throws InvalidFileFormatException { /** * Given one statement: A -> B where -> is false * - * Asserts that this is a valid application of the rule if and only if B is - * set to false. + *

Asserts that this is a valid application of the rule if and only if B is set to false. * * @throws InvalidFileFormatException */ @Test public void FalseConditionalFalseBTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/FalseConditional", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -120,18 +129,24 @@ public void FalseConditionalFalseBTest() throws InvalidFileFormatException { /** * Given one statement: A -> B where -> is true * - * Asserts that you cannot set any combination of both A and B at the same time. + *

Asserts that you cannot set any combination of both A and B at the same time. * * @throws InvalidFileFormatException */ @Test public void CannotSetBothAandBTrueConditionalTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditional", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditional", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -153,14 +168,15 @@ public void CannotSetBothAandBTrueConditionalTest() throws InvalidFileFormatExce /** * Given one statement: A -> B where A and -> are true * - * Asserts that this is a valid application of this rule if and only if B - * is set to true. + *

Asserts that this is a valid application of this rule if and only if B is set to true. * * @throws InvalidFileFormatException */ @Test public void TrueAMeansTrueBTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueA", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueA", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -180,14 +196,15 @@ public void TrueAMeansTrueBTest() throws InvalidFileFormatException { /** * Given one statement: A -> B where B is false and -> is true * - * Asserts that this is a valid application of this rule if and only if A - * is set to false. + *

Asserts that this is a valid application of this rule if and only if A is set to false. * * @throws InvalidFileFormatException */ @Test public void FalseBMeansFalseATest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithFalseB", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithFalseB", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -207,14 +224,15 @@ public void FalseBMeansFalseATest() throws InvalidFileFormatException { /** * Given one statement: A -> B where B and -> are true * - * Asserts that this is not a valid application of this rule no matter what - * A is set to. + *

Asserts that this is not a valid application of this rule no matter what A is set to. * * @throws InvalidFileFormatException */ @Test public void TrueBCannotDetermineA() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueB", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/ConditionalEliminationDirectRule/TrueConditionalWithTrueB", + stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -230,4 +248,4 @@ public void TrueBCannotDetermineA() throws InvalidFileFormatException { board.addModifiedData(boniato); Assert.assertNotNull(RULE.checkRule(transition)); } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/ConditionalIntroductionTest.java b/src/test/java/puzzles/shorttruthtable/rules/ConditionalIntroductionTest.java index c1507eab1..1bc28373d 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/ConditionalIntroductionTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/ConditionalIntroductionTest.java @@ -15,7 +15,8 @@ import org.junit.Test; public class ConditionalIntroductionTest { - private static final DirectRuleConditionalIntroduction RULE = new DirectRuleConditionalIntroduction(); + private static final DirectRuleConditionalIntroduction RULE = + new DirectRuleConditionalIntroduction(); private static ShortTruthTable stt; @BeforeClass @@ -27,8 +28,8 @@ public static void setup() { /** * Given a statement: A -> B * - * Asserts that if setting -> to false is a valid application of this rule if and - * only if A is true and B is false. + *

Asserts that if setting -> to false is a valid application of this rule if and only if A + * is true and B is false. * * @throws InvalidFileFormatException */ @@ -58,10 +59,10 @@ private void falseConditionalHelper(String filePath) throws InvalidFileFormatExc ShortTruthTableCell a = board.getCell(0, 0); ShortTruthTableCell b = board.getCell(2, 0); - if (a.getType() == ShortTruthTableCellType.TRUE && b.getType() == ShortTruthTableCellType.FALSE) { + if (a.getType() == ShortTruthTableCellType.TRUE + && b.getType() == ShortTruthTableCellType.FALSE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } @@ -69,8 +70,8 @@ private void falseConditionalHelper(String filePath) throws InvalidFileFormatExc /** * Given a statement: A -> B * - * Asserts that if setting -> to true is a valid application of this rule if and - * only if A is false or B is true. + *

Asserts that if setting -> to true is a valid application of this rule if and only if A is + * false or B is true. * * @throws InvalidFileFormatException */ @@ -100,11 +101,11 @@ private void trueConditionalTestHelper(String filePath) throws InvalidFileFormat ShortTruthTableCell a = board.getCell(0, 0); ShortTruthTableCell b = board.getCell(2, 0); - if (a.getType() == ShortTruthTableCellType.FALSE || b.getType() == ShortTruthTableCellType.TRUE) { + if (a.getType() == ShortTruthTableCellType.FALSE + || b.getType() == ShortTruthTableCellType.TRUE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/NotContradictionRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/NotContradictionRuleTest.java new file mode 100644 index 000000000..b95612235 --- /dev/null +++ b/src/test/java/puzzles/shorttruthtable/rules/NotContradictionRuleTest.java @@ -0,0 +1,67 @@ +package puzzles.shorttruthtable.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleNot; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class NotContradictionRuleTest { + + private static final ContradictionRuleNot RULE = new ContradictionRuleNot(); + private static ShortTruthTable stt; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + stt = new ShortTruthTable(); + } + + /** + * Given a statement: ¬A + * + *

Asserts that this is a valid application of the rule if and only if A and B are both true + * or are both false. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void notContradictionTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/NotContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + notContradictionTestHelper(path + first + second); + } + } + } + + private void notContradictionTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell not = board.getCell(0, 0); + ShortTruthTableCell a = board.getCell(1, 0); + + if ((not.getType() == ShortTruthTableCellType.TRUE + && a.getType() == ShortTruthTableCellType.TRUE) + || (not.getType() == ShortTruthTableCellType.FALSE + && a.getType() == ShortTruthTableCellType.FALSE)) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/NotEliminationTest.java b/src/test/java/puzzles/shorttruthtable/rules/NotEliminationTest.java index 6dbbf141c..589e3cfb9 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/NotEliminationTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/NotEliminationTest.java @@ -27,18 +27,23 @@ public static void setup() { /** * Given one statement: ¬A where ¬ is false * - * Asserts that this is a valid application of this rule if and only if A is true + *

Asserts that this is a valid application of this rule if and only if A is true * * @throws InvalidFileFormatException */ @Test public void FalseNot() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotEliminationDirectRule/FalseNot", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/NotEliminationDirectRule/FalseNot", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType : cellTypes) { ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); @@ -48,8 +53,7 @@ public void FalseNot() throws InvalidFileFormatException { if (cellType == ShortTruthTableCellType.TRUE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } @@ -58,18 +62,23 @@ public void FalseNot() throws InvalidFileFormatException { /** * Given one statement: ¬A where ¬ is true * - * Asserts that this is a valid application of this rule if and only if A is false + *

Asserts that this is a valid application of this rule if and only if A is false * * @throws InvalidFileFormatException */ @Test public void TrueNot() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotEliminationDirectRule/TrueNot", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/NotEliminationDirectRule/TrueNot", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType : cellTypes) { ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); @@ -79,46 +88,47 @@ public void TrueNot() throws InvalidFileFormatException { if (cellType == ShortTruthTableCellType.FALSE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } } -// /** -// * Given one statement: ¬A -// * -// * Asserts that setting both ¬ and A to any values would not be a valid -// * application of this rule -// * -// * @throws InvalidFileFormatException -// */ -// @Test -// public void CannotSetBothAtOnceTest() throws InvalidFileFormatException { -// TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotEliminationDirectRule/BlankNot", stt); -// TreeNode rootNode = stt.getTree().getRootNode(); -// TreeTransition transition = rootNode.getChildren().get(0); -// transition.setRule(RULE); -// -// ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; -// -// for (ShortTruthTableCellType cellType1 : cellTypes) { -// for (ShortTruthTableCellType cellType2 : cellTypes) { -// ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); -// ShortTruthTableCell not = board.getCell(0, 0); -// ShortTruthTableCell a = board.getCell(1, 0); -// -// not.setData(cellType1); -// a.setData(cellType2); -// -// board.addModifiedData(not); -// board.addModifiedData(a); -// -// System.out.println("TYPE1:" + cellType1); -// System.out.println("TYPE2:" + cellType2); -// Assert.assertNotNull(RULE.checkRule(transition)); -// } -// } -// } -} \ No newline at end of file + // /** + // * Given one statement: ¬A + // * + // * Asserts that setting both ¬ and A to any values would not be a valid + // * application of this rule + // * + // * @throws InvalidFileFormatException + // */ + // @Test + // public void CannotSetBothAtOnceTest() throws InvalidFileFormatException { + // + // TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotEliminationDirectRule/BlankNot", stt); + // TreeNode rootNode = stt.getTree().getRootNode(); + // TreeTransition transition = rootNode.getChildren().get(0); + // transition.setRule(RULE); + // + // ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, + // ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + // + // for (ShortTruthTableCellType cellType1 : cellTypes) { + // for (ShortTruthTableCellType cellType2 : cellTypes) { + // ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + // ShortTruthTableCell not = board.getCell(0, 0); + // ShortTruthTableCell a = board.getCell(1, 0); + // + // not.setData(cellType1); + // a.setData(cellType2); + // + // board.addModifiedData(not); + // board.addModifiedData(a); + // + // System.out.println("TYPE1:" + cellType1); + // System.out.println("TYPE2:" + cellType2); + // Assert.assertNotNull(RULE.checkRule(transition)); + // } + // } + // } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/NotIntroductionTest.java b/src/test/java/puzzles/shorttruthtable/rules/NotIntroductionTest.java index a0a062ab3..e338fb9bd 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/NotIntroductionTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/NotIntroductionTest.java @@ -27,18 +27,23 @@ public static void setup() { /** * Given one statement: ¬A where A is false * - * Asserts that this is a valid application of this rule if and only if ¬ is true + *

Asserts that this is a valid application of this rule if and only if ¬ is true * * @throws InvalidFileFormatException */ @Test public void FalseNot() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotIntroductionDirectRule/FalseA", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/NotIntroductionDirectRule/FalseA", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType : cellTypes) { ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); @@ -48,8 +53,7 @@ public void FalseNot() throws InvalidFileFormatException { if (cellType == ShortTruthTableCellType.TRUE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } @@ -58,18 +62,23 @@ public void FalseNot() throws InvalidFileFormatException { /** * Given one statement: ¬A where A is true * - * Asserts that this is a valid application of this rule if and only if ¬ is false + *

Asserts that this is a valid application of this rule if and only if ¬ is false * * @throws InvalidFileFormatException */ @Test public void TrueNot() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotIntroductionDirectRule/TrueA", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/NotIntroductionDirectRule/TrueA", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType : cellTypes) { ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); @@ -79,8 +88,7 @@ public void TrueNot() throws InvalidFileFormatException { if (cellType == ShortTruthTableCellType.FALSE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } @@ -89,19 +97,24 @@ public void TrueNot() throws InvalidFileFormatException { /** * Given one statement: ¬A * - * Asserts that setting both ¬ and A to any values would not be a valid - * application of this rule + *

Asserts that setting both ¬ and A to any values would not be a valid application of this + * rule * * @throws InvalidFileFormatException */ @Test public void CannotSetBothAtOnceTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/NotIntroductionDirectRule/BlankA", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/NotIntroductionDirectRule/BlankA", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -119,4 +132,4 @@ public void CannotSetBothAtOnceTest() throws InvalidFileFormatException { } } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/OrCaseRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/OrCaseRuleTest.java index 0f7e93db5..4c0fbe8c0 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/OrCaseRuleTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/OrCaseRuleTest.java @@ -7,17 +7,15 @@ import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; -import edu.rpi.legup.puzzle.shorttruthtable.rules.caserule.CaseRuleAnd; import edu.rpi.legup.puzzle.shorttruthtable.rules.caserule.CaseRuleOr; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.util.ArrayList; - public class OrCaseRuleTest { private static final CaseRuleOr RULE = new CaseRuleOr(); @@ -29,17 +27,15 @@ public static void setUp() { stt = new ShortTruthTable(); } - private void trueOrTest(String fileName, - int andX, int andY, - int aX, int aY, - int bX, int bY) throws InvalidFileFormatException { + private void trueOrTest(String fileName, int andX, int andY, int aX, int aY, int bX, int bY) + throws InvalidFileFormatException { TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrCaseRule/" + fileName, stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); - ShortTruthTableCell cell = board.getCell(andX,andY); + ShortTruthTableCell cell = board.getCell(andX, andY); ArrayList cases = RULE.getCases(board, cell); // Make sure that the rule checks out @@ -62,62 +58,66 @@ private void trueOrTest(String fileName, Assert.assertNotEquals(board1B, board2B); // First assert the two cells are not equal, then verify that they are either - // unknown or false. + // unknown or true. Assert.assertNotEquals(board1A, board1B); - Assert.assertTrue(board1A.equals(ShortTruthTableCellType.UNKNOWN) || board1A.equals(ShortTruthTableCellType.TRUE)); - Assert.assertTrue(board1B.equals(ShortTruthTableCellType.UNKNOWN) || board1B.equals(ShortTruthTableCellType.TRUE)); + Assert.assertTrue( + board1A.equals(ShortTruthTableCellType.UNKNOWN) + || board1A.equals(ShortTruthTableCellType.TRUE)); + Assert.assertTrue( + board1B.equals(ShortTruthTableCellType.UNKNOWN) + || board1B.equals(ShortTruthTableCellType.TRUE)); Assert.assertNotEquals(board2A, board2B); - Assert.assertTrue(board2A.equals(ShortTruthTableCellType.UNKNOWN) || board1A.equals(ShortTruthTableCellType.TRUE)); - Assert.assertTrue(board2B.equals(ShortTruthTableCellType.UNKNOWN) || board2B.equals(ShortTruthTableCellType.TRUE)); + Assert.assertTrue( + board2A.equals(ShortTruthTableCellType.UNKNOWN) + || board1A.equals(ShortTruthTableCellType.TRUE)); + Assert.assertTrue( + board2B.equals(ShortTruthTableCellType.UNKNOWN) + || board2B.equals(ShortTruthTableCellType.TRUE)); // Verify the board dimensions are unchanged Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); // Verify that everywhere else on the board is unchanged - for (int i = 0; i< caseBoard1.getWidth(); i++) { + for (int i = 0; i < caseBoard1.getWidth(); i++) { for (int j = 0; j < caseBoard1.getHeight(); j++) { // Make sure not to check the two cells that should be different if (!((i == aX && j == aY) || (i == bX && j == bY))) { - Assert.assertEquals(caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); + Assert.assertEquals( + caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); } } } } /** - * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that - * two branches are created: one where A is false and one where B is false. + * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that two branches + * are created: one where A is false and one where B is false. */ @Test public void SimpleStatement1TrueTest() throws InvalidFileFormatException { - trueOrTest("SimpleStatement1_True", 1, 0, 0, 0, - 2, 0); + trueOrTest("SimpleStatement1_True", 1, 0, 0, 0, 2, 0); } /** - * Given a statement ~(A|B)^(C^D) where the first ^ is false, tests this case rule - * by ensuring that two branches are created: one where ~ is false and one where - * the second ^ is false. + * Given a statement ~(A|B)^(C^D) where the first ^ is false, tests this case rule by ensuring + * that two branches are created: one where ~ is false and one where the second ^ is false. */ @Test public void ComplexStatement1TrueTest() throws InvalidFileFormatException { - trueOrTest("ComplexStatement1_True", 6, 0, 0, 0, - 9, 0); + trueOrTest("ComplexStatement1_True", 6, 0, 0, 0, 9, 0); } - private void falseOrTest(String fileName, - int andX, int andY, - int aX, int aY, - int bX, int bY) throws InvalidFileFormatException { + private void falseOrTest(String fileName, int andX, int andY, int aX, int aY, int bX, int bY) + throws InvalidFileFormatException { TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrCaseRule/" + fileName, stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); - ShortTruthTableCell cell = board.getCell(andX,andY); + ShortTruthTableCell cell = board.getCell(andX, andY); ArrayList cases = RULE.getCases(board, cell); // Make sure that the rule checks out @@ -130,7 +130,7 @@ private void falseOrTest(String fileName, ShortTruthTableCellType caseBoardAType = caseBoard.getCell(aX, aY).getType(); ShortTruthTableCellType caseBoardBType = caseBoard.getCell(bX, bY).getType(); - // Both cells should be true + // Both cells should be false Assert.assertEquals(caseBoardAType, ShortTruthTableCellType.FALSE); Assert.assertEquals(caseBoardBType, ShortTruthTableCellType.FALSE); Assert.assertEquals(caseBoardAType, caseBoardBType); @@ -140,22 +140,20 @@ private void falseOrTest(String fileName, } /** - * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that - * one branch is created where A and B are both true. + * Given a statement A ^ B where ^ is false, tests this case rule by ensuring that one branch is + * created where A and B are both true. */ @Test public void SimpleStatement1FalseTest() throws InvalidFileFormatException { - falseOrTest("SimpleStatement1_False", 1, 0, 0, 0, - 2, 0); + falseOrTest("SimpleStatement1_False", 1, 0, 0, 0, 2, 0); } /** - * Given a statement ~(A|B)^(C^D) where the first ^ is true, tests this case rule - * by ensuring that one branch is created where both ~ and the second ^ are true. + * Given a statement ~(A|B)^(C^D) where the first ^ is true, tests this case rule by ensuring + * that one branch is created where both ~ and the second ^ are true. */ @Test public void ComplexStatement1FalseTest() throws InvalidFileFormatException { - falseOrTest("ComplexStatement1_False", 6, 0, 0, 0, - 9, 0); + falseOrTest("ComplexStatement1_False", 6, 0, 0, 0, 9, 0); } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/OrContradictionRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/OrContradictionRuleTest.java new file mode 100644 index 000000000..d03328640 --- /dev/null +++ b/src/test/java/puzzles/shorttruthtable/rules/OrContradictionRuleTest.java @@ -0,0 +1,132 @@ +package puzzles.shorttruthtable.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTable; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableBoard; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCell; +import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; +import edu.rpi.legup.puzzle.shorttruthtable.rules.contradiction.ContradictionRuleOr; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class OrContradictionRuleTest { + + private static final ContradictionRuleOr RULE = new ContradictionRuleOr(); + private static ShortTruthTable stt; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + stt = new ShortTruthTable(); + } + + /** + * Given a statement: A V B where V is true + * + *

Asserts that this is a valid application of the rule if and only if both A and B are set + * to false. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void trueOrTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/OrContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + trueOrTestHelper(path + first + "T" + second); + } + } + } + + private void trueOrTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(2, 0); + + if (a.getType() == ShortTruthTableCellType.FALSE + && b.getType() == ShortTruthTableCellType.FALSE) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } + + /** + * Given a statement: A V B where V is false + * + *

Asserts that this is a valid application of the rule if and only if A or B is set to true + * or both A and B are set to true. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void falseOrTest() throws InvalidFileFormatException { + String path = "puzzles/shorttruthtable/rules/OrContradictionRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + falseOrTestHelper(path + first + "F" + second); + } + } + } + + private void falseOrTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); + ShortTruthTableCell a = board.getCell(0, 0); + ShortTruthTableCell b = board.getCell(2, 0); + + if (a.getType() == ShortTruthTableCellType.TRUE + || b.getType() == ShortTruthTableCellType.TRUE) { + Assert.assertNull(RULE.checkContradiction(transition.getBoard())); + } else { + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } + } + + /** + * Given a statement: A V B where V is unknown + * + *

Asserts that this is not a valid application of this rule. + * + * @param filePath The file path for test board setup. + * @throws InvalidFileFormatException + */ + @Test + public void unknownOrTest() throws InvalidFileFormatException { + // Getting the files that have or set to unknown from Or Introduction + String path = "puzzles/shorttruthtable/rules/OrIntroductionDirectRule/"; + String[] letters = {"T", "F", "U"}; + for (String first : letters) { + for (String second : letters) { + unknownOrTestHelper(path + first + "U" + second); + } + } + } + + private void unknownOrTestHelper(String filePath) throws InvalidFileFormatException { + TestUtilities.importTestBoard(filePath, stt); + TreeNode rootNode = stt.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction(transition.getBoard())); + } +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/OrEliminationTest.java b/src/test/java/puzzles/shorttruthtable/rules/OrEliminationTest.java index 6cdd0d639..e4efad465 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/OrEliminationTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/OrEliminationTest.java @@ -27,13 +27,14 @@ public static void setup() { /** * Given a statement: A V B, where A is false and V is true * - * Asserts that this is a valid application of the rule if and only if B is true. + *

Asserts that this is a valid application of the rule if and only if B is true. * * @throws InvalidFileFormatException */ @Test public void FTUTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrEliminationDirectRule/FTU", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/OrEliminationDirectRule/FTU", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -53,13 +54,14 @@ public void FTUTest() throws InvalidFileFormatException { /** * Given a statement: A V B, where B is false and V is true * - * Asserts that this is a valid application of the rule if and only if B is true. + *

Asserts that this is a valid application of the rule if and only if B is true. * * @throws InvalidFileFormatException */ @Test public void UTFTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTF", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTF", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -79,19 +81,24 @@ public void UTFTest() throws InvalidFileFormatException { /** * Given a statement: A V B, where V is false * - * Asserts that this is a valid application of the rule if and only if both A - * and B are false. + *

Asserts that this is a valid application of the rule if and only if both A and B are + * false. * * @throws InvalidFileFormatException */ @Test public void UFUTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrEliminationDirectRule/UFU", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/OrEliminationDirectRule/UFU", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -105,10 +112,10 @@ public void UFUTest() throws InvalidFileFormatException { board.addModifiedData(a); board.addModifiedData(b); - if (cellType1 == ShortTruthTableCellType.FALSE && cellType2 == ShortTruthTableCellType.FALSE) { + if (cellType1 == ShortTruthTableCellType.FALSE + && cellType2 == ShortTruthTableCellType.FALSE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } @@ -118,18 +125,23 @@ public void UFUTest() throws InvalidFileFormatException { /** * Given a statement: A V B, where V is true * - * Asserts that setting both A and B is not a valid application of this rule. + *

Asserts that setting both A and B is not a valid application of this rule. * * @throws InvalidFileFormatException */ @Test public void UTUTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTU", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/OrEliminationDirectRule/UTU", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); - ShortTruthTableCellType[] cellTypes = {ShortTruthTableCellType.TRUE, ShortTruthTableCellType.FALSE, ShortTruthTableCellType.UNKNOWN}; + ShortTruthTableCellType[] cellTypes = { + ShortTruthTableCellType.TRUE, + ShortTruthTableCellType.FALSE, + ShortTruthTableCellType.UNKNOWN + }; for (ShortTruthTableCellType cellType1 : cellTypes) { for (ShortTruthTableCellType cellType2 : cellTypes) { @@ -147,4 +159,4 @@ public void UTUTest() throws InvalidFileFormatException { } } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/OrIntroductionTest.java b/src/test/java/puzzles/shorttruthtable/rules/OrIntroductionTest.java index 13cb10d55..d5f9387eb 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/OrIntroductionTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/OrIntroductionTest.java @@ -27,8 +27,8 @@ public static void setup() { /** * Given a statement: A V B * - * Asserts that if at least 1 of A or B is true, then this is a valid application - * of the rule if and only if V is true. + *

Asserts that if at least 1 of A or B is true, then this is a valid application of the rule + * if and only if V is true. * * @param filePath The file path for test board setup. * @throws InvalidFileFormatException @@ -64,8 +64,8 @@ private void trueOrTestHelper(String filePath) throws InvalidFileFormatException /** * Given a statement: A V B * - * Asserts that setting V to false is a valid application of the rule if - * and only if both A and B are false. + *

Asserts that setting V to false is a valid application of the rule if and only if both A + * and B are false. * * @param filePath The file path for test board setup. * @throws InvalidFileFormatException @@ -95,11 +95,11 @@ private void falseOrTestHelper(String filePath) throws InvalidFileFormatExceptio or.setData(ShortTruthTableCellType.FALSE); board.addModifiedData(or); - if (a.getType() == ShortTruthTableCellType.FALSE && b.getType() == ShortTruthTableCellType.FALSE) { + if (a.getType() == ShortTruthTableCellType.FALSE + && b.getType() == ShortTruthTableCellType.FALSE) { Assert.assertNull(RULE.checkRule(transition)); - } - else { + } else { Assert.assertNotNull(RULE.checkRule(transition)); } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/shorttruthtable/rules/TrueOrFalseCaseRuleTest.java b/src/test/java/puzzles/shorttruthtable/rules/TrueOrFalseCaseRuleTest.java index 2c0b9fb15..d0c390785 100644 --- a/src/test/java/puzzles/shorttruthtable/rules/TrueOrFalseCaseRuleTest.java +++ b/src/test/java/puzzles/shorttruthtable/rules/TrueOrFalseCaseRuleTest.java @@ -9,14 +9,13 @@ import edu.rpi.legup.puzzle.shorttruthtable.ShortTruthTableCellType; import edu.rpi.legup.puzzle.shorttruthtable.rules.caserule.CaseRuleAtomic; import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.util.ArrayList; - public class TrueOrFalseCaseRuleTest { private static final CaseRuleAtomic RULE = new CaseRuleAtomic(); @@ -29,18 +28,19 @@ public static void setUp() { } /** - * Tests the True or False case rule by ensuring that it results in two children, - * one that contains Statement as true and one that contains Statement as false. + * Tests the True or False case rule by ensuring that it results in two children, one that + * contains Statement as true and one that contains Statement as false. */ @Test public void TwoBranchesTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/shorttruthtable/rules/TrueOrFalseCaseRule/Statement", stt); + TestUtilities.importTestBoard( + "puzzles/shorttruthtable/rules/TrueOrFalseCaseRule/Statement", stt); TreeNode rootNode = stt.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); ShortTruthTableBoard board = (ShortTruthTableBoard) transition.getBoard(); - ShortTruthTableCell cell = board.getCell(0,0); + ShortTruthTableCell cell = board.getCell(0, 0); ArrayList cases = RULE.getCases(board, cell); // Make sure that the rule checks out @@ -52,27 +52,32 @@ public void TwoBranchesTest() throws InvalidFileFormatException { ShortTruthTableBoard caseBoard1 = (ShortTruthTableBoard) cases.get(0); ShortTruthTableBoard caseBoard2 = (ShortTruthTableBoard) cases.get(1); - ShortTruthTableCellType cellType1 = caseBoard1.getCell(0,0).getType(); - ShortTruthTableCellType cellType2 = caseBoard2.getCell(0,0).getType(); + ShortTruthTableCellType cellType1 = caseBoard1.getCell(0, 0).getType(); + ShortTruthTableCellType cellType2 = caseBoard2.getCell(0, 0).getType(); // First assert the two cells are not equal, then verify that they are true // or false. Assert.assertNotEquals(cellType1, cellType2); - Assert.assertTrue(cellType1.equals(ShortTruthTableCellType.TRUE) || cellType1.equals(ShortTruthTableCellType.FALSE)); - Assert.assertTrue(cellType2.equals(ShortTruthTableCellType.TRUE) || cellType2.equals(ShortTruthTableCellType.FALSE)); + Assert.assertTrue( + cellType1.equals(ShortTruthTableCellType.TRUE) + || cellType1.equals(ShortTruthTableCellType.FALSE)); + Assert.assertTrue( + cellType2.equals(ShortTruthTableCellType.TRUE) + || cellType2.equals(ShortTruthTableCellType.FALSE)); // Verify the board dimensions are unchanged Assert.assertEquals(caseBoard1.getHeight(), caseBoard2.getHeight(), board.getHeight()); Assert.assertEquals(caseBoard1.getWidth(), caseBoard2.getWidth(), board.getWidth()); // Verify that everywhere else on the board is unchanged - for (int i = 0; i< caseBoard1.getWidth(); i++) { + for (int i = 0; i < caseBoard1.getWidth(); i++) { for (int j = 0; j < caseBoard1.getHeight(); j++) { // Make sure not to check the one cell that should be different if (i != 0 && j != 0) { - Assert.assertEquals(caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); + Assert.assertEquals( + caseBoard1.getCell(i, j).getType(), caseBoard2.getCell(i, j).getType()); } } } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/skyscrapers/rules/CellForNumberCaseRuleTest.java b/src/test/java/puzzles/skyscrapers/rules/CellForNumberCaseRuleTest.java new file mode 100644 index 000000000..1fce24cf1 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/CellForNumberCaseRuleTest.java @@ -0,0 +1,258 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.rules.CellForNumberCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CellForNumberCaseRuleTest { + + private static final CellForNumberCaseRule RULE = new CellForNumberCaseRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // basic, max cases + @Test + public void CellForNumberCaseRule_BasicEmpty() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(false); + + ArrayList cases = RULE.getCasesFor(board, board.getNorthClues().get(0), 1); + + Assert.assertEquals(board.getWidth(), cases.size()); + + for (int i = 0; i < board.getWidth(); i++) { + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(0, i); + changedCell.setData(1); + expected.addModifiedData(changedCell); + + boolean exists = false; + for (Board caseBoard : cases) { + if (expected.equalsBoard(caseBoard)) { + exists = true; + break; + } + } + + Assert.assertTrue(exists); + } + } + + // dupe, max cases + @Test + public void CellForNumberCaseRule_DupeEmpty() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(true); + board.setViewFlag(false); + + ArrayList cases = RULE.getCasesFor(board, board.getNorthClues().get(0), 1); + + Assert.assertEquals(board.getWidth(), cases.size()); + + for (int i = 0; i < board.getWidth(); i++) { + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(0, i); + changedCell.setData(1); + expected.addModifiedData(changedCell); + + boolean exists = false; + for (Board caseBoard : cases) { + if (expected.equalsBoard(caseBoard)) { + exists = true; + break; + } + } + + Assert.assertTrue(exists); + } + } + + // dupe, 1 case + @Test + public void CellForNumberCaseRule_DupeSingular() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0RowOpening", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(true); + board.setViewFlag(false); + + ArrayList cases = RULE.getCasesFor(board, board.getWestClues().get(3), 1); + + Assert.assertEquals(1, cases.size()); + + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(2, 3); + changedCell.setData(1); + expected.addModifiedData(changedCell); + + Assert.assertTrue(expected.equalsBoard(cases.get(0))); + } + + // dupe, no cases + @Test + public void CellForNumberCaseRule_DupeNone() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(true); + board.setViewFlag(false); + + ArrayList cases = RULE.getCasesFor(board, board.getWestClues().get(3), 1); + + Assert.assertEquals(0, cases.size()); + } + + // visibility, max cases + @Test + public void CellForNumberCaseRule_ViewEmpty() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(true); + + ArrayList cases = RULE.getCasesFor(board, board.getWestClues().get(1), 1); + + Assert.assertEquals(board.getWidth(), cases.size()); + + for (int i = 0; i < board.getWidth(); i++) { + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(i, 1); + changedCell.setData(1); + expected.addModifiedData(changedCell); + + boolean exists = false; + for (Board caseBoard : cases) { + if (expected.equalsBoard(caseBoard)) { + exists = true; + break; + } + } + + Assert.assertTrue(exists); + } + } + + // visibility, 1 Case, direct + @Test + public void CellForNumberCaseRule_ViewSingular() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0RowOpening", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(true); + + ArrayList cases = RULE.getCasesFor(board, board.getWestClues().get(3), 1); + + Assert.assertEquals(1, cases.size()); + + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(2, 3); + changedCell.setData(1); + expected.addModifiedData(changedCell); + + Assert.assertTrue(expected.equalsBoard(cases.get(0))); + } + + // visibility, 1 Case, implied + @Test + public void CellForNumberCaseRule_ImpliedViewSingular() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(true); + + ArrayList cases = RULE.getCasesFor(board, board.getWestClues().get(0), 5); + + Assert.assertEquals(1, cases.size()); + + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(4, 0); + changedCell.setData(5); + expected.addModifiedData(changedCell); + + Assert.assertTrue(expected.equalsBoard(cases.get(0))); + } + + // visibility, no cases + @Test + public void CellForNumberCaseRule_ViewNone() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(true); + + ArrayList cases = RULE.getCasesFor(board, board.getWestClues().get(3), 1); + + Assert.assertEquals(0, cases.size()); + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/DuplicateNumberContradictionTest.java b/src/test/java/puzzles/skyscrapers/rules/DuplicateNumberContradictionTest.java new file mode 100644 index 000000000..a7bb63a08 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/DuplicateNumberContradictionTest.java @@ -0,0 +1,162 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.rules.DuplicateNumberContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class DuplicateNumberContradictionTest { + + private static final DuplicateNumberContradictionRule RULE = + new DuplicateNumberContradictionRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // empty + @Test + public void DuplicateNumberContradictionRule_EmptyBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + // correct board, no cont + @Test + public void DuplicateNumberContradictionRule_SolvedBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/Solved", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + // invalid board, no cont + @Test + public void DuplicateNumberContradictionRule_OtherContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/FullRowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + // on row + @Test + public void DuplicateNumberContradictionRule_RowContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + if ((k == 0 || k == 1) && i == 0) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // on col + @Test + public void DuplicateNumberContradictionRule_ColContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/ColContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + if (k == 0 && (i == 0 || i == 1)) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // multitudes + @Test + public void DuplicateNumberContradictionRule_AllContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/AllContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/ExceedingVisibilityContradictionTest.java b/src/test/java/puzzles/skyscrapers/rules/ExceedingVisibilityContradictionTest.java new file mode 100644 index 000000000..a5a07f997 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/ExceedingVisibilityContradictionTest.java @@ -0,0 +1,150 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.rules.ExceedingVisibilityContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class ExceedingVisibilityContradictionTest { + + private static final ExceedingVisibilityContradictionRule RULE = + new ExceedingVisibilityContradictionRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // empty + @Test + public void ExceedingVisibilityContradictionRule_EmptyBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // correct board, no cont + @Test + public void ExceedingVisibilityContradictionRule_SolvedBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/Solved", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // invalid board, no cont + @Test + public void ExceedingVisibilityContradictionRule_OtherContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // on row + @Test + public void ExceedingVisibilityContradictionRule_RowContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/FullRowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 1 || i == 3) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // on col + @Test + public void ExceedingVisibilityContradictionRule_ColContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/FullColContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 2 || i == 3) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // multitudes + @Test + public void ExceedingVisibilityContradictionRule_AllContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/AllContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/InsufficientVisibilityContradictionTest.java b/src/test/java/puzzles/skyscrapers/rules/InsufficientVisibilityContradictionTest.java new file mode 100644 index 000000000..ee0f3349a --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/InsufficientVisibilityContradictionTest.java @@ -0,0 +1,150 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.rules.InsufficientVisibilityContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class InsufficientVisibilityContradictionTest { + + private static final InsufficientVisibilityContradictionRule RULE = + new InsufficientVisibilityContradictionRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // empty + @Test + public void InsufficientVisibilityContradictionRule_EmptyBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // correct board, no cont + @Test + public void InsufficientVisibilityContradictionRule_SolvedBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/Solved", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // invalid board, no cont + @Test + public void InsufficientVisibilityContradictionRule_OtherContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // on row + @Test + public void InsufficientVisibilityContradictionRule_RowContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/FullRowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 1 || i == 3) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // on col + @Test + public void InsufficientVisibilityContradictionRule_ColContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/FullColContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 2 || i == 3) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // multitudes + @Test + public void InsufficientVisibilityContradictionRule_AllContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/AllContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/LastSingularCellDirectTest.java b/src/test/java/puzzles/skyscrapers/rules/LastSingularCellDirectTest.java new file mode 100644 index 000000000..76540f010 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/LastSingularCellDirectTest.java @@ -0,0 +1,230 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.rules.LastSingularCellDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LastSingularCellDirectTest { + + private static final LastSingularCellDirectRule RULE = new LastSingularCellDirectRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // full row + @Test + public void LastSingularCellDirectRule_FullRowTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(2, 3); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // full col + @Test + public void LastSingularCellDirectRule_FullColTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(3, 1); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // empty row/col + @Test + public void LastSingularCellDirectRule_EmptyTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastSingularCellDirectRule/0-3Opening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(0, 1); + cell.setData(3); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2-1 row + @Test + public void LastSingularCellDirectRule_PartialRowTest1() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastSingularCellDirectRule/2-1RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(3, 1); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2-1 col + @Test + public void LastSingularCellDirectRule_PartialColTest1() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastSingularCellDirectRule/2-1ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(1, 2); + cell.setData(3); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 1-2 row + @Test + public void LastSingularCellDirectRule_PartialRowTest2() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastSingularCellDirectRule/1-2RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(1, 1); + cell.setData(2); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 1-2 col + @Test + public void LastSingularCellDirectRule_PartialColTest2() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastSingularCellDirectRule/1-2ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(0, 0); + cell.setData(4); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/LastSingularNumberDirectTest.java b/src/test/java/puzzles/skyscrapers/rules/LastSingularNumberDirectTest.java new file mode 100644 index 000000000..6b99994a2 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/LastSingularNumberDirectTest.java @@ -0,0 +1,147 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.rules.LastSingularNumberDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LastSingularNumberDirectTest { + + private static final LastSingularNumberDirectRule RULE = new LastSingularNumberDirectRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // full row / empty col + @Test + public void LastSingularNumberDirectRule_FullRowTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(2, 3); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // full col / empty row + @Test + public void LastSingularNumberDirectRule_FullColTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(3, 1); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2-1 row / 1-2 col + @Test + public void LastSingularNumberDirectRule_PartialRowColTest1() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastSingularNumberDirectRule/2-1RowOpening", + skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(2, 1); + cell.setData(4); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2-1 col / 1-2 row + @Test + public void LastSingularNumberDirectRule_PartialRowColTest2() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastSingularNumberDirectRule/2-1ColOpening", + skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(0, 2); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/LastVisibleCellDirectTest.java b/src/test/java/puzzles/skyscrapers/rules/LastVisibleCellDirectTest.java new file mode 100644 index 000000000..756ff7468 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/LastVisibleCellDirectTest.java @@ -0,0 +1,253 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.rules.LastVisibleCellDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LastVisibleCellDirectTest { + + private static final LastVisibleCellDirectRule RULE = new LastVisibleCellDirectRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // full row + @Test + public void LastVisibleCellDirectRule_FullRowTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(2, 3); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // full col + @Test + public void LastVisibleCellDirectRule_FullColTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(3, 1); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // empty row + @Test + public void LastVisibleCellDirectRule_EmptyRowTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(0, 2); + cell.setData(5); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // empty col + @Test + public void LastVisibleCellDirectRule_EmptyColTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(3, 4); + cell.setData(5); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 1-2 row + public void LastVisibleCellDirectRule_PartialRowTest1() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(1, 2); + cell.setData(3); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 1-2 col + public void LastVisibleCellDirectRule_PartialColTest1() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(2, 2); + cell.setData(2); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2-1 row + public void LastVisibleCellDirectRule_PartialRowTest2() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(1, 1); + cell.setData(2); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2-1 col + public void LastVisibleCellDirectRule_PartialColTest2() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(0, 2); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/LastVisibleNumberDirectTest.java b/src/test/java/puzzles/skyscrapers/rules/LastVisibleNumberDirectTest.java new file mode 100644 index 000000000..c628b89da --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/LastVisibleNumberDirectTest.java @@ -0,0 +1,253 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.rules.LastVisibleNumberDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LastVisibleNumberDirectTest { + + private static final LastVisibleNumberDirectRule RULE = new LastVisibleNumberDirectRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // full row + @Test + public void LastVisibleNumberDirectRule_FullRowTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(2, 3); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // full col + @Test + public void LastVisibleNumberDirectRule_FullColTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(3, 1); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // empty row + @Test + public void LastVisibleNumberDirectRule_EmptyRowTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(0, 2); + cell.setData(5); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // empty col + @Test + public void LastVisibleNumberDirectRule_EmptyColTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(3, 4); + cell.setData(5); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 1-2 row + public void LastVisibleNumberDirectRule_PartialRowTest1() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(1, 2); + cell.setData(3); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 1-2 col + public void LastVisibleNumberDirectRule_PartialColTest1() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(2, 2); + cell.setData(2); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2-1 row + public void LastVisibleNumberDirectRule_PartialRowTest2() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1ColOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(1, 1); + cell.setData(2); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2-1 col + public void LastVisibleNumberDirectRule_PartialColTest2() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1RowOpening", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(0, 2); + cell.setData(1); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/NEdgeDirectTest.java b/src/test/java/puzzles/skyscrapers/rules/NEdgeDirectTest.java new file mode 100644 index 000000000..ed70fce40 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/NEdgeDirectTest.java @@ -0,0 +1,142 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell; +import edu.rpi.legup.puzzle.skyscrapers.rules.NEdgeDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class NEdgeDirectTest { + + private static final NEdgeDirectRule RULE = new NEdgeDirectRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // -> row, empty -> full + @Test + public void NEdgeDirectRule_RightRowTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < 5; i++) { + SkyscrapersCell cell = board.getCell(i, 0); + cell.setData(i + 1); + board.addModifiedData(cell); + } + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + if (i == 0) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // <-row, partial -> partial + @Test + public void NEdgeDirectRule_LeftRowTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/NEdgeDirectRule/LeftRowPartial", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + SkyscrapersCell cell = board.getCell(1, 3); + cell.setData(2); + + board.addModifiedData(cell); + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Point point = new Point(k, i); + if (point.equals(cell.getLocation())) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // up col, partial -> full + @Test + public void NEdgeDirectRule_UpColTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/NEdgeDirectRule/UpColPartial", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < 2; i++) { + SkyscrapersCell cell = board.getCell(1, i); + cell.setData(i + 1); + board.addModifiedData(cell); + } + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + if (k == 1 && i < 2) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // down col, empty -> partial + @Test + public void NEdgeDirectRule_DownColTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/NEdgeDirectRule/DownColEmpty", skyscrapers); + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 1; i < 5; i++) { + SkyscrapersCell cell = board.getCell(3, i); + cell.setData(5 - i); + board.addModifiedData(cell); + } + + Assert.assertNull(RULE.checkRule(transition)); + + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + if (k == 3 && i > 0) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/NumberForCellCaseRuleTest.java b/src/test/java/puzzles/skyscrapers/rules/NumberForCellCaseRuleTest.java new file mode 100644 index 000000000..b417a5227 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/NumberForCellCaseRuleTest.java @@ -0,0 +1,232 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.gameboard.PuzzleElement; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.rules.NumberForCellCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class NumberForCellCaseRuleTest { + + private static final NumberForCellCaseRule RULE = new NumberForCellCaseRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // basic, max cases + @Test + public void NumberForCellCaseRule_BasicEmpty() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(false); + + ArrayList cases = RULE.getCases(board, board.getCell(0, 0)); + + Assert.assertEquals(board.getWidth(), cases.size()); + + for (int i = 0; i < board.getWidth(); i++) { + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(0, 0); + changedCell.setData(i + 1); + expected.addModifiedData(changedCell); + + boolean exists = false; + for (Board caseBoard : cases) { + if (expected.equalsBoard(caseBoard)) { + exists = true; + break; + } + } + + Assert.assertTrue(exists); + } + } + + // dupe, max cases + @Test + public void NumberForCellCaseRule_DupeEmpty() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(true); + board.setViewFlag(false); + + ArrayList cases = RULE.getCases(board, board.getCell(0, 0)); + + Assert.assertEquals(board.getWidth(), cases.size()); + + for (int i = 0; i < board.getWidth(); i++) { + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(0, 0); + changedCell.setData(i + 1); + expected.addModifiedData(changedCell); + + boolean exists = false; + for (Board caseBoard : cases) { + if (expected.equalsBoard(caseBoard)) { + exists = true; + break; + } + } + + Assert.assertTrue(exists); + } + } + + // dupe, 1 case + @Test + public void NumberForCellCaseRule_DupeSingular() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0RowOpening", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(true); + board.setViewFlag(false); + + ArrayList cases = RULE.getCases(board, board.getCell(2, 3)); + + Assert.assertEquals(1, cases.size()); + + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(2, 3); + changedCell.setData(1); + expected.addModifiedData(changedCell); + + Assert.assertTrue(expected.equalsBoard(cases.get(0))); + } + + // dupe, no cases + @Test + public void NumberForCellCaseRule_DupeNone() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(true); + board.setViewFlag(false); + + ArrayList cases = RULE.getCases(board, board.getCell(2, 3)); + + Assert.assertEquals(0, cases.size()); + } + + // visibility, max cases + @Test + public void NumberForCellCaseRule_ViewEmpty() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(true); + + ArrayList cases = RULE.getCases(board, board.getCell(1, 4)); + + Assert.assertEquals(4, cases.size()); + + for (int i = 0; i < board.getWidth() - 1; i++) { + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(1, 4); + changedCell.setData(i + 1); + expected.addModifiedData(changedCell); + + boolean exists = false; + for (Board caseBoard : cases) { + if (expected.equalsBoard(caseBoard)) { + exists = true; + break; + } + } + + Assert.assertTrue(exists); + } + } + + // visibility, 1 case + @Test + public void NumberForCellCaseRule_ViewSingular() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/common/3-0RowOpening", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(true); + + ArrayList cases = RULE.getCases(board, board.getCell(2, 3)); + + Assert.assertEquals(1, cases.size()); + + SkyscrapersBoard expected = ((SkyscrapersBoard) transition.getBoard()).copy(); + PuzzleElement changedCell = expected.getCell(2, 3); + changedCell.setData(1); + expected.addModifiedData(changedCell); + + Assert.assertTrue(expected.equalsBoard(cases.get(0))); + } + + // visibility, no cases + @Test + public void NumberForCellCaseRule_ViewNone() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + + board.setDupeFlag(false); + board.setViewFlag(true); + + ArrayList cases = RULE.getCases(board, board.getCell(2, 3)); + + Assert.assertEquals(0, cases.size()); + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/PreemptiveVisibilityContradictionTest.java b/src/test/java/puzzles/skyscrapers/rules/PreemptiveVisibilityContradictionTest.java new file mode 100644 index 000000000..ec49a8194 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/PreemptiveVisibilityContradictionTest.java @@ -0,0 +1,170 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.rules.PreemptiveVisibilityContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PreemptiveVisibilityContradictionTest { + + private static final PreemptiveVisibilityContradictionRule RULE = + new PreemptiveVisibilityContradictionRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // empty + @Test + public void PreemptiveVisibilityContradictionRule_EmptyBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // correct board, no cont + @Test + public void PreemptiveVisibilityContradictionRule_SolvedBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/Solved", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // invalid board, no cont + @Test + public void PreemptiveVisibilityContradictionRule_OtherContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2CellContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // on row + @Test + public void PreemptiveVisibilityContradictionRule_RowContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedRowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 1) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // on col + @Test + public void PreemptiveVisibilityContradictionRule_ColContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedColContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 2) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // multitudes + @Test + public void PreemptiveVisibilityContradictionRule_AllContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/AllContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // multitudes - preemptive + @Test + public void PreemptiveVisibilityContradictionRule_ImpliedAllContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedAllContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/UnresolvedCellContradictionTest.java b/src/test/java/puzzles/skyscrapers/rules/UnresolvedCellContradictionTest.java new file mode 100644 index 000000000..398bba6e5 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/UnresolvedCellContradictionTest.java @@ -0,0 +1,165 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.rules.UnresolvedCellContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class UnresolvedCellContradictionTest { + + private static final UnresolvedCellContradictionRule RULE = + new UnresolvedCellContradictionRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // empty + @Test + public void UnresolvedCellContradictionRule_EmptyBoardTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + // correct board, no cont + @Test + public void UnresolvedCellContradictionRule_SolvedBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/Solved", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + // invalid board, no cont + @Test + public void UnresolvedCellContradictionRule_OtherContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedAllContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + + // 3 in a row, 1 in col creates contradiction + @Test + public void UnresolvedCellContradictionRule_RowContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + if (k == 2 && i == 3) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 3 in a col, 1 in row creates contradiction + @Test + public void UnresolvedCellContradictionRule_ColContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1ColContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + if (k == 1 && i == 0) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } + + // 2 in a col, 2 in row creates cell contradiction + @Test + public void UnresolvedCellContradictionRule_MixedContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2CellContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { + if (k == 2 && i == 3) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + } + } + } + } +} diff --git a/src/test/java/puzzles/skyscrapers/rules/UnresolvedNumberContradictionTest.java b/src/test/java/puzzles/skyscrapers/rules/UnresolvedNumberContradictionTest.java new file mode 100644 index 000000000..17139fb60 --- /dev/null +++ b/src/test/java/puzzles/skyscrapers/rules/UnresolvedNumberContradictionTest.java @@ -0,0 +1,178 @@ +package puzzles.skyscrapers.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.skyscrapers.Skyscrapers; +import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersBoard; +import edu.rpi.legup.puzzle.skyscrapers.rules.UnresolvedNumberContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class UnresolvedNumberContradictionTest { + + private static final UnresolvedNumberContradictionRule RULE = + new UnresolvedNumberContradictionRule(); + private static Skyscrapers skyscrapers; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + skyscrapers = new Skyscrapers(); + } + + // empty + @Test + public void UnresolvedNumberContradictionRule_EmptyBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/empty", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // correct board, no cont + @Test + public void UnresolvedNumberContradictionRule_SolvedBoardTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/skyscrapers/rules/common/Solved", skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // invalid board, no cont + @Test + public void UnresolvedNumberContradictionRule_OtherContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedAllContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNotNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + + // 3 in a row, 1 in col creates contradiction + @Test + public void UnresolvedNumberContradictionRule_RowContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 3) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // 3 in a col, 1 in row creates contradiction + @Test + public void UnresolvedNumberContradictionRule_ColContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1ColContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 1) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // 2 in a row/col, 2 in other row/cols creates number contradiction + @Test + public void UnresolvedNumberContradictionRule_TwoContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2NumberContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 1 || i == 3) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } + + // 1 in a row/col, 3 in other row/cols creates number contradiction + @Test + public void UnresolvedNumberContradictionRule_ThreeContradictionTest() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/skyscrapers/rules/UnresolvedContradictionRules/1-3NumberContradiction", + skyscrapers); + + TreeNode rootNode = skyscrapers.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + Assert.assertNull(RULE.checkContradiction((SkyscrapersBoard) transition.getBoard())); + + SkyscrapersBoard board = (SkyscrapersBoard) transition.getBoard(); + for (int i = 0; i < board.getHeight(); i++) { + if (i == 1 || i == 2) { + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(i, i))); + } + } + } +} diff --git a/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java new file mode 100644 index 000000000..59d5b37af --- /dev/null +++ b/src/test/java/puzzles/starbattle/rules/BlackoutDirectRuleTest.java @@ -0,0 +1,76 @@ +// This test is for a puzzle that is not fully implemented yet and is causing issues. +// Commenting this out for now, but once Star Battle is fully implemented this should +// be uncommented and finished. + +// package puzzles.starbattle.rules; +// +// import edu.rpi.legup.puzzle.nurikabe.Nurikabe; +// import edu.rpi.legup.puzzle.nurikabe.NurikabeBoard; +// import edu.rpi.legup.puzzle.nurikabe.NurikabeCell; +// import edu.rpi.legup.puzzle.nurikabe.NurikabeType; +// import legup.MockGameBoardFacade; +// import legup.TestUtilities; +// import edu.rpi.legup.model.tree.TreeNode; +// import edu.rpi.legup.model.tree.TreeTransition; +// import org.junit.Assert; +// import org.junit.BeforeClass; +// import org.junit.Test; +// +// import edu.rpi.legup.puzzle.starbattle.StarBattle; +// import edu.rpi.legup.puzzle.starbattle.StarBattleBoard; +// import edu.rpi.legup.puzzle.starbattle.StarBattleCell; +// import edu.rpi.legup.puzzle.starbattle.StarBattleCellType; +// import edu.rpi.legup.puzzle.starbattle.rules.BlackoutDirectRule; +// import edu.rpi.legup.save.InvalidFileFormatException; +// +// import java.awt.*; +// +// public class BlackoutDirectRuleTest { +// +// private static final BlackoutDirectRule RULE = new BlackoutDirectRule(); +// private static StarBattle starbattle; +// +// @BeforeClass +// public static void setUp() { +// MockGameBoardFacade.getInstance(); +// starbattle = new StarBattle(); +// } +// +// @Test +// public void BlackoutDirectRuleTest_ColumnBlackout() throws InvalidFileFormatException { +// +// TestUtilities.importTestBoard("puzzles/starbattle/rules/BlackoutDirectRule/ColumnBlackout", +// starbattle); +// TreeNode rootNode = starbattle.getTree().getRootNode(); +// TreeTransition transition = rootNode.getChildren().get(0); +// transition.setRule(RULE); +// +// StarBattleBoard board = (StarBattleBoard) transition.getBoard(); +// +// StarBattleCell cell1 = board.getCell(1, 1); +// cell1.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell2 = board.getCell(1, 2); +// cell2.setData(StarBattleCellType.BLACK.value); +// StarBattleCell cell3 = board.getCell(1, 3); +// cell3.setData(StarBattleCellType.BLACK.value); +// +// board.addModifiedData(cell1); +// board.addModifiedData(cell2); +// board.addModifiedData(cell3); +// +// Assert.assertNull(RULE.checkRule(transition)); +// +// for (int i = 0; i < board.getHeight(); i++) { +// for (int k = 0; k < board.getWidth(); k++) { +// Point point = new Point(k, i); +// if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || +// point.equals(cell3.getLocation())) { +// Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// else { +// Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); +// } +// } +// } +// } +// } diff --git a/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java new file mode 100644 index 000000000..f27f38d8a --- /dev/null +++ b/src/test/java/puzzles/sudoku/rules/LastNumberForCellDirectRuleRegionTest.java @@ -0,0 +1,100 @@ +package puzzles.sudoku.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.Sudoku; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.rules.LastNumberForCellDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LastNumberForCellDirectRuleRegionTest { + private static final LastNumberForCellDirectRule RULE = new LastNumberForCellDirectRule(); + private static Sudoku sudoku; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + sudoku = new Sudoku(); + } + + @Test + public void LastNumberForCellDirectRule_FullRegionTest() throws InvalidFileFormatException { + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion", sudoku); + TreeNode rootNode = sudoku.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + SudokuCell cell1 = board.getCell(2, 5); + cell1.setData(i); + board.addModifiedData(cell1); + + // Test the case + if (i == 9) { + Assert.assertNull(RULE.checkRuleAt(transition, cell1)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell1)); + } + } + + // Import Board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + SudokuCell cell = board.getCell(4, 4); + cell.setData(i); + board.addModifiedData(cell); + + // Test the case + if (i == 5) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + } + + // Import Board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop all numbers at point + for (int i = 1; i < 10; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + SudokuCell cell = board.getCell(5, 3); + cell.setData(i); + board.addModifiedData(cell); + + // Test the case + if (i == 2) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + } + } +} diff --git a/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java new file mode 100644 index 000000000..704167a29 --- /dev/null +++ b/src/test/java/puzzles/sudoku/rules/RepeatedNumberContradictionRuleTest.java @@ -0,0 +1,88 @@ +package puzzles.sudoku.rules; + +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.sudoku.Sudoku; +import edu.rpi.legup.puzzle.sudoku.SudokuBoard; +import edu.rpi.legup.puzzle.sudoku.SudokuCell; +import edu.rpi.legup.puzzle.sudoku.rules.RepeatedNumberContradictionRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RepeatedNumberContradictionRuleTest { + private static final RepeatedNumberContradictionRule RULE = + new RepeatedNumberContradictionRule(); + private static Sudoku sudoku; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + sudoku = new Sudoku(); + } + + @Test + public void RepeatedNumberContradictionRule_GlobalTest() throws InvalidFileFormatException { + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7", sudoku); + TreeNode rootNode = sudoku.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop through every cell + for (int i = 0; i < 81; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + int x = i / 9; + int y = i % 9; + if (x == 0 && y == 0) { + continue; + } + SudokuCell cell = board.getCell(x, y); + cell.setData(7); + + // Test the case + if (x == 0 || y == 0 || (x < 3 && y < 3)) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + cell.setData(0); + } + // Import board and create transition + TestUtilities.importTestBoard( + "puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4", sudoku); + rootNode = sudoku.getTree().getRootNode(); + transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + // Loop through every cell + for (int i = 0; i < 81; i++) { + // Reset board + SudokuBoard board = (SudokuBoard) transition.getBoard(); + // Set cell + int x = i / 9; + int y = i % 9; + if ((x == 3 && y == 0) || (x == 6 && y == 8)) { + continue; + } + SudokuCell cell = board.getCell(x, y); + cell.setData(4); + + // Test the case + if ((x == 3 || y == 0 || x == 6 || y == 8) + || (x > 2 && x < 6 && y < 3) + || (x > 5 && y > 5)) { + Assert.assertNull(RULE.checkRuleAt(transition, cell)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, cell)); + } + cell.setData(0); + } + } +} diff --git a/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java index b7ec8eb02..c704d59b7 100644 --- a/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/EmptyFieldDirectRuleTest.java @@ -8,14 +8,13 @@ import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.rules.EmptyFieldDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.awt.*; - public class EmptyFieldDirectRuleTest { private static final EmptyFieldDirectRule RULE = new EmptyFieldDirectRule(); @@ -27,12 +26,18 @@ public static void setUp() { treetent = new TreeTent(); } - // creates a 3x3 puzzle with no trees - // make the (1,1) tile GRASS - // checks if tiles logically follow the EmptyFieldDirectRule + /** + * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule + * + *

Empty XXX XGX XXX + * + *

Makes the (1, 1) tile GRASS Checks if the rule correctly detects no trees around the grass + * tile + */ @Test public void EmptyFieldTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyField", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/EmptyFieldDirectRule/EmptyField", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -56,8 +61,7 @@ public void EmptyFieldTest() throws InvalidFileFormatException { if (c.getLocation().equals(cell1.getLocation())) { // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } @@ -65,13 +69,18 @@ public void EmptyFieldTest() throws InvalidFileFormatException { } } - // creates a 3x3 puzzle with 4 trees - // trees are at (0,0), (2,0), (0,2), and (2,2) - // make the (1,1) tile GRASS. - // checks if tiles logically follow the EmptyFieldDirectRule + /** + * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule + * + *

Trees are at (0, 0), (2, 0), (0, 2), and (2, 2) RXR XGX RXR + * + *

Makes the (1, 1) tile GRASS Checks if the rule correctly ignores the trees on the + * diagonals + */ @Test public void DiagonalTreeTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/DiagonalTree", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/EmptyFieldDirectRule/DiagonalTree", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -79,7 +88,7 @@ public void DiagonalTreeTest() throws InvalidFileFormatException { // get board state TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - //change the board's cells considering the EmptyField rule + // change the board's cells considering the EmptyField rule TreeTentCell cell1 = board.getCell(1, 1); cell1.setData(TreeTentType.GRASS); board.addModifiedData(cell1); @@ -95,8 +104,7 @@ public void DiagonalTreeTest() throws InvalidFileFormatException { if (c.getLocation().equals(cell1.getLocation())) { // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } @@ -104,13 +112,17 @@ public void DiagonalTreeTest() throws InvalidFileFormatException { } } - // creates a 3x3 puzzle with 4 trees - // trees are at (0,1), (1,0), (1,2), and (2,1) - // make the (1,1) tile GRASS. - // checks if tiles don't logically follow the EmptyFieldDirectRule + /** + * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule + * + *

Trees are at (0, 1), (1, 0), (1, 2), and (2, 1) XRX RGR XRX + * + *

Makes the (1, 1) tile GRASS Checks if the rule is not valid when there are adjacent trees + */ @Test public void EmptyFieldTestFail() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFail", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFail", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -118,7 +130,7 @@ public void EmptyFieldTestFail() throws InvalidFileFormatException { // get board state TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - //change the board's cells considering breaking the EmptyField rule + // change the board's cells considering breaking the EmptyField rule TreeTentCell cell1 = board.getCell(1, 1); cell1.setData(TreeTentType.GRASS); board.addModifiedData(cell1); @@ -137,13 +149,18 @@ public void EmptyFieldTestFail() throws InvalidFileFormatException { } } - // creates a 3x3 puzzle with 1 tree - // tree is at (1,0) - // make the (1,1) tile GRASS. - // checks if tiles don't logically follow the EmptyFieldDirectRule + /** + * 3x3 TreeTent puzzle Tests EmptyFieldDirectRule + * + *

Tree at (1, 0) XRX XGX XXX + * + *

Makes the (1, 1) tile GRASS Checks if the rule is not valid when there is one adjacent + * tree + */ @Test public void EmptyFieldTestFailTop() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailTop", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailTop", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -151,106 +168,7 @@ public void EmptyFieldTestFailTop() throws InvalidFileFormatException { // get board state TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - //change the board's cells considering breaking the EmptyField rule - TreeTentCell cell1 = board.getCell(1, 1); - cell1.setData(TreeTentType.GRASS); - board.addModifiedData(cell1); - - // confirm there is not a logical following of the EmptyField rule - Assert.assertNotNull(RULE.checkRule(transition)); - - // the cells should not follow the rule - TreeTentCell c; - for (int i = 0; i < board.getWidth(); i++) { - for (int j = 0; j < board.getHeight(); j++) { - c = board.getCell(j, i); - // does not use the rule to logically follow - Assert.assertNotNull(RULE.checkRuleAt(transition, c)); - } - } - } - - // creates a 3x3 puzzle with 1 tree - // tree is at (1,2) - // make the (1,1) tile GRASS. - // checks if tiles don't logically follow the EmptyFieldDirectRule - @Test - public void EmptyFieldTestFailTopBottom() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailBottom", treetent); - TreeNode rootNode = treetent.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - // get board state - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - - //change the board's cells considering breaking the EmptyField rule - TreeTentCell cell1 = board.getCell(1, 1); - cell1.setData(TreeTentType.GRASS); - board.addModifiedData(cell1); - - // confirm there is not a logical following of the EmptyField rule - Assert.assertNotNull(RULE.checkRule(transition)); - - // the cells should not follow the rule - TreeTentCell c; - for (int i = 0; i < board.getWidth(); i++) { - for (int j = 0; j < board.getHeight(); j++) { - c = board.getCell(j, i); - // does not use the rule to logically follow - Assert.assertNotNull(RULE.checkRuleAt(transition, c)); - } - } - } - - // creates a 3x3 puzzle with 1 tree - // tree is at (0,1) - // make the (1,1) tile GRASS. - // checks if tiles don't logically follow the EmptyFieldDirectRule - @Test - public void EmptyFieldTestFailLeft() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailLeft", treetent); - TreeNode rootNode = treetent.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - // get board state - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - - //change the board's cells considering breaking the EmptyField rule - TreeTentCell cell1 = board.getCell(1, 1); - cell1.setData(TreeTentType.GRASS); - board.addModifiedData(cell1); - - // confirm there is not a logical following of the EmptyField rule - Assert.assertNotNull(RULE.checkRule(transition)); - - // the cells should not follow the rule - TreeTentCell c; - for (int i = 0; i < board.getWidth(); i++) { - for (int j = 0; j < board.getHeight(); j++) { - c = board.getCell(j, i); - // does not use the rule to logically follow - Assert.assertNotNull(RULE.checkRuleAt(transition, c)); - } - } - } - - // creates a 3x3 puzzle with 1 tree - // tree is at (2,1) - // make the (1,1) tile GRASS. - // checks if tiles don't logically follow the EmptyFieldDirectRule - @Test - public void EmptyFieldTestFailRight() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailRight", treetent); - TreeNode rootNode = treetent.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - // get board state - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - - //change the board's cells considering breaking the EmptyField rule + // change the board's cells considering breaking the EmptyField rule TreeTentCell cell1 = board.getCell(1, 1); cell1.setData(TreeTentType.GRASS); board.addModifiedData(cell1); @@ -269,4 +187,3 @@ public void EmptyFieldTestFailRight() throws InvalidFileFormatException { } } } - diff --git a/src/test/java/puzzles/treetent/rules/FillinRowCaseRuleTest.java b/src/test/java/puzzles/treetent/rules/FillinRowCaseRuleTest.java new file mode 100644 index 000000000..3b8389407 --- /dev/null +++ b/src/test/java/puzzles/treetent/rules/FillinRowCaseRuleTest.java @@ -0,0 +1,455 @@ +package puzzles.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.*; +import edu.rpi.legup.puzzle.treetent.rules.FillinRowCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class FillinRowCaseRuleTest { + private static final FillinRowCaseRule RULE = new FillinRowCaseRule(); + private static TreeTent treetent; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + treetent = new TreeTent(); + } + + /** + * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles and a clue of 0 + * tents in the row. + * + *

checks that 1 case is created and that it is equivalent to FinishWithGrass rule May need + * to change checks due to issue #777 + * + * @throws InvalidFileFormatException + */ + @Test + public void TentOrTreeTestZeroTentClue() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3ZeroTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + /* Test the Row */ + TreeTentClue testing_row = board.getClue(3, 1); + ArrayList cases = RULE.getCases(board, testing_row); + + // assert that one case was found + Assert.assertEquals(1, cases.size()); + + // assert the case filled the row with grass + TreeTentBoard testCase = (TreeTentBoard) cases.getFirst(); + Assert.assertEquals(3, testCase.getRowCol(1, TreeTentType.GRASS, true).size()); + + // checks other cells have not been modified + TreeTentCell original_cell; + TreeTentCell case_cell; + + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + if (h == 1) { + continue; + } + + original_cell = board.getCell(w, h); + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + + /* Test the Column */ + TreeTentClue testing_col = board.getClue(1, 3); + cases = RULE.getCases(board, testing_col); + + // assert one case was created + Assert.assertEquals(1, cases.size()); + + // assert the case filled the column with grass + testCase = (TreeTentBoard) cases.getFirst(); + Assert.assertEquals(3, testCase.getRowCol(1, TreeTentType.GRASS, false).size()); + + // checks other cells have not been modified + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + if (w == 1) { + continue; + } + + original_cell = board.getCell(w, h); + + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + + /** + * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles and a clue of 1 + * tent in the row. The column rules make the board impossible, but they are not checked here. + * + *

checks 3 cases are created checks; first case is TENT tile at x=0, second case is TENT + * tile at x=1, and a third case is TENT tile at x=2. The cases can be in any order. Then, it + * checks that other cells have not been modified + * + * @throws InvalidFileFormatException + */ + @Test + public void FillInRowEmptyOneTentClue() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3OneTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + /* Test the Row */ + TreeTentClue testing_row = board.getClue(3, 1); + ArrayList cases = RULE.getCases(board, testing_row); + + // assert correct number of cases created + Assert.assertEquals(3, cases.size()); + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + + // Each case must have 1 tent in the row + Assert.assertEquals(1, testCase.getRowCol(1, TreeTentType.TENT, true).size()); + + // and they must have 2 grass tiles in the row + Assert.assertEquals(2, testCase.getRowCol(1, TreeTentType.GRASS, true).size()); + } + + // checks other cells have not been modified + TreeTentCell original_cell; + TreeTentCell case_cell; + + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + if (h == 1) { + continue; + } + + original_cell = board.getCell(w, h); + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + + /* Test the Column */ + TreeTentClue testing_col = board.getClue(1, 3); + cases = RULE.getCases(board, testing_col); + + // assert correct number of cases created + Assert.assertEquals(3, cases.size()); + // Only one arrangement is possible when taking into account the + // touching tents contradiction rule. + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + + // Each case must have 1 tent in the column + Assert.assertEquals(1, testCase.getRowCol(1, TreeTentType.TENT, false).size()); + + // and they must have 2 grass tiles in the column + Assert.assertEquals(2, testCase.getRowCol(1, TreeTentType.GRASS, false).size()); + } + + // checks other cells have not been modified + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + if (w == 1) { + continue; + } + + original_cell = board.getCell(w, h); + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + } + + /** + * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles and a clue of 2 + * tent in the row. The column rules make the board impossible, but they are not checked here. + * + *

checks 1 case is created. Checks that the case is when there are TENT tiles at x=0 and + * x=2. Then, it checks that other cells have not been modified + * + * @throws InvalidFileFormatException + */ + @Test + public void FillInRowEmptyTwoTentClue() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3TwoTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + /* Test the Row */ + TreeTentClue testing_row = board.getClue(3, 1); + ArrayList cases = RULE.getCases(board, testing_row); + + // assert correct number of cases created + Assert.assertEquals(1, cases.size()); + // Only one arrangement is possible when taking into account the + // touching tents contradiction rule. + + TreeTentBoard testCase = (TreeTentBoard) cases.getFirst(); + + // The two side tiles are tents, + Assert.assertEquals(TreeTentType.TENT, testCase.getCell(0, 1).getType()); + Assert.assertEquals(TreeTentType.TENT, testCase.getCell(2, 1).getType()); + + // and the center tile is grass. + Assert.assertEquals(TreeTentType.GRASS, testCase.getCell(1, 1).getType()); + + // checks other cells have not been modified + TreeTentCell original_cell; + TreeTentCell case_cell; + + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + if (h == 1) { + continue; + } + + original_cell = board.getCell(w, h); + + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + + /* Test the Column */ + TreeTentClue testing_col = board.getClue(1, 3); + cases = RULE.getCases(board, testing_col); + + // assert correct number of cases created + Assert.assertEquals(1, cases.size()); + // Only one arrangement is possible when taking into account the + // touching tents contradiction rule. + + testCase = (TreeTentBoard) cases.getFirst(); + + // The two side tiles are tents, + Assert.assertEquals(TreeTentType.TENT, testCase.getCell(1, 0).getType()); + Assert.assertEquals(TreeTentType.TENT, testCase.getCell(1, 2).getType()); + + // and the center tile is grass. + Assert.assertEquals(TreeTentType.GRASS, testCase.getCell(1, 1).getType()); + + // checks other cells have not been modified + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + if (w == 1) { + continue; + } + + original_cell = board.getCell(w, h); + + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + + /** + * empty 3x3 TreeTent puzzle Tests FillinRowCaseRule on row with 3 UNKNOWN tiles and a clue of 3 + * tent in the row. + * + *

checks that 0 cases are created + * + * @throws InvalidFileFormatException + */ + @Test + public void FillInRowEmptyThreeTentClue() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3ThreeTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + /* Test the Row */ + TreeTentClue testing_row = board.getClue(3, 1); + ArrayList cases = RULE.getCases(board, testing_row); + + // assert there were no cases found, as filling in all tiles causes the tents to touch + Assert.assertNull(cases); + + /* Test the Column */ + TreeTentClue testing_col = board.getClue(1, 3); + cases = RULE.getCases(board, testing_row); + + Assert.assertNull(cases); + } + + /** + * empty 5x5 TreeTent puzzle Tests FillinRowCaseRule on row with 5 UNKNOWN tiles and a clue of 2 + * tents in the row. + * + *

checks that 6 cases are created and each case has the right number of tents + * + * @throws InvalidFileFormatException + */ + @Test + public void FillInRowEmpty5x5TwoTentClue() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FillinRowCaseRule/EmptyRow5x5TwoTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + // Test the Row + TreeTentClue testing_row = board.getClue(5, 2); + ArrayList cases = RULE.getCases(board, testing_row); + + // assert correct number of cases created + Assert.assertEquals(6, cases.size()); + // Only one arrangement is possible when taking into account the + // touching tents contradiction rule. + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + + // Each case must have 2 tens in the row + Assert.assertEquals(2, testCase.getRowCol(2, TreeTentType.TENT, true).size()); + + // and they must have 3 grass tiles in the row + Assert.assertEquals(3, testCase.getRowCol(2, TreeTentType.GRASS, true).size()); + } + + TreeTentCell original_cell; + TreeTentCell case_cell; + + // checks other cells have not been modified + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + if (h == 2) { + continue; + } + + original_cell = board.getCell(w, h); + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + + // Test the Column + TreeTentClue testing_col = board.getClue(2, 5); + cases = RULE.getCases(board, testing_col); + + // assert correct number of cases created + Assert.assertEquals(6, cases.size()); + // Only one arrangement is possible when taking into account the + // touching tents contradiction rule. + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + + // Each case must have 2 tents in the column + Assert.assertEquals(2, testCase.getRowCol(2, TreeTentType.TENT, false).size()); + + // and they must have 4 grass tiles in the column + Assert.assertEquals(3, testCase.getRowCol(2, TreeTentType.GRASS, false).size()); + } + + // checks other cells have not been modified + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + if (w == 2) { + continue; + } + + original_cell = board.getCell(w, h); + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + } + + /** + * 7x3 TreeTent puzzle Tests FillinRowCaseRule on col with 3 UNKNOWN tiles separated by grass + * tiles and a clue of 3 tents in the col. + * + *

checks that 1 case is created and that all three UNKNOWN tiles have become tents + * + * @throws InvalidFileFormatException + */ + @Test + public void FillInRowPartialFillThreeTent() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FillinRowCaseRule/PartialFillOneTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentClue testing_col = board.getClue(1, 7); + ArrayList cases = RULE.getCases(board, testing_col); + + // assert that one case was found + Assert.assertEquals(1, cases.size()); + + // assert the case has three tents in the column + TreeTentBoard testCase = (TreeTentBoard) cases.getFirst(); + Assert.assertEquals(3, testCase.getRowCol(1, TreeTentType.TENT, false).size()); + + Assert.assertEquals(TreeTentType.TENT, testCase.getCell(1, 1).getType()); + Assert.assertEquals(TreeTentType.TENT, testCase.getCell(1, 3).getType()); + Assert.assertEquals(TreeTentType.TENT, testCase.getCell(1, 5).getType()); + + // checks other cells have not been modified + TreeTentCell original_cell; + TreeTentCell case_cell; + + for (int w = 0; w < board.getWidth(); w++) { + if (w == 1) { + continue; + } + for (int h = 0; h < board.getHeight(); h++) { + + original_cell = board.getCell(w, h); + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } +} diff --git a/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java index 2517df563..c89c96dd1 100644 --- a/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/FinishWithGrassDirectRuleTest.java @@ -8,16 +8,15 @@ import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.rules.FinishWithGrassDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.awt.*; -import java.util.List; -import java.util.ArrayList; - public class FinishWithGrassDirectRuleTest { private static final FinishWithGrassDirectRule RULE = new FinishWithGrassDirectRule(); @@ -30,15 +29,17 @@ public static void setUp() { } /** - * 3x3 TreeTent puzzle with a tent at (0,0) - * Tests FinishWithGrassDirectRule on GRASS tiles horizontal of the tent - * at (1,0) and (2,0) - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tent at (1, 1) XXX x GTG 1 XXX x xxx + * + *

Makes (0, 1) and (2, 1) GRASS Checks if the rule detects the middle row to be filled in + * correctly */ @Test public void FinishWithGrassHorizontalTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -63,11 +64,11 @@ public void FinishWithGrassHorizontalTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { c = board.getCell(k, i); - if (c.getLocation().equals(cell1.getLocation()) || c.getLocation().equals(cell2.getLocation())) { + if (c.getLocation().equals(cell1.getLocation()) + || c.getLocation().equals(cell2.getLocation())) { // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } @@ -76,15 +77,17 @@ public void FinishWithGrassHorizontalTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with a tent at (0,0) - * Tests FinishWithGrassDirectRule on GRASS tiles vertical of the tent - * at (0,1) and (0,2) - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tent at (0, 0) TXX x GXX x GXX x 1xx + * + *

Makes (0, 1) and (0, 2) GRASS Checks if the rule detects the leftmost column to be filled + * in correctly */ @Test public void FinishWithGrassVerticalTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -109,11 +112,11 @@ public void FinishWithGrassVerticalTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { c = board.getCell(k, i); - if (c.getLocation().equals(cell1.getLocation()) || c.getLocation().equals(cell2.getLocation())) { + if (c.getLocation().equals(cell1.getLocation()) + || c.getLocation().equals(cell2.getLocation())) { // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } @@ -122,15 +125,17 @@ public void FinishWithGrassVerticalTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with a tent at (0,0) - * Tests FinishWithGrassDirectRule on GRASS tiles - * at (1,0), (2,0), (0,1), and (0,2) - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tent at (0, 0) TGG 1 GXX x GXX x 1xx + * + *

Makes (0, 1), (0, 2), (1, 0), and (2, 0) GRASS Checks if the rule detects the top row and + * leftmost column to be filled in correctly */ @Test public void FinishWithGrassTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithGrassDirectRule/CornerTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -161,14 +166,13 @@ public void FinishWithGrassTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { c = board.getCell(k, i); - if (c.getLocation().equals(cell1.getLocation()) || - c.getLocation().equals(cell2.getLocation()) || - c.getLocation().equals(cell3.getLocation()) || - c.getLocation().equals(cell4.getLocation())) { + if (c.getLocation().equals(cell1.getLocation()) + || c.getLocation().equals(cell2.getLocation()) + || c.getLocation().equals(cell3.getLocation()) + || c.getLocation().equals(cell4.getLocation())) { // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } @@ -177,15 +181,17 @@ public void FinishWithGrassTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with no tents - * Tests FinishWithGrassDirectRule on GRASS tiles - * GRASS tiles fill entire board - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Empty GGG 0 GGG 0 GGG 0 000 + * + *

Fill Board with GRASS Checks if the rule allows all cells to be filled when the clue for + * all rows and columns is zero. */ @Test public void NoTentTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/NoTent", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithGrassDirectRule/NoTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -216,16 +222,19 @@ public void NoTentTest() throws InvalidFileFormatException { Assert.assertNull(RULE.checkRuleAt(transition, c)); } } + /** - * 3x3 TreeTent puzzle with a tent at (1,1) - * Tests FinishWithGrassDirectRule on GRASS tiles surrounding the tent - * at (1,0), (0,1), (2,1), and (1,2) - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tent at (1, 1) XGX x GTG 1 XGX x x1x + * + *

Makes (1, 0), (0, 1), (2, 1), and (1, 2) GRASS Checks if the rule correctly allows the + * central row and column to be filled with grass. */ @Test public void MiddleTentTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/MiddleTent", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithGrassDirectRule/MiddleTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -257,14 +266,13 @@ public void MiddleTentTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { c = board.getCell(k, i); - if (c.getLocation().equals(cell1.getLocation()) || - c.getLocation().equals(cell2.getLocation()) || - c.getLocation().equals(cell3.getLocation()) || - c.getLocation().equals(cell4.getLocation())) { + if (c.getLocation().equals(cell1.getLocation()) + || c.getLocation().equals(cell2.getLocation()) + || c.getLocation().equals(cell3.getLocation()) + || c.getLocation().equals(cell4.getLocation())) { // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } @@ -273,15 +281,17 @@ public void MiddleTentTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with missing tents - * Tests FinishWithGrassDirectRule on GRASS tiles filling the puzzle - * all GRASS tiles should fail the FinishWithGrassDirectRule - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Empty GGG 1 GGG 1 GGG 1 111 + * + *

Fill Board with GRASS Checks if the rule is not valid when a row or column does not have + * the required number of tents but is filled with grass */ @Test public void FailTentTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/FailTent", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithGrassDirectRule/FailTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -312,16 +322,20 @@ public void FailTentTest() throws InvalidFileFormatException { Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } + /** - * 7x7 TreeTent puzzle with multiple tents spaced out - * Tests FinishWithGrassDirectRule on GRASS tiles between the tents - * at (0,3), (2,3), (4,3), and (6,3) - * - * @throws InvalidFileFormatException + * 7x7 TreeTent puzzle Tests FinishWithGrassDirectRule + * + *

Tents at (1, 3), (3, 3), and (5, 3) XXXXXXX x XXXXXXX x XXXXXXX x TGTGTGT 4 XXXXXXX x + * XXXXXXX x XXXXXXX x xxxxxxx + * + *

Makes (0, 3), (2, 3), (4, 3), and (6, 3) GRASS Checks if applying the rule on row 3 is + * valid */ @Test public void SpacedOutTentTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithGrassDirectRule/SpacedOutTent", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithGrassDirectRule/SpacedOutTent", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -353,18 +367,17 @@ public void SpacedOutTentTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { c = board.getCell(k, i); - if (c.getLocation().equals(cell1.getLocation()) || - c.getLocation().equals(cell2.getLocation()) || - c.getLocation().equals(cell3.getLocation()) || - c.getLocation().equals(cell4.getLocation())) { + if (c.getLocation().equals(cell1.getLocation()) + || c.getLocation().equals(cell2.getLocation()) + || c.getLocation().equals(cell3.getLocation()) + || c.getLocation().equals(cell4.getLocation())) { // logically follows Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { // does not use the rule to logically follow Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } } } -} \ No newline at end of file +} diff --git a/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java index 725c3c9de..b72b0f556 100644 --- a/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/FinishWithTentsDirectRuleTest.java @@ -8,15 +8,14 @@ import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.rules.FinishWithTentsDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import java.util.*; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.awt.*; -import java.util.*; - public class FinishWithTentsDirectRuleTest { private static final FinishWithTentsDirectRule RULE = new FinishWithTentsDirectRule(); @@ -27,17 +26,19 @@ public static void setUp() { MockGameBoardFacade.getInstance(); treetent = new TreeTent(); } - + /** - * 3x3 TreeTent puzzle with a GRASS tile at (0,0) - * Tests FinishWithTentsDirectRule on TENT tiles horizontal of the GRASS tile - * at (1,0) and (2,0) - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Grass at (0, 0) GTT 2 XXX x XXX x xxx + * + *

Makes (1, 0) and (2, 0) TENT Checks that the rule correctly fills in the first row */ @Test public void FinishWithHorizontalTentsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithHorizontalTents", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithHorizontalTents", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -57,10 +58,10 @@ public void FinishWithHorizontalTentsTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { TreeTentCell c = board.getCell(k, i); - if ((c.getLocation()).equals(cell1.getLocation()) || (c.getLocation()).equals(cell2.getLocation())) { + if ((c.getLocation()).equals(cell1.getLocation()) + || (c.getLocation()).equals(cell2.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } @@ -68,15 +69,17 @@ public void FinishWithHorizontalTentsTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with a GRASS tile at (0,0) - * Tests FinishWithTentsDirectRule on TENT tiles vertical of the GRASS tile - * at (0,1) and (0,2) - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Grass at (0, 0) GXX x TXX x TXX x 2xx + * + *

Makes (0, 1) and (0, 2) TENT Checks that the rule correctly fills in the first column */ @Test public void FinishWithVerticalTentsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithVerticalTents", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithVerticalTents", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -96,10 +99,10 @@ public void FinishWithVerticalTentsTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { TreeTentCell c = board.getCell(k, i); - if ((c.getLocation()).equals(cell1.getLocation()) || (c.getLocation()).equals(cell2.getLocation())) { + if ((c.getLocation()).equals(cell1.getLocation()) + || (c.getLocation()).equals(cell2.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } @@ -107,15 +110,17 @@ public void FinishWithVerticalTentsTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with a GRASS tile at (1,1) - * Tests FinishWithTentsDirectRule on TENT tiles around the GRASS tile - * at (1,0), (1,2), (0,1), and (2,1) - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Grass at (0, 0) GTT 2 TXX x TXX x 2xx + * + *

Makes (1, 0), (2, 0), (0, 1) and (0, 2) TENT Checks that the rule correctly fills both the + * first row and first column */ @Test public void FinishWithTentsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTents", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -126,7 +131,7 @@ public void FinishWithTentsTest() throws InvalidFileFormatException { TreeTentCell cell2 = board.getCell(1, 2); TreeTentCell cell3 = board.getCell(0, 1); TreeTentCell cell4 = board.getCell(2, 1); - + cell1.setData(TreeTentType.TENT); cell2.setData(TreeTentType.TENT); cell3.setData(TreeTentType.TENT); @@ -142,13 +147,12 @@ public void FinishWithTentsTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { TreeTentCell c = board.getCell(k, i); - if ((c.getLocation()).equals(cell1.getLocation()) || - (c.getLocation()).equals(cell2.getLocation()) || - (c.getLocation()).equals(cell3.getLocation()) || - (c.getLocation()).equals(cell4.getLocation())) { + if ((c.getLocation()).equals(cell1.getLocation()) + || (c.getLocation()).equals(cell2.getLocation()) + || (c.getLocation()).equals(cell3.getLocation()) + || (c.getLocation()).equals(cell4.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } @@ -156,15 +160,17 @@ public void FinishWithTentsTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with a TENT tile at (1,1) - * Tests FinishWithTentsDirectRule on TENT tiles around the TENT tile - * at (1,0), (1,2), (0,1), and (2,1) - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Tent at (1, 1) XTX x TTT 3 XTX x x3x + * + *

Makes (1, 0), (0, 1), (2, 1), and (1, 2) TENT Checks that the rule correctly fills in the + * middle row and column when a tent starts at (1, 1) */ @Test public void AdditionalTentsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/AdditionalTents", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithTentsDirectRule/AdditionalTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -191,13 +197,12 @@ public void AdditionalTentsTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { TreeTentCell c = board.getCell(k, i); - if ((c.getLocation()).equals(cell1.getLocation()) || - (c.getLocation()).equals(cell2.getLocation()) || - (c.getLocation()).equals(cell3.getLocation()) || - (c.getLocation()).equals(cell4.getLocation())) { + if ((c.getLocation()).equals(cell1.getLocation()) + || (c.getLocation()).equals(cell2.getLocation()) + || (c.getLocation()).equals(cell3.getLocation()) + || (c.getLocation()).equals(cell4.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, c)); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, c)); } } @@ -205,16 +210,17 @@ public void AdditionalTentsTest() throws InvalidFileFormatException { } /** - * Empty 3x3 TreeTent puzzle - * Tests FinishWithTentsDirectRule on TENT tiles of entire puzzle - * all TENT tiles should fail FinishWithTentsDirectRule - * as no TENT tiles should be there - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Empty TTT 0 TTT 0 TTT 0 000 + * + *

Fills the board with tents Checks that the rule does not allow for more tents in any of + * the rows or columns */ @Test public void FinishWithTentsFailTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsFail", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithTentsDirectRule/FinishWithTentsFail", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -242,17 +248,17 @@ public void FinishWithTentsFailTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with a TENT tile at (1,1) - * Tests FinishWithTentsDirectRule on TENT tiles around the TENT tile - * at (1,0), (1,2), (0,1), and (2,1) - * all TENT tiles should fail FinishWithTentsDirectRule - * as there were already sufficient number of TENT tiles - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Tent at (1, 1) XTX x TTT 1 XTX x x1x + * + *

Makes (1, 0), (0, 1), (2, 1) and (1, 2) Tent Checks that the rule does not allow for more + * tents in the central row or central column */ @Test public void TooManyTentsTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/TooManyTents", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithTentsDirectRule/TooManyTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -263,7 +269,7 @@ public void TooManyTentsTest() throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { - if((k == 1)&&(i == 1)) { + if ((k == 1) && (i == 1)) { continue; } TreeTentCell c = board.getCell(k, i); @@ -283,18 +289,17 @@ public void TooManyTentsTest() throws InvalidFileFormatException { } /** - * 3x3 TreeTent puzzle with a TENT tile at (1,1) - * Tests FinishWithTentsDirectRule on TENT tiles around the TENT tile - * at (1,0), (1,2), (0,1), and (2,1) - * all TENT tiles should fail FinishWithTentsDirectRule - * as there are multiple configurations of the placement - * of the TENT tiles - * - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests FinishWithTentsDirectRule + * + *

Tent at (1, 1) XTX x TTT 2 XTX x x2x + * + *

Makes (1, 0), (0, 1), (2, 1) and (1, 2) Tent Checks that the rule is not satisfied because + * there are multiple configurations of tents for the central row and central column */ @Test - public void AmbiguousTentsTest () throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/FinishWithTentsDirectRule/AmbiguousTents", treetent); + public void AmbiguousTentsTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/FinishWithTentsDirectRule/AmbiguousTents", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -309,7 +314,7 @@ public void AmbiguousTentsTest () throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -323,7 +328,7 @@ public void AmbiguousTentsTest () throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -337,7 +342,7 @@ public void AmbiguousTentsTest () throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -351,11 +356,8 @@ public void AmbiguousTentsTest () throws InvalidFileFormatException { for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } } } - - - diff --git a/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java index 3e1b390fb..fdd55029f 100644 --- a/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/LastCampingSpotDirectRuleTest.java @@ -8,14 +8,13 @@ import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.rules.LastCampingSpotDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.awt.*; - public class LastCampingSpotDirectRuleTest { private static final LastCampingSpotDirectRule RULE = new LastCampingSpotDirectRule(); @@ -28,13 +27,16 @@ public static void setUp() { } /** - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule + * + *

TREE at (1, 1) and (0, 1); GRASS at (1, 2) and (2, 1) XTX RRG XGX * - * Checks if a test works for an empty square above a tree which is surrounded on all other sides. + *

Makes (1, 0) TENT Checks that a tent must be placed above the central tree */ @Test public void EmptyFieldTest_Up() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotUp", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotUp", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -53,8 +55,7 @@ public void EmptyFieldTest_Up() throws InvalidFileFormatException { Point point = new Point(k, i); if (point.equals(cell1.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -62,13 +63,16 @@ public void EmptyFieldTest_Up() throws InvalidFileFormatException { } /** - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule + * + *

TREE at (1, 1) and (0, 1); GRASS at (1, 0) and (1, 2) XGX RRG XTX * - * Checks if a test works for an empty square below a tree which is surrounded on all other sides. + *

Makes (1, 2) TENT Checks that a tent must be placed below the central tree */ @Test public void EmptyFieldTest_Down() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotDown", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotDown", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -87,8 +91,7 @@ public void EmptyFieldTest_Down() throws InvalidFileFormatException { Point point = new Point(k, i); if (point.equals(cell1.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -96,13 +99,16 @@ public void EmptyFieldTest_Down() throws InvalidFileFormatException { } /** - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule * - * Checks if a test works for an empty square to the left of a tree which is surrounded on all other sides. + *

TREE at (1, 1) and (2, 1); GRASS at (1, 0) and (1, 2) XGX TRR XGX + * + *

Makes (0, 1) TENT Checks that a tent must be placed on the left of the central tree */ @Test public void EmptyFieldTest_Left() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotLeft", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotLeft", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -121,8 +127,7 @@ public void EmptyFieldTest_Left() throws InvalidFileFormatException { Point point = new Point(k, i); if (point.equals(cell1.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -130,13 +135,16 @@ public void EmptyFieldTest_Left() throws InvalidFileFormatException { } /** - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests LastCampingSpotDirectRule * - * Checks if a test works for an empty square to the right of a tree which is surrounded on all other sides. + *

TREE at (1, 1) and (1, 2); GRASS at (0, 1) and (1, 0) XGX GRT XRX + * + *

Makes (2, 1) TENT Checks that a tent must be placed to the right of the central tree */ @Test public void EmptyFieldTest_Right() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotRight", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/LastCampingSpotDirectRule/LastCampingSpotRight", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -155,14 +163,10 @@ public void EmptyFieldTest_Right() throws InvalidFileFormatException { Point point = new Point(k, i); if (point.equals(cell1.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } } } } - - - diff --git a/src/test/java/puzzles/treetent/rules/LinkTentCaseRuleTest.java b/src/test/java/puzzles/treetent/rules/LinkTentCaseRuleTest.java new file mode 100644 index 000000000..ed482eba0 --- /dev/null +++ b/src/test/java/puzzles/treetent/rules/LinkTentCaseRuleTest.java @@ -0,0 +1,184 @@ +package puzzles.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.*; +import edu.rpi.legup.puzzle.treetent.rules.LinkTentCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LinkTentCaseRuleTest { + private static final LinkTentCaseRule RULE = new LinkTentCaseRule(); + private static TreeTent treetent; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + treetent = new TreeTent(); + } + + /** + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent with one tree surrounding + * it. + * + *

checks that 1 cases is with the line connecting the central tent and the tree + * + * @throws InvalidFileFormatException + */ + @Test + public void LinkTentOneTreeTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/LinkTentCaseRule/OneTreeOneTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell test_location = board.getCell(1, 1); + ArrayList cases = RULE.getCases(board, test_location); + + // assert that one cases was found + Assert.assertEquals(1, cases.size()); + TreeTentBoard testCase = (TreeTentBoard) cases.getFirst(); + + TreeTentLine expectedLine = new TreeTentLine(board.getCell(1, 1), board.getCell(1, 0)); + + ArrayList lines = testCase.getLines(); + + // One line connecting the tree to the tent + Assert.assertEquals(1, lines.size()); + TreeTentLine line = lines.getFirst(); + + // Expected line + Assert.assertTrue(line.compare(expectedLine)); + + // checks other cells have not been modified + TreeTentCell original_cell; + TreeTentCell case_cell; + + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + original_cell = board.getCell(w, h); + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + + /** + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent with four trees + * surrounding it. + * + *

checks that 4 cases are created, each of which create a line connecting the tent to one of + * the four trees without repeat. + * + * @throws InvalidFileFormatException + */ + @Test + public void LinkTentFourTreesTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/LinkTentCaseRule/FourTreesOneTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell test_location = board.getCell(1, 1); + ArrayList cases = RULE.getCases(board, test_location); + + // assert that four cases were found + Assert.assertEquals(4, cases.size()); + + ArrayList expectedLines = new ArrayList<>(); + expectedLines.addFirst(new TreeTentLine(board.getCell(1, 1), board.getCell(1, 0))); + expectedLines.addFirst(new TreeTentLine(board.getCell(1, 1), board.getCell(0, 1))); + expectedLines.addFirst(new TreeTentLine(board.getCell(1, 1), board.getCell(2, 1))); + expectedLines.addFirst(new TreeTentLine(board.getCell(1, 1), board.getCell(1, 2))); + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + ArrayList lines = testCase.getLines(); + + // Each case should connect one line from the tent to + // one of the four trees next to it + Assert.assertEquals(1, lines.size()); + TreeTentLine line = lines.getFirst(); + + // Check to make sure that cases do not repeat + // and cover all four possibilities + boolean exists = false; + for (TreeTentLine expectedLine : expectedLines) { + if (line.compare(expectedLine)) { + expectedLines.remove(expectedLine); + exists = true; + break; + } + } + + Assert.assertTrue(exists); + + // checks other cells have not been modified + TreeTentCell original_cell; + TreeTentCell case_cell; + + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + original_cell = board.getCell(w, h); + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + } + + /** + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent with zero trees around it. + * + *

Ensures no cases are created + * + * @throws InvalidFileFormatException + */ + @Test + public void LinkTentNoTreesTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTentCaseRule/NoTrees", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell test_location = board.getCell(1, 1); + ArrayList cases = RULE.getCases(board, test_location); + + // assert that no cases were found + Assert.assertEquals(0, cases.size()); + } + + /** + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tent with trees on a diagonal. + * + *

Ensures no cases are created + * + * @throws InvalidFileFormatException + */ + @Test + public void LinkTentDiagTreesTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/LinkTentCaseRule/DiagTrees", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell test_location = board.getCell(1, 1); + ArrayList cases = RULE.getCases(board, test_location); + + // assert that no cases were found + Assert.assertEquals(0, cases.size()); + } +} diff --git a/src/test/java/puzzles/treetent/rules/LinkTreeCaseRuleTest.java b/src/test/java/puzzles/treetent/rules/LinkTreeCaseRuleTest.java new file mode 100644 index 000000000..be237e8d4 --- /dev/null +++ b/src/test/java/puzzles/treetent/rules/LinkTreeCaseRuleTest.java @@ -0,0 +1,182 @@ +package puzzles.treetent.rules; + +import edu.rpi.legup.model.gameboard.Board; +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTent; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.rules.LinkTreeCaseRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class LinkTreeCaseRuleTest { + private static final LinkTreeCaseRule RULE = new LinkTreeCaseRule(); + private static TreeTent treetent; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + treetent = new TreeTent(); + } + + /** + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree with one tent above + * + *

Ensures one case is created that connects the tree to the tent. + * + * @throws InvalidFileFormatException + */ + @Test + public void LinkTentOneTentTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTreeCaseRule/OneTent", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell test_location = board.getCell(1, 1); + ArrayList cases = RULE.getCases(board, test_location); + + // assert that no cases were found + Assert.assertEquals(1, cases.size()); + TreeTentBoard testCase = (TreeTentBoard) cases.getFirst(); + + TreeTentLine expectedLine = new TreeTentLine(board.getCell(1, 1), board.getCell(1, 0)); + + ArrayList lines = testCase.getLines(); + + // One line connecting the tree to the tent + Assert.assertEquals(1, lines.size()); + TreeTentLine line = lines.getFirst(); + + // Expected line + Assert.assertTrue(line.compare(expectedLine)); + + // checks other cells have not been modified + TreeTentCell original_cell; + TreeTentCell case_cell; + + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + original_cell = board.getCell(w, h); + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + + /** + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree with two tents, one on the + * left and one on the right. + * + *

Ensures two cases are created, one connecting the tree and the left tent, and one + * connecting the tree and the right tent. Because tents must be surrounded by grass, there can + * be at most two tents around a given tree. + * + * @throws InvalidFileFormatException + */ + @Test + public void LinkTentTwoTentsTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTreeCaseRule/TwoTents", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell test_location = board.getCell(1, 1); + ArrayList cases = RULE.getCases(board, test_location); + + // assert that no cases were found + Assert.assertEquals(2, cases.size()); + + ArrayList expectedLines = new ArrayList<>(); + expectedLines.addFirst(new TreeTentLine(board.getCell(1, 1), board.getCell(0, 1))); + expectedLines.addFirst(new TreeTentLine(board.getCell(1, 1), board.getCell(2, 1))); + + for (Board testCaseBoard : cases) { + TreeTentBoard testCase = (TreeTentBoard) testCaseBoard; + ArrayList lines = testCase.getLines(); + + // Each case should connect one line from the tent to + // either the left or right tree + Assert.assertEquals(1, lines.size()); + TreeTentLine line = lines.getFirst(); + + // Check to make sure that cases do not repeat + // and cover both possibilities + boolean exists = false; + for (TreeTentLine expectedLine : expectedLines) { + if (line.compare(expectedLine)) { + expectedLines.remove(expectedLine); + exists = true; + break; + } + } + + Assert.assertTrue(exists); + + // checks other cells have not been modified + TreeTentCell original_cell; + TreeTentCell case_cell; + + for (int w = 0; w < board.getWidth(); w++) { + for (int h = 0; h < board.getHeight(); h++) { + original_cell = board.getCell(w, h); + case_cell = testCase.getCell(w, h); + Assert.assertEquals(original_cell.getType(), case_cell.getType()); + } + } + } + } + + /** + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree with zero tents around it. + * + *

Ensures no cases are created + * + * @throws InvalidFileFormatException + */ + @Test + public void LinkTentNoTreesTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTreeCaseRule/NoTents", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell test_location = board.getCell(1, 1); + ArrayList cases = RULE.getCases(board, test_location); + + // assert that no cases were found + Assert.assertEquals(0, cases.size()); + } + + /** + * empty 3x3 TreeTent puzzle Tests LinkTentCaseRule on a central tree with tents on a diagonal. + * + *

Ensures no cases are created + * + * @throws InvalidFileFormatException + */ + @Test + public void LinkTentDiagTentsTest() throws InvalidFileFormatException { + TestUtilities.importTestBoard("puzzles/treetent/rules/LinkTreeCaseRule/NoTents", treetent); + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell test_location = board.getCell(1, 1); + ArrayList cases = RULE.getCases(board, test_location); + + // assert that no cases were found + Assert.assertEquals(0, cases.size()); + } +} diff --git a/src/test/java/puzzles/treetent/rules/NoTentForTreeContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/NoTentForTreeContradictionRuleTest.java index 52aea28c0..b17c92486 100644 --- a/src/test/java/puzzles/treetent/rules/NoTentForTreeContradictionRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/NoTentForTreeContradictionRuleTest.java @@ -1,21 +1,17 @@ package puzzles.treetent.rules; -import legup.MockGameBoardFacade; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - import edu.rpi.legup.puzzle.treetent.TreeTent; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.rules.NoTentForTreeContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; - import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class NoTentForTreeContradictionRuleTest { @@ -29,12 +25,13 @@ public static void setUp() { } /** - * @throws InvalidFileFormatException - * Tests if a tree is next to only grass in a 2x2 grid triggers the contradiction + * @throws InvalidFileFormatException Tests if a tree is next to only grass in a 2x2 grid + * triggers the contradiction */ @Test public void NoTentForTreeContradictionRule_Basic() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTree", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTree", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -49,12 +46,14 @@ public void NoTentForTreeContradictionRule_Basic() throws InvalidFileFormatExcep } /** - * @throws InvalidFileFormatException - * Tests similarly to above, but now with a tent diagonally next to the tree, which should still contradict + * @throws InvalidFileFormatException Tests similarly to above, but now with a tent diagonally + * next to the tree, which should still contradict */ @Test public void NoTentForTreeContradictionRule_Diagonal() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeDiagonal", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeDiagonal", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -69,12 +68,13 @@ public void NoTentForTreeContradictionRule_Diagonal() throws InvalidFileFormatEx } /** - * @throws InvalidFileFormatException - * Tests that adjacent trees do not allow a pass + * @throws InvalidFileFormatException Tests that adjacent trees do not allow a pass */ @Test public void NoTentForTreeContradictionRule_TwoTrees() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTrees", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTrees", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -89,12 +89,15 @@ public void NoTentForTreeContradictionRule_TwoTrees() throws InvalidFileFormatEx } /** - * @throws InvalidFileFormatException - * Tests similarly to above, but now with a tent diagonally next to two trees, which should still contradict on one. + * @throws InvalidFileFormatException Tests similarly to above, but now with a tent diagonally + * next to two trees, which should still contradict on one. */ @Test - public void NoTentForTreeContradictionRule_TwoTreesDiagonal() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTreesDiagonal", treetent); + public void NoTentForTreeContradictionRule_TwoTreesDiagonal() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTentForTreeContradictionRule/NoTentForTreeTwoTreesDiagonal", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -108,4 +111,3 @@ public void NoTentForTreeContradictionRule_TwoTreesDiagonal() throws InvalidFile Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); } } - diff --git a/src/test/java/puzzles/treetent/rules/NoTreeForTentContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/NoTreeForTentContradictionRuleTest.java index 2ad2ac90e..fd6be92de 100644 --- a/src/test/java/puzzles/treetent/rules/NoTreeForTentContradictionRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/NoTreeForTentContradictionRuleTest.java @@ -1,17 +1,16 @@ package puzzles.treetent.rules; -import legup.MockGameBoardFacade; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - import edu.rpi.legup.puzzle.treetent.TreeTent; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.rules.NoTreeForTentContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class NoTreeForTentContradictionRuleTest { @@ -25,12 +24,13 @@ public static void setUp() { } /** - * @throws InvalidFileFormatException - * Tests if, in a 2x2 Grid, a Tent in the NW corner has no adjacent trees + * @throws InvalidFileFormatException Tests if, in a 2x2 Grid, a Tent in the NW corner has no + * adjacent trees */ @Test public void NoTreeForTentContradictionRule_NW() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNW", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNW", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -45,12 +45,13 @@ public void NoTreeForTentContradictionRule_NW() throws InvalidFileFormatExceptio } /** - * @throws InvalidFileFormatException - * Tests if, in a 2x2 Grid, a Tent in the NE corner has no adjacent trees + * @throws InvalidFileFormatException Tests if, in a 2x2 Grid, a Tent in the NE corner has no + * adjacent trees */ @Test public void NoTreeForTentContradictionRule_NE() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNE", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentNE", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -65,12 +66,13 @@ public void NoTreeForTentContradictionRule_NE() throws InvalidFileFormatExceptio } /** - * @throws InvalidFileFormatException - * Tests if, in a 2x2 Grid, a Tent in the NW corner has no adjacent trees + * @throws InvalidFileFormatException Tests if, in a 2x2 Grid, a Tent in the NW corner has no + * adjacent trees */ @Test public void NoTreeForTentContradictionRule_SW() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSW", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSW", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -85,12 +87,13 @@ public void NoTreeForTentContradictionRule_SW() throws InvalidFileFormatExceptio } /** - * @throws InvalidFileFormatException - * Tests if, in a 2x2 Grid, a Tent in the SE corner has no adjacent trees + * @throws InvalidFileFormatException Tests if, in a 2x2 Grid, a Tent in the SE corner has no + * adjacent trees */ @Test public void NoTreeForTentContradictionRule_SE() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSE", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentSE", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -105,12 +108,13 @@ public void NoTreeForTentContradictionRule_SE() throws InvalidFileFormatExceptio } /** - * @throws InvalidFileFormatException - * Tests if, in a 3x3 Grid with no trees, a Tent in the center cell has no adjacent trees + * @throws InvalidFileFormatException Tests if, in a 3x3 Grid with no trees, a Tent in the + * center cell has no adjacent trees */ @Test - public void NoTreeForTentContradictionRule_3x3() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent3x3", treetent); + public void NoTreeForTentContradictionRule_3x3() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTent3x3", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -130,12 +134,15 @@ public void NoTreeForTentContradictionRule_3x3() throws InvalidFileFormatExcepti } /** - * @throws InvalidFileFormatException - * Tests if, in a 3x3 Grid with diagonal trees, a Tent in the center cell has no adjacent trees + * @throws InvalidFileFormatException Tests if, in a 3x3 Grid with diagonal trees, a Tent in the + * center cell has no adjacent trees */ @Test - public void NoTreeForTentContradictionRule_3x3WithDiagonalTrees() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentDiagonals", treetent); + public void NoTreeForTentContradictionRule_3x3WithDiagonalTrees() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentDiagonals", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -155,12 +162,14 @@ public void NoTreeForTentContradictionRule_3x3WithDiagonalTrees() throws Invalid } /** - * @throws InvalidFileFormatException - * Tests if, in a 3x3 Grid with an adjacent tree, test does not assert null. + * @throws InvalidFileFormatException Tests if, in a 3x3 Grid with an adjacent tree, test does + * not assert null. */ @Test - public void NoTreeForTentContradictionRule_YesTree() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentYesTree", treetent); + public void NoTreeForTentContradictionRule_YesTree() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentYesTree", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -180,12 +189,14 @@ public void NoTreeForTentContradictionRule_YesTree() throws InvalidFileFormatExc } /** - * @throws InvalidFileFormatException - * Tests if, in a 3x3 Grid with touching tents, a Tent in the center cell has no adjacent trees + * @throws InvalidFileFormatException Tests if, in a 3x3 Grid with touching tents, a Tent in the + * center cell has no adjacent trees */ @Test - public void NoTreeForTentContradictionRule_JustTent() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentJustTent", treetent); + public void NoTreeForTentContradictionRule_JustTent() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/NoTreeForTentContradictionRule/NoTreeForTentJustTent", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -204,4 +215,3 @@ public void NoTreeForTentContradictionRule_JustTent() throws InvalidFileFormatEx Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(2, 2))); } } - diff --git a/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java index 999405747..dc61cb863 100644 --- a/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/SurroundTentWithGrassDirectRuleTest.java @@ -8,17 +8,17 @@ import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.rules.SurroundTentWithGrassDirectRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.awt.*; - public class SurroundTentWithGrassDirectRuleTest { - private static final SurroundTentWithGrassDirectRule RULE = new SurroundTentWithGrassDirectRule(); + private static final SurroundTentWithGrassDirectRule RULE = + new SurroundTentWithGrassDirectRule(); private static TreeTent treetent; @BeforeClass @@ -28,12 +28,18 @@ public static void setUp() { } /** - * @throws InvalidFileFormatException - * Test to check if all adjacent and diagonals not filled with a tree are filled with grass + * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule + * + *

TREE at (0, 0), (2, 0), (0, 1), (2, 1), (1, 2), and (2, 2); TENT at (1, 1) RGR RTR GRR + * + *

Makes (1, 0) and (0, 2) GRASS Checks that the rule detects unknown adjacent and diagonal + * tiles correctly */ @Test public void SurroundTentWithGrassBasicRuleTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrass", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrass", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -55,8 +61,7 @@ public void SurroundTentWithGrassBasicRuleTest() throws InvalidFileFormatExcepti Point point = new Point(k, i); if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -64,14 +69,18 @@ public void SurroundTentWithGrassBasicRuleTest() throws InvalidFileFormatExcepti } /** - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule + * + *

TENT at (1, 1) GGG GTG GGG * - * Test with a 3x3 board with an absolutely empty area aside from a tent in the middle - * While such a situation is an illegal treetent setup, this direct rule doesn't consider that aspect, so its ok in this context + *

Makes all cells adjacent and diagonal to the tent GRASS Checks that the rule detects all + * adjacent and diagonal tiles correctly */ @Test public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassBad", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassBad", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -86,7 +95,7 @@ public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileForm cell3.setData(TreeTentType.GRASS); TreeTentCell cell4 = board.getCell(0, 1); cell4.setData(TreeTentType.GRASS); - //Skip (1,1) due to being the Tent + // Skip (1,1) due to being the Tent TreeTentCell cell5 = board.getCell(2, 1); cell5.setData(TreeTentType.GRASS); TreeTentCell cell6 = board.getCell(0, 2); @@ -99,7 +108,7 @@ public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileForm board.addModifiedData(cell1); board.addModifiedData(cell2); board.addModifiedData(cell3); - //board.addModifiedData(cell4); + // board.addModifiedData(cell4); board.addModifiedData(cell5); board.addModifiedData(cell6); board.addModifiedData(cell7); @@ -110,14 +119,16 @@ public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileForm for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || //point.equals(cell4.getLocation()) || - point.equals(cell5.getLocation()) || point.equals(cell6.getLocation()) || - point.equals(cell7.getLocation()) || point.equals(cell8.getLocation()) - ) { + if (point.equals(cell1.getLocation()) + || point.equals(cell2.getLocation()) + || point.equals(cell3.getLocation()) + || // point.equals(cell4.getLocation()) || + point.equals(cell5.getLocation()) + || point.equals(cell6.getLocation()) + || point.equals(cell7.getLocation()) + || point.equals(cell8.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -125,13 +136,17 @@ public void SurroundTentWithGrassBasicRuleTest_BadBoard() throws InvalidFileForm } /** - * @throws InvalidFileFormatException + * 3x3 TreeTent puzzle Tests SurroundTentWithGrassDirectRule + * + *

TENT at (1, 1); TREE on all adjacent and diagonal tiles RRR RTR RRR * - * Test to see if the rule passes even if no grass was able to be placed due to the presence of trees. + *

Null Checks that the rule correctly detects no missing tiles */ @Test - public void SurroundTentWithGrassBasicRuleTest_FullBoard() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassTrees", treetent); + public void SurroundTentWithGrassBasicRuleTest_FullBoard() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/SurroundTentWithGrassDirectRule/SurroundTentWithGrassTrees", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -140,13 +155,10 @@ public void SurroundTentWithGrassBasicRuleTest_FullBoard() throws InvalidFileFor Assert.assertNull(RULE.checkRule(transition)); - for (int i = 0; i < board.getHeight(); i++){ - for (int k = 0; k < board.getWidth(); k++){ + for (int i = 0; i < board.getHeight(); i++) { + for (int k = 0; k < board.getWidth(); k++) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } } } - - - diff --git a/src/test/java/puzzles/treetent/rules/TentForTreeDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/TentForTreeDirectRuleTest.java index 33f37910c..6bd2db071 100644 --- a/src/test/java/puzzles/treetent/rules/TentForTreeDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/TentForTreeDirectRuleTest.java @@ -1,17 +1,158 @@ package puzzles.treetent.rules; -// This feature is no longer supported +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.*; +import edu.rpi.legup.puzzle.treetent.rules.TentForTreeDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + public class TentForTreeDirectRuleTest { -// private static final TentForTreeBasicRule RULE = new TentForTreeBasicRule(); -// private static TreeTent treetent; -// -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// treetent = new TreeTent(); -// } -} + private static final TentForTreeDirectRule RULE = new TentForTreeDirectRule(); + private static TreeTent treetent; + + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + treetent = new TreeTent(); + } + + /** + * 3x3 TreeTent puzzle Tests TentForTreeDirectRule + * + *

TREE at (1, 0); TENT at (1, 1) XRX XTX XXX + * + *

Makes a line between (1, 0) and (1, 1) Checks that the rule correctly detects the central + * tent as the only possible connection + */ + @Test + public void TentForTreeTestOneTreeOneTentTest() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TentForTreeDirectRule/OneTreeOneTent", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + TreeTentCell cell1 = board.getCell(1, 0); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + + board.addModifiedData(line); + board.getLines().add(line); + + Assert.assertNull(RULE.checkRule(transition)); + + ArrayList lines = board.getLines(); + for (TreeTentLine l : lines) { + if (l.compare((line))) { + Assert.assertNull(RULE.checkRuleAt(transition, l)); + } else { + Assert.assertNotNull(RULE.checkRuleAt(transition, l)); + } + } + } + + /** + * 3x3 TreeTent puzzle Tests TentForTreeDirectRule + * + *

TREE at (1, 0) and (1, 2); TENT at (1, 1) XRX XTX XRX + * + *

Makes a line between (1, 0) and (1, 1) Checks that the rule works when connecting a line + * between the tree at (1, 0) and tent at (1, 1) + */ + @Test + public void TentForTreeArbitraryTreeTest() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + TreeTentCell cell1 = board.getCell(1, 0); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + board.addModifiedData(line); + board.getLines().add(line); + Assert.assertNull(RULE.checkRule(transition)); + } + + /** + * 3x3 TreeTent puzzle Tests TentForTreeDirectRule + * + *

TREE at (1, 0) and (1, 2); TENT at (1, 1); LINE between (1, 0) and (1, 1) XRX XTX XRX + * + *

Makes a line between (1, 1) and (1, 2) Checks that the rule fails for the tree at (1, 2) + * because there are no valid tents to connect to + */ + @Test + public void TentForTreeConnectedTent() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + TreeTentCell cell1 = board.getCell(1, 2); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + + board.addModifiedData(line); + board.getLines().add(line); + + Assert.assertNull(RULE.checkRule(transition)); + + ArrayList lines = board.getLines(); + for (TreeTentLine l : lines) { + Assert.assertNotNull(RULE.checkRuleAt(transition, l)); + } + } + + /** + * 3x3 TreeTent puzzle Tests TentForTreeDirectRule + * + *

TREE at (1, 1); TENT at (1, 0) and (1, 2) XTX XRX XTX + * + *

Makes a line between (1, 1) and (1, 2) Checks that the rule fails for the tree at (1, 1) + * because there are two valid tents to connect to + */ + @Test + public void TentForTreeOneTreeTwoAdjacentTent() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TentForTreeDirectRule/OneTreeTwoAdjacentTent", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + TreeTentCell cell1 = board.getCell(1, 2); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + + board.addModifiedData(line); + board.getLines().add(line); + + Assert.assertNotNull(RULE.checkRule(transition)); + } +} diff --git a/src/test/java/puzzles/treetent/rules/TentOrGrassCaseRuleTest.java b/src/test/java/puzzles/treetent/rules/TentOrGrassCaseRuleTest.java index 4ec8b4e36..1fe7e4bd0 100644 --- a/src/test/java/puzzles/treetent/rules/TentOrGrassCaseRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/TentOrGrassCaseRuleTest.java @@ -9,19 +9,18 @@ import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.rules.TentOrGrassCaseRule; import edu.rpi.legup.save.InvalidFileFormatException; +import java.awt.*; +import java.util.ArrayList; import legup.MockGameBoardFacade; import legup.TestUtilities; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import java.awt.*; -import java.util.ArrayList; - public class TentOrGrassCaseRuleTest { private static final TentOrGrassCaseRule RULE = new TentOrGrassCaseRule(); private static TreeTent treetent; - + @BeforeClass public static void setUp() { MockGameBoardFacade.getInstance(); @@ -29,20 +28,17 @@ public static void setUp() { } /** - * empty 3x3 TreeTent puzzle - * Tests TentOrGrassCaseRule on UNKOWN tile - * at (0,0) - * - * checks 2 cases are created - * checks first case is TENT tile - * checks second case is GRASS tile + * empty 3x3 TreeTent puzzle Tests TentOrGrassCaseRule on UNKOWN tile at (0,0) + * + *

checks 2 cases are created checks first case is TENT tile checks second case is GRASS tile * checks other cells have not been modified - * + * * @throws InvalidFileFormatException */ @Test public void TentOrTreeTest() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TentOrGrassCaseRule/TestPuzzle", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TentOrGrassCaseRule/TestPuzzle", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -66,9 +62,9 @@ public void TentOrTreeTest() throws InvalidFileFormatException { TreeTentCell original_cell; TreeTentCell case_cell; - for (int w =0; w < board.getWidth(); w++) { + for (int w = 0; w < board.getWidth(); w++) { for (int h = 0; h < board.getHeight(); h++) { - if (w == 0 && h ==0) { + if (w == 0 && h == 0) { continue; } original_cell = board.getCell(w, h); diff --git a/src/test/java/puzzles/treetent/rules/TooFewTentsContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/TooFewTentsContradictionRuleTest.java index a5999dc6e..e1773827d 100644 --- a/src/test/java/puzzles/treetent/rules/TooFewTentsContradictionRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/TooFewTentsContradictionRuleTest.java @@ -1,20 +1,18 @@ package puzzles.treetent.rules; -import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import legup.MockGameBoardFacade; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - import edu.rpi.legup.puzzle.treetent.TreeTent; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; import edu.rpi.legup.puzzle.treetent.rules.TooFewTentsContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; - import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class TooFewTentsContradictionRuleTest { @@ -28,12 +26,13 @@ public static void setUp() { } /** - * @throws InvalidFileFormatException - * Using a 1x1 Puzzle Grid, which is just grass, checks if the fact it expects a tent on the y-axis is caught. + * @throws InvalidFileFormatException Using a 1x1 Puzzle Grid, which is just grass, checks if + * the fact it expects a tent on the y-axis is caught. */ @Test public void TooFewTentsContradictionRule_JustY() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsJustY", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsJustY", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -44,13 +43,15 @@ public void TooFewTentsContradictionRule_JustY() throws InvalidFileFormatExcepti } /** - * @throws InvalidFileFormatException - * Using a 1x1 Puzzle Grid, which is just a tent, checks if the fact it expects 2 tents on the y-axis is caught. - * (This is an impossible situation given the constraints, but for the purposes of the test it is fine) + * @throws InvalidFileFormatException Using a 1x1 Puzzle Grid, which is just a tent, checks if + * the fact it expects 2 tents on the y-axis is caught. (This is an impossible situation + * given the constraints, but for the purposes of the test it is fine) */ @Test public void TooFewTentsContradictionRule_WithTent() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsWithTent", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsWithTent", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -61,12 +62,14 @@ public void TooFewTentsContradictionRule_WithTent() throws InvalidFileFormatExce } /** - * @throws InvalidFileFormatException - * Using a 1x1 Puzzle Grid, which is just grass, checks if the fact it expects a tent on both x and y is caught. + * @throws InvalidFileFormatException Using a 1x1 Puzzle Grid, which is just grass, checks if + * the fact it expects a tent on both x and y is caught. */ @Test public void TooFewTentsContradictionRule_DoubleBad() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsDoubleBad", treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsDoubleBad", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -77,15 +80,14 @@ public void TooFewTentsContradictionRule_DoubleBad() throws InvalidFileFormatExc } /** - * @throws InvalidFileFormatException - * Looks at a 2x2 Board in the format: - * [] Tr - * [] Gr - * Column 2 is checked to have 1 Tent (which is not present, thus producing a contradiction) + * @throws InvalidFileFormatException Looks at a 2x2 Board in the format: [] Tr [] Gr Column 2 + * is checked to have 1 Tent (which is not present, thus producing a contradiction) */ @Test public void TooFewTentsContradictionRule_2x2ColumnOnly() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Column",treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Column", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -94,16 +96,15 @@ public void TooFewTentsContradictionRule_2x2ColumnOnly() throws InvalidFileForma Assert.assertNull(RULE.checkContradiction(board)); - TreeTentCell cell1 = board.getCell(1,0); - TreeTentCell cell2 = board.getCell(1,1); + TreeTentCell cell1 = board.getCell(1, 0); + TreeTentCell cell2 = board.getCell(1, 1); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Point point = new Point(k, i); if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -111,15 +112,13 @@ public void TooFewTentsContradictionRule_2x2ColumnOnly() throws InvalidFileForma } /** - * @throws InvalidFileFormatException - * Looks at a 2x2 Board in the format: - * Tr Gr - * [] [] - * Row 1 is checked to have 1 Tent (which is not present, thus producing a contradiction) + * @throws InvalidFileFormatException Looks at a 2x2 Board in the format: Tr Gr [] [] Row 1 is + * checked to have 1 Tent (which is not present, thus producing a contradiction) */ @Test public void TooFewTentsContradictionRule_2x2RowOnly() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Row",treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents2x2Row", treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -128,16 +127,15 @@ public void TooFewTentsContradictionRule_2x2RowOnly() throws InvalidFileFormatEx Assert.assertNull(RULE.checkContradiction(board)); - TreeTentCell cell1 = board.getCell(0,0); - TreeTentCell cell2 = board.getCell(1,0); + TreeTentCell cell1 = board.getCell(0, 0); + TreeTentCell cell2 = board.getCell(1, 0); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Point point = new Point(k, i); if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -145,16 +143,15 @@ public void TooFewTentsContradictionRule_2x2RowOnly() throws InvalidFileFormatEx } /** - * @throws InvalidFileFormatException - * Looks at a 3x3 Board in the format: - * [] Tr [] - * [] Gr [] - * [] Gr [] - * Column 2 is checked to have 1 Tent (which is not present, thus producing a contradiction) + * @throws InvalidFileFormatException Looks at a 3x3 Board in the format: [] Tr [] [] Gr [] [] + * Gr [] Column 2 is checked to have 1 Tent (which is not present, thus producing a + * contradiction) */ @Test public void TooFewTentsContradictionRule_3x3OneColumn() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3Column",treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3Column", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -163,17 +160,18 @@ public void TooFewTentsContradictionRule_3x3OneColumn() throws InvalidFileFormat Assert.assertNull(RULE.checkContradiction(board)); - TreeTentCell cell1 = board.getCell(1,0); - TreeTentCell cell2 = board.getCell(1,1); - TreeTentCell cell3 = board.getCell(1,2); + TreeTentCell cell1 = board.getCell(1, 0); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentCell cell3 = board.getCell(1, 2); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || point.equals(cell3.getLocation())) { + if (point.equals(cell1.getLocation()) + || point.equals(cell2.getLocation()) + || point.equals(cell3.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -181,16 +179,15 @@ public void TooFewTentsContradictionRule_3x3OneColumn() throws InvalidFileFormat } /** - * @throws InvalidFileFormatException - * Looks at a 3x3 Board in the format: - * Gr Tr Gr - * Gr [] Gr - * Gr Tr Gr - * Column 1 and 3 are checked to have 1 Tent (which is not present, thus producing a contradiction) + * @throws InvalidFileFormatException Looks at a 3x3 Board in the format: Gr Tr Gr Gr [] Gr Gr + * Tr Gr Column 1 and 3 are checked to have 1 Tent (which is not present, thus producing a + * contradiction) */ @Test public void TooFewTentsContradictionRule_3x3TwoColumn() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3DoubleColumn",treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTents3x3DoubleColumn", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -199,21 +196,24 @@ public void TooFewTentsContradictionRule_3x3TwoColumn() throws InvalidFileFormat Assert.assertNull(RULE.checkContradiction(board)); - TreeTentCell cell1 = board.getCell(0,0); - TreeTentCell cell2 = board.getCell(0,1); - TreeTentCell cell3 = board.getCell(0,2); - TreeTentCell cell4 = board.getCell(2,0); - TreeTentCell cell5 = board.getCell(2,1); - TreeTentCell cell6 = board.getCell(2,2); + TreeTentCell cell1 = board.getCell(0, 0); + TreeTentCell cell2 = board.getCell(0, 1); + TreeTentCell cell3 = board.getCell(0, 2); + TreeTentCell cell4 = board.getCell(2, 0); + TreeTentCell cell5 = board.getCell(2, 1); + TreeTentCell cell6 = board.getCell(2, 2); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || point.equals(cell3.getLocation()) || - point.equals(cell4.getLocation()) || point.equals(cell5.getLocation()) || point.equals(cell6.getLocation())) { + if (point.equals(cell1.getLocation()) + || point.equals(cell2.getLocation()) + || point.equals(cell3.getLocation()) + || point.equals(cell4.getLocation()) + || point.equals(cell5.getLocation()) + || point.equals(cell6.getLocation())) { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -221,15 +221,14 @@ public void TooFewTentsContradictionRule_3x3TwoColumn() throws InvalidFileFormat } /** - * @throws InvalidFileFormatException - * Looks at a 2x2 Board in the format: - * Tn [] - * Tr [] - * This should fail the contradiction as it is a legal board. + * @throws InvalidFileFormatException Looks at a 2x2 Board in the format: Tn [] Tr [] This + * should fail the contradiction as it is a legal board. */ @Test public void TooFewTentsContradictionRule_NoContradiction() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsNoContradiction",treetent); + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooFewTentsContradictionRule/TooFewTentsNoContradiction", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -244,8 +243,4 @@ public void TooFewTentsContradictionRule_NoContradiction() throws InvalidFileFor } } } - - - } - diff --git a/src/test/java/puzzles/treetent/rules/TooManyTentsContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/TooManyTentsContradictionRuleTest.java index 2a351556b..c1dc6380a 100644 --- a/src/test/java/puzzles/treetent/rules/TooManyTentsContradictionRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/TooManyTentsContradictionRuleTest.java @@ -1,21 +1,18 @@ package puzzles.treetent.rules; -import legup.MockGameBoardFacade; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - import edu.rpi.legup.puzzle.treetent.TreeTent; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.TreeTentCell; -import edu.rpi.legup.puzzle.treetent.TreeTentType; import edu.rpi.legup.puzzle.treetent.rules.TooManyTentsContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; - import java.awt.*; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class TooManyTentsContradictionRuleTest { @@ -32,26 +29,26 @@ public static void setUp() { TESTING BASIS: All test in this Rule use a 3x3 table. There is a Tree at (1,1) - There are tents at (0,1) and (2,2) + There are tents at (1,0) and (2,2) All Tent Counts are listed left to right or top to bottom */ /** - * @throws InvalidFileFormatException - * Tests for TooManyTents if: - * Row Tent Counts: 0,0,0 - * Column Tent Counts: 0,0,0 + * @throws InvalidFileFormatException Tests for TooManyTents if: Row Tent Counts: 0,0,0 Column + * Tent Counts: 0,0,0 */ @Test - public void TooManyTentsContradictionRule_TotalFail() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTotalFail",treetent); + public void TooManyTentsContradictionRule_TotalFail() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTotalFail", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentCell cell1 = board.getCell(0,1); + TreeTentCell cell1 = board.getCell(0, 1); Assert.assertNull(RULE.checkContradiction(board)); @@ -60,8 +57,7 @@ public void TooManyTentsContradictionRule_TotalFail() throws InvalidFileFormatEx Point point = new Point(k, i); if (point.equals(cell1.getLocation())) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -69,22 +65,22 @@ public void TooManyTentsContradictionRule_TotalFail() throws InvalidFileFormatEx } /** - * @throws InvalidFileFormatException - * Tests for TooManyTents if: - * Row Tent Counts: 1,0,0 - * Column Tent Counts: 0,0,0 + * @throws InvalidFileFormatException Tests for TooManyTents if: Row Tent Counts: 1,0,0 Column + * Tent Counts: 0,0,0 */ @Test - public void TooManyTentsContradictionRule_TopRight() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopRight",treetent); + public void TooManyTentsContradictionRule_TopRight() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopRight", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentCell cell1 = board.getCell(0,0); - TreeTentCell cell2 = board.getCell(0,1); + TreeTentCell cell1 = board.getCell(0, 0); + TreeTentCell cell2 = board.getCell(0, 1); Assert.assertNull(RULE.checkContradiction(board)); @@ -93,8 +89,7 @@ public void TooManyTentsContradictionRule_TopRight() throws InvalidFileFormatExc Point point = new Point(k, i); if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -102,22 +97,22 @@ public void TooManyTentsContradictionRule_TopRight() throws InvalidFileFormatExc } /** - * @throws InvalidFileFormatException - * Tests for TooManyTests if: - * Row Tent Counts: 0,0,1 - * Column Tent Counts: 0,0,0 + * @throws InvalidFileFormatException Tests for TooManyTests if: Row Tent Counts: 0,0,1 Column + * Tent Counts: 0,0,0 */ @Test - public void TooManyTentsContradictionRule_BottomRight() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomRight",treetent); + public void TooManyTentsContradictionRule_BottomRight() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomRight", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentCell cell1 = board.getCell(0,1); - TreeTentCell cell2 = board.getCell(0,2); + TreeTentCell cell1 = board.getCell(0, 1); + TreeTentCell cell2 = board.getCell(0, 2); Assert.assertNull(RULE.checkContradiction(board)); @@ -126,8 +121,7 @@ public void TooManyTentsContradictionRule_BottomRight() throws InvalidFileFormat Point point = new Point(k, i); if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -135,22 +129,22 @@ public void TooManyTentsContradictionRule_BottomRight() throws InvalidFileFormat } /** - * @throws InvalidFileFormatException - * Tests for TooManyTents if: - * Row Tent Counts: 0,0,0 - * Column Tent Counts: 0,1,0 + * @throws InvalidFileFormatException Tests for TooManyTents if: Row Tent Counts: 0,0,0 Column + * Tent Counts: 0,1,0 */ @Test - public void TooManyTentsContradictionRule_TopDown() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopDown",treetent); + public void TooManyTentsContradictionRule_TopDown() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopDown", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentCell cell1 = board.getCell(0,1); - TreeTentCell cell2 = board.getCell(1,1); + TreeTentCell cell1 = board.getCell(0, 1); + TreeTentCell cell2 = board.getCell(1, 1); Assert.assertNull(RULE.checkContradiction(board)); @@ -159,8 +153,7 @@ public void TooManyTentsContradictionRule_TopDown() throws InvalidFileFormatExce Point point = new Point(k, i); if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -168,22 +161,22 @@ public void TooManyTentsContradictionRule_TopDown() throws InvalidFileFormatExce } /** - * @throws InvalidFileFormatException - * Tests for TooManyTents if: - * Row Tent Counts: 0,0,0 - * Column Tent Counts: 0,0,1 + * @throws InvalidFileFormatException Tests for TooManyTents if: Row Tent Counts: 0,0,0 Column + * Tent Counts: 0,0,1 */ @Test - public void TooManyTentsContradictionRule_BottomDown() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomDown",treetent); + public void TooManyTentsContradictionRule_BottomDown() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomDown", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentCell cell1 = board.getCell(0,1); - TreeTentCell cell2 = board.getCell(2,1); + TreeTentCell cell1 = board.getCell(0, 1); + TreeTentCell cell2 = board.getCell(2, 1); Assert.assertNull(RULE.checkContradiction(board)); @@ -192,8 +185,7 @@ public void TooManyTentsContradictionRule_BottomDown() throws InvalidFileFormatE Point point = new Point(k, i); if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation())) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -201,35 +193,36 @@ public void TooManyTentsContradictionRule_BottomDown() throws InvalidFileFormatE } /** - * @throws InvalidFileFormatException - * Tests for TooManyTents if the Top Tent is completely accounted for, but not the bottom - * Row Tent Counts: 1,0,0 - * Column Tent Counts: 0,1,0 + * @throws InvalidFileFormatException Tests for TooManyTents if the Top Tent is completely + * accounted for, but not the bottom Row Tent Counts: 1,0,0 Column Tent Counts: 0,1,0 */ @Test - public void TooManyTentsContradictionRule_TopAccount() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopAccount",treetent); + public void TooManyTentsContradictionRule_TopAccount() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsTopAccount", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentCell cell1 = board.getCell(0,0); - TreeTentCell cell2 = board.getCell(1,0); - TreeTentCell cell3 = board.getCell(0,1); - TreeTentCell cell4 = board.getCell(1,1); + TreeTentCell cell1 = board.getCell(0, 0); + TreeTentCell cell2 = board.getCell(1, 0); + TreeTentCell cell3 = board.getCell(0, 1); + TreeTentCell cell4 = board.getCell(1, 1); Assert.assertNull(RULE.checkContradiction(board)); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + if (point.equals(cell1.getLocation()) + || point.equals(cell2.getLocation()) + || point.equals(cell3.getLocation()) + || point.equals(cell4.getLocation())) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } @@ -237,39 +230,39 @@ public void TooManyTentsContradictionRule_TopAccount() throws InvalidFileFormatE } /** - * @throws InvalidFileFormatException - * Tests for TooManyTents if the Bottom Tent is completely accounted for, but not the Top - * Row Tent Counts: 0,0,1 - * Column Tent Counts: 0,0,1 + * @throws InvalidFileFormatException Tests for TooManyTents if the Bottom Tent is completely + * accounted for, but not the Top Row Tent Counts: 0,0,1 Column Tent Counts: 0,0,1 */ @Test - public void TooManyTentsContradictionRule_BottomAccount() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomAccount",treetent); + public void TooManyTentsContradictionRule_BottomAccount() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TooManyTentsContradictionRule/TooManyTentsBottomAccount", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - TreeTentCell cell1 = board.getCell(0,1); - TreeTentCell cell2 = board.getCell(2,1); - TreeTentCell cell3 = board.getCell(0,2); - TreeTentCell cell4 = board.getCell(2,2); + TreeTentCell cell1 = board.getCell(0, 1); + TreeTentCell cell2 = board.getCell(2, 1); + TreeTentCell cell3 = board.getCell(0, 2); + TreeTentCell cell4 = board.getCell(2, 2); Assert.assertNull(RULE.checkContradiction(board)); for (int i = 0; i < board.getHeight(); i++) { for (int k = 0; k < board.getWidth(); k++) { Point point = new Point(k, i); - if (point.equals(cell1.getLocation()) || point.equals(cell2.getLocation()) || - point.equals(cell3.getLocation()) || point.equals(cell4.getLocation())) { + if (point.equals(cell1.getLocation()) + || point.equals(cell2.getLocation()) + || point.equals(cell3.getLocation()) + || point.equals(cell4.getLocation())) { Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(k, i))); - } - else { + } else { Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(k, i))); } } } } } - diff --git a/src/test/java/puzzles/treetent/rules/TouchingTentsContradictionRuleTest.java b/src/test/java/puzzles/treetent/rules/TouchingTentsContradictionRuleTest.java index f48afe5d7..e44543ab6 100644 --- a/src/test/java/puzzles/treetent/rules/TouchingTentsContradictionRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/TouchingTentsContradictionRuleTest.java @@ -1,17 +1,16 @@ package puzzles.treetent.rules; -import legup.MockGameBoardFacade; -import legup.TestUtilities; import edu.rpi.legup.model.tree.TreeNode; import edu.rpi.legup.model.tree.TreeTransition; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - import edu.rpi.legup.puzzle.treetent.TreeTent; import edu.rpi.legup.puzzle.treetent.TreeTentBoard; import edu.rpi.legup.puzzle.treetent.rules.TouchingTentsContradictionRule; import edu.rpi.legup.save.InvalidFileFormatException; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; public class TouchingTentsContradictionRuleTest { @@ -24,15 +23,16 @@ public static void setUp() { treetent = new TreeTent(); } - //DIAGONAL TESTS + // DIAGONAL TESTS /** - * @throws InvalidFileFormatException - * Tests a tent diagonal of orientation T - * T - **/ + * @throws InvalidFileFormatException Tests a tent diagonal of orientation T T + */ @Test - public void TouchingTentsContradictionRule_DiagonalUpLeftToDownRight() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonal", treetent); + public void TouchingTentsContradictionRule_DiagonalUpLeftToDownRight() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonal", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -47,13 +47,14 @@ public void TouchingTentsContradictionRule_DiagonalUpLeftToDownRight() throws In } /** - * @throws InvalidFileFormatException - * Tests a tent diagonal of orientation T - * T - **/ + * @throws InvalidFileFormatException Tests a tent diagonal of orientation T T + */ @Test - public void TouchingTentsContradictionRule_DiagonalDownLeftToUpRight() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonalAlt",treetent); + public void TouchingTentsContradictionRule_DiagonalDownLeftToUpRight() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsDiagonalAlt", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -61,21 +62,22 @@ public void TouchingTentsContradictionRule_DiagonalDownLeftToUpRight() throws In TreeTentBoard board = (TreeTentBoard) transition.getBoard(); Assert.assertNull(RULE.checkContradiction(board)); - Assert.assertNull(RULE.checkRuleAt(transition,board.getCell(1,0))); - Assert.assertNull(RULE.checkRuleAt(transition,board.getCell(0,1))); + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0))); + Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1))); Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0))); Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); } - //ADJACENT TESTS + // ADJACENT TESTS /** - * @throws InvalidFileFormatException - * Tests a tent adjacent of orientation T - * T - **/ + * @throws InvalidFileFormatException Tests a tent adjacent of orientation T T + */ @Test - public void TouchingTentsContradictionRule_AdjacentVertical() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacent", treetent); + public void TouchingTentsContradictionRule_AdjacentVertical() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacent", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -90,12 +92,14 @@ public void TouchingTentsContradictionRule_AdjacentVertical() throws InvalidFile } /** - * @throws InvalidFileFormatException - * Tests a tent adjacent of orientation TT - **/ + * @throws InvalidFileFormatException Tests a tent adjacent of orientation TT + */ @Test - public void TouchingTentsContradictionRule_AdjacentHorizontal() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacentAlt", treetent); + public void TouchingTentsContradictionRule_AdjacentHorizontal() + throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsAdjacentAlt", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -108,55 +112,16 @@ public void TouchingTentsContradictionRule_AdjacentHorizontal() throws InvalidFi Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1))); Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); } - //MIXED TESTS - /** - * @throws InvalidFileFormatException - * Tests a tent of orientation TT - * TT - **/ - @Test - public void TouchingTentsContradictionRule_2By2Square() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsFull2By2",treetent); - TreeNode rootNode = treetent.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - - Assert.assertNull(RULE.checkContradiction(board)); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0))); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1))); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0))); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); - } - /** - * @throws InvalidFileFormatException - * Tests a tent of orientation TT - * T - **/ - @Test - public void TouchingTentsContradictionRule_UpLeft() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpLeft",treetent); - TreeNode rootNode = treetent.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - - Assert.assertNull(RULE.checkContradiction(board)); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0))); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1))); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0))); - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); - } + // MIXED TESTS /** - * @throws InvalidFileFormatException - * Tests a tent of orientation TT - * T - **/ + * @throws InvalidFileFormatException Tests a tent of orientation TT TT + */ @Test - public void TouchingTentsContradictionRule_UpRight() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpRight",treetent); + public void TouchingTentsContradictionRule_2By2Square() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsFull2By2", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -166,56 +131,18 @@ public void TouchingTentsContradictionRule_UpRight() throws InvalidFileFormatExc Assert.assertNull(RULE.checkContradiction(board)); Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0))); Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1))); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0))); - } - /** - * @throws InvalidFileFormatException - * Tests a tent of orientation T - * TT - **/ - @Test - public void TouchingTentsContradictionRule_DownLeft() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownLeft",treetent); - TreeNode rootNode = treetent.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - - Assert.assertNull(RULE.checkContradiction(board)); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 0))); Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0))); Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1))); } - /** - * @throws InvalidFileFormatException - * Tests a tent of orientation T - * TT - **/ - @Test - public void TouchingTentsContradictionRule_DownRight() throws InvalidFileFormatException { - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownRight",treetent); - TreeNode rootNode = treetent.getTree().getRootNode(); - TreeTransition transition = rootNode.getChildren().get(0); - transition.setRule(RULE); - - TreeTentBoard board = (TreeTentBoard) transition.getBoard(); - Assert.assertNull(RULE.checkContradiction(board)); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(0, 1))); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 0))); - Assert.assertNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0))); - } /** - * @throws InvalidFileFormatException - * Tests if tree adjacent triggers a null + * @throws InvalidFileFormatException Tests if tree adjacent triggers a null */ @Test - public void TouchingTentsContradictionRule_TreeAdjacent() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeAdjacent",treetent); + public void TouchingTentsContradictionRule_TreeAdjacent() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeAdjacent", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -226,13 +153,15 @@ public void TouchingTentsContradictionRule_TreeAdjacent() throws InvalidFileForm Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0))); Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 1))); } + /** - * @throws InvalidFileFormatException - * Tests if tree diagonal triggers a null + * @throws InvalidFileFormatException Tests if tree diagonal triggers a null */ @Test - public void TouchingTentsContradictionRule_TreeDiagonal() throws InvalidFileFormatException{ - TestUtilities.importTestBoard("puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal",treetent); + public void TouchingTentsContradictionRule_TreeDiagonal() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal", + treetent); TreeNode rootNode = treetent.getTree().getRootNode(); TreeTransition transition = rootNode.getChildren().get(0); transition.setRule(RULE); @@ -241,9 +170,6 @@ public void TouchingTentsContradictionRule_TreeDiagonal() throws InvalidFileForm Assert.assertNotNull(RULE.checkContradiction(board)); Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(0, 0))); - Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 0))); + Assert.assertNotNull(RULE.checkRuleAt(transition, board.getCell(1, 1))); } - } - - diff --git a/src/test/java/puzzles/treetent/rules/TreeForTentDirectRuleTest.java b/src/test/java/puzzles/treetent/rules/TreeForTentDirectRuleTest.java index 5b96fcf1c..3cccdc417 100644 --- a/src/test/java/puzzles/treetent/rules/TreeForTentDirectRuleTest.java +++ b/src/test/java/puzzles/treetent/rules/TreeForTentDirectRuleTest.java @@ -1,17 +1,152 @@ package puzzles.treetent.rules; -// This feature is no longer supported +import edu.rpi.legup.model.tree.TreeNode; +import edu.rpi.legup.model.tree.TreeTransition; +import edu.rpi.legup.puzzle.treetent.TreeTent; +import edu.rpi.legup.puzzle.treetent.TreeTentBoard; +import edu.rpi.legup.puzzle.treetent.TreeTentCell; +import edu.rpi.legup.puzzle.treetent.TreeTentLine; +import edu.rpi.legup.puzzle.treetent.rules.TreeForTentDirectRule; +import edu.rpi.legup.save.InvalidFileFormatException; +import java.util.ArrayList; +import legup.MockGameBoardFacade; +import legup.TestUtilities; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + public class TreeForTentDirectRuleTest { -// private static final TreeForTentBasicRule RULE = new TreeForTentBasicRule(); -// private static TreeTent treetent; + private static final TreeForTentDirectRule RULE = new TreeForTentDirectRule(); + private static TreeTent treetent; -// @BeforeClass -// public static void setUp() { -// MockGameBoardFacade.getInstance(); -// treetent = new TreeTent(); -// } -} + @BeforeClass + public static void setUp() { + MockGameBoardFacade.getInstance(); + treetent = new TreeTent(); + } + + /** + * 3x3 TreeTent puzzle Tests TreeForTentDirectRule + * + *

TENT at (1, 0); TREE at (1, 1) XTX XRX XXX + * + *

Makes a line between (1, 0) and (1, 1) Checks that the rule correctly detects the central + * tree as the only possible connection + */ + @Test + public void TreeForTentTestOneTreeOneTentTest() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TreeForTentDirectRule/OneTentOneTree", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + TreeTentCell cell1 = board.getCell(1, 0); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + + board.addModifiedData(line); + board.getLines().add(line); + + Assert.assertNull(RULE.checkRule(transition)); + } + + /** + * 3x3 TreeTent puzzle Tests TreeForTentDirectRule + * + *

TENT at (1, 0) and (1, 2); TREE at (1, 1) XTX XRX XTX + * + *

Makes a line between (1, 0) and (1, 1) Checks that the rule works when connecting a line + * between the tent at (1, 0) and the tree at (1, 1) + */ + @Test + public void TentForTreeWithArbitraryTreeTest() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TreeForTentDirectRule/ArbitraryTent", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + TreeTentCell cell1 = board.getCell(1, 0); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + board.addModifiedData(line); + board.getLines().add(line); + Assert.assertNull(RULE.checkRule(transition)); + } + /** + * 3x3 TreeTent puzzle Tests TreeForTentDirectRule + * + *

TENT at (1, 0) and (1, 2); TREE at (1, 1); LINE between (1, 0) and (1, 1) XTX XRX XTX + * + *

Makes a line between (1, 1) and (1, 2) Checks that the rule fails for the tent at (1, 2) + * because there are no valid trees to connect to + */ + @Test + public void TentForTreeConnectedTent() throws InvalidFileFormatException { + + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TreeForTentDirectRule/ConnectedTree", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + TreeTentCell cell1 = board.getCell(1, 2); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + + board.addModifiedData(line); + board.getLines().add(line); + + Assert.assertNull(RULE.checkRule(transition)); + + ArrayList lines = board.getLines(); + for (TreeTentLine l : lines) { + Assert.assertNotNull(RULE.checkRuleAt(transition, l)); + } + } + + /** + * 3x3 TreeTent puzzle Tests TreeForTentDirectRule + * + *

TENT at (1, 1); TREE at (1, 0) and (1, 2) XRX XTX XRX + * + *

Makes a line between (1, 1) and (1, 2) Checks that the rule fails for the tree at (1, 1) + * because there are two valid trees to connect to + */ + @Test + public void TentForTreeOneTreeTwoAdjacentTent() throws InvalidFileFormatException { + TestUtilities.importTestBoard( + "puzzles/treetent/rules/TreeForTentDirectRule/OneTentTwoAdjacentTrees", treetent); + + TreeNode rootNode = treetent.getTree().getRootNode(); + TreeTransition transition = rootNode.getChildren().get(0); + transition.setRule(RULE); + + TreeTentBoard board = (TreeTentBoard) transition.getBoard(); + + TreeTentCell cell1 = board.getCell(1, 2); + TreeTentCell cell2 = board.getCell(1, 1); + TreeTentLine line = new TreeTentLine(cell1, cell2); + + board.addModifiedData(line); + board.getLines().add(line); + + Assert.assertNotNull(RULE.checkRule(transition)); + } +} diff --git a/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes b/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes new file mode 100644 index 000000000..026742fea --- /dev/null +++ b/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/SurroundTwoZerosWithTwoOnes @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/native/macos/.keep b/src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/test similarity index 100% rename from native/macos/.keep rename to src/test/resources/puzzles/binary/rules/SurroundPairDirectRule/test diff --git a/src/test/resources/puzzles/lightup/rules/FinishWithEmptyDirectRule/FinishWithEmptyWithThree b/src/test/resources/puzzles/lightup/rules/FinishWithEmptyDirectRule/FinishWithEmptyWithThree index c5ad17cba..2e2712a50 100644 --- a/src/test/resources/puzzles/lightup/rules/FinishWithEmptyDirectRule/FinishWithEmptyWithThree +++ b/src/test/resources/puzzles/lightup/rules/FinishWithEmptyDirectRule/FinishWithEmptyWithThree @@ -3,9 +3,9 @@ - + diff --git a/src/test/resources/puzzles/minesweeper/utilities/3x3test b/src/test/resources/puzzles/minesweeper/utilities/3x3test new file mode 100644 index 000000000..2bf4f5c3b --- /dev/null +++ b/src/test/resources/puzzles/minesweeper/utilities/3x3test @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes b/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes new file mode 100644 index 000000000..026742fea --- /dev/null +++ b/src/test/resources/puzzles/nurikabe/rules/BlackBetweenRegionsDirectRule/SurroundTwoZerosWithTwoOnes @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/nurikabe/rules/FinishRoomCaseRule/FinishRoomCaseRuleBase b/src/test/resources/puzzles/nurikabe/rules/FinishRoomCaseRule/FinishRoomCaseRuleBase new file mode 100644 index 000000000..c40870b96 --- /dev/null +++ b/src/test/resources/puzzles/nurikabe/rules/FinishRoomCaseRule/FinishRoomCaseRuleBase @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFF b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFF new file mode 100644 index 000000000..5285dbb86 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFT b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFT new file mode 100644 index 000000000..18d6030d9 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFU b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFU new file mode 100644 index 000000000..39b9e9811 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FFU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTF b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTF new file mode 100644 index 000000000..9df198c5f --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTT b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTT new file mode 100644 index 000000000..0c2feabe7 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTU b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTU new file mode 100644 index 000000000..d024cb841 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/FTU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFF b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFF new file mode 100644 index 000000000..8234ebd2a --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFT b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFT new file mode 100644 index 000000000..4a6b0f1d7 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFU b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFU new file mode 100644 index 000000000..b2bb6e1a5 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TFU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTF b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTF new file mode 100644 index 000000000..9e53ac8e3 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTT b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTT new file mode 100644 index 000000000..837730943 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTU b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTU new file mode 100644 index 000000000..893f7d3ec --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/TTU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFF b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFF new file mode 100644 index 000000000..6d4f44071 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFT b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFT new file mode 100644 index 000000000..7fcda3fba --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFU b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFU new file mode 100644 index 000000000..5285dbb86 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UFU @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTF b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTF new file mode 100644 index 000000000..d11a314b8 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTT b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTT new file mode 100644 index 000000000..1772e1986 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTU b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTU new file mode 100644 index 000000000..9df198c5f --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AndContradictionRule/UTU @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FF b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FF new file mode 100644 index 000000000..47ede6499 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FT b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FT new file mode 100644 index 000000000..56192a97b --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FU b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FU new file mode 100644 index 000000000..9e25868fc --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/FU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TF b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TF new file mode 100644 index 000000000..326988fbb --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TT b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TT new file mode 100644 index 000000000..0b8b9b690 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TU b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TU new file mode 100644 index 000000000..4ee98e3d4 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/TU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UF b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UF new file mode 100644 index 000000000..03432df5f --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UT b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UT new file mode 100644 index 000000000..a69e019a2 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UU b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UU new file mode 100644 index 000000000..7d1f0bae6 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/AtomicContradictionRule/UU @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/ComplexStatement1_False b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/ComplexStatement1_False new file mode 100644 index 000000000..8f31d9771 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/ComplexStatement1_False @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/ComplexStatement1_True b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/ComplexStatement1_True new file mode 100644 index 000000000..f0bb0d508 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/ComplexStatement1_True @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/FalseBiconditional b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/FalseBiconditional new file mode 100644 index 000000000..5ea1c8a63 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/FalseBiconditional @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/TrueBiconditional b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/TrueBiconditional new file mode 100644 index 000000000..cbf64468f --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/TrueBiconditional @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/UnknownConditional b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/UnknownConditional new file mode 100644 index 000000000..82cdeb3ea --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalCaseRule/UnknownConditional @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFF new file mode 100644 index 000000000..b1c975982 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFT new file mode 100644 index 000000000..9aaa26431 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFU new file mode 100644 index 000000000..150134e46 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FFU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTF new file mode 100644 index 000000000..e1cecaeb7 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTT new file mode 100644 index 000000000..370cefc0a --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTU new file mode 100644 index 000000000..4ac904290 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/FTU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFF new file mode 100644 index 000000000..48e1fa36b --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFT new file mode 100644 index 000000000..a260489cc --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFU new file mode 100644 index 000000000..08a999c1a --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TFU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTF new file mode 100644 index 000000000..c6764d0fb --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTT new file mode 100644 index 000000000..7ce20257b --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTU new file mode 100644 index 000000000..b440c157a --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/TTU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFF new file mode 100644 index 000000000..865d9b59b --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFT new file mode 100644 index 000000000..31f372a95 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFU new file mode 100644 index 000000000..b1c975982 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UFU @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTF b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTF new file mode 100644 index 000000000..e1e7eeafc --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTT b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTT new file mode 100644 index 000000000..15ed9b08f --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTU b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTU new file mode 100644 index 000000000..e1cecaeb7 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/BiconditionalContradictionRule/UTU @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/ComplexStatement1_False b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/ComplexStatement1_False new file mode 100644 index 000000000..f8be5f275 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/ComplexStatement1_False @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/ComplexStatement1_True b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/ComplexStatement1_True new file mode 100644 index 000000000..d919b7214 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/ComplexStatement1_True @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/FalseConditional b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/FalseConditional new file mode 100644 index 000000000..2da458f51 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/FalseConditional @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/TrueConditional b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/TrueConditional new file mode 100644 index 000000000..829861f75 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/TrueConditional @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/UnknownConditional b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/UnknownConditional new file mode 100644 index 000000000..deb93776d --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalCaseRule/UnknownConditional @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFF new file mode 100644 index 000000000..479b8172d --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFT new file mode 100644 index 000000000..4c328f840 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFU new file mode 100644 index 000000000..2a5220f46 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FFU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTF new file mode 100644 index 000000000..d28a4b9f9 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTT new file mode 100644 index 000000000..aa0c242b3 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTU new file mode 100644 index 000000000..b9867188f --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/FTU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFF new file mode 100644 index 000000000..ad3329472 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFT new file mode 100644 index 000000000..92eaf7cb3 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFU new file mode 100644 index 000000000..0ea50831a --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TFU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTF new file mode 100644 index 000000000..d0e4ec7bb --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTT new file mode 100644 index 000000000..e2f1a7102 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTU new file mode 100644 index 000000000..0a38381b1 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/TTU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFF new file mode 100644 index 000000000..78ff4e0f0 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFT new file mode 100644 index 000000000..9ac9c39fa --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFU new file mode 100644 index 000000000..479b8172d --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UFU @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTF b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTF new file mode 100644 index 000000000..cc05da528 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTT b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTT new file mode 100644 index 000000000..0559dcf83 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTU b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTU new file mode 100644 index 000000000..d28a4b9f9 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/ConditionalContradictionRule/UTU @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FF b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FF new file mode 100644 index 000000000..56b5cd97e --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FT b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FT new file mode 100644 index 000000000..5091d620c --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FU b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FU new file mode 100644 index 000000000..ae65d166d --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/FU @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TF b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TF new file mode 100644 index 000000000..cf510f0c3 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TT b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TT new file mode 100644 index 000000000..7bcb69b15 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TU b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TU new file mode 100644 index 000000000..a33ef3016 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/TU @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UF b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UF new file mode 100644 index 000000000..96bc1fb52 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UF @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UT b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UT new file mode 100644 index 000000000..b87293cdc --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UT @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UU b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UU new file mode 100644 index 000000000..78bd1d67e --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/NotContradictionRule/UU @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFF b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFF new file mode 100644 index 000000000..32c62f59e --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFT b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFT new file mode 100644 index 000000000..96e3122bf --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFU b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFU new file mode 100644 index 000000000..b9bb63a6b --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FFU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTF b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTF new file mode 100644 index 000000000..062c5d3e4 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTT b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTT new file mode 100644 index 000000000..4fbb5922a --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTU b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTU new file mode 100644 index 000000000..1767546df --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/FTU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFF b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFF new file mode 100644 index 000000000..3e50d3b54 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFT b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFT new file mode 100644 index 000000000..69cbef4db --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFU b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFU new file mode 100644 index 000000000..018064192 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TFU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTF b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTF new file mode 100644 index 000000000..8247a1cfa --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTF @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTT b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTT new file mode 100644 index 000000000..4446c1e34 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTT @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTU b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTU new file mode 100644 index 000000000..c662ec79b --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/TTU @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFF b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFF new file mode 100644 index 000000000..dae9e4311 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFT b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFT new file mode 100644 index 000000000..1c68eb53b --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFU b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFU new file mode 100644 index 000000000..32c62f59e --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UFU @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTF b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTF new file mode 100644 index 000000000..67169da0c --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTF @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTT b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTT new file mode 100644 index 000000000..c761569c5 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTT @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTU b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTU new file mode 100644 index 000000000..062c5d3e4 --- /dev/null +++ b/src/test/resources/puzzles/shorttruthtable/rules/OrContradictionRule/UTU @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/AllContradiction b/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/AllContradiction new file mode 100644 index 000000000..a1e81a86e --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/AllContradiction @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/ColContradiction b/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/ColContradiction new file mode 100644 index 000000000..2fd32645c --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/ColContradiction @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/RowContradiction b/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/RowContradiction new file mode 100644 index 000000000..29da502d9 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/DuplicateNumberContradictionRule/RowContradiction @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/0-3Opening b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/0-3Opening new file mode 100644 index 000000000..ed281abae --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/0-3Opening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/1-2ColOpening b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/1-2ColOpening new file mode 100644 index 000000000..193fd2cff --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/1-2ColOpening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/1-2RowOpening b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/1-2RowOpening new file mode 100644 index 000000000..10c3d6d4e --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/1-2RowOpening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/2-1ColOpening b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/2-1ColOpening new file mode 100644 index 000000000..f96d920f5 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/2-1ColOpening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/2-1RowOpening b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/2-1RowOpening new file mode 100644 index 000000000..1924e1336 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastSingularCellDirectRule/2-1RowOpening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastSingularNumberDirectRule/2-1ColOpening b/src/test/resources/puzzles/skyscrapers/rules/LastSingularNumberDirectRule/2-1ColOpening new file mode 100644 index 000000000..1d1f9e1ba --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastSingularNumberDirectRule/2-1ColOpening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastSingularNumberDirectRule/2-1RowOpening b/src/test/resources/puzzles/skyscrapers/rules/LastSingularNumberDirectRule/2-1RowOpening new file mode 100644 index 000000000..a3089ea98 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastSingularNumberDirectRule/2-1RowOpening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2ColOpening b/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2ColOpening new file mode 100644 index 000000000..978bafec4 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2ColOpening @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2RowOpening b/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2RowOpening new file mode 100644 index 000000000..6b35d20f7 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/1-2RowOpening @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1ColOpening b/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1ColOpening new file mode 100644 index 000000000..766bf4151 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1ColOpening @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1RowOpening b/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1RowOpening new file mode 100644 index 000000000..2c9892dea --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/LastVisibleDirectRules/2-1RowOpening @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/DownColEmpty b/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/DownColEmpty new file mode 100644 index 000000000..111d2bd87 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/DownColEmpty @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/LeftRowPartial b/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/LeftRowPartial new file mode 100644 index 000000000..b8ccb00e3 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/LeftRowPartial @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/UpColPartial b/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/UpColPartial new file mode 100644 index 000000000..5b8fd6023 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/NEdgeDirectRule/UpColPartial @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/1-3NumberContradiction b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/1-3NumberContradiction new file mode 100644 index 000000000..51aa44822 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/1-3NumberContradiction @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2CellContradiction b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2CellContradiction new file mode 100644 index 000000000..2d6dd8df0 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2CellContradiction @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2NumberContradiction b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2NumberContradiction new file mode 100644 index 000000000..7bd380e92 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/2-2NumberContradiction @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1ColContradiction b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1ColContradiction new file mode 100644 index 000000000..046d2ea8e --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1ColContradiction @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction new file mode 100644 index 000000000..3063aeea1 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/UnresolvedContradictionRules/3-1RowContradiction @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/AllContradiction b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/AllContradiction new file mode 100644 index 000000000..1b2a81ca8 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/AllContradiction @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/FullColContradiction b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/FullColContradiction new file mode 100644 index 000000000..3c0e67993 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/FullColContradiction @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/FullRowContradiction b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/FullRowContradiction new file mode 100644 index 000000000..0a731bc7d --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/FullRowContradiction @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedAllContradiction b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedAllContradiction new file mode 100644 index 000000000..29aa271bf --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedAllContradiction @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedColContradiction b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedColContradiction new file mode 100644 index 000000000..bdef438d5 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedColContradiction @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedRowContradiction b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedRowContradiction new file mode 100644 index 000000000..3402712ad --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/VisibilityContradictionRules/ImpliedRowContradiction @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/common/3-0ColOpening b/src/test/resources/puzzles/skyscrapers/rules/common/3-0ColOpening new file mode 100644 index 000000000..8b63a4035 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/common/3-0ColOpening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/common/3-0RowOpening b/src/test/resources/puzzles/skyscrapers/rules/common/3-0RowOpening new file mode 100644 index 000000000..89bf1193b --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/common/3-0RowOpening @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/common/Solved b/src/test/resources/puzzles/skyscrapers/rules/common/Solved new file mode 100644 index 000000000..5dc1210e9 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/common/Solved @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/skyscrapers/rules/common/empty b/src/test/resources/puzzles/skyscrapers/rules/common/empty new file mode 100644 index 000000000..87f7db3d7 --- /dev/null +++ b/src/test/resources/puzzles/skyscrapers/rules/common/empty @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion b/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion new file mode 100644 index 000000000..4d3c57225 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastCellForNumberDirectRule/CorneredRegion @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed new file mode 100644 index 000000000..55b501fec --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullMixed @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion new file mode 100644 index 000000000..58fd02162 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRegion @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow new file mode 100644 index 000000000..07e502ed9 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/LastNumberForCellDirectRule/FullRow @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 new file mode 100644 index 000000000..abaa0ba6b --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard4 @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 new file mode 100644 index 000000000..5692dea64 --- /dev/null +++ b/src/test/resources/puzzles/sudoku/rules/RepeatedNumberContradictionRule/BlankBoard7 @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailLeft b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3OneTent similarity index 78% rename from src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailLeft rename to src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3OneTent index d19e01daf..1e1259a44 100644 --- a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailLeft +++ b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3OneTent @@ -2,16 +2,15 @@ - - + - + diff --git a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailRight b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3ThreeTent similarity index 78% rename from src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailRight rename to src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3ThreeTent index bf3954964..7c352347d 100644 --- a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailRight +++ b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3ThreeTent @@ -2,16 +2,15 @@ - - + - + diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownLeft b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3TwoTent similarity index 57% rename from src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownLeft rename to src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3TwoTent index af4ca0831..1f4a907eb 100644 --- a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownLeft +++ b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3TwoTent @@ -1,18 +1,17 @@ - + - - - - + + - + + diff --git a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailBottom b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3ZeroTent similarity index 92% rename from src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailBottom rename to src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3ZeroTent index 80deadaea..a13c7cc55 100644 --- a/src/test/resources/puzzles/treetent/rules/EmptyFieldDirectRule/EmptyFieldFailBottom +++ b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow3x3ZeroTent @@ -2,7 +2,6 @@ - diff --git a/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow5x5TwoTent b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow5x5TwoTent new file mode 100644 index 000000000..ddfcf44db --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/EmptyRow5x5TwoTent @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/PartialFillOneTent b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/PartialFillOneTent new file mode 100644 index 000000000..47d06d5b9 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/FillinRowCaseRule/PartialFillOneTent @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/DiagTrees b/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/DiagTrees new file mode 100644 index 000000000..4a10b61f2 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/DiagTrees @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/FourTreesOneTent b/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/FourTreesOneTent new file mode 100644 index 000000000..96a06de3b --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/FourTreesOneTent @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/NoTrees b/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/NoTrees new file mode 100644 index 000000000..c781cfde9 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/NoTrees @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/OneTreeOneTent b/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/OneTreeOneTent new file mode 100644 index 000000000..103c1ce3e --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/LinkTentCaseRule/OneTreeOneTent @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/DiagTents b/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/DiagTents new file mode 100644 index 000000000..e50bef8c1 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/DiagTents @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/NoTents b/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/NoTents new file mode 100644 index 000000000..3bab63f75 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/NoTents @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/OneTent b/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/OneTent new file mode 100644 index 000000000..69eb680de --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/OneTent @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/TwoTents b/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/TwoTents new file mode 100644 index 000000000..7fb4b6e46 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/LinkTreeCaseRule/TwoTents @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree b/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree new file mode 100644 index 000000000..258ebec21 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/ArbitraryTree @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/ConnectedTent b/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/ConnectedTent new file mode 100644 index 000000000..031bca068 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/ConnectedTent @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/OneTreeOneTent b/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/OneTreeOneTent new file mode 100644 index 000000000..dcc428c8b --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/OneTreeOneTent @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/OneTreeTwoAdjacentTent b/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/OneTreeTwoAdjacentTent new file mode 100644 index 000000000..508cda0a8 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/TentForTreeDirectRule/OneTreeTwoAdjacentTent @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownRight b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownRight deleted file mode 100644 index 05b7a7667..000000000 --- a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedDownRight +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpLeft b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpLeft deleted file mode 100644 index b8b81c7b4..000000000 --- a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpLeft +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpRight b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpRight deleted file mode 100644 index af7fb5df2..000000000 --- a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsMixedUpRight +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal index b2f54aef3..b25eb6c4c 100644 --- a/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal +++ b/src/test/resources/puzzles/treetent/rules/TouchingTentsContradictionRule/TouchingTentsTreeDiagonal @@ -3,7 +3,7 @@ - + diff --git a/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/ArbitraryTent b/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/ArbitraryTent new file mode 100644 index 000000000..ce083cfc0 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/ArbitraryTent @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/ConnectedTree b/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/ConnectedTree new file mode 100644 index 000000000..6ebecc06f --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/ConnectedTree @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/OneTentOneTree b/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/OneTentOneTree new file mode 100644 index 000000000..fabfe06e2 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/OneTentOneTree @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/OneTentTwoAdjacentTrees b/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/OneTentTwoAdjacentTrees new file mode 100644 index 000000000..8218fb2f1 --- /dev/null +++ b/src/test/resources/puzzles/treetent/rules/TreeForTentDirectRule/OneTentTwoAdjacentTrees @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file