From 240e25205c09631fd7d997615e010114979f0c4f Mon Sep 17 00:00:00 2001
From: Charles Tian <46334090+charlestian23@users.noreply.github.com>
Date: Sat, 7 Jan 2023 13:09:00 -0500
Subject: [PATCH] Revert "Master Push for Fall 22"
---
.github/workflows/publish-javadoc.yml | 21 -
.gitignore | 51 +-
README.md | 4 +-
.../org.eclipse.jdt.ui/dialog_settings.xml | 11 +
.../logback.1.6.0.20150526-2032.xml | 43 +
.../org.eclipse.ui.ide/dialog_settings.xml | 11 +
.../org.eclipse.ui.intro/dialog_settings.xml | 4 +
.../dialog_settings.xml | 15 +
.../org.eclipse.ui.workbench/workingsets.xml | 5 +
.../org.eclipse.jdt.ui/dialog_settings.xml | 11 +
.../logback.1.6.0.20150526-2032.xml | 43 +
.../org.eclipse.ui.ide/dialog_settings.xml | 11 +
.../dialog_settings.xml | 15 +
.../org.eclipse.ui.workbench/workingsets.xml | 5 +
bin/main/edu/rpi/legup/legup/config | 4 +-
.../edu/rpi/legup/puzzle/skyscrapers/TODO.md | 11 +
.../legup/puzzle/skyscrapers/rules/TODO.md | 34 +-
build.gradle | 108 +
build.gradle.kts | 90 -
gradle/wrapper/gradle-wrapper.properties | 2 +-
gradlew | 0
.../bin/main/edu.rpi.legupupdate/VERSION | 1 +
legup-update/build.gradle | 22 +
.../java/edu/rpi/legupupdate/NetUtil.java | 112 +
.../main/java/edu/rpi/legupupdate/Update.java | 252 ++
.../edu/rpi/legupupdate/UpdateProgress.java | 11 +
.../resources/edu.rpi.legupupdate/VERSION | 1 +
.../10x10 Fillapix Very Easy/03010000074 | 1 -
puzzles files/lightup/10x10 Easy/1514228 | 1 -
puzzles files/lightup/10x10 Easy/1721067 | 1 -
puzzles files/lightup/10x10 Easy/5403393 | 1 -
puzzles files/lightup/10x10 Easy/5774519 | 1 -
puzzles files/lightup/10x10 Easy/954498 | 1 -
puzzles files/lightup/10x10 Hard/5373598 | 1 -
puzzles files/lightup/10x10 Hard/573404 | 1 -
puzzles files/lightup/10x10 Hard/5787104 | 1 -
puzzles files/lightup/10x10 Hard/8003166 | 1 -
puzzles files/lightup/10x10 Hard/8918995 | 1 -
puzzles files/lightup/10x10 Normal/2761230 | 1 -
puzzles files/lightup/10x10 Normal/343176 | 1 -
puzzles files/lightup/10x10 Normal/632466 | 1 -
puzzles files/lightup/10x10 Normal/7752941 | 1 -
puzzles files/lightup/10x10 Normal/8090631 | 1 -
puzzles files/lightup/14x14 Easy/1412335 | 1 -
puzzles files/lightup/14x14 Easy/1949915 | 1 -
puzzles files/lightup/14x14 Easy/6778348 | 1 -
puzzles files/lightup/14x14 Easy/976495 | 1 -
puzzles files/lightup/14x14 Easy/9949966 | 1 -
puzzles files/lightup/14x14 Hard/1974912 | 1 -
puzzles files/lightup/14x14 Hard/3618696 | 1 -
puzzles files/lightup/14x14 Hard/578987 | 1 -
puzzles files/lightup/14x14 Hard/8087653 | 1 -
puzzles files/lightup/14x14 Hard/9554192 | 1 -
puzzles files/lightup/14x14 Normal/2659779 | 1 -
puzzles files/lightup/14x14 Normal/448333 | 1 -
puzzles files/lightup/14x14 Normal/5063453 | 1 -
puzzles files/lightup/14x14 Normal/606275 | 1 -
puzzles files/lightup/14x14 Normal/830231 | 1 -
puzzles files/lightup/7x7 Easy/2408448 | 1 -
puzzles files/lightup/7x7 Easy/2736784 | 1 -
puzzles files/lightup/7x7 Easy/2855683 | 1 -
puzzles files/lightup/7x7 Easy/3535701 | 1 -
puzzles files/lightup/7x7 Easy/393454 | 1 -
puzzles files/lightup/7x7 Easy/4238934 | 1 -
puzzles files/lightup/7x7 Easy/4604288 | 1 -
puzzles files/lightup/7x7 Easy/4608986 | 1 -
puzzles files/lightup/7x7 Easy/517362 | 1 -
puzzles files/lightup/7x7 Easy/5229613 | 1 -
puzzles files/lightup/7x7 Easy/5435528 | 1 -
puzzles files/lightup/7x7 Easy/5488697 | 1 -
puzzles files/lightup/7x7 Easy/6110408 | 1 -
puzzles files/lightup/7x7 Easy/6300100 | 1 -
puzzles files/lightup/7x7 Easy/6506194 | 1 -
puzzles files/lightup/7x7 Easy/69495 | 1 -
puzzles files/lightup/7x7 Easy/7936304 | 1 -
puzzles files/lightup/7x7 Easy/7982513 | 1 -
puzzles files/lightup/7x7 Easy/8949430 | 1 -
puzzles files/lightup/7x7 Easy/9080685 | 1 -
puzzles files/lightup/7x7 Hard/1130370 | 1 -
puzzles files/lightup/7x7 Hard/2790971 | 1 -
puzzles files/lightup/7x7 Hard/3421347 | 1 -
puzzles files/lightup/7x7 Hard/4159457 | 1 -
puzzles files/lightup/7x7 Hard/4674087 | 1 -
puzzles files/lightup/7x7 Hard/507817 | 1 -
puzzles files/lightup/7x7 Hard/5280094 | 1 -
puzzles files/lightup/7x7 Hard/5677803 | 1 -
puzzles files/lightup/7x7 Hard/6178908 | 1 -
puzzles files/lightup/7x7 Hard/8122162 | 1 -
puzzles files/lightup/7x7 Normal/2637310 | 1 -
puzzles files/lightup/7x7 Normal/2979943 | 1 -
puzzles files/lightup/7x7 Normal/3710905 | 1 -
puzzles files/lightup/7x7 Normal/3727425 | 1 -
puzzles files/lightup/7x7 Normal/3787583 | 1 -
puzzles files/lightup/7x7 Normal/5570754 | 1 -
puzzles files/lightup/7x7 Normal/7270504 | 1 -
puzzles files/lightup/7x7 Normal/8000000 | 1 -
puzzles files/lightup/7x7 Normal/9489812 | 1 -
puzzles files/lightup/7x7 Normal/9806740 | 1 -
puzzles files/masyu/6x6 Masyu Easy/6E_b0011 | 1 -
puzzles files/masyu/6x6 Masyu Easy/6E_b0012 | 1 -
puzzles files/masyu/6x6 Masyu Easy/6E_b0013 | 1 -
puzzles files/masyu/6x6 Masyu Easy/6E_b0014 | 1 -
puzzles files/masyu/6x6 Masyu Easy/6E_b0015 | 1 -
puzzles files/masyu/6x6 Masyu Hard/6H_b0011 | 1 -
puzzles files/masyu/6x6 Masyu Hard/6H_b0012 | 1 -
puzzles files/masyu/6x6 Masyu Hard/6H_b0013 | 1 -
puzzles files/masyu/6x6 Masyu Hard/6H_b0014 | 1 -
puzzles files/masyu/6x6 Masyu Hard/6H_b0015 | 1 -
puzzles files/masyu/6x6 Masyu Medium/6M_b0011 | 1 -
puzzles files/masyu/6x6 Masyu Medium/6M_b0012 | 1 -
puzzles files/masyu/6x6 Masyu Medium/6M_b0013 | 1 -
puzzles files/masyu/6x6 Masyu Medium/6M_b0014 | 1 -
puzzles files/masyu/6x6 Masyu Medium/6M_b0015 | 1 -
puzzles files/narukabe_export tet | 57 +-
.../nurikabe/10x10 Nurikabe Hard/3323808 | 1 -
.../nurikabe/10x10 Nurikabe Hard/7675382 | 1 -
.../nurikabe/10x10 Nurikabe Hard/8264437 | 1 -
.../nurikabe/10x10 Nurikabe Hard/8991218 | 1 -
.../nurikabe/10x10 Nurikabe Hard/9120893 | 1 -
.../nurikabe/10x10 Nurikabe Normal/2852229 | 1 -
.../nurikabe/10x10 Nurikabe Normal/5759900 | 1 -
.../nurikabe/10x10 Nurikabe Normal/6274292 | 1 -
.../nurikabe/10x10 Nurikabe Normal/8920015 | 1 -
.../nurikabe/10x10 Nurikabe Normal/9757357 | 1 -
.../nurikabe/12x12 Nurikabe Hard/1276535 | 1 -
.../nurikabe/12x12 Nurikabe Hard/4284912 | 1 -
.../nurikabe/12x12 Nurikabe Hard/4459392 | 1 -
.../nurikabe/12x12 Nurikabe Hard/7738199 | 1 -
.../nurikabe/12x12 Nurikabe Hard/9205907 | 1 -
.../nurikabe/12x12 Nurikabe Normal/1570101 | 1 -
.../nurikabe/12x12 Nurikabe Normal/3731930 | 1 -
.../nurikabe/12x12 Nurikabe Normal/3755957 | 1 -
.../nurikabe/12x12 Nurikabe Normal/786806 | 1 -
.../nurikabe/12x12 Nurikabe Normal/9946063 | 1 -
.../nurikabe/15x15 Nurikabe Hard/1125631 | 1 -
.../nurikabe/15x15 Nurikabe Hard/5955292 | 1 -
.../nurikabe/15x15 Nurikabe Hard/6763936 | 1 -
.../nurikabe/15x15 Nurikabe Hard/7005298 | 1 -
.../nurikabe/15x15 Nurikabe Hard/9975093 | 1 -
.../nurikabe/15x15 Nurikabe Normal/141420 | 1 -
.../nurikabe/15x15 Nurikabe Normal/4123443 | 1 -
.../nurikabe/15x15 Nurikabe Normal/731385 | 1 -
.../nurikabe/15x15 Nurikabe Normal/8213677 | 1 -
.../nurikabe/15x15 Nurikabe Normal/8372309 | 1 -
.../nurikabe/20x20 Nurikabe Normal/175081 | 1 -
.../nurikabe/20x20 Nurikabe Normal/3131243 | 1 -
.../nurikabe/20x20 Nurikabe Normal/4400487 | 1 -
.../nurikabe/20x20 Nurikabe Normal/5096090 | 1 -
.../nurikabe/20x20 Nurikabe Normal/8595641 | 1 -
.../nurikabe/5x5 Nurikabe Easy/118040 | 1 -
.../nurikabe/5x5 Nurikabe Easy/235235 | 1 -
.../nurikabe/5x5 Nurikabe Hard/118040 | 1 -
.../nurikabe/5x5 Nurikabe Hard/1726232 | 1 -
.../nurikabe/5x5 Nurikabe Hard/2168054 | 1 -
.../nurikabe/5x5 Nurikabe Hard/7209030 | 1 -
.../nurikabe/5x5 Nurikabe Hard/7897030 | 1 -
.../nurikabe/5x5 Nurikabe Normal/1795638 | 1 -
.../nurikabe/5x5 Nurikabe Normal/2663893 | 1 -
.../nurikabe/5x5 Nurikabe Normal/3282122 | 1 -
.../nurikabe/5x5 Nurikabe Normal/6403086 | 1 -
.../nurikabe/5x5 Nurikabe Normal/7587733 | 1 -
.../nurikabe/7x7 Nurikabe Hard/4478248 | 1 -
.../nurikabe/7x7 Nurikabe Hard/5631322 | 1 -
.../nurikabe/7x7 Nurikabe Hard/6734769 | 1 -
.../nurikabe/7x7 Nurikabe Hard/8078467 | 1 -
.../nurikabe/7x7 Nurikabe Hard/9225348 | 1 -
.../nurikabe/7x7 Nurikabe Normal/42455 | 1 -
.../nurikabe/7x7 Nurikabe Normal/4390561 | 1 -
.../nurikabe/7x7 Nurikabe Normal/4877172 | 1 -
.../nurikabe/7x7 Nurikabe Normal/7958242 | 1 -
.../nurikabe/7x7 Nurikabe Normal/8786625 | 1 -
puzzles files/shorttruthtable/DeMorgan.xml | 1 -
puzzles files/shorttruthtable/Heuveln_01.xml | 1 -
puzzles files/shorttruthtable/Heuveln_02.xml | 1 -
puzzles files/shorttruthtable/Heuveln_03.xml | 1 -
puzzles files/shorttruthtable/Heuveln_04.xml | 1 -
.../shorttruthtable/Heuveln_04.xml_test02 | 47 +-
.../Heuveln_04_export test.xml | 1 -
.../shorttruthtable/Heuveln_04_test.xml | 1 -
.../shorttruthtable/Heuveln_04_test01.xml | 1 -
.../shorttruthtable/Heuveln_04_test03.xml | 1 -
.../shorttruthtable/Heuveln_04_test_exprt.xml | 1 -
puzzles files/shorttruthtable/Heuveln_05.xml | 1 -
puzzles files/shorttruthtable/invalid1.xml | 1 -
puzzles files/shorttruthtable/invalid2.xml | 1 -
puzzles files/shorttruthtable/invalid3.xml | 1 -
puzzles files/shorttruthtable/test.xml | 1 -
puzzles files/skyscrapers/1646651 | 1 -
.../skyscrapers/4x4 Skyscrapers Easy1 | 24 -
.../skyscrapers/4x4 Skyscrapers Easy3 | 23 -
.../skyscrapers/5x5 Skyscrapers Easy1 | 26 -
.../skyscrapers/5x5 Skyscrapers Easy2 | 26 -
.../skyscrapers/5x5 Skyscrapers Easy3 | 26 -
.../skyscrapers/5x5 Skyscrapers Medium1 | 26 -
.../skyscrapers/5x5 Skyscrapers Medium2 | 26 -
.../skyscrapers/5x5 Skyscrapers Medium3 | 26 -
.../{4x4 Skyscrapers Easy2 => easy} | 11 +-
puzzles files/skyscrapers/easy1.xml | 1 -
.../sudoku/3x3 Sudoku Advanced/15189327 | 1 -
.../sudoku/3x3 Sudoku Advanced/20628823 | 1 -
.../sudoku/3x3 Sudoku Advanced/45527956 | 1 -
.../sudoku/3x3 Sudoku Advanced/9370592 | 1 -
.../sudoku/3x3 Sudoku Advanced/9680726 | 1 -
.../sudoku/3x3 Sudoku Basic/14538464 | 1 -
.../sudoku/3x3 Sudoku Basic/32722678 | 1 -
.../sudoku/3x3 Sudoku Basic/61362355 | 1 -
.../sudoku/3x3 Sudoku Basic/63397584 | 1 -
.../sudoku/3x3 Sudoku Basic/75565282 | 1 -
puzzles files/sudoku/3x3 Sudoku Easy/1602661 | 1 -
puzzles files/sudoku/3x3 Sudoku Easy/17756306 | 1 -
puzzles files/sudoku/3x3 Sudoku Easy/48718527 | 1 -
puzzles files/sudoku/3x3 Sudoku Easy/50638522 | 1 -
puzzles files/sudoku/3x3 Sudoku Easy/52671552 | 1 -
puzzles files/sudoku/3x3 Sudoku Evil/10251277 | 1 -
puzzles files/sudoku/3x3 Sudoku Evil/112402 | 1 -
puzzles files/sudoku/3x3 Sudoku Evil/285907 | 1 -
puzzles files/sudoku/3x3 Sudoku Evil/3152911 | 1 -
puzzles files/sudoku/3x3 Sudoku Evil/89765 | 1 -
.../sudoku/3x3 Sudoku Extreme/10119634 | 1 -
.../sudoku/3x3 Sudoku Extreme/1922600 | 1 -
.../sudoku/3x3 Sudoku Extreme/3924003 | 1 -
.../sudoku/3x3 Sudoku Extreme/469747 | 1 -
.../sudoku/3x3 Sudoku Extreme/7643647 | 1 -
.../sudoku/3x3 Sudoku Intermediate/22925923 | 1 -
.../sudoku/3x3 Sudoku Intermediate/44179211 | 1 -
.../sudoku/3x3 Sudoku Intermediate/59467143 | 1 -
.../sudoku/3x3 Sudoku Intermediate/7405304 | 1 -
.../sudoku/3x3 Sudoku Intermediate/78017020 | 1 -
.../treetent/12x12 TreeTent Easy/061177 | 1 -
.../treetent/12x12 TreeTent Easy/198217 | 1 -
.../treetent/12x12 TreeTent Easy/255410 | 1 -
.../treetent/12x12 TreeTent Easy/790635 | 1 -
.../treetent/12x12 TreeTent Easy/805457 | 1 -
.../treetent/12x12 TreeTent Medium/154674 | 1 -
.../treetent/12x12 TreeTent Medium/330689 | 1 -
.../treetent/12x12 TreeTent Medium/538746 | 1 -
.../treetent/12x12 TreeTent Medium/579921 | 1 -
.../treetent/12x12 TreeTent Medium/723664 | 1 -
.../treetent/8x8 TreeTent Easy/13547135 | 1 -
.../treetent/8x8 TreeTent Easy/1646651 | 1 -
.../treetent/8x8 TreeTent Easy/1789167 | 1 -
.../treetent/8x8 TreeTent Easy/32518510 | 1 -
.../treetent/8x8 TreeTent Easy/4614656 | 1 -
.../treetent/8x8 TreeTent Medium/351654 | 1 -
.../treetent/8x8 TreeTent Medium/35496 | 1 -
.../treetent/8x8 TreeTent Medium/4656816 | 1 -
.../treetent/8x8 TreeTent Medium/6549871 | 1 -
.../treetent/8x8 TreeTent Medium/989496 | 1 -
settings.gradle | 4 +
settings.gradle.kts | 2 -
src/.idea/.gitignore | 3 +
.../org_junit_jupiter_junit_jupiter_5_4_2.xml | 17 +
src/.idea/misc.xml | 9 +
src/.idea/modules.xml | 8 +
src/.idea/src.iml | 12 +
src/.idea/vcs.xml | 6 +
src/main/java/edu/.idea/.gitignore | 3 +
src/main/java/edu/.idea/edu.iml | 9 +
src/main/java/edu/.idea/misc.xml | 6 +
src/main/java/edu/.idea/modules.xml | 8 +
src/main/java/edu/.idea/vcs.xml | 6 +
src/main/java/edu/build.gradle | 62 +
src/main/java/edu/rpi/.metadata/.lock | 0
.../.mylyn/.taskListIndex/segments.gen | Bin 0 -> 20 bytes
.../.mylyn/.taskListIndex/segments_1 | Bin 0 -> 32 bytes
.../.root/.indexes/history.version | 1 +
.../.root/.indexes/properties.index | Bin 0 -> 57 bytes
.../.root/.indexes/properties.version | 1 +
.../org.eclipse.core.resources/.root/2.tree | Bin 0 -> 81 bytes
.../.safetable/org.eclipse.core.resources | Bin 0 -> 436 bytes
.../org.eclipse.core.resources.prefs | 2 +
.../.settings/org.eclipse.jdt.ui.prefs | 13 +
.../.settings/org.eclipse.m2e.discovery.prefs | 2 +
.../org.eclipse.mylyn.context.core.prefs | 2 +
.../org.eclipse.mylyn.monitor.ui.prefs | 2 +
.../org.eclipse.mylyn.tasks.ui.prefs | 5 +
.../.settings/org.eclipse.ui.ide.prefs | 5 +
.../.settings/org.eclipse.ui.prefs | 2 +
.../.settings/org.eclipse.ui.workbench.prefs | 3 +
.../org.eclipse.e4.workbench/workbench.xmi | 2304 ++++++++++++++++
.../history/_0.fdt | Bin 0 -> 11 bytes
.../history/_0.fdx | Bin 0 -> 12 bytes
.../history/_0.fnm | 1 +
.../history/_0.frq | 0
.../history/_0.nrm | 1 +
.../history/_0.tii | Bin 0 -> 24 bytes
.../history/_0.tis | Bin 0 -> 24 bytes
.../history/segments.gen | Bin 0 -> 20 bytes
.../history/segments_1 | Bin 0 -> 243 bytes
.../remote-index/_0.fdt | Bin 0 -> 11 bytes
.../remote-index/_0.fdx | Bin 0 -> 12 bytes
.../remote-index/_0.fnm | 1 +
.../remote-index/_0.frq | 0
.../remote-index/_0.nrm | 1 +
.../remote-index/_0.tii | Bin 0 -> 24 bytes
.../remote-index/_0.tis | Bin 0 -> 24 bytes
.../remote-index/segments.gen | Bin 0 -> 20 bytes
.../remote-index/segments_1 | Bin 0 -> 243 bytes
.../assumedExternalFilesCache | Bin 0 -> 4 bytes
.../org.eclipse.jdt.core/externalFilesCache | Bin 0 -> 4 bytes
.../org.eclipse.jdt.core/nonChainingJarsCache | Bin 0 -> 4 bytes
.../variablesAndContainers.dat | Bin 0 -> 110 bytes
.../org.eclipse.jdt.ui/OpenTypeHistory.xml | 2 +
.../QualifiedTypeNameHistory.xml | 2 +
.../org.eclipse.jdt.ui/dialog_settings.xml | 11 +
.../logback.1.6.0.20150526-2032.xml | 43 +
.../org.eclipse.oomph.setup/workspace.setup | 6 +
.../org.eclipse.ui.ide/dialog_settings.xml | 11 +
.../org.eclipse.ui.intro/dialog_settings.xml | 4 +
.../dialog_settings.xml | 15 +
.../org.eclipse.ui.workbench/workingsets.xml | 5 +
src/main/java/edu/rpi/.metadata/version.ini | 3 +
src/main/java/edu/rpi/legup/.metadata/.lock | 0
.../.mylyn/.taskListIndex/segments.gen | Bin 0 -> 20 bytes
.../.mylyn/.taskListIndex/segments_1 | Bin 0 -> 32 bytes
.../.root/.indexes/history.version | 1 +
.../.root/.indexes/properties.index | Bin 0 -> 57 bytes
.../.root/.indexes/properties.version | 1 +
.../org.eclipse.core.resources/.root/2.tree | Bin 0 -> 81 bytes
.../.safetable/org.eclipse.core.resources | Bin 0 -> 436 bytes
.../org.eclipse.core.resources.prefs | 2 +
.../.settings/org.eclipse.jdt.ui.prefs | 13 +
.../.settings/org.eclipse.m2e.discovery.prefs | 2 +
.../org.eclipse.mylyn.context.core.prefs | 2 +
.../org.eclipse.mylyn.monitor.ui.prefs | 2 +
.../org.eclipse.mylyn.tasks.ui.prefs | 5 +
.../.settings/org.eclipse.ui.ide.prefs | 5 +
.../.settings/org.eclipse.ui.prefs | 2 +
.../.settings/org.eclipse.ui.workbench.prefs | 3 +
.../org.eclipse.e4.workbench/workbench.xmi | 2308 +++++++++++++++++
.../history/_0.fdt | Bin 0 -> 11 bytes
.../history/_0.fdx | Bin 0 -> 12 bytes
.../history/_0.fnm | 1 +
.../history/_0.frq | 0
.../history/_0.nrm | 1 +
.../history/_0.tii | Bin 0 -> 24 bytes
.../history/_0.tis | Bin 0 -> 24 bytes
.../history/segments.gen | Bin 0 -> 20 bytes
.../history/segments_1 | Bin 0 -> 243 bytes
.../remote-index/_0.fdt | Bin 0 -> 11 bytes
.../remote-index/_0.fdx | Bin 0 -> 12 bytes
.../remote-index/_0.fnm | 1 +
.../remote-index/_0.frq | 0
.../remote-index/_0.nrm | 1 +
.../remote-index/_0.tii | Bin 0 -> 24 bytes
.../remote-index/_0.tis | Bin 0 -> 24 bytes
.../remote-index/segments.gen | Bin 0 -> 20 bytes
.../remote-index/segments_1 | Bin 0 -> 243 bytes
.../assumedExternalFilesCache | Bin 0 -> 4 bytes
.../org.eclipse.jdt.core/externalFilesCache | Bin 0 -> 4 bytes
.../org.eclipse.jdt.core/nonChainingJarsCache | Bin 0 -> 4 bytes
.../variablesAndContainers.dat | Bin 0 -> 110 bytes
.../org.eclipse.jdt.ui/OpenTypeHistory.xml | 2 +
.../QualifiedTypeNameHistory.xml | 2 +
.../org.eclipse.jdt.ui/dialog_settings.xml | 11 +
.../logback.1.6.0.20150526-2032.xml | 43 +
.../org.eclipse.oomph.setup/workspace.setup | 6 +
.../org.eclipse.ui.ide/dialog_settings.xml | 11 +
.../dialog_settings.xml | 15 +
.../org.eclipse.ui.workbench/workingsets.xml | 5 +
.../java/edu/rpi/legup/.metadata/version.ini | 3 +
.../controller/EditorElementController.java | 18 -
.../legup/history/AutoCaseRuleCommand.java | 4 -
.../lightup/rules/MustLightBasicRule.java | 85 +-
.../edu/rpi/legup/puzzle/masyu/MasyuCell.java | 2 -
.../legup/puzzle/masyu/MasyuController.java | 16 +-
.../edu/rpi/legup/puzzle/masyu/MasyuType.java | 2 +-
.../puzzle/nurikabe/NurikabeUtilities.java | 122 +-
.../rules/BlackBottleNeckBasicRule.java | 2 +-
.../rules/CannotReachCellBasicRule.java | 12 +-
...UnreachableWhiteCellContradictionRule.java | 63 +-
.../legup/puzzle/skyscrapers/Skyscrapers.java | 4 +
.../puzzle/skyscrapers/SkyscrapersBoard.java | 198 +-
.../skyscrapers/SkyscrapersCellFactory.java | 11 +-
.../puzzle/skyscrapers/SkyscrapersClue.java | 6 +-
.../skyscrapers/SkyscrapersClueView.java | 8 +-
.../skyscrapers/SkyscrapersController.java | 12 +-
.../skyscrapers/SkyscrapersElementView.java | 25 +-
.../skyscrapers/SkyscrapersExporter.java | 8 +-
.../skyscrapers/SkyscrapersImporter.java | 94 +-
.../skyscrapers/SkyscrapersLineView.java | 1 +
.../puzzle/skyscrapers/SkyscrapersType.java | 2 +-
.../puzzle/skyscrapers/SkyscrapersView.java | 98 +-
.../edu/rpi/legup/puzzle/skyscrapers/TODO.md | 11 +
.../rules/CellForNumberCaseRule.java | 135 -
.../DuplicateNumberContradictionRule.java | 5 +-
.../ExceedingVisibilityContradictionRule.java | 178 +-
...rBasicRule.java => FixedMaxBasicRule.java} | 61 +-
...sufficientVisibilityContradictionRule.java | 175 +-
.../skyscrapers/rules/LastCellBasicRule.java | 132 +
...asicRule.java => LastNumberBasicRule.java} | 77 +-
.../rules/LastVisibleCellBasicRule.java | 117 -
.../skyscrapers/rules/NEdgeBasicRule.java | 10 +-
...erBasicRule.java => OneEdgeBasicRule.java} | 64 +-
...ule.java => PossibleContentsCaseRule.java} | 54 +-
...PreemptiveVisibilityContradictionRule.java | 193 --
.../skyscrapers/rules/Skyscrapers Ruleset.pdf | Bin 194684 -> 0 bytes
.../legup/puzzle/skyscrapers/rules/TODO.md | 34 +-
.../UnresolvedCellContradictionRule.java | 34 +-
.../UnresolvedNumberContradictionRule.java | 97 -
.../rules/skyscrapers_reference_sheet.txt | 59 +-
src/main/java/edu/rpi/legup/ui/HomePanel.java | 484 +---
src/main/java/edu/rpi/legup/ui/LegupUI.java | 2 +
.../edu/rpi/legup/ui/ProofEditorPanel.java | 183 +-
.../edu/rpi/legup/ui/PuzzleEditorPanel.java | 41 +-
.../proofeditorui/rulesview/RuleButton.java | 2 +-
.../ui/proofeditorui/rulesview/RuleFrame.java | 19 +-
.../ui/proofeditorui/rulesview/RulePanel.java | 186 +-
.../rulesview/SearchBarPanel.java | 19 -
.../elementsview/ElementButton.java | 14 -
.../elementsview/ElementFrame.java | 13 -
.../java/edu/rpi/legup/user/Submission.java | 13 +
.../edu/rpi/legup/user/UsageStatistics.java | 63 +
src/main/java/edu/rpi/legup/user/User.java | 5 +
.../images/skyscraper/DuplicateNumber.png | Bin 0 -> 2413 bytes
.../legup/images/skyscraper/LastNumber.png | Bin 0 -> 28799 bytes
.../images/skyscraper/PossibleContents.png | Bin 0 -> 67322 bytes
.../skyscrapers/cases/CellForNumber.png | Bin 1871 -> 0 bytes
.../skyscrapers/cases/NumberForCell.png | Bin 1875 -> 0 bytes
.../contradictions/DuplicateNumber.png | Bin 954 -> 0 bytes
.../contradictions/ExceedingVisibility.png | Bin 1184 -> 0 bytes
.../contradictions/InsufficientVisibility.png | Bin 1291 -> 0 bytes
.../contradictions/PreemptiveVisibility.png | Bin 1101 -> 0 bytes
.../contradictions/UnresolvedCell.png | Bin 1165 -> 0 bytes
.../contradictions/UnresolvedNumber.png | Bin 1357 -> 0 bytes
.../images/skyscrapers/rules/FixedMax.png | Bin 1225 -> 0 bytes
.../images/skyscrapers/rules/LastCell.png | Bin 1352 -> 0 bytes
.../images/skyscrapers/rules/LastNumber.png | Bin 1335 -> 0 bytes
.../legup/images/skyscrapers/rules/NEdge.png | Bin 1523 -> 0 bytes
.../images/skyscrapers/rules/OneEdge.png | Bin 934 -> 0 bytes
430 files changed, 6812 insertions(+), 2938 deletions(-)
delete mode 100644 .github/workflows/publish-javadoc.yml
create mode 100644 bin/main/edu/rpi/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
create mode 100644 bin/main/edu/rpi/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
create mode 100644 bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
create mode 100644 bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml
create mode 100644 bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
create mode 100644 bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
create mode 100644 bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
create mode 100644 bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
create mode 100644 bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
create mode 100644 bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
create mode 100644 bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
create mode 100644 bin/main/edu/rpi/legup/puzzle/skyscrapers/TODO.md
create mode 100644 build.gradle
delete mode 100644 build.gradle.kts
mode change 100755 => 100644 gradlew
create mode 100644 legup-update/bin/main/edu.rpi.legupupdate/VERSION
create mode 100644 legup-update/build.gradle
create mode 100644 legup-update/src/main/java/edu/rpi/legupupdate/NetUtil.java
create mode 100644 legup-update/src/main/java/edu/rpi/legupupdate/Update.java
create mode 100644 legup-update/src/main/java/edu/rpi/legupupdate/UpdateProgress.java
create mode 100644 legup-update/src/main/resources/edu.rpi.legupupdate/VERSION
delete mode 100644 puzzles files/skyscrapers/4x4 Skyscrapers Easy1
delete mode 100644 puzzles files/skyscrapers/4x4 Skyscrapers Easy3
delete mode 100644 puzzles files/skyscrapers/5x5 Skyscrapers Easy1
delete mode 100644 puzzles files/skyscrapers/5x5 Skyscrapers Easy2
delete mode 100644 puzzles files/skyscrapers/5x5 Skyscrapers Easy3
delete mode 100644 puzzles files/skyscrapers/5x5 Skyscrapers Medium1
delete mode 100644 puzzles files/skyscrapers/5x5 Skyscrapers Medium2
delete mode 100644 puzzles files/skyscrapers/5x5 Skyscrapers Medium3
rename puzzles files/skyscrapers/{4x4 Skyscrapers Easy2 => easy} (77%)
create mode 100644 settings.gradle
delete mode 100644 settings.gradle.kts
create mode 100644 src/.idea/.gitignore
create mode 100644 src/.idea/libraries/org_junit_jupiter_junit_jupiter_5_4_2.xml
create mode 100644 src/.idea/misc.xml
create mode 100644 src/.idea/modules.xml
create mode 100644 src/.idea/src.iml
create mode 100644 src/.idea/vcs.xml
create mode 100644 src/main/java/edu/.idea/.gitignore
create mode 100644 src/main/java/edu/.idea/edu.iml
create mode 100644 src/main/java/edu/.idea/misc.xml
create mode 100644 src/main/java/edu/.idea/modules.xml
create mode 100644 src/main/java/edu/.idea/vcs.xml
create mode 100644 src/main/java/edu/build.gradle
create mode 100644 src/main/java/edu/rpi/.metadata/.lock
create mode 100644 src/main/java/edu/rpi/.metadata/.mylyn/.taskListIndex/segments.gen
create mode 100644 src/main/java/edu/rpi/.metadata/.mylyn/.taskListIndex/segments_1
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.resources/.root/2.tree
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.m2e.discovery.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.context.core.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.monitor.ui.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.tasks.ui.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fdt
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fdx
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fnm
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.frq
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.nrm
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.tii
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.tis
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/segments.gen
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/segments_1
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fdt
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fdx
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fnm
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.frq
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.nrm
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.tii
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.tis
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/segments.gen
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/segments_1
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.jdt.core/assumedExternalFilesCache
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.jdt.core/externalFilesCache
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
create mode 100644 src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
create mode 100644 src/main/java/edu/rpi/.metadata/version.ini
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.lock
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.mylyn/.taskListIndex/segments.gen
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.mylyn/.taskListIndex/segments_1
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.resources/.root/2.tree
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.m2e.discovery.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.context.core.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.monitor.ui.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.tasks.ui.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fdt
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fdx
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fnm
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.frq
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.nrm
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.tii
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.tis
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/segments.gen
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/segments_1
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fdt
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fdx
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fnm
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.frq
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.nrm
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.tii
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.tis
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/segments.gen
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/segments_1
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/assumedExternalFilesCache
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/externalFilesCache
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
create mode 100644 src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
create mode 100644 src/main/java/edu/rpi/legup/.metadata/version.ini
create mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/TODO.md
delete mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java
rename src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/{LastSingularNumberBasicRule.java => FixedMaxBasicRule.java} (63%)
create mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastCellBasicRule.java
rename src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/{LastSingularCellBasicRule.java => LastNumberBasicRule.java} (58%)
delete mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleCellBasicRule.java
rename src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/{LastVisibleNumberBasicRule.java => OneEdgeBasicRule.java} (63%)
rename src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/{NumberForCellCaseRule.java => PossibleContentsCaseRule.java} (75%)
delete mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PreemptiveVisibilityContradictionRule.java
delete mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/Skyscrapers Ruleset.pdf
delete mode 100644 src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/UnresolvedNumberContradictionRule.java
delete mode 100644 src/main/java/edu/rpi/legup/ui/proofeditorui/rulesview/SearchBarPanel.java
create mode 100644 src/main/java/edu/rpi/legup/user/Submission.java
create mode 100644 src/main/java/edu/rpi/legup/user/UsageStatistics.java
create mode 100644 src/main/java/edu/rpi/legup/user/User.java
create mode 100644 src/main/resources/edu/rpi/legup/images/skyscraper/DuplicateNumber.png
create mode 100644 src/main/resources/edu/rpi/legup/images/skyscraper/LastNumber.png
create mode 100644 src/main/resources/edu/rpi/legup/images/skyscraper/PossibleContents.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/cases/CellForNumber.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/cases/NumberForCell.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/DuplicateNumber.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/PreemptiveVisibility.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedCell.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/contradictions/UnresolvedNumber.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/rules/FixedMax.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastCell.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/rules/LastNumber.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/rules/NEdge.png
delete mode 100644 src/main/resources/edu/rpi/legup/images/skyscrapers/rules/OneEdge.png
diff --git a/.github/workflows/publish-javadoc.yml b/.github/workflows/publish-javadoc.yml
deleted file mode 100644
index 99183fdee..000000000
--- a/.github/workflows/publish-javadoc.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-# modified from https://github.com/MathieuSoysal/Javadoc-publisher.yml
-
-name: Publish Javadoc
-
-on:
- push:
- branches:
- - dev
-
-jobs:
- publish:
- runs-on: ubuntu-latest
- steps:
- - name: Publish JavaDoc
- uses: MathieuSoysal/Javadoc-publisher.yml@v2.3.0
- with:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- javadoc-branch: javadoc
- java-version: 8
- target-folder: docs
- project: gradle
diff --git a/.gitignore b/.gitignore
index baee37e51..a09e801d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,9 +2,38 @@
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
# CMake
cmake-build-*/
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
# File-based project format
*.iws
@@ -23,19 +52,32 @@ native/windows/bin/*
# JIRA plugin
atlassian-ide-plugin.xml
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
### Intellij+all Patch ###
# Ignore everything but code style settings and run configurations
# that are supposed to be shared within teams.
-**/.idea
-!.idea/codeStyles/*
-!.idea/runConfigurations/*
+.idea/*
+
+!.idea/codeStyles
+!.idea/runConfigurations
### Java ###
# Compiled class file
@@ -90,6 +132,3 @@ gradle-app.setting
**/.DS_Store
gradle/wrapper/gradle-wrapper.properties
-
-# Visual Studio Code configs
-.vscode/*
\ No newline at end of file
diff --git a/README.md b/README.md
index ea9df1770..c59342248 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
@@ -47,8 +47,6 @@ Additionally, if you are interested in computer science and programming, please
## Documentation
Documentation is actively being worked on on the [Legup wiki](https://github.com/Bram-Hub/Legup/wiki).
-The Javadocs for our application are currently hosted directly on [our Github Pages site](https://bram-hub.github.io/Legup/).
-
Documentation is very much in the early stages, and we would greatly appreciate anyone who is willing to help write and structure the documentation. Currently, the priority is to write detailed documentation on how Nurikabe works, as it is the puzzle that is the most developed within Legup.
## Contributing
diff --git a/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
new file mode 100644
index 000000000..105ea7e2b
--- /dev/null
+++ b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
new file mode 100644
index 000000000..63d411340
--- /dev/null
+++ b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
@@ -0,0 +1,43 @@
+
+
+
+ %date [%thread] %-5level %logger{35} - %msg%n
+
+
+ OFF
+
+
+
+
+ ${org.eclipse.m2e.log.dir}/0.log
+
+ ${org.eclipse.m2e.log.dir}/%i.log
+ 1
+ 10
+
+
+ 100MB
+
+
+ %date [%thread] %-5level %logger{35} - %msg%n
+
+
+
+
+
+ WARN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
new file mode 100644
index 000000000..c00d6ca9e
--- /dev/null
+++ b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml
new file mode 100644
index 000000000..541da6a75
--- /dev/null
+++ b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml
@@ -0,0 +1,4 @@
+
+
diff --git a/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
new file mode 100644
index 000000000..01f7412af
--- /dev/null
+++ b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
new file mode 100644
index 000000000..ef53d8bf2
--- /dev/null
+++ b/bin/main/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
new file mode 100644
index 000000000..0bf6a8c76
--- /dev/null
+++ b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
new file mode 100644
index 000000000..63d411340
--- /dev/null
+++ b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
@@ -0,0 +1,43 @@
+
+
+
+ %date [%thread] %-5level %logger{35} - %msg%n
+
+
+ OFF
+
+
+
+
+ ${org.eclipse.m2e.log.dir}/0.log
+
+ ${org.eclipse.m2e.log.dir}/%i.log
+ 1
+ 10
+
+
+ 100MB
+
+
+ %date [%thread] %-5level %logger{35} - %msg%n
+
+
+
+
+
+ WARN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
new file mode 100644
index 000000000..c00d6ca9e
--- /dev/null
+++ b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
new file mode 100644
index 000000000..d2ff1eed0
--- /dev/null
+++ b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
new file mode 100644
index 000000000..5e61d80ea
--- /dev/null
+++ b/bin/main/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/bin/main/edu/rpi/legup/legup/config b/bin/main/edu/rpi/legup/legup/config
index 8e3b4b84c..cfa1ebeac 100644
--- a/bin/main/edu/rpi/legup/legup/config
+++ b/bin/main/edu/rpi/legup/legup/config
@@ -15,7 +15,7 @@
+ fileCreationDisabled="false"/>
+ fileCreationDisabled="false"/>
("buildNativeWindows") {
- dependsOn(shadowJar, createExe)
- workingDir = File("${project.buildDir}/../native/windows")
- commandLine("cmd", "/c", "make_windows_installer.bat")
- }
-}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2d2fd7c74..830458866 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
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-5.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
\ No newline at end of file
diff --git a/gradlew b/gradlew
old mode 100755
new mode 100644
diff --git a/legup-update/bin/main/edu.rpi.legupupdate/VERSION b/legup-update/bin/main/edu.rpi.legupupdate/VERSION
new file mode 100644
index 000000000..227cea215
--- /dev/null
+++ b/legup-update/bin/main/edu.rpi.legupupdate/VERSION
@@ -0,0 +1 @@
+2.0.0
diff --git a/legup-update/build.gradle b/legup-update/build.gradle
new file mode 100644
index 000000000..097f18413
--- /dev/null
+++ b/legup-update/build.gradle
@@ -0,0 +1,22 @@
+plugins {
+ id 'java'
+}
+
+version '2.0'
+
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile 'com.google.code.gson:gson:2.8.2'
+ compile 'commons-cli:commons-cli:1.4'
+ compile 'commons-io:commons-io:2.6'
+ compile 'org.apache.commons:commons-lang3:3.7'
+ compile 'org.apache.logging.log4j:log4j-api:2.10.0'
+ compile 'org.apache.logging.log4j:log4j-core:2.10.0'
+
+ testCompile group: 'junit', name: 'junit', version: '4.12'
+}
\ No newline at end of file
diff --git a/legup-update/src/main/java/edu/rpi/legupupdate/NetUtil.java b/legup-update/src/main/java/edu/rpi/legupupdate/NetUtil.java
new file mode 100644
index 000000000..03eb5e38d
--- /dev/null
+++ b/legup-update/src/main/java/edu/rpi/legupupdate/NetUtil.java
@@ -0,0 +1,112 @@
+package edu.rpi.legupupdate;
+
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class NetUtil {
+
+ public static final String ARIS_NAME = "Aris-Java";
+ public static final String AUTH_BAN = "AUTH BAN";
+ public static final String AUTH_FAIL = "AUTH FAIL";
+ public static final String AUTH_OK = "AUTH OK";
+ public static final String AUTH_ERR = "AUTH UNKNOWN_ERROR";
+ public static final String AUTH_INVALID = "AUTH INVALID";
+ public static final String AUTH = "AUTH";
+ public static final String AUTH_PASS = "PASS";
+ public static final String AUTH_ACCESS_TOKEN = "TOKEN";
+
+ public static final String USER_STUDENT = "student";
+ public static final String USER_INSTRUCTOR = "instructor";
+
+ public static final long MAX_FILE_SIZE = 5242880; // 5MiB
+ public static final String UNAUTHORIZED = "UNAUTHORIZED";
+ public static final String ERROR = "UNKNOWN_ERROR";
+ public static final String OK = "OK";
+ public static final String INVALID = "INVALID";
+
+ public static final String INVALID_VERSION = "INVALID VERSION";
+ public static final String VERSION_OK = "VERSION OK";
+ public static final String DONE = "DONE";
+ public static final String USER_EXISTS = "EXISTS";
+
+ public static final String STATUS_GRADING = "Grading";
+ public static final String STATUS_CORRECT = "Correct";
+ public static final String STATUS_INCORRECT = "Incorrect";
+ public static final String STATUS_ERROR = "Grading Error. Please Resubmit";
+ public static final String STATUS_NO_SUBMISSION = "No Submissions";
+
+ public static final int SOCKET_TIMEOUT = 15000;
+ public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ public static final DateTimeFormatter ZDT_FORMAT = DateTimeFormatter.ISO_DATE_TIME;
+ public static final String TOO_LARGE = "TOO_LARGE";
+ public static final String NO_DATA = "NO_DATA";
+ public static final String RENAME = "RENAME";
+ public static final String ADD_PROOF = "ADD_PROOF";
+ public static final String REMOVE_PROOF = "REMOVE_PROOF";
+ public static final String CHANGE_DUE = "CHANGE_DUE";
+ public static final String UPLOAD = "UPLOAD";
+
+ /**
+ * Compares two version strings.
+ *
+ * Use this instead of String.compareTo() for a non-lexicographical
+ * comparison that works for version strings. e.g. "1.10".compareTo("1.6").
+ *
+ *
+ *
+ * Note: It does not work if "1.10" is supposed to be equal to "1.10.0".
+ *
+ * @param str1 a string of ordinal numbers separated by decimal points.
+ * @param str2 a string of ordinal numbers separated by decimal points.
+ * @return The result is a negative integer if str1 is numerically less than str2.
+ * The result is a positive integer if str1 is numerically greater than str2.
+ * The result is zero if the strings are numerically equal.
+ */
+ public static int versionCompare(String str1, String str2) {
+ String[] vals1 = str1.split("\\.");
+ String[] vals2 = str2.split("\\.");
+ int i = 0;
+ // set index to first non-equal ordinal or length of shortest version string
+ while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
+ i++;
+ }
+ // compare first non-equal ordinal number
+ if (i < vals1.length && i < vals2.length) {
+ int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i]));
+ return Integer.signum(diff);
+ }
+ // the strings are equal or one string is a substring of the other
+ // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4"
+ return Integer.signum(vals1.length - vals2.length);
+ }
+
+ public static ZonedDateTime localToUTC(LocalDateTime localDateTime) {
+ return localDateTime.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC);
+ }
+
+ public static ZonedDateTime zoneToUTC(ZonedDateTime dateTime) {
+ return dateTime.withZoneSameInstant(ZoneOffset.UTC);
+ }
+
+ public static LocalDateTime UTCToLocal(ZonedDateTime utcTime) {
+ return utcTime.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
+ }
+
+ public static Timestamp ZDTToTimestamp(ZonedDateTime zdt) {
+ return new Timestamp(UTCToMilli(zoneToUTC(zdt)));
+ }
+
+ public static ZonedDateTime zoneToLocal(ZonedDateTime dateTime) {
+ return dateTime.withZoneSameInstant(ZoneOffset.systemDefault());
+ }
+
+ public static long UTCToMilli(ZonedDateTime utcTime) {
+ return zoneToLocal(utcTime).toInstant().toEpochMilli();
+ }
+
+}
diff --git a/legup-update/src/main/java/edu/rpi/legupupdate/Update.java b/legup-update/src/main/java/edu/rpi/legupupdate/Update.java
new file mode 100644
index 000000000..578c4f002
--- /dev/null
+++ b/legup-update/src/main/java/edu/rpi/legupupdate/Update.java
@@ -0,0 +1,252 @@
+package edu.rpi.legupupdate;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.*;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static edu.rpi.legupupdate.Update.Stream.CLIENT;
+
+public class Update {
+
+ private static final Logger logger = Logger.getLogger(Update.class.getName());
+
+ private static final String RELEASE_CHECK_URL = "https://api.github.com/repos/jpoegs/Legup2.0/releases/latest";
+ private static final String REPO_BASE_URL = "https://github.com/jpoegs/Legup2.0/releases/download/";
+ private static final String MAVEN_BASE_URL = "http://central.maven.org/maven2/";
+ private static final String CLIENT_LIBS_LOC = "/client/client.iml";
+ private static final String LIBRARY_LINE_ID = "type=\"library\"";
+ private static final Pattern LIB_PATTERN = Pattern.compile("(?<=name=\").*?(?=\")");
+ private static final int UPDATE_EXIT_CODE = 52;
+ private File downloadDir;
+ private Stream updateStream;
+ private JsonObject releaseData;
+ private String updateVersion;
+ private UpdateProgress progress;
+
+ public static final String VERSION;
+
+ static {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(Update.class.getResourceAsStream("/edu/rpi/legup/VERSION")));
+ String version = "UNKNOWN";
+ try {
+ version = reader.readLine();
+ reader.close();
+ }
+ catch (IOException e) {
+ logger.severe("An error occurred while attempting to read the version\n" + e.getMessage());
+ }
+ VERSION = version;
+ }
+
+ public Update(Stream updateStream, File updateDownloadDir) {
+ Objects.requireNonNull(updateStream);
+ Objects.requireNonNull(updateDownloadDir);
+ this.downloadDir = updateDownloadDir;
+ this.updateStream = updateStream;
+ }
+
+ public void setUpdateProgress(UpdateProgress progress) {
+ this.progress = progress;
+ }
+
+ public boolean checkUpdate() {
+ try {
+ if (progress != null) {
+ progress.setTotalDownloads(-1);
+ progress.setDescription("Checking for update");
+ }
+ logger.info("Checking for update");
+ URL releaseUrl = new URL(RELEASE_CHECK_URL);
+ try (InputStream in = releaseUrl.openStream();
+ InputStreamReader reader = new InputStreamReader(in)) {
+ releaseData = new JsonParser().parse(reader).getAsJsonObject();
+ JsonElement tagElement = releaseData.get("tag_name");
+ if (tagElement == null) {
+ return false;
+ }
+ updateVersion = tagElement.getAsString();
+ logger.info("Current version: " + VERSION);
+ logger.info("Latest version: " + updateVersion);
+ if (NetUtil.versionCompare(VERSION, updateVersion) < 0) {
+ logger.info("Update available");
+ return true;
+ }
+ else {
+ logger.info("No update available");
+ }
+ }
+ }
+ catch (IOException e) {
+ logger.severe("Failed to check for update\n" + e.getMessage());
+ }
+ return false;
+ }
+
+ private String getAssetUrl(String assetName) {
+ JsonArray array = releaseData.get("assets").getAsJsonArray();
+ if (array == null) {
+ return null;
+ }
+ for (int i = 0; i < array.size(); ++i) {
+ JsonObject asset = array.get(i).getAsJsonObject();
+ if (asset.get("name").getAsString().equals(assetName)) {
+ return asset.get("browser_download_url").getAsString();
+ }
+ }
+ return null;
+ }
+
+ private void getLibs(String urlStr, HashMap set) throws IOException {
+ URL url = new URL(urlStr);
+ try (InputStream is = url.openStream();
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader reader = new BufferedReader(isr)) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (!line.contains(LIBRARY_LINE_ID)) {
+ continue;
+ }
+ Matcher m = LIB_PATTERN.matcher(line);
+ if (!m.find()) {
+ continue;
+ }
+ line = m.group();
+ String[] split = line.split(":");
+ if (split.length != 3) {
+ throw new IOException("Invalid library list in remote repository");
+ }
+ String groupId = split[0].replaceAll("\\.", "/");
+ String artifactId = split[1];
+ String version = split[2];
+ String name = artifactId + "-" + version + ".jar";
+ set.put(name, MAVEN_BASE_URL + groupId + "/" + artifactId + "/" + version + "/" + name);
+ }
+ }
+ }
+
+ private HashMap getLibs() throws IOException {
+ HashMap libs = new HashMap<>();
+ getLibs(REPO_BASE_URL + updateVersion + "/" + CLIENT.assetName, libs);
+ return libs;
+ }
+
+ private boolean guessDevEnvironment() {
+ return !Update.class.getResource(Update.class.getSimpleName() + ".class").toString().toLowerCase().startsWith("jar:");
+ }
+
+ private void downloadFile(String urlStr, File destination) throws IOException {
+ logger.info("Downloading: " + urlStr);
+ URL url = new URL(urlStr);
+ FileUtils.copyURLToFile(url, destination, 10000, 10000);
+ }
+
+ public boolean update() {
+ if (releaseData == null) {
+ return false;
+ }
+ if (guessDevEnvironment()) {
+ logger.warning("Legup appears to be running in a development environment so automatic updating has been disabled");
+// return false;
+ }
+ logger.info("Starting update");
+ logger.info("Getting download list");
+ if (progress != null) {
+ progress.setTotalDownloads(-1);
+ progress.setDescription("Starting update");
+ }
+ String jarUrl = getAssetUrl(updateStream.assetName);
+ if (jarUrl == null) {
+ return false;
+ }
+ try {
+ HashMap libs = getLibs();
+ if (!downloadDir.exists() && !downloadDir.mkdirs()) {
+ logger.warning("Failed to create temporary download directory");
+ return false;
+ }
+ int current = 0;
+ if (progress != null) {
+ progress.setTotalDownloads(libs.size());
+ progress.setCurrentDownload(current);
+ progress.setDescription("Downloading " + updateStream.assetName);
+ }
+ downloadFile(jarUrl, new File(downloadDir, updateStream.assetName));
+ current++;
+ File libDir = new File(downloadDir, "lib");
+ for (Map.Entry lib : libs.entrySet()) {
+ if (progress != null) {
+ progress.setCurrentDownload(current);
+ progress.setDescription("Downloading " + lib.getKey());
+ }
+ downloadFile(lib.getValue(), new File(libDir, lib.getKey()));
+ current++;
+ }
+ if (progress != null) {
+ progress.setCurrentDownload(current);
+ progress.setDescription("Download complete!");
+ }
+ logger.info("Download complete");
+ return true;
+ }
+ catch (IOException e) {
+ logger.severe("Failed to update Legup\n" + e.getMessage());
+ return false;
+ }
+ }
+
+ private void unzipFile(File file) throws IOException {
+ try (ZipFile zipFile = new ZipFile(file)) {
+ Enumeration extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ File entryDestination = new File(downloadDir, entry.getName());
+ if (entry.isDirectory()) {
+ if (!entryDestination.exists() && !entryDestination.mkdirs()) {
+ throw new IOException("Failed to unzip file: " + file.getCanonicalPath());
+ }
+ }
+ else {
+ if (!entryDestination.getParentFile().exists() && !entryDestination.getParentFile().mkdirs()) {
+ throw new IOException("Failed to unzip file: " + file.getCanonicalPath());
+ }
+ try (InputStream in = zipFile.getInputStream(entry);
+ OutputStream out = new FileOutputStream(entryDestination)) {
+ IOUtils.copy(in, out);
+ }
+ }
+ }
+ }
+ }
+
+ public void exit() {
+ System.exit(UPDATE_EXIT_CODE);
+ }
+
+ public enum Stream {
+ CLIENT("Legup(1).jar", "client-update.zip");
+
+ public final String assetName;
+ public final String extraName;
+
+ Stream(String assetName, String extraName) {
+ this.assetName = assetName;
+ this.extraName = extraName;
+ }
+ }
+
+}
diff --git a/legup-update/src/main/java/edu/rpi/legupupdate/UpdateProgress.java b/legup-update/src/main/java/edu/rpi/legupupdate/UpdateProgress.java
new file mode 100644
index 000000000..1c137ad04
--- /dev/null
+++ b/legup-update/src/main/java/edu/rpi/legupupdate/UpdateProgress.java
@@ -0,0 +1,11 @@
+package edu.rpi.legupupdate;
+
+public interface UpdateProgress {
+
+ void setTotalDownloads(double total);
+
+ void setCurrentDownload(double current);
+
+ void setDescription(String description);
+
+}
diff --git a/legup-update/src/main/resources/edu.rpi.legupupdate/VERSION b/legup-update/src/main/resources/edu.rpi.legupupdate/VERSION
new file mode 100644
index 000000000..227cea215
--- /dev/null
+++ b/legup-update/src/main/resources/edu.rpi.legupupdate/VERSION
@@ -0,0 +1 @@
+2.0.0
diff --git a/puzzles files/fillapix/10x10 Fillapix Very Easy/03010000074 b/puzzles files/fillapix/10x10 Fillapix Very Easy/03010000074
index face5ef48..d514b73d0 100644
--- a/puzzles files/fillapix/10x10 Fillapix Very Easy/03010000074
+++ b/puzzles files/fillapix/10x10 Fillapix Very Easy/03010000074
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/lightup/10x10 Easy/1514228 b/puzzles files/lightup/10x10 Easy/1514228
index b60ba98df..4eb263016 100644
--- a/puzzles files/lightup/10x10 Easy/1514228
+++ b/puzzles files/lightup/10x10 Easy/1514228
@@ -30,5 +30,4 @@
-
diff --git a/puzzles files/lightup/10x10 Easy/1721067 b/puzzles files/lightup/10x10 Easy/1721067
index 07665470d..a4b113ddb 100644
--- a/puzzles files/lightup/10x10 Easy/1721067
+++ b/puzzles files/lightup/10x10 Easy/1721067
@@ -30,5 +30,4 @@
-
diff --git a/puzzles files/lightup/10x10 Easy/5403393 b/puzzles files/lightup/10x10 Easy/5403393
index 75b55ed99..7b316c678 100644
--- a/puzzles files/lightup/10x10 Easy/5403393
+++ b/puzzles files/lightup/10x10 Easy/5403393
@@ -26,5 +26,4 @@
-
diff --git a/puzzles files/lightup/10x10 Easy/5774519 b/puzzles files/lightup/10x10 Easy/5774519
index fdcf54e2f..591d6366a 100644
--- a/puzzles files/lightup/10x10 Easy/5774519
+++ b/puzzles files/lightup/10x10 Easy/5774519
@@ -26,5 +26,4 @@
-
diff --git a/puzzles files/lightup/10x10 Easy/954498 b/puzzles files/lightup/10x10 Easy/954498
index 852899d94..ef4680cb4 100644
--- a/puzzles files/lightup/10x10 Easy/954498
+++ b/puzzles files/lightup/10x10 Easy/954498
@@ -26,5 +26,4 @@
-
diff --git a/puzzles files/lightup/10x10 Hard/5373598 b/puzzles files/lightup/10x10 Hard/5373598
index b7cc9791d..67e0bbdb9 100644
--- a/puzzles files/lightup/10x10 Hard/5373598
+++ b/puzzles files/lightup/10x10 Hard/5373598
@@ -26,5 +26,4 @@
-
diff --git a/puzzles files/lightup/10x10 Hard/573404 b/puzzles files/lightup/10x10 Hard/573404
index 6e4f67a61..12d4ce960 100644
--- a/puzzles files/lightup/10x10 Hard/573404
+++ b/puzzles files/lightup/10x10 Hard/573404
@@ -26,5 +26,4 @@
-
diff --git a/puzzles files/lightup/10x10 Hard/5787104 b/puzzles files/lightup/10x10 Hard/5787104
index 59a6f95db..03ef1fe87 100644
--- a/puzzles files/lightup/10x10 Hard/5787104
+++ b/puzzles files/lightup/10x10 Hard/5787104
@@ -30,5 +30,4 @@
-
diff --git a/puzzles files/lightup/10x10 Hard/8003166 b/puzzles files/lightup/10x10 Hard/8003166
index 3ea9496d9..fe4cb461b 100644
--- a/puzzles files/lightup/10x10 Hard/8003166
+++ b/puzzles files/lightup/10x10 Hard/8003166
@@ -26,5 +26,4 @@
-
diff --git a/puzzles files/lightup/10x10 Hard/8918995 b/puzzles files/lightup/10x10 Hard/8918995
index f89fcce5d..22c95573a 100644
--- a/puzzles files/lightup/10x10 Hard/8918995
+++ b/puzzles files/lightup/10x10 Hard/8918995
@@ -34,5 +34,4 @@
-
diff --git a/puzzles files/lightup/10x10 Normal/2761230 b/puzzles files/lightup/10x10 Normal/2761230
index 32a8e2b7b..c2f5dee6f 100644
--- a/puzzles files/lightup/10x10 Normal/2761230
+++ b/puzzles files/lightup/10x10 Normal/2761230
@@ -30,5 +30,4 @@
-
diff --git a/puzzles files/lightup/10x10 Normal/343176 b/puzzles files/lightup/10x10 Normal/343176
index 7b34df834..2a6160327 100644
--- a/puzzles files/lightup/10x10 Normal/343176
+++ b/puzzles files/lightup/10x10 Normal/343176
@@ -30,5 +30,4 @@
-
diff --git a/puzzles files/lightup/10x10 Normal/632466 b/puzzles files/lightup/10x10 Normal/632466
index 7501eb7ef..f8a6c6d99 100644
--- a/puzzles files/lightup/10x10 Normal/632466
+++ b/puzzles files/lightup/10x10 Normal/632466
@@ -26,5 +26,4 @@
-
diff --git a/puzzles files/lightup/10x10 Normal/7752941 b/puzzles files/lightup/10x10 Normal/7752941
index 100de78cd..52397a6b2 100644
--- a/puzzles files/lightup/10x10 Normal/7752941
+++ b/puzzles files/lightup/10x10 Normal/7752941
@@ -26,5 +26,4 @@
-
diff --git a/puzzles files/lightup/10x10 Normal/8090631 b/puzzles files/lightup/10x10 Normal/8090631
index f0ea906e9..f481414c9 100644
--- a/puzzles files/lightup/10x10 Normal/8090631
+++ b/puzzles files/lightup/10x10 Normal/8090631
@@ -30,5 +30,4 @@
-
diff --git a/puzzles files/lightup/14x14 Easy/1412335 b/puzzles files/lightup/14x14 Easy/1412335
index 29863daae..5959d9bb6 100644
--- a/puzzles files/lightup/14x14 Easy/1412335
+++ b/puzzles files/lightup/14x14 Easy/1412335
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Easy/1949915 b/puzzles files/lightup/14x14 Easy/1949915
index f11c997f5..3742cdba8 100644
--- a/puzzles files/lightup/14x14 Easy/1949915
+++ b/puzzles files/lightup/14x14 Easy/1949915
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Easy/6778348 b/puzzles files/lightup/14x14 Easy/6778348
index a2025b627..074f1d836 100644
--- a/puzzles files/lightup/14x14 Easy/6778348
+++ b/puzzles files/lightup/14x14 Easy/6778348
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Easy/976495 b/puzzles files/lightup/14x14 Easy/976495
index 4abc0813a..7321a5b87 100644
--- a/puzzles files/lightup/14x14 Easy/976495
+++ b/puzzles files/lightup/14x14 Easy/976495
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Easy/9949966 b/puzzles files/lightup/14x14 Easy/9949966
index 9a363631c..8ae7d5abe 100644
--- a/puzzles files/lightup/14x14 Easy/9949966
+++ b/puzzles files/lightup/14x14 Easy/9949966
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/lightup/14x14 Hard/1974912 b/puzzles files/lightup/14x14 Hard/1974912
index 9174bbd50..3ac9c44a6 100644
--- a/puzzles files/lightup/14x14 Hard/1974912
+++ b/puzzles files/lightup/14x14 Hard/1974912
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Hard/3618696 b/puzzles files/lightup/14x14 Hard/3618696
index 5e555d8ec..91f02e1ba 100644
--- a/puzzles files/lightup/14x14 Hard/3618696
+++ b/puzzles files/lightup/14x14 Hard/3618696
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Hard/578987 b/puzzles files/lightup/14x14 Hard/578987
index 281effef3..3ccfaa1e7 100644
--- a/puzzles files/lightup/14x14 Hard/578987
+++ b/puzzles files/lightup/14x14 Hard/578987
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Hard/8087653 b/puzzles files/lightup/14x14 Hard/8087653
index dfd8f161c..1f7c77e99 100644
--- a/puzzles files/lightup/14x14 Hard/8087653
+++ b/puzzles files/lightup/14x14 Hard/8087653
@@ -62,5 +62,4 @@
-
diff --git a/puzzles files/lightup/14x14 Hard/9554192 b/puzzles files/lightup/14x14 Hard/9554192
index c0ef178d7..120adddb2 100644
--- a/puzzles files/lightup/14x14 Hard/9554192
+++ b/puzzles files/lightup/14x14 Hard/9554192
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Normal/2659779 b/puzzles files/lightup/14x14 Normal/2659779
index e54876bfa..d367b6c65 100644
--- a/puzzles files/lightup/14x14 Normal/2659779
+++ b/puzzles files/lightup/14x14 Normal/2659779
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Normal/448333 b/puzzles files/lightup/14x14 Normal/448333
index 3a1a2b999..b93938bfe 100644
--- a/puzzles files/lightup/14x14 Normal/448333
+++ b/puzzles files/lightup/14x14 Normal/448333
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Normal/5063453 b/puzzles files/lightup/14x14 Normal/5063453
index 579622ab9..e3cc8578c 100644
--- a/puzzles files/lightup/14x14 Normal/5063453
+++ b/puzzles files/lightup/14x14 Normal/5063453
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/lightup/14x14 Normal/606275 b/puzzles files/lightup/14x14 Normal/606275
index 377747988..0b5bb6590 100644
--- a/puzzles files/lightup/14x14 Normal/606275
+++ b/puzzles files/lightup/14x14 Normal/606275
@@ -54,5 +54,4 @@
-
diff --git a/puzzles files/lightup/14x14 Normal/830231 b/puzzles files/lightup/14x14 Normal/830231
index cfc8fbf43..118c41d24 100644
--- a/puzzles files/lightup/14x14 Normal/830231
+++ b/puzzles files/lightup/14x14 Normal/830231
@@ -61,5 +61,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/2408448 b/puzzles files/lightup/7x7 Easy/2408448
index de29dc419..b8fe2d7fe 100644
--- a/puzzles files/lightup/7x7 Easy/2408448
+++ b/puzzles files/lightup/7x7 Easy/2408448
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/2736784 b/puzzles files/lightup/7x7 Easy/2736784
index a5041796e..1160ced8b 100644
--- a/puzzles files/lightup/7x7 Easy/2736784
+++ b/puzzles files/lightup/7x7 Easy/2736784
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/2855683 b/puzzles files/lightup/7x7 Easy/2855683
index fc84f34b8..47e9cff0d 100644
--- a/puzzles files/lightup/7x7 Easy/2855683
+++ b/puzzles files/lightup/7x7 Easy/2855683
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/3535701 b/puzzles files/lightup/7x7 Easy/3535701
index 7a1e79aaa..27b4be065 100644
--- a/puzzles files/lightup/7x7 Easy/3535701
+++ b/puzzles files/lightup/7x7 Easy/3535701
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/393454 b/puzzles files/lightup/7x7 Easy/393454
index f10385f1c..039718e13 100644
--- a/puzzles files/lightup/7x7 Easy/393454
+++ b/puzzles files/lightup/7x7 Easy/393454
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/4238934 b/puzzles files/lightup/7x7 Easy/4238934
index 6106f8f73..58108606d 100644
--- a/puzzles files/lightup/7x7 Easy/4238934
+++ b/puzzles files/lightup/7x7 Easy/4238934
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/4604288 b/puzzles files/lightup/7x7 Easy/4604288
index c74b7a07a..0cc8d862a 100644
--- a/puzzles files/lightup/7x7 Easy/4604288
+++ b/puzzles files/lightup/7x7 Easy/4604288
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/4608986 b/puzzles files/lightup/7x7 Easy/4608986
index b80712533..eb6fd1405 100644
--- a/puzzles files/lightup/7x7 Easy/4608986
+++ b/puzzles files/lightup/7x7 Easy/4608986
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/517362 b/puzzles files/lightup/7x7 Easy/517362
index e2242e266..a6b7c32e7 100644
--- a/puzzles files/lightup/7x7 Easy/517362
+++ b/puzzles files/lightup/7x7 Easy/517362
@@ -19,5 +19,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/5229613 b/puzzles files/lightup/7x7 Easy/5229613
index 78fa909ac..f755e6a27 100644
--- a/puzzles files/lightup/7x7 Easy/5229613
+++ b/puzzles files/lightup/7x7 Easy/5229613
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/5435528 b/puzzles files/lightup/7x7 Easy/5435528
index a34ef0587..6c5c133d1 100644
--- a/puzzles files/lightup/7x7 Easy/5435528
+++ b/puzzles files/lightup/7x7 Easy/5435528
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/5488697 b/puzzles files/lightup/7x7 Easy/5488697
index 538665943..18c21eb4f 100644
--- a/puzzles files/lightup/7x7 Easy/5488697
+++ b/puzzles files/lightup/7x7 Easy/5488697
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/6110408 b/puzzles files/lightup/7x7 Easy/6110408
index 8905837d8..302dfb1a7 100644
--- a/puzzles files/lightup/7x7 Easy/6110408
+++ b/puzzles files/lightup/7x7 Easy/6110408
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/6300100 b/puzzles files/lightup/7x7 Easy/6300100
index 4e4578de6..37855feba 100644
--- a/puzzles files/lightup/7x7 Easy/6300100
+++ b/puzzles files/lightup/7x7 Easy/6300100
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/6506194 b/puzzles files/lightup/7x7 Easy/6506194
index 1feeead80..a21e6b9ec 100644
--- a/puzzles files/lightup/7x7 Easy/6506194
+++ b/puzzles files/lightup/7x7 Easy/6506194
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/69495 b/puzzles files/lightup/7x7 Easy/69495
index 71a0914c5..a3b048963 100644
--- a/puzzles files/lightup/7x7 Easy/69495
+++ b/puzzles files/lightup/7x7 Easy/69495
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/7936304 b/puzzles files/lightup/7x7 Easy/7936304
index 3fdc7c5f1..bd4a81f6d 100644
--- a/puzzles files/lightup/7x7 Easy/7936304
+++ b/puzzles files/lightup/7x7 Easy/7936304
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/7982513 b/puzzles files/lightup/7x7 Easy/7982513
index 4246b04e1..d140be9cf 100644
--- a/puzzles files/lightup/7x7 Easy/7982513
+++ b/puzzles files/lightup/7x7 Easy/7982513
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/8949430 b/puzzles files/lightup/7x7 Easy/8949430
index 45eb4e763..a4c87729f 100644
--- a/puzzles files/lightup/7x7 Easy/8949430
+++ b/puzzles files/lightup/7x7 Easy/8949430
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Easy/9080685 b/puzzles files/lightup/7x7 Easy/9080685
index d1071de3b..a5ef8e22f 100644
--- a/puzzles files/lightup/7x7 Easy/9080685
+++ b/puzzles files/lightup/7x7 Easy/9080685
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/1130370 b/puzzles files/lightup/7x7 Hard/1130370
index a5d6ab650..afab8ece1 100644
--- a/puzzles files/lightup/7x7 Hard/1130370
+++ b/puzzles files/lightup/7x7 Hard/1130370
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/2790971 b/puzzles files/lightup/7x7 Hard/2790971
index 87b7dc5fc..2f91d1aff 100644
--- a/puzzles files/lightup/7x7 Hard/2790971
+++ b/puzzles files/lightup/7x7 Hard/2790971
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/3421347 b/puzzles files/lightup/7x7 Hard/3421347
index 68c6cb4fe..f16a9ecf1 100644
--- a/puzzles files/lightup/7x7 Hard/3421347
+++ b/puzzles files/lightup/7x7 Hard/3421347
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/4159457 b/puzzles files/lightup/7x7 Hard/4159457
index 05b3a0bc5..d08b1c012 100644
--- a/puzzles files/lightup/7x7 Hard/4159457
+++ b/puzzles files/lightup/7x7 Hard/4159457
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/4674087 b/puzzles files/lightup/7x7 Hard/4674087
index ed4dd0002..ca79fb87f 100644
--- a/puzzles files/lightup/7x7 Hard/4674087
+++ b/puzzles files/lightup/7x7 Hard/4674087
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/507817 b/puzzles files/lightup/7x7 Hard/507817
index 0bedc7cd5..64a53c371 100644
--- a/puzzles files/lightup/7x7 Hard/507817
+++ b/puzzles files/lightup/7x7 Hard/507817
@@ -19,5 +19,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/5280094 b/puzzles files/lightup/7x7 Hard/5280094
index 36e4fe127..cda81c889 100644
--- a/puzzles files/lightup/7x7 Hard/5280094
+++ b/puzzles files/lightup/7x7 Hard/5280094
@@ -19,5 +19,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/5677803 b/puzzles files/lightup/7x7 Hard/5677803
index 6fa56c0d9..d7fee9e79 100644
--- a/puzzles files/lightup/7x7 Hard/5677803
+++ b/puzzles files/lightup/7x7 Hard/5677803
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/6178908 b/puzzles files/lightup/7x7 Hard/6178908
index 0cb8be391..bc3febaf0 100644
--- a/puzzles files/lightup/7x7 Hard/6178908
+++ b/puzzles files/lightup/7x7 Hard/6178908
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Hard/8122162 b/puzzles files/lightup/7x7 Hard/8122162
index 539fb9641..cfd808ccf 100644
--- a/puzzles files/lightup/7x7 Hard/8122162
+++ b/puzzles files/lightup/7x7 Hard/8122162
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/2637310 b/puzzles files/lightup/7x7 Normal/2637310
index 8fd9d073b..c1e88ea4f 100644
--- a/puzzles files/lightup/7x7 Normal/2637310
+++ b/puzzles files/lightup/7x7 Normal/2637310
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/2979943 b/puzzles files/lightup/7x7 Normal/2979943
index 6cf281463..7164eff19 100644
--- a/puzzles files/lightup/7x7 Normal/2979943
+++ b/puzzles files/lightup/7x7 Normal/2979943
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/3710905 b/puzzles files/lightup/7x7 Normal/3710905
index 235b91e00..9ae7304dd 100644
--- a/puzzles files/lightup/7x7 Normal/3710905
+++ b/puzzles files/lightup/7x7 Normal/3710905
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/3727425 b/puzzles files/lightup/7x7 Normal/3727425
index c06aa1903..96495d463 100644
--- a/puzzles files/lightup/7x7 Normal/3727425
+++ b/puzzles files/lightup/7x7 Normal/3727425
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/3787583 b/puzzles files/lightup/7x7 Normal/3787583
index 192fe831d..a3972a249 100644
--- a/puzzles files/lightup/7x7 Normal/3787583
+++ b/puzzles files/lightup/7x7 Normal/3787583
@@ -19,5 +19,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/5570754 b/puzzles files/lightup/7x7 Normal/5570754
index 01e6224cd..5e94bc9c3 100644
--- a/puzzles files/lightup/7x7 Normal/5570754
+++ b/puzzles files/lightup/7x7 Normal/5570754
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/7270504 b/puzzles files/lightup/7x7 Normal/7270504
index 57d3f0fa8..a5a539f40 100644
--- a/puzzles files/lightup/7x7 Normal/7270504
+++ b/puzzles files/lightup/7x7 Normal/7270504
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/8000000 b/puzzles files/lightup/7x7 Normal/8000000
index 6de8dd8ba..bad645ee2 100644
--- a/puzzles files/lightup/7x7 Normal/8000000
+++ b/puzzles files/lightup/7x7 Normal/8000000
@@ -19,5 +19,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/9489812 b/puzzles files/lightup/7x7 Normal/9489812
index fb5bd3113..e342523b8 100644
--- a/puzzles files/lightup/7x7 Normal/9489812
+++ b/puzzles files/lightup/7x7 Normal/9489812
@@ -15,5 +15,4 @@
-
diff --git a/puzzles files/lightup/7x7 Normal/9806740 b/puzzles files/lightup/7x7 Normal/9806740
index f3493a021..cd87ca7dc 100644
--- a/puzzles files/lightup/7x7 Normal/9806740
+++ b/puzzles files/lightup/7x7 Normal/9806740
@@ -19,5 +19,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Easy/6E_b0011 b/puzzles files/masyu/6x6 Masyu Easy/6E_b0011
index 637567c9f..d88dc4abb 100644
--- a/puzzles files/masyu/6x6 Masyu Easy/6E_b0011
+++ b/puzzles files/masyu/6x6 Masyu Easy/6E_b0011
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Easy/6E_b0012 b/puzzles files/masyu/6x6 Masyu Easy/6E_b0012
index 304f51bd8..ea47166ce 100644
--- a/puzzles files/masyu/6x6 Masyu Easy/6E_b0012
+++ b/puzzles files/masyu/6x6 Masyu Easy/6E_b0012
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Easy/6E_b0013 b/puzzles files/masyu/6x6 Masyu Easy/6E_b0013
index 4c8c5171a..af7040555 100644
--- a/puzzles files/masyu/6x6 Masyu Easy/6E_b0013
+++ b/puzzles files/masyu/6x6 Masyu Easy/6E_b0013
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Easy/6E_b0014 b/puzzles files/masyu/6x6 Masyu Easy/6E_b0014
index 209eb2863..a02ef4068 100644
--- a/puzzles files/masyu/6x6 Masyu Easy/6E_b0014
+++ b/puzzles files/masyu/6x6 Masyu Easy/6E_b0014
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Easy/6E_b0015 b/puzzles files/masyu/6x6 Masyu Easy/6E_b0015
index 6ec496107..9e66c9eb1 100644
--- a/puzzles files/masyu/6x6 Masyu Easy/6E_b0015
+++ b/puzzles files/masyu/6x6 Masyu Easy/6E_b0015
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Hard/6H_b0011 b/puzzles files/masyu/6x6 Masyu Hard/6H_b0011
index bafaa7bdb..4e4ddc3bc 100644
--- a/puzzles files/masyu/6x6 Masyu Hard/6H_b0011
+++ b/puzzles files/masyu/6x6 Masyu Hard/6H_b0011
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Hard/6H_b0012 b/puzzles files/masyu/6x6 Masyu Hard/6H_b0012
index 15212f451..57b5ace30 100644
--- a/puzzles files/masyu/6x6 Masyu Hard/6H_b0012
+++ b/puzzles files/masyu/6x6 Masyu Hard/6H_b0012
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Hard/6H_b0013 b/puzzles files/masyu/6x6 Masyu Hard/6H_b0013
index 9c5b410bd..ed78214e7 100644
--- a/puzzles files/masyu/6x6 Masyu Hard/6H_b0013
+++ b/puzzles files/masyu/6x6 Masyu Hard/6H_b0013
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Hard/6H_b0014 b/puzzles files/masyu/6x6 Masyu Hard/6H_b0014
index c271db9a4..24cd73827 100644
--- a/puzzles files/masyu/6x6 Masyu Hard/6H_b0014
+++ b/puzzles files/masyu/6x6 Masyu Hard/6H_b0014
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Hard/6H_b0015 b/puzzles files/masyu/6x6 Masyu Hard/6H_b0015
index ae37a1e41..30bb3ecf2 100644
--- a/puzzles files/masyu/6x6 Masyu Hard/6H_b0015
+++ b/puzzles files/masyu/6x6 Masyu Hard/6H_b0015
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Medium/6M_b0011 b/puzzles files/masyu/6x6 Masyu Medium/6M_b0011
index bc378de72..3dcd13d61 100644
--- a/puzzles files/masyu/6x6 Masyu Medium/6M_b0011
+++ b/puzzles files/masyu/6x6 Masyu Medium/6M_b0011
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Medium/6M_b0012 b/puzzles files/masyu/6x6 Masyu Medium/6M_b0012
index 564245639..52a5e16ad 100644
--- a/puzzles files/masyu/6x6 Masyu Medium/6M_b0012
+++ b/puzzles files/masyu/6x6 Masyu Medium/6M_b0012
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Medium/6M_b0013 b/puzzles files/masyu/6x6 Masyu Medium/6M_b0013
index 388908083..e7ccb2980 100644
--- a/puzzles files/masyu/6x6 Masyu Medium/6M_b0013
+++ b/puzzles files/masyu/6x6 Masyu Medium/6M_b0013
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Medium/6M_b0014 b/puzzles files/masyu/6x6 Masyu Medium/6M_b0014
index 01b2baafa..3274804b3 100644
--- a/puzzles files/masyu/6x6 Masyu Medium/6M_b0014
+++ b/puzzles files/masyu/6x6 Masyu Medium/6M_b0014
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/masyu/6x6 Masyu Medium/6M_b0015 b/puzzles files/masyu/6x6 Masyu Medium/6M_b0015
index cf246c891..a645a3936 100644
--- a/puzzles files/masyu/6x6 Masyu Medium/6M_b0015
+++ b/puzzles files/masyu/6x6 Masyu Medium/6M_b0015
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/narukabe_export tet b/puzzles files/narukabe_export tet
index b24ae3073..9a76535e0 100644
--- a/puzzles files/narukabe_export tet
+++ b/puzzles files/narukabe_export tet
@@ -1,32 +1,31 @@
-
-
-
- |
- |
- |
- |
- |
-
-
-
-
-
-
- |
- |
- |
- |
- |
- |
- |
- |
-
-
-
-
-
-
-
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Hard/3323808 b/puzzles files/nurikabe/10x10 Nurikabe Hard/3323808
index 755fb9411..ffdfee88f 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Hard/3323808
+++ b/puzzles files/nurikabe/10x10 Nurikabe Hard/3323808
@@ -17,5 +17,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Hard/7675382 b/puzzles files/nurikabe/10x10 Nurikabe Hard/7675382
index 87681726a..414f9bb47 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Hard/7675382
+++ b/puzzles files/nurikabe/10x10 Nurikabe Hard/7675382
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Hard/8264437 b/puzzles files/nurikabe/10x10 Nurikabe Hard/8264437
index 92fc60999..e3d993ca7 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Hard/8264437
+++ b/puzzles files/nurikabe/10x10 Nurikabe Hard/8264437
@@ -21,5 +21,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Hard/8991218 b/puzzles files/nurikabe/10x10 Nurikabe Hard/8991218
index 52babddd6..f707c9edb 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Hard/8991218
+++ b/puzzles files/nurikabe/10x10 Nurikabe Hard/8991218
@@ -19,5 +19,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Hard/9120893 b/puzzles files/nurikabe/10x10 Nurikabe Hard/9120893
index c846329f9..d30061ab6 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Hard/9120893
+++ b/puzzles files/nurikabe/10x10 Nurikabe Hard/9120893
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Normal/2852229 b/puzzles files/nurikabe/10x10 Nurikabe Normal/2852229
index 159d5d405..7752cc3a9 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Normal/2852229
+++ b/puzzles files/nurikabe/10x10 Nurikabe Normal/2852229
@@ -18,5 +18,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Normal/5759900 b/puzzles files/nurikabe/10x10 Nurikabe Normal/5759900
index 064b04617..4f9eaeb45 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Normal/5759900
+++ b/puzzles files/nurikabe/10x10 Nurikabe Normal/5759900
@@ -19,5 +19,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Normal/6274292 b/puzzles files/nurikabe/10x10 Nurikabe Normal/6274292
index 834e61259..ccffd35da 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Normal/6274292
+++ b/puzzles files/nurikabe/10x10 Nurikabe Normal/6274292
@@ -22,5 +22,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Normal/8920015 b/puzzles files/nurikabe/10x10 Nurikabe Normal/8920015
index 4ac1c391a..273dc5ecc 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Normal/8920015
+++ b/puzzles files/nurikabe/10x10 Nurikabe Normal/8920015
@@ -22,5 +22,4 @@
-
diff --git a/puzzles files/nurikabe/10x10 Nurikabe Normal/9757357 b/puzzles files/nurikabe/10x10 Nurikabe Normal/9757357
index a014eb32d..da3ab0a74 100644
--- a/puzzles files/nurikabe/10x10 Nurikabe Normal/9757357
+++ b/puzzles files/nurikabe/10x10 Nurikabe Normal/9757357
@@ -17,5 +17,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Hard/1276535 b/puzzles files/nurikabe/12x12 Nurikabe Hard/1276535
index 70fbdfe8a..bbfa5ed1f 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Hard/1276535
+++ b/puzzles files/nurikabe/12x12 Nurikabe Hard/1276535
@@ -22,5 +22,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Hard/4284912 b/puzzles files/nurikabe/12x12 Nurikabe Hard/4284912
index bdc358496..401e68fb7 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Hard/4284912
+++ b/puzzles files/nurikabe/12x12 Nurikabe Hard/4284912
@@ -22,5 +22,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Hard/4459392 b/puzzles files/nurikabe/12x12 Nurikabe Hard/4459392
index 949683386..a715a8bca 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Hard/4459392
+++ b/puzzles files/nurikabe/12x12 Nurikabe Hard/4459392
@@ -23,5 +23,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Hard/7738199 b/puzzles files/nurikabe/12x12 Nurikabe Hard/7738199
index 107b1f1a8..bba566af4 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Hard/7738199
+++ b/puzzles files/nurikabe/12x12 Nurikabe Hard/7738199
@@ -21,5 +21,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Hard/9205907 b/puzzles files/nurikabe/12x12 Nurikabe Hard/9205907
index 185f1959b..3757c89c9 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Hard/9205907
+++ b/puzzles files/nurikabe/12x12 Nurikabe Hard/9205907
@@ -22,5 +22,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Normal/1570101 b/puzzles files/nurikabe/12x12 Nurikabe Normal/1570101
index 74cdcc65a..f1eef204e 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Normal/1570101
+++ b/puzzles files/nurikabe/12x12 Nurikabe Normal/1570101
@@ -24,5 +24,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Normal/3731930 b/puzzles files/nurikabe/12x12 Nurikabe Normal/3731930
index 071d482de..67114d31e 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Normal/3731930
+++ b/puzzles files/nurikabe/12x12 Nurikabe Normal/3731930
@@ -27,5 +27,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Normal/3755957 b/puzzles files/nurikabe/12x12 Nurikabe Normal/3755957
index 10313d422..04cd4c0ce 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Normal/3755957
+++ b/puzzles files/nurikabe/12x12 Nurikabe Normal/3755957
@@ -24,5 +24,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Normal/786806 b/puzzles files/nurikabe/12x12 Nurikabe Normal/786806
index c0d9d97f6..99f2ff3a2 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Normal/786806
+++ b/puzzles files/nurikabe/12x12 Nurikabe Normal/786806
@@ -23,5 +23,4 @@
-
diff --git a/puzzles files/nurikabe/12x12 Nurikabe Normal/9946063 b/puzzles files/nurikabe/12x12 Nurikabe Normal/9946063
index 5746d1373..b82e4ff98 100644
--- a/puzzles files/nurikabe/12x12 Nurikabe Normal/9946063
+++ b/puzzles files/nurikabe/12x12 Nurikabe Normal/9946063
@@ -22,5 +22,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Hard/1125631 b/puzzles files/nurikabe/15x15 Nurikabe Hard/1125631
index 04c045ce8..65ea67b8c 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Hard/1125631
+++ b/puzzles files/nurikabe/15x15 Nurikabe Hard/1125631
@@ -40,5 +40,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Hard/5955292 b/puzzles files/nurikabe/15x15 Nurikabe Hard/5955292
index 2dc656c36..d086a352a 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Hard/5955292
+++ b/puzzles files/nurikabe/15x15 Nurikabe Hard/5955292
@@ -38,5 +38,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Hard/6763936 b/puzzles files/nurikabe/15x15 Nurikabe Hard/6763936
index 4be19301f..ba2d0a248 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Hard/6763936
+++ b/puzzles files/nurikabe/15x15 Nurikabe Hard/6763936
@@ -38,5 +38,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Hard/7005298 b/puzzles files/nurikabe/15x15 Nurikabe Hard/7005298
index 79d16ffd0..6270e7930 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Hard/7005298
+++ b/puzzles files/nurikabe/15x15 Nurikabe Hard/7005298
@@ -40,5 +40,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Hard/9975093 b/puzzles files/nurikabe/15x15 Nurikabe Hard/9975093
index bf7cf35ef..92b2e2212 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Hard/9975093
+++ b/puzzles files/nurikabe/15x15 Nurikabe Hard/9975093
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Normal/141420 b/puzzles files/nurikabe/15x15 Nurikabe Normal/141420
index affb5d2e9..9897588c8 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Normal/141420
+++ b/puzzles files/nurikabe/15x15 Nurikabe Normal/141420
@@ -46,5 +46,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Normal/4123443 b/puzzles files/nurikabe/15x15 Nurikabe Normal/4123443
index 0acf06e84..f92577c26 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Normal/4123443
+++ b/puzzles files/nurikabe/15x15 Nurikabe Normal/4123443
@@ -42,5 +42,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Normal/731385 b/puzzles files/nurikabe/15x15 Nurikabe Normal/731385
index db29874c5..b1dfd7580 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Normal/731385
+++ b/puzzles files/nurikabe/15x15 Nurikabe Normal/731385
@@ -41,5 +41,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Normal/8213677 b/puzzles files/nurikabe/15x15 Nurikabe Normal/8213677
index 62c27f67d..f9b4c63b4 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Normal/8213677
+++ b/puzzles files/nurikabe/15x15 Nurikabe Normal/8213677
@@ -41,5 +41,4 @@
-
diff --git a/puzzles files/nurikabe/15x15 Nurikabe Normal/8372309 b/puzzles files/nurikabe/15x15 Nurikabe Normal/8372309
index cf2728b1a..97a6eae91 100644
--- a/puzzles files/nurikabe/15x15 Nurikabe Normal/8372309
+++ b/puzzles files/nurikabe/15x15 Nurikabe Normal/8372309
@@ -45,5 +45,4 @@
-
diff --git a/puzzles files/nurikabe/20x20 Nurikabe Normal/175081 b/puzzles files/nurikabe/20x20 Nurikabe Normal/175081
index 67c0ed170..bfd66a5be 100644
--- a/puzzles files/nurikabe/20x20 Nurikabe Normal/175081
+++ b/puzzles files/nurikabe/20x20 Nurikabe Normal/175081
@@ -76,5 +76,4 @@
-
diff --git a/puzzles files/nurikabe/20x20 Nurikabe Normal/3131243 b/puzzles files/nurikabe/20x20 Nurikabe Normal/3131243
index 8b9ade2de..7f85c4b35 100644
--- a/puzzles files/nurikabe/20x20 Nurikabe Normal/3131243
+++ b/puzzles files/nurikabe/20x20 Nurikabe Normal/3131243
@@ -81,5 +81,4 @@
-
diff --git a/puzzles files/nurikabe/20x20 Nurikabe Normal/4400487 b/puzzles files/nurikabe/20x20 Nurikabe Normal/4400487
index 143d1a6c9..1c65e93f3 100644
--- a/puzzles files/nurikabe/20x20 Nurikabe Normal/4400487
+++ b/puzzles files/nurikabe/20x20 Nurikabe Normal/4400487
@@ -75,5 +75,4 @@
-
diff --git a/puzzles files/nurikabe/20x20 Nurikabe Normal/5096090 b/puzzles files/nurikabe/20x20 Nurikabe Normal/5096090
index 47ec237e4..f8ad5b129 100644
--- a/puzzles files/nurikabe/20x20 Nurikabe Normal/5096090
+++ b/puzzles files/nurikabe/20x20 Nurikabe Normal/5096090
@@ -76,5 +76,4 @@
-
diff --git a/puzzles files/nurikabe/20x20 Nurikabe Normal/8595641 b/puzzles files/nurikabe/20x20 Nurikabe Normal/8595641
index 82df8e7a7..84f1c9f08 100644
--- a/puzzles files/nurikabe/20x20 Nurikabe Normal/8595641
+++ b/puzzles files/nurikabe/20x20 Nurikabe Normal/8595641
@@ -79,5 +79,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Easy/118040 b/puzzles files/nurikabe/5x5 Nurikabe Easy/118040
index 29b2585e1..fdd9c438f 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Easy/118040
+++ b/puzzles files/nurikabe/5x5 Nurikabe Easy/118040
@@ -11,5 +11,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Easy/235235 b/puzzles files/nurikabe/5x5 Nurikabe Easy/235235
index 59ca2a706..635f48456 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Easy/235235
+++ b/puzzles files/nurikabe/5x5 Nurikabe Easy/235235
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Hard/118040 b/puzzles files/nurikabe/5x5 Nurikabe Hard/118040
index 8b6c004e3..abff61ac5 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Hard/118040
+++ b/puzzles files/nurikabe/5x5 Nurikabe Hard/118040
@@ -9,5 +9,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Hard/1726232 b/puzzles files/nurikabe/5x5 Nurikabe Hard/1726232
index a28ba98fc..f3e6785a9 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Hard/1726232
+++ b/puzzles files/nurikabe/5x5 Nurikabe Hard/1726232
@@ -9,5 +9,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Hard/2168054 b/puzzles files/nurikabe/5x5 Nurikabe Hard/2168054
index 1ed31751c..f9f4e6a5e 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Hard/2168054
+++ b/puzzles files/nurikabe/5x5 Nurikabe Hard/2168054
@@ -9,5 +9,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Hard/7209030 b/puzzles files/nurikabe/5x5 Nurikabe Hard/7209030
index 2b1d486c4..e179e74ad 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Hard/7209030
+++ b/puzzles files/nurikabe/5x5 Nurikabe Hard/7209030
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Hard/7897030 b/puzzles files/nurikabe/5x5 Nurikabe Hard/7897030
index 64b4b6819..b6d770487 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Hard/7897030
+++ b/puzzles files/nurikabe/5x5 Nurikabe Hard/7897030
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Normal/1795638 b/puzzles files/nurikabe/5x5 Nurikabe Normal/1795638
index 9ae7d9480..509569d0b 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Normal/1795638
+++ b/puzzles files/nurikabe/5x5 Nurikabe Normal/1795638
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Normal/2663893 b/puzzles files/nurikabe/5x5 Nurikabe Normal/2663893
index 3a2c2c411..75b801777 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Normal/2663893
+++ b/puzzles files/nurikabe/5x5 Nurikabe Normal/2663893
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Normal/3282122 b/puzzles files/nurikabe/5x5 Nurikabe Normal/3282122
index 6f3316b3b..3f0c5c591 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Normal/3282122
+++ b/puzzles files/nurikabe/5x5 Nurikabe Normal/3282122
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Normal/6403086 b/puzzles files/nurikabe/5x5 Nurikabe Normal/6403086
index c0b7a51be..1f0d68b19 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Normal/6403086
+++ b/puzzles files/nurikabe/5x5 Nurikabe Normal/6403086
@@ -12,5 +12,4 @@
-
diff --git a/puzzles files/nurikabe/5x5 Nurikabe Normal/7587733 b/puzzles files/nurikabe/5x5 Nurikabe Normal/7587733
index 0ed10b168..26995e095 100644
--- a/puzzles files/nurikabe/5x5 Nurikabe Normal/7587733
+++ b/puzzles files/nurikabe/5x5 Nurikabe Normal/7587733
@@ -11,5 +11,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Hard/4478248 b/puzzles files/nurikabe/7x7 Nurikabe Hard/4478248
index 724c71cf0..6db0bf4fd 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Hard/4478248
+++ b/puzzles files/nurikabe/7x7 Nurikabe Hard/4478248
@@ -11,5 +11,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Hard/5631322 b/puzzles files/nurikabe/7x7 Nurikabe Hard/5631322
index 87220741e..f8478f601 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Hard/5631322
+++ b/puzzles files/nurikabe/7x7 Nurikabe Hard/5631322
@@ -12,5 +12,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Hard/6734769 b/puzzles files/nurikabe/7x7 Nurikabe Hard/6734769
index c74abb042..a85a959e4 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Hard/6734769
+++ b/puzzles files/nurikabe/7x7 Nurikabe Hard/6734769
@@ -12,5 +12,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Hard/8078467 b/puzzles files/nurikabe/7x7 Nurikabe Hard/8078467
index 4212e5748..7cb47794c 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Hard/8078467
+++ b/puzzles files/nurikabe/7x7 Nurikabe Hard/8078467
@@ -12,5 +12,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Hard/9225348 b/puzzles files/nurikabe/7x7 Nurikabe Hard/9225348
index a34516063..49d0def37 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Hard/9225348
+++ b/puzzles files/nurikabe/7x7 Nurikabe Hard/9225348
@@ -11,5 +11,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Normal/42455 b/puzzles files/nurikabe/7x7 Nurikabe Normal/42455
index 9e2f4b265..abc674184 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Normal/42455
+++ b/puzzles files/nurikabe/7x7 Nurikabe Normal/42455
@@ -11,5 +11,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Normal/4390561 b/puzzles files/nurikabe/7x7 Nurikabe Normal/4390561
index d69bcb1f0..7f802752b 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Normal/4390561
+++ b/puzzles files/nurikabe/7x7 Nurikabe Normal/4390561
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Normal/4877172 b/puzzles files/nurikabe/7x7 Nurikabe Normal/4877172
index f9e72c054..c67b48c7b 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Normal/4877172
+++ b/puzzles files/nurikabe/7x7 Nurikabe Normal/4877172
@@ -14,5 +14,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Normal/7958242 b/puzzles files/nurikabe/7x7 Nurikabe Normal/7958242
index 0adc01651..f7eaab0b1 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Normal/7958242
+++ b/puzzles files/nurikabe/7x7 Nurikabe Normal/7958242
@@ -12,5 +12,4 @@
-
diff --git a/puzzles files/nurikabe/7x7 Nurikabe Normal/8786625 b/puzzles files/nurikabe/7x7 Nurikabe Normal/8786625
index 7f7553915..c6e01656a 100644
--- a/puzzles files/nurikabe/7x7 Nurikabe Normal/8786625
+++ b/puzzles files/nurikabe/7x7 Nurikabe Normal/8786625
@@ -12,5 +12,4 @@
-
diff --git a/puzzles files/shorttruthtable/DeMorgan.xml b/puzzles files/shorttruthtable/DeMorgan.xml
index 70b806068..d6acef677 100644
--- a/puzzles files/shorttruthtable/DeMorgan.xml
+++ b/puzzles files/shorttruthtable/DeMorgan.xml
@@ -8,5 +8,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_01.xml b/puzzles files/shorttruthtable/Heuveln_01.xml
index be62afcf9..b71e69f02 100644
--- a/puzzles files/shorttruthtable/Heuveln_01.xml
+++ b/puzzles files/shorttruthtable/Heuveln_01.xml
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_02.xml b/puzzles files/shorttruthtable/Heuveln_02.xml
index dde0fa162..8446e568f 100644
--- a/puzzles files/shorttruthtable/Heuveln_02.xml
+++ b/puzzles files/shorttruthtable/Heuveln_02.xml
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_03.xml b/puzzles files/shorttruthtable/Heuveln_03.xml
index 6f1fbaebc..06259e63d 100644
--- a/puzzles files/shorttruthtable/Heuveln_03.xml
+++ b/puzzles files/shorttruthtable/Heuveln_03.xml
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_04.xml b/puzzles files/shorttruthtable/Heuveln_04.xml
index fc7ad31ad..476115bda 100644
--- a/puzzles files/shorttruthtable/Heuveln_04.xml
+++ b/puzzles files/shorttruthtable/Heuveln_04.xml
@@ -9,5 +9,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_04.xml_test02 b/puzzles files/shorttruthtable/Heuveln_04.xml_test02
index bcfdbe2bd..917855ed3 100644
--- a/puzzles files/shorttruthtable/Heuveln_04.xml_test02
+++ b/puzzles files/shorttruthtable/Heuveln_04.xml_test02
@@ -1,27 +1,26 @@
-
-
-
-
-
-
- |
- |
- |
-
-
-
-
-
-
- |
- |
-
-
-
-
-
-
-
+
+
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
diff --git a/puzzles files/shorttruthtable/Heuveln_04_export test.xml b/puzzles files/shorttruthtable/Heuveln_04_export test.xml
index 5d9c3f2d1..3fd197411 100644
--- a/puzzles files/shorttruthtable/Heuveln_04_export test.xml
+++ b/puzzles files/shorttruthtable/Heuveln_04_export test.xml
@@ -65,5 +65,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_04_test.xml b/puzzles files/shorttruthtable/Heuveln_04_test.xml
index 2678f6b3a..97809fa02 100644
--- a/puzzles files/shorttruthtable/Heuveln_04_test.xml
+++ b/puzzles files/shorttruthtable/Heuveln_04_test.xml
@@ -23,5 +23,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_04_test01.xml b/puzzles files/shorttruthtable/Heuveln_04_test01.xml
index fa5326e40..967710d9d 100644
--- a/puzzles files/shorttruthtable/Heuveln_04_test01.xml
+++ b/puzzles files/shorttruthtable/Heuveln_04_test01.xml
@@ -23,5 +23,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_04_test03.xml b/puzzles files/shorttruthtable/Heuveln_04_test03.xml
index 441b16a3a..6120636f4 100644
--- a/puzzles files/shorttruthtable/Heuveln_04_test03.xml
+++ b/puzzles files/shorttruthtable/Heuveln_04_test03.xml
@@ -23,5 +23,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_04_test_exprt.xml b/puzzles files/shorttruthtable/Heuveln_04_test_exprt.xml
index 60583987b..a46806253 100644
--- a/puzzles files/shorttruthtable/Heuveln_04_test_exprt.xml
+++ b/puzzles files/shorttruthtable/Heuveln_04_test_exprt.xml
@@ -23,5 +23,4 @@
-
diff --git a/puzzles files/shorttruthtable/Heuveln_05.xml b/puzzles files/shorttruthtable/Heuveln_05.xml
index 5ade9817e..a93f5aec6 100644
--- a/puzzles files/shorttruthtable/Heuveln_05.xml
+++ b/puzzles files/shorttruthtable/Heuveln_05.xml
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/shorttruthtable/invalid1.xml b/puzzles files/shorttruthtable/invalid1.xml
index e3be7fbb8..dc0f3723d 100644
--- a/puzzles files/shorttruthtable/invalid1.xml
+++ b/puzzles files/shorttruthtable/invalid1.xml
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/shorttruthtable/invalid2.xml b/puzzles files/shorttruthtable/invalid2.xml
index 03a304db5..08cacd95b 100644
--- a/puzzles files/shorttruthtable/invalid2.xml
+++ b/puzzles files/shorttruthtable/invalid2.xml
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/shorttruthtable/invalid3.xml b/puzzles files/shorttruthtable/invalid3.xml
index e5ad96525..2b352548d 100644
--- a/puzzles files/shorttruthtable/invalid3.xml
+++ b/puzzles files/shorttruthtable/invalid3.xml
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/shorttruthtable/test.xml b/puzzles files/shorttruthtable/test.xml
index 06298261c..78326985c 100644
--- a/puzzles files/shorttruthtable/test.xml
+++ b/puzzles files/shorttruthtable/test.xml
@@ -10,5 +10,4 @@
-
diff --git a/puzzles files/skyscrapers/1646651 b/puzzles files/skyscrapers/1646651
index 9e2536931..3facc12fe 100644
--- a/puzzles files/skyscrapers/1646651
+++ b/puzzles files/skyscrapers/1646651
@@ -27,5 +27,4 @@
-
diff --git a/puzzles files/skyscrapers/4x4 Skyscrapers Easy1 b/puzzles files/skyscrapers/4x4 Skyscrapers Easy1
deleted file mode 100644
index 5b91e64ca..000000000
--- a/puzzles files/skyscrapers/4x4 Skyscrapers Easy1
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/skyscrapers/4x4 Skyscrapers Easy3 b/puzzles files/skyscrapers/4x4 Skyscrapers Easy3
deleted file mode 100644
index 61fa8054b..000000000
--- a/puzzles files/skyscrapers/4x4 Skyscrapers Easy3
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/skyscrapers/5x5 Skyscrapers Easy1 b/puzzles files/skyscrapers/5x5 Skyscrapers Easy1
deleted file mode 100644
index 111d2bd87..000000000
--- a/puzzles files/skyscrapers/5x5 Skyscrapers Easy1
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/skyscrapers/5x5 Skyscrapers Easy2 b/puzzles files/skyscrapers/5x5 Skyscrapers Easy2
deleted file mode 100644
index 45a1db188..000000000
--- a/puzzles files/skyscrapers/5x5 Skyscrapers Easy2
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/skyscrapers/5x5 Skyscrapers Easy3 b/puzzles files/skyscrapers/5x5 Skyscrapers Easy3
deleted file mode 100644
index 87f7db3d7..000000000
--- a/puzzles files/skyscrapers/5x5 Skyscrapers Easy3
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/skyscrapers/5x5 Skyscrapers Medium1 b/puzzles files/skyscrapers/5x5 Skyscrapers Medium1
deleted file mode 100644
index 9e79c6248..000000000
--- a/puzzles files/skyscrapers/5x5 Skyscrapers Medium1
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/skyscrapers/5x5 Skyscrapers Medium2 b/puzzles files/skyscrapers/5x5 Skyscrapers Medium2
deleted file mode 100644
index fab87f9f7..000000000
--- a/puzzles files/skyscrapers/5x5 Skyscrapers Medium2
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/skyscrapers/5x5 Skyscrapers Medium3 b/puzzles files/skyscrapers/5x5 Skyscrapers Medium3
deleted file mode 100644
index efd123165..000000000
--- a/puzzles files/skyscrapers/5x5 Skyscrapers Medium3
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/puzzles files/skyscrapers/4x4 Skyscrapers Easy2 b/puzzles files/skyscrapers/easy
similarity index 77%
rename from puzzles files/skyscrapers/4x4 Skyscrapers Easy2
rename to puzzles files/skyscrapers/easy
index e30fbd89e..48c255771 100644
--- a/puzzles files/skyscrapers/4x4 Skyscrapers Easy2
+++ b/puzzles files/skyscrapers/easy
@@ -1,23 +1,22 @@
-
+
-
-
+
+
-
+
+
-
-
diff --git a/puzzles files/skyscrapers/easy1.xml b/puzzles files/skyscrapers/easy1.xml
index ce09cdf7b..9233705e9 100644
--- a/puzzles files/skyscrapers/easy1.xml
+++ b/puzzles files/skyscrapers/easy1.xml
@@ -34,7 +34,6 @@
-
+
+
+
+
+ ${org.eclipse.m2e.log.dir}/0.log
+
+ ${org.eclipse.m2e.log.dir}/%i.log
+ 1
+ 10
+
+
+ 100MB
+
+
+ %date [%thread] %-5level %logger{35} - %msg%n
+
+
+
+
+
+ WARN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup
new file mode 100644
index 000000000..1f73e14c1
--- /dev/null
+++ b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup
@@ -0,0 +1,6 @@
+
+
diff --git a/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
new file mode 100644
index 000000000..c00d6ca9e
--- /dev/null
+++ b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml
new file mode 100644
index 000000000..541da6a75
--- /dev/null
+++ b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.intro/dialog_settings.xml
@@ -0,0 +1,4 @@
+
+
diff --git a/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
new file mode 100644
index 000000000..01f7412af
--- /dev/null
+++ b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
new file mode 100644
index 000000000..ef53d8bf2
--- /dev/null
+++ b/src/main/java/edu/rpi/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/.metadata/version.ini b/src/main/java/edu/rpi/.metadata/version.ini
new file mode 100644
index 000000000..a612e14df
--- /dev/null
+++ b/src/main/java/edu/rpi/.metadata/version.ini
@@ -0,0 +1,3 @@
+#Wed Nov 06 12:29:47 EST 2019
+org.eclipse.core.runtime=2
+org.eclipse.platform=4.5.2.v20160212-1500
diff --git a/src/main/java/edu/rpi/legup/.metadata/.lock b/src/main/java/edu/rpi/legup/.metadata/.lock
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/main/java/edu/rpi/legup/.metadata/.mylyn/.taskListIndex/segments.gen b/src/main/java/edu/rpi/legup/.metadata/.mylyn/.taskListIndex/segments.gen
new file mode 100644
index 0000000000000000000000000000000000000000..63a7ec9a3ce3e4c844ffb7c8dd88e6eb3ff32ef5
GIT binary patch
literal 20
QcmezW|NlP*2w;TK07=6G{r~^~
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.mylyn/.taskListIndex/segments_1 b/src/main/java/edu/rpi/legup/.metadata/.mylyn/.taskListIndex/segments_1
new file mode 100644
index 0000000000000000000000000000000000000000..adecb06199ff8e2649f8a0c89bcb7b1d747b3395
GIT binary patch
literal 32
acmezW|NmD82FBcFG|--P0qyJm
CSO?Dl
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources
new file mode 100644
index 0000000000000000000000000000000000000000..f063e7cafc20c0a3642b699c3ea7eed318d5b30c
GIT binary patch
literal 436
zcmZ?R*xjhShe1S2b=vdAllRFf=Oz}Hq!uZZBqrsgaw&(DrYiU+mnaxnDi|4A8CqDG
zS}3@>geVvp7+P|rq~??)x>giq7A2Ns=I6!d7p3c^Cg)@p6sPKCrIhF;=NF~g8k(9L
znE+KATbNi{awX@aCKkDX^kG+>mY7qVic3{)Wlm+DUP)qccClV*rY%IRzFtXDYO1Xf
X*MW%NpTRx}{M=K$yZo5Lu=N=LbmN;7
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 000000000..dffc6b513
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+version=1
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 000000000..1768a1e88
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,13 @@
+content_assist_proposals_background=255,255,255
+content_assist_proposals_foreground=0,0,0
+eclipse.preferences.version=1
+fontPropagated=true
+org.eclipse.jdt.ui.editor.tab.width=
+org.eclipse.jdt.ui.formatterprofiles.version=12
+org.eclipse.jdt.ui.javadoclocations.migrated=true
+org.eclipse.jface.textfont=1|Monaco|11.0|0|COCOA|1|;
+proposalOrderMigrated=true
+spelling_locale_initialized=true
+tabWidthPropagated=true
+useAnnotationsPrefPage=true
+useQuickDiffPrefPage=true
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.m2e.discovery.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.m2e.discovery.prefs
new file mode 100644
index 000000000..67b1d96c9
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.m2e.discovery.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.m2e.discovery.pref.projects=
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.context.core.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.context.core.prefs
new file mode 100644
index 000000000..43e97e405
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.context.core.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+mylyn.attention.migrated=true
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.monitor.ui.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.monitor.ui.prefs
new file mode 100644
index 000000000..8d462a6cf
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.monitor.ui.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.mylyn.monitor.activity.tracking.enabled.checked=true
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.tasks.ui.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.tasks.ui.prefs
new file mode 100644
index 000000000..2b60c21d6
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.mylyn.tasks.ui.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+migrated.task.repositories.secure.store=true
+org.eclipse.mylyn.tasks.ui.filters.nonmatching=true
+org.eclipse.mylyn.tasks.ui.filters.nonmatching.encouraged=true
+org.eclipse.mylyn.tasks.ui.welcome.message=true
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs
new file mode 100644
index 000000000..da2be0834
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs
@@ -0,0 +1,5 @@
+PROBLEMS_FILTERS_MIGRATE=true
+eclipse.preferences.version=1
+platformState=1554955212164
+quickStart=false
+tipsAndTricks=true
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
new file mode 100644
index 000000000..08076f236
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+showIntro=false
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs
new file mode 100644
index 000000000..dd774965c
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs
@@ -0,0 +1,3 @@
+//org.eclipse.ui.commands/state/org.eclipse.ui.navigator.resources.nested.changeProjectPresentation/org.eclipse.ui.commands.radioState=false
+PLUGINS_NOT_ACTIVATED_ON_STARTUP=org.eclipse.m2e.discovery;
+eclipse.preferences.version=1
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
new file mode 100644
index 000000000..51f42e4ed
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
@@ -0,0 +1,2308 @@
+
+
+
+ activeSchemeId:org.eclipse.ui.defaultAcceleratorConfiguration
+ ModelMigrationProcessor.001
+
+
+
+
+
+
+
+ topLevel
+
+
+ Minimized
+ MinimizedByZoom
+
+
+ persp.actionSet:org.eclipse.mylyn.doc.actionSet
+ persp.actionSet:org.eclipse.mylyn.tasks.ui.navigation
+ persp.actionSet:org.eclipse.ui.cheatsheets.actionSet
+ persp.actionSet:org.eclipse.search.searchActionSet
+ persp.actionSet:org.eclipse.ui.edit.text.actionSet.annotationNavigation
+ persp.actionSet:org.eclipse.ui.edit.text.actionSet.navigation
+ persp.actionSet:org.eclipse.ui.edit.text.actionSet.convertLineDelimitersTo
+ persp.actionSet:org.eclipse.ui.externaltools.ExternalToolsSet
+ persp.actionSet:org.eclipse.ui.actionSet.keyBindings
+ persp.actionSet:org.eclipse.ui.actionSet.openFiles
+ persp.actionSet:org.eclipse.wb.core.ui.actionset
+ persp.actionSet:org.eclipse.debug.ui.launchActionSet
+ persp.actionSet:org.eclipse.jdt.ui.JavaActionSet
+ persp.actionSet:org.eclipse.jdt.ui.JavaElementCreationActionSet
+ persp.actionSet:org.eclipse.ui.NavigateActionSet
+ persp.viewSC:org.eclipse.jdt.ui.PackageExplorer
+ persp.viewSC:org.eclipse.jdt.ui.TypeHierarchy
+ persp.viewSC:org.eclipse.jdt.ui.SourceView
+ persp.viewSC:org.eclipse.jdt.ui.JavadocView
+ persp.viewSC:org.eclipse.search.ui.views.SearchView
+ persp.viewSC:org.eclipse.ui.console.ConsoleView
+ persp.viewSC:org.eclipse.ui.views.ContentOutline
+ persp.viewSC:org.eclipse.ui.views.ProblemView
+ persp.viewSC:org.eclipse.ui.views.ResourceNavigator
+ persp.viewSC:org.eclipse.ui.views.TaskList
+ persp.viewSC:org.eclipse.ui.views.ProgressView
+ persp.viewSC:org.eclipse.ui.navigator.ProjectExplorer
+ persp.viewSC:org.eclipse.ui.texteditor.TemplatesView
+ persp.viewSC:org.eclipse.pde.runtime.LogView
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.JavaProjectWizard
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.NewPackageCreationWizard
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.NewClassCreationWizard
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.NewInterfaceCreationWizard
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.NewEnumCreationWizard
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.NewAnnotationCreationWizard
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.NewSourceFolderCreationWizard
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.NewSnippetFileCreationWizard
+ persp.newWizSC:org.eclipse.jdt.ui.wizards.NewJavaWorkingSetWizard
+ persp.newWizSC:org.eclipse.ui.wizards.new.folder
+ persp.newWizSC:org.eclipse.ui.wizards.new.file
+ persp.newWizSC:org.eclipse.ui.editors.wizards.UntitledTextFileWizard
+ persp.perspSC:org.eclipse.jdt.ui.JavaBrowsingPerspective
+ persp.perspSC:org.eclipse.debug.ui.DebugPerspective
+ persp.perspSC:com.android.ide.eclipse.ddms.Perspective
+ persp.viewSC:org.eclipse.ant.ui.views.AntView
+ persp.actionSet:org.eclipse.eclemma.ui.CoverageActionSet
+ persp.showIn:org.eclipse.eclemma.ui.CoverageView
+ persp.showIn:org.eclipse.egit.ui.RepositoriesView
+ persp.actionSet:org.eclipse.debug.ui.breakpointActionSet
+ persp.actionSet:org.eclipse.jdt.debug.ui.JDTDebugActionSet
+ persp.newWizSC:org.eclipse.jdt.junit.wizards.NewTestCaseCreationWizard
+ persp.actionSet:org.eclipse.jdt.junit.JUnitActionSet
+ persp.showIn:org.eclipse.jdt.ui.PackageExplorer
+ persp.showIn:org.eclipse.team.ui.GenericHistoryView
+ persp.showIn:org.eclipse.ui.views.ResourceNavigator
+ persp.showIn:org.eclipse.ui.navigator.ProjectExplorer
+ persp.viewSC:org.eclipse.mylyn.tasks.ui.views.tasks
+ persp.newWizSC:org.eclipse.mylyn.tasks.ui.wizards.new.repository.task
+ persp.viewSC:org.eclipse.wb.core.StructureView
+ persp.viewSC:org.eclipse.wb.core.PaletteView
+
+
+
+ org.eclipse.e4.primaryNavigationStack
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.eclipse.e4.secondaryNavigationStack
+
+
+
+
+
+
+
+ org.eclipse.e4.secondaryDataStack
+
+
+
+
+
+
+
+
+
+
+
+
+
+ active
+ Maximized
+
+
+
+
+
+
+ View
+ categoryTag:Help
+
+
+
+ View
+ categoryTag:General
+ active
+ activeOnClose
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+ View
+ categoryTag:Help
+
+
+
+ org.eclipse.e4.primaryDataStack
+ EditorStack
+
+
+
+
+ View
+ categoryTag:Java
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+
+ View
+ categoryTag:General
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+
+ View
+ categoryTag:General
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:Ant
+
+
+ View
+ categoryTag:Git
+
+
+ View
+ categoryTag:Java
+
+
+
+ View
+ categoryTag:Mylyn
+
+ ViewMenu
+ menuContribution:menu
+
+
+
+
+ View
+ categoryTag:WindowBuilder
+
+
+ View
+ categoryTag:WindowBuilder
+
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+ Draggable
+
+
+ Draggable
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+
+ toolbarSeparator
+
+
+
+ toolbarSeparator
+
+
+
+ Draggable
+
+
+ stretch
+ SHOW_RESTORE_MENU
+
+
+ Draggable
+ HIDEABLE
+ SHOW_RESTORE_MENU
+
+
+
+
+ stretch
+
+
+ Draggable
+
+
+ Draggable
+
+
+
+
+
+ TrimStack
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+ platform:cocoa
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Editor
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Android
+
+
+ View
+ categoryTag:Tracer for OpenGL ES
+
+
+ View
+ categoryTag:Tracer for OpenGL ES
+
+
+ View
+ categoryTag:Tracer for OpenGL ES
+
+
+ View
+ categoryTag:Ant
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:Git
+
+
+ View
+ categoryTag:Git
+
+
+ View
+ categoryTag:Git
+
+
+ View
+ categoryTag:Git
+
+
+ View
+ categoryTag:Git
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:Help
+
+
+ View
+ categoryTag:Debug
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:Java Browsing
+
+
+ View
+ categoryTag:Java Browsing
+
+
+ View
+ categoryTag:Java Browsing
+
+
+ View
+ categoryTag:Java Browsing
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:Java
+
+
+ View
+ categoryTag:Maven
+
+
+ View
+ categoryTag:Maven
+
+
+ View
+ categoryTag:Mylyn
+
+
+ View
+ categoryTag:Mylyn
+
+
+ View
+ categoryTag:Mylyn
+
+
+ View
+ categoryTag:Mylyn
+
+
+ View
+ categoryTag:Oomph
+
+
+ View
+ categoryTag:Code Recommenders
+
+
+ View
+ categoryTag:Code Recommenders
+
+
+ View
+ categoryTag:Code Recommenders
+
+
+ View
+ categoryTag:Code Recommenders
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:Team
+
+
+ View
+ categoryTag:Team
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:Help
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:WindowBuilder
+
+
+ View
+ categoryTag:WindowBuilder
+
+
+ View
+ categoryTag:General
+
+
+ View
+ categoryTag:XML
+
+
+ View
+ categoryTag:XML
+
+
+
+ glue
+ move_after:PerspectiveSpacer
+ SHOW_RESTORE_MENU
+
+
+ move_after:Spacer Glue
+ HIDEABLE
+ SHOW_RESTORE_MENU
+
+
+ glue
+ move_after:SearchField
+ SHOW_RESTORE_MENU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fdt b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fdt
new file mode 100644
index 0000000000000000000000000000000000000000..d5abf41cc49dfca7560ba7bda088ecb22c377ca6
GIT binary patch
literal 11
QcmZQzU|?nhVgo%h00CG4oB#j-
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fdx b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fdx
new file mode 100644
index 0000000000000000000000000000000000000000..b8ee80957685785cf4fa43c7adecee1e634fd737
GIT binary patch
literal 12
OcmZQzU|?o|02TlMD*y-p
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fnm b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fnm
new file mode 100644
index 000000000..523c92e25
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.fnm
@@ -0,0 +1 @@
+ýÿÿÿversion
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.frq b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.frq
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.nrm b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.nrm
new file mode 100644
index 000000000..cf8dc7529
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.nrm
@@ -0,0 +1 @@
+NRMÿ
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.tii b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.tii
new file mode 100644
index 0000000000000000000000000000000000000000..ebd518d6e4ff5decae514a3f6233ba3198b30ae3
GIT binary patch
literal 24
UcmezW|NkEb1ZV&<1%Q|f0A5)HlmGw#
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.tis b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/_0.tis
new file mode 100644
index 0000000000000000000000000000000000000000..ebd518d6e4ff5decae514a3f6233ba3198b30ae3
GIT binary patch
literal 24
UcmezW|NkEb1ZV&<1%Q|f0A5)HlmGw#
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/segments.gen b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/segments.gen
new file mode 100644
index 0000000000000000000000000000000000000000..63a7ec9a3ce3e4c844ffb7c8dd88e6eb3ff32ef5
GIT binary patch
literal 20
QcmezW|NlP*2w;TK07=6G{r~^~
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/segments_1 b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/history/segments_1
new file mode 100644
index 0000000000000000000000000000000000000000..4f495c834e1a2cd7916f279dcc6d6d4d60b20827
GIT binary patch
literal 243
zcmYjLJqyAx5Uq->UpP29W*0-Q#u8nfrHG4L2{B@&Z6vWp|CT?+#b4s!RAW`}amT%P
zkNYUg^5HnO^m)6i982EWnBZwWB5zv$;UjFff>&3jwd4YYYqaSec)@WYv#rvDP;-$;
zv{3q}G(W{E>wRr)tY`yfm_#svev%8BNjp~=BYPGT1U{iN#?Tmip@O=by
sPJ{UrJY_J~V(*?=5CzmVD%V0bcS&yc9qWBpdO$Ex9Q>Yk-1~L-0*0qf4gdfE
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fdt b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fdt
new file mode 100644
index 0000000000000000000000000000000000000000..d5abf41cc49dfca7560ba7bda088ecb22c377ca6
GIT binary patch
literal 11
QcmZQzU|?nhVgo%h00CG4oB#j-
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fdx b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fdx
new file mode 100644
index 0000000000000000000000000000000000000000..b8ee80957685785cf4fa43c7adecee1e634fd737
GIT binary patch
literal 12
OcmZQzU|?o|02TlMD*y-p
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fnm b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fnm
new file mode 100644
index 000000000..523c92e25
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.fnm
@@ -0,0 +1 @@
+ýÿÿÿversion
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.frq b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.frq
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.nrm b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.nrm
new file mode 100644
index 000000000..cf8dc7529
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.nrm
@@ -0,0 +1 @@
+NRMÿ
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.tii b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.tii
new file mode 100644
index 0000000000000000000000000000000000000000..ebd518d6e4ff5decae514a3f6233ba3198b30ae3
GIT binary patch
literal 24
UcmezW|NkEb1ZV&<1%Q|f0A5)HlmGw#
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.tis b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/_0.tis
new file mode 100644
index 0000000000000000000000000000000000000000..ebd518d6e4ff5decae514a3f6233ba3198b30ae3
GIT binary patch
literal 24
UcmezW|NkEb1ZV&<1%Q|f0A5)HlmGw#
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/segments.gen b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/segments.gen
new file mode 100644
index 0000000000000000000000000000000000000000..63a7ec9a3ce3e4c844ffb7c8dd88e6eb3ff32ef5
GIT binary patch
literal 20
QcmezW|NlP*2w;TK07=6G{r~^~
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/segments_1 b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.epp.logging.aeri.ui/remote-index/segments_1
new file mode 100644
index 0000000000000000000000000000000000000000..4f495c834e1a2cd7916f279dcc6d6d4d60b20827
GIT binary patch
literal 243
zcmYjLJqyAx5Uq->UpP29W*0-Q#u8nfrHG4L2{B@&Z6vWp|CT?+#b4s!RAW`}amT%P
zkNYUg^5HnO^m)6i982EWnBZwWB5zv$;UjFff>&3jwd4YYYqaSec)@WYv#rvDP;-$;
zv{3q}G(W{E>wRr)tY`yfm_#svev%8BNjp~=BYPGT1U{iN#?Tmip@O=by
sPJ{UrJY_J~V(*?=5CzmVD%V0bcS&yc9qWBpdO$Ex9Q>Yk-1~L-0*0qf4gdfE
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/assumedExternalFilesCache b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/assumedExternalFilesCache
new file mode 100644
index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
GIT binary patch
literal 4
LcmZQzU|;|M00aO5
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/externalFilesCache b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/externalFilesCache
new file mode 100644
index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
GIT binary patch
literal 4
LcmZQzU|;|M00aO5
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache
new file mode 100644
index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4
GIT binary patch
literal 4
LcmZQzU|;|M00aO5
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat
new file mode 100644
index 0000000000000000000000000000000000000000..0edae4b20855dcd5c83bdac184b9ed16afb1b634
GIT binary patch
literal 110
zcmZQzU|?c^05&ki?iJ)3@8jvj2;?y`aD#ZkLC!(`{vjX{CI&9AP(RO*cn^PHSC9ZR
e16Tu435dtSzz2~A^5IHY8Q6V|;)7fR{22i=Q4xRu
literal 0
HcmV?d00001
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml
new file mode 100644
index 000000000..a4ee3cbc9
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml
new file mode 100644
index 000000000..9e390f501
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
new file mode 100644
index 000000000..0bf6a8c76
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
new file mode 100644
index 000000000..63d411340
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.m2e.logback.configuration/logback.1.6.0.20150526-2032.xml
@@ -0,0 +1,43 @@
+
+
+
+ %date [%thread] %-5level %logger{35} - %msg%n
+
+
+ OFF
+
+
+
+
+ ${org.eclipse.m2e.log.dir}/0.log
+
+ ${org.eclipse.m2e.log.dir}/%i.log
+ 1
+ 10
+
+
+ 100MB
+
+
+ %date [%thread] %-5level %logger{35} - %msg%n
+
+
+
+
+
+ WARN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup
new file mode 100644
index 000000000..1f73e14c1
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup
@@ -0,0 +1,6 @@
+
+
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
new file mode 100644
index 000000000..c00d6ca9e
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.ide/dialog_settings.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
new file mode 100644
index 000000000..d2ff1eed0
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/dialog_settings.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
new file mode 100644
index 000000000..5e61d80ea
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/edu/rpi/legup/.metadata/version.ini b/src/main/java/edu/rpi/legup/.metadata/version.ini
new file mode 100644
index 000000000..026f9536e
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/.metadata/version.ini
@@ -0,0 +1,3 @@
+#Tue Oct 29 22:17:24 EDT 2019
+org.eclipse.core.runtime=2
+org.eclipse.platform=4.5.2.v20160212-1500
diff --git a/src/main/java/edu/rpi/legup/controller/EditorElementController.java b/src/main/java/edu/rpi/legup/controller/EditorElementController.java
index 80e7dd35a..211012c9f 100644
--- a/src/main/java/edu/rpi/legup/controller/EditorElementController.java
+++ b/src/main/java/edu/rpi/legup/controller/EditorElementController.java
@@ -5,9 +5,7 @@
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;
@@ -19,8 +17,6 @@
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;
@@ -30,12 +26,10 @@
public class EditorElementController implements ActionListener {
protected Object lastSource;
protected ElementController elementController;
- protected ElementButton prevButton;
public EditorElementController() {
super();
elementController = null;
- prevButton = null;
}
public void setElementController(ElementController elementController) {
@@ -44,7 +38,6 @@ public void setElementController(ElementController elementController) {
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);
@@ -56,16 +49,5 @@ public void actionPerformed(ActionEvent e) {
lastSource = e.getSource();
ElementButton button = (ElementButton) lastSource;
buttonPressed(button.getElement());
-
- // reset border in previous selected button
- if (this.prevButton != null) {
- this.prevButton.resetBorder();
- }
-
- // change border color when select a button
- button.setBorderToSelected();
-
- this.prevButton = button;
-
}
}
diff --git a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java
index f6f67c8d7..ae5f62f22 100644
--- a/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java
+++ b/src/main/java/edu/rpi/legup/history/AutoCaseRuleCommand.java
@@ -105,10 +105,6 @@ public String getErrorString() {
return "The selected data element is not pickable with this case rule.";
}
- if(caseRule.getCases(caseBoard.getBaseBoard(), elementView.getPuzzleElement()).size() == 0){
- return "The selection must produce at least one case";
- }
-
return null;
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/MustLightBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/MustLightBasicRule.java
index 92d080cf8..2830a497a 100644
--- a/src/main/java/edu/rpi/legup/puzzle/lightup/rules/MustLightBasicRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/lightup/rules/MustLightBasicRule.java
@@ -38,8 +38,9 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
return super.getInvalidUseOfRuleMessage() + ": Modified cells must be bulbs";
}
+ finalCell.setData(LightUpCellType.EMPTY.value);
finalBoard.fillWithLight();
- boolean isForced = isForcedBulb(parentBoard, finalCell.getLocation());
+ boolean isForced = isForcedBulb(finalBoard, finalCell.getLocation());
finalCell.setData(LightUpCellType.BULB.value);
finalBoard.fillWithLight();
@@ -52,13 +53,12 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
}
private boolean isForcedBulb(LightUpBoard board, Point loc) {
+ CannotLightACellContradictionRule cannotLite = new CannotLightACellContradictionRule();
LightUpCell cell = board.getCell(loc.x, loc.y);
- //Check if this cell itself (the one with the bulb) has no other lighting option
if ((cell.getType() == LightUpCellType.EMPTY || cell.getType() == LightUpCellType.UNKNOWN) &&
- !cell.isLite() && countPossibleBulbs(board, cell) == 0) {
+ !cell.isLite() && cannotLite.checkContradictionAt(board, cell) == null) {
return true;
}
- //Look right
for (int i = loc.x + 1; i < board.getWidth(); i++) {
LightUpCell c = board.getCell(i, loc.y);
if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
@@ -66,12 +66,11 @@ private boolean isForcedBulb(LightUpBoard board, Point loc) {
}
else {
if (c.getType() == LightUpCellType.EMPTY &&
- !c.isLite() && countPossibleBulbs(board, c) == 1) {
+ !c.isLite() && cannotLite.checkContradictionAt(board, c) == null) {
return true;
}
}
}
- //Look left
for (int i = loc.x - 1; i >= 0; i--) {
LightUpCell c = board.getCell(i, loc.y);
if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
@@ -79,12 +78,11 @@ private boolean isForcedBulb(LightUpBoard board, Point loc) {
}
else {
if (c.getType() == LightUpCellType.EMPTY &&
- !c.isLite() && countPossibleBulbs(board, c) == 1) {
+ !c.isLite() && cannotLite.checkContradictionAt(board, c) == null) {
return true;
}
}
}
- //Look down
for (int i = loc.y + 1; i < board.getHeight(); i++) {
LightUpCell c = board.getCell(loc.x, i);
if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
@@ -92,12 +90,11 @@ private boolean isForcedBulb(LightUpBoard board, Point loc) {
}
else {
if (c.getType() == LightUpCellType.EMPTY &&
- !c.isLite() && countPossibleBulbs(board, c) == 1) {
+ !c.isLite() && cannotLite.checkContradictionAt(board, c) == null) {
return true;
}
}
}
- //Look up
for (int i = loc.y - 1; i >= 0; i--) {
LightUpCell c = board.getCell(loc.x, i);
if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
@@ -105,7 +102,7 @@ private boolean isForcedBulb(LightUpBoard board, Point loc) {
}
else {
if (c.getType() == LightUpCellType.EMPTY &&
- !c.isLite() && countPossibleBulbs(board, c) == 1) {
+ !c.isLite() && cannotLite.checkContradictionAt(board, c) == null) {
return true;
}
}
@@ -113,72 +110,6 @@ private boolean isForcedBulb(LightUpBoard board, Point loc) {
return false;
}
- /**
- * Checks the number of cells that can contain a bulb that lights the given cell
- *
- * @param board transition to check
- * @param cell index of the puzzleElement
- * @return -1 if the cell is already lit,
- * otherwise the number of that can contain a bulb that lights the given cell
- */
- public int countPossibleBulbs(LightUpBoard board, LightUpCell cell) {
- if (cell.isLite()) {
- return -1;
- }
- Point location = cell.getLocation();
- int ver_count = 0;
- int hor_count = 0;
- //Look right
- for (int i = location.x + 1; i < board.getWidth(); i++) {
- LightUpCell c = board.getCell(i, location.y);
- if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
- break;
- }
- else {
- if (c.getType() == LightUpCellType.UNKNOWN && !c.isLite()) {
- hor_count += 1;
- }
- }
- }
- //Look left
- for (int i = location.x - 1; i >= 0; i--) {
- LightUpCell c = board.getCell(i, location.y);
- if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
- break;
- }
- else {
- if (c.getType() == LightUpCellType.UNKNOWN && !c.isLite()) {
- hor_count += 1;
- }
- }
- }
- //Look down
- for (int i = location.y + 1; i < board.getHeight(); i++) {
- LightUpCell c = board.getCell(location.x, i);
- if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
- break;
- }
- else {
- if (c.getType() == LightUpCellType.UNKNOWN && !c.isLite()) {
- ver_count += 1;
- }
- }
- }
- //Look up
- for (int i = location.y - 1; i >= 0; i--) {
- LightUpCell c = board.getCell(location.x, i);
- if (c.getType() == LightUpCellType.BLACK || c.getType() == LightUpCellType.NUMBER) {
- break;
- }
- else {
- if (c.getType() == LightUpCellType.UNKNOWN && !c.isLite()) {
- ver_count += 1;
- }
- }
- }
- return hor_count + ver_count;
- }
-
/**
* Creates a transition {@link Board} that has this rule applied to it using the {@link TreeNode}.
*
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 1510a3124..b0a49d338 100644
--- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCell.java
+++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuCell.java
@@ -18,8 +18,6 @@ public MasyuType getType() {
return MasyuType.BLACK;
case 2:
return MasyuType.WHITE;
- case 3:
- return MasyuType.LINE;
default:
return null;
}
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 67894f368..72c5e634a 100644
--- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuController.java
+++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuController.java
@@ -80,22 +80,8 @@ public void mouseReleased(MouseEvent e) {
masyuLine.clear();
}
- /**
- * Alters the cells as they are being dragged over or clicked
- * @param e Mouse event being used
- * @param data Data of selected cell
- */
@Override
public void changeCell(MouseEvent e, PuzzleElement data) {
- MasyuCell cell = (MasyuCell) data;
- if(cell.getData() == 1 || cell.getData() == 2) {
- return;
- }
- if(cell.getData() == 0) {
- data.setData(3);
- }
- else {
- data.setData(0);
- }
+
}
}
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 fa6abdfb6..9b23ed285 100644
--- a/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuType.java
+++ b/src/main/java/edu/rpi/legup/puzzle/masyu/MasyuType.java
@@ -1,5 +1,5 @@
package edu.rpi.legup.puzzle.masyu;
public enum MasyuType {
- UNKNOWN, BLACK, WHITE, LINE
+ UNKNOWN, BLACK, WHITE
}
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 d3fea6a21..f8125ad43 100644
--- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeUtilities.java
+++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/NurikabeUtilities.java
@@ -4,9 +4,8 @@
import edu.rpi.legup.utility.DisjointSets;
import java.awt.*;
-import java.util.HashMap;
+import java.util.ArrayList;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.Set;
public class NurikabeUtilities {
@@ -166,79 +165,72 @@ 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
+ * Gets a list of flood filled white regions with remaining white cells
*
* @param board nurikabe board
- * @return a map of cell keys to integer values
+ * @return a list of flood filled white regions
*/
- public static HashMap getWhiteRegionMap(NurikabeBoard board) {
+ public static ArrayList> getFloodFillWhite(NurikabeBoard board) {
int width = board.getWidth();
int height = board.getHeight();
- Set numberedCells = getNurikabeNumberedCells(board);
- // 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
- int size = 1;
- // Mark all the vertices as not visited(By default
- // set as false)
- HashMap visited= new HashMap<>();
-
- // Create a queue for BFS
- LinkedList queue = new LinkedList<>();
-
- // Mark the current node as visited and enqueue it
- visited.put(center,true);
- queue.add(center);
-
- // Set of cells in the current region
- Set connected = new HashSet<>();
-
- while (queue.size() != 0) {
- // Dequeue a vertex from queue and print it
- // s is the source node in the graph
- NurikabeCell s = queue.poll();
- System.out.print(s+" ");
-
- // Make a linked list of all adjacent squares
- Set adj = new HashSet<>();
-
- Point loc = s.getLocation();
- // First check if the side is on the board
- if (loc.x >= 1) {
- adj.add(board.getCell(loc.x-1, loc.y));
- }
- if (loc.x < width-1) {
- adj.add(board.getCell(loc.x+1, loc.y));
- }
- if (loc.y >= 1) {
- adj.add(board.getCell(loc.x, loc.y-1));
- }
- if (loc.y < height-1) {
- adj.add(board.getCell(loc.x, loc.y+1));
- }
- // Get all adjacent vertices of the dequeued vertex s
- // 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) {
- connected.add(n);
- visited.put(n,true);
- queue.add(n);
- ++size;
+ DisjointSets whiteRegions = new DisjointSets<>();
+ for (PuzzleElement data : board.getPuzzleElements()) {
+ NurikabeCell cell = (NurikabeCell) data;
+ whiteRegions.createSet(cell);
+ }
+
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ 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) {
+ if (rightCell != null && (rightCell.getType() == NurikabeType.WHITE ||
+ rightCell.getType() == NurikabeType.NUMBER)) {
+ whiteRegions.union(cell, rightCell);
+ }
+ if (downCell != null && (downCell.getType() == NurikabeType.WHITE ||
+ downCell.getType() == NurikabeType.NUMBER)) {
+ whiteRegions.union(cell, downCell);
}
}
}
- // Map the cells to the center-size (including the center)
- whiteRegionMap.put(center,center.getData()-size);
- for (NurikabeCell member : connected) {
- whiteRegionMap.put(member,center.getData()-size);
+ }
+
+ Set numberedCells = getNurikabeNumberedCells(board);
+ ArrayList> floodFilledRegions = new ArrayList<>();
+ for (NurikabeCell numberCell : numberedCells) {
+ int number = numberCell.getData();
+ Set region = whiteRegions.getSet(numberCell);
+ floodFilledRegions.add(region);
+
+ int flood = number - region.size();
+ for (int i = 0; i < flood; i++) {
+ Set newSet = new HashSet<>();
+ for (NurikabeCell c : region) {
+ Point loc = c.getLocation();
+ NurikabeCell upCell = board.getCell(loc.x, loc.y - 1);
+ NurikabeCell rightCell = board.getCell(loc.x + 1, loc.y);
+ NurikabeCell downCell = board.getCell(loc.x, loc.y + 1);
+ NurikabeCell leftCell = board.getCell(loc.x - 1, loc.y);
+ if (upCell != null) {
+ newSet.add(upCell);
+ }
+ if (rightCell != null) {
+ newSet.add(rightCell);
+ }
+ if (downCell != null) {
+ newSet.add(downCell);
+ }
+ if (leftCell != null) {
+ newSet.add(leftCell);
+ }
+ }
+ region.addAll(newSet);
}
}
- return whiteRegionMap;
+
+ return floodFilledRegions;
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBottleNeckBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBottleNeckBasicRule.java
index a483236b8..9df8ac70b 100644
--- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBottleNeckBasicRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/BlackBottleNeckBasicRule.java
@@ -15,7 +15,7 @@ public class BlackBottleNeckBasicRule extends BasicRule {
public BlackBottleNeckBasicRule() {
super("NURI-BASC-0002",
"Black Bottle Neck",
- "If there is only one path for a black to escape, then those unknowns must be black.",
+ "If there is only one path for a black to escape, then those unknowns must be white.",
"edu/rpi/legup/images/nurikabe/rules/OneUnknownBlack.png");
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CannotReachCellBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CannotReachCellBasicRule.java
index 4076ff9bd..7b4deb4ae 100644
--- a/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CannotReachCellBasicRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/nurikabe/rules/CannotReachCellBasicRule.java
@@ -40,12 +40,20 @@ protected String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleE
NurikabeBoard origBoardState = (NurikabeBoard) transition.getParents().get(0).getBoard();
NurikabeBoard modified = origBoardState.copy();
+ for (int i = 0; i < modified.getWidth(); i++) {
+ for (int j = 0; j < modified.getHeight(); j++) {
+ NurikabeCell currentCell = modified.getCell(i, j);
+ if (currentCell.getType() == NurikabeType.WHITE) {
+ currentCell.setData(NurikabeType.UNKNOWN.toValue());
+ }
+ }
+ }
NurikabeCell modifiedCell = (NurikabeCell) modified.getPuzzleElement(puzzleElement);
modifiedCell.setData(NurikabeType.WHITE.toValue());
- if (contraRule.checkContradictionAt(modified,modifiedCell) == null) {
+ if (contraRule.checkContradiction(modified) == null) {
return null;
}
- return super.getInvalidUseOfRuleMessage() + ": Cell at this index can be reached";
+ return super.getInvalidUseOfRuleMessage() + ": This is not the only way for black to escape!";
}
/**
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 cdad16bcb..f12bdb57f 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
@@ -8,8 +8,8 @@
import edu.rpi.legup.puzzle.nurikabe.NurikabeType;
import edu.rpi.legup.puzzle.nurikabe.NurikabeUtilities;
-import java.awt.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Set;
public class UnreachableWhiteCellContradictionRule extends ContradictionRule {
@@ -40,63 +40,14 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
return super.getInvalidUseOfRuleMessage() + ": " + this.INVALID_USE_MESSAGE;
}
- int height = nurikabeBoard.getHeight();
- int width = nurikabeBoard.getWidth();
+ ArrayList> regions = NurikabeUtilities.getFloodFillWhite(nurikabeBoard);
- // Get regions
- HashMap whiteRegionMap = NurikabeUtilities.getWhiteRegionMap(nurikabeBoard);
- if (whiteRegionMap.containsKey(cell)) {
- return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE;
- }
- // BFS to a region
-
- // Create a queue for BFS
- LinkedList queue = new LinkedList<>();
-
- // Mark the current node as visited and enqueue it
- HashMap visited= new HashMap<>();
- visited.put(cell,true);
- queue.add(cell);
- int pathLength = 1;
- while (queue.size() != 0) {
- // Set of adjacent squares
- Set adj = new HashSet<>();
- while (queue.size() != 0) {
- // Dequeue a vertex from queue and print it
- NurikabeCell s = queue.poll();
-
- Point loc = s.getLocation();
- // First check if the side is on the board
- if (loc.x >= 1) {
- adj.add(nurikabeBoard.getCell(loc.x-1, loc.y));
- }
- if (loc.x < width-1) {
- adj.add(nurikabeBoard.getCell(loc.x+1, loc.y));
- }
- if (loc.y >= 1) {
- adj.add(nurikabeBoard.getCell(loc.x, loc.y-1));
- }
- if (loc.y < height-1) {
- adj.add(nurikabeBoard.getCell(loc.x, loc.y+1));
- }
-
- for (NurikabeCell n :adj) {
- int regionNeed = whiteRegionMap.getOrDefault(n,-1);
- if (pathLength <= regionNeed) {
- return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE;
- }
- }
- }
-
- for (NurikabeCell n : adj) {
- if (!visited.getOrDefault(n,false)
- && (n.getType() == NurikabeType.UNKNOWN ||
- n.getType() == NurikabeType.WHITE)) {
- visited.put(n,true);
- queue.add(n);
+ for (Set region : regions) {
+ for (NurikabeCell c : region) {
+ if (c == cell) {
+ return super.getNoContradictionMessage() + ": " + this.NO_CONTRADICTION_MESSAGE;
}
}
- ++pathLength;
}
return null;
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 71e8f8306..a4853993d 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/Skyscrapers.java
@@ -4,6 +4,9 @@
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.lightup.LightUpBoard;
+import edu.rpi.legup.puzzle.lightup.LightUpCell;
+import edu.rpi.legup.puzzle.lightup.LightUpCellType;
public class Skyscrapers extends Puzzle {
@@ -23,6 +26,7 @@ public Skyscrapers() {
*/
@Override
public void initializeView() {
+ SkyscrapersBoard board = (SkyscrapersBoard) currentBoard;
boardView = new SkyscrapersView((SkyscrapersBoard) currentBoard);
}
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 c23d2c46f..0e8786874 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersBoard.java
@@ -12,90 +12,57 @@ public class SkyscrapersBoard extends GridBoard {
private ArrayList lines;
+ private ArrayList rowClues;
+ private ArrayList colClues;
+ private ArrayList row;
+ private ArrayList col;
- private ArrayList eastClues;
- //EAST clues
- private ArrayList southClues;
- //SOUTH clues
- private ArrayList westClues;
- //WEST clues
- private ArrayList northClues;
- //NORTH clues
-
- private boolean viewFlag = false;
- private boolean dupeFlag = false;
-
- private SkyscrapersClue modClue = null;
- //helper variable for case rule verification, tracks recently modified row/col
-
- public SkyscrapersBoard(int size) {
- super(size, size);
+ public SkyscrapersBoard(int width, int height) {
+ super(width, height);
this.lines = new ArrayList<>();
- this.eastClues = new ArrayList<>();
- this.southClues = new ArrayList<>();
- this.westClues = new ArrayList<>();
- this.northClues = new ArrayList<>();
+ this.rowClues = new ArrayList<>();
+ this.colClues = new ArrayList<>();
+ this.row = new ArrayList<>();
+ this.col = new ArrayList<>();
- for (int i = 0; i < size; i++) {
- eastClues.add(null);
- southClues.add(null);
- westClues.add(null);
- northClues.add(null);
+ for (int i = 0; i < height; i++) {
+ rowClues.add(null);
+ }
+ for (int i = 0; i < width; i++) {
+ colClues.add(null);
+ }
+ for (int i = 0; i < height; i++) {
+ row.add(null);
+ }
+ for (int i = 0; i < width; i++) {
+ col.add(null);
}
}
- public ArrayList getLines() {
- return lines;
- }
-
- /**
- * Returns a list of the eastern clues ordered from loc.y = 0->max
- */
- public ArrayList getEastClues() {
- return eastClues;
+ public SkyscrapersBoard(int size) {
+ this(size, size);
}
- /**
- * Returns a list of the southern clues ordered from loc.x = 0->max
- */
- public ArrayList getSouthClues() {
- return southClues;
+ public ArrayList getLines() {
+ return lines;
}
- /**
- * Returns a list of the western clues ordered from loc.y = 0->max
- */
- public ArrayList getWestClues() {
- return westClues;
+ public ArrayList getRowClues() { //EAST CLUE
+ return rowClues;
}
- /**
- * Returns a list of the northern clues ordered from loc.x = 0->max
- */
- public ArrayList getNorthClues() {
- return northClues;
+ public ArrayList getColClues() { //SOUTH CLUE
+ return colClues;
}
- public boolean getDupeFlag(){
- return dupeFlag;
- }
- public boolean getViewFlag(){
- return viewFlag;
- }
- public void setDupeFlag(boolean newFlag){
- dupeFlag = newFlag;
- }
- public void setViewFlag(boolean newFlag){
- viewFlag = newFlag;
+ public ArrayList getRow() { //WEST CLUE
+ return row;
}
- public SkyscrapersClue getmodClue(){
- return modClue;
- }
- public void setModClue(SkyscrapersClue newClue){
- modClue = newClue;
+ public ArrayList getCol() { //NORTH CLUE
+ return col;
}
@Override
@@ -103,10 +70,6 @@ public SkyscrapersCell getCell(int x, int y) {
return (SkyscrapersCell) super.getCell(x, y);
}
- public int getSize() {
- return this.getWidth();
- }
-
@Override
public PuzzleElement getPuzzleElement(PuzzleElement element) {
switch (element.getIndex()) {
@@ -156,13 +119,6 @@ public void notifyDeletion(PuzzleElement puzzleElement) {
}
}
- /**
- * Gets the cells of a certain type directly adjacent to a given cell
- *
- * @param cell at the center,
- * type of cell to collect
- * @return list of cells of the given type
- */
public List getAdjacent(SkyscrapersCell cell, SkyscrapersType type) {
List adj = new ArrayList<>();
Point loc = cell.getLocation();
@@ -170,28 +126,21 @@ public List getAdjacent(SkyscrapersCell cell, SkyscrapersType t
SkyscrapersCell right = getCell(loc.x + 1, loc.y);
SkyscrapersCell down = getCell(loc.x, loc.y + 1);
SkyscrapersCell left = getCell(loc.x - 1, loc.y);
- if (up != null && (up.getType() == type || type == SkyscrapersType.ANY)) {
+ if (up != null && up.getType() == type) {
adj.add(up);
}
- if (right != null && (right.getType() == type || type == SkyscrapersType.ANY)) {
+ if (right != null && right.getType() == type) {
adj.add(right);
}
- if (down != null && (down.getType() == type || type == SkyscrapersType.ANY)) {
+ if (down != null && down.getType() == type) {
adj.add(down);
}
- if (left != null && (left.getType() == type || type == SkyscrapersType.ANY)) {
+ if (left != null && left.getType() == type) {
adj.add(left);
}
return adj;
}
- /**
- * Gets the cells of a certain type directly diagonal to a given cell
- *
- * @param cell at the center,
- * type of cell to collect
- * @return list of cells of the given type
- */
public List getDiagonals(SkyscrapersCell cell, SkyscrapersType type) {
List dia = new ArrayList<>();
Point loc = cell.getLocation();
@@ -199,62 +148,40 @@ public List getDiagonals(SkyscrapersCell cell, SkyscrapersType
SkyscrapersCell downRight = getCell(loc.x + 1, loc.y + 1);
SkyscrapersCell downLeft = getCell(loc.x - 1, loc.y + 1);
SkyscrapersCell upLeft = getCell(loc.x - 1, loc.y - 1);
- if (upRight != null && (upRight.getType() == type || type == SkyscrapersType.ANY)) {
+ if (upRight != null && upRight.getType() == type) {
dia.add(upRight);
}
- if (downLeft != null && (downLeft.getType() == type || type == SkyscrapersType.ANY)) {
+ if (downLeft != null && downLeft.getType() == type) {
dia.add(downLeft);
}
- if (downRight != null && (downRight.getType() == type || type == SkyscrapersType.ANY)) {
+ if (downRight != null && downRight.getType() == type) {
dia.add(downRight);
}
- if (upLeft != null && (upLeft.getType() == type || type == SkyscrapersType.ANY)) {
+ if (upLeft != null && upLeft.getType() == type) {
dia.add(upLeft);
}
return dia;
}
- /**
- * Gets the cells of a certain type in a given row/column
- *
- * @param index: y pos of row or x pos of col,
- * type of cell to collect,
- * boolean true if row, false if col
- * @return list of cells of the given type, ordered west to east or north to south
- */
public List getRowCol(int index, SkyscrapersType type, boolean isRow) {
List list = new ArrayList<>();
- for (int i = 0; i < dimension.height; i++) {
- SkyscrapersCell cell;
- if (isRow) {
- cell = getCell(i, index);
- }
- else {
- cell = getCell(index, i);
- }
-
- if (cell.getType() == type || type == SkyscrapersType.ANY) {
- list.add(cell);
+ if (isRow) {
+ for (int i = 0; i < dimension.height; i++) {
+ SkyscrapersCell cell = getCell(i, index);
+ if (cell.getType() == type) {
+ list.add(cell);
+ }
}
}
- return list;
- }
-
- /**
- * Prints a semblance of the board to console (helps in debugging)
- */
- public void printBoard(){
- for(int i =0; i {
public SkyscrapersClue(int value, int clueIndex, SkyscrapersType type) {
super(value);
this.index = -2;
- this.clueIndex = clueIndex;//index in list
+ this.clueIndex = clueIndex;
this.type = type;
this.setModifiable(false);
}
@@ -38,6 +38,10 @@ public int getClueIndex() {
return clueIndex;
}
+ public void setClueIndex(int clueIndex) {
+ this.clueIndex = clueIndex;
+ }
+
public SkyscrapersType getType() {
return type;
}
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 d070fdf4d..549789c01 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersClueView.java
@@ -23,15 +23,9 @@ public SkyscrapersClue getPuzzleElement() {
return (SkyscrapersClue) super.getPuzzleElement();
}
- @Override
+ @Override
public void draw(Graphics2D graphics2D) {
drawElement(graphics2D);
- if (this.isShowCasePicker() && this.isCaseRulePickable()) {
- drawCase(graphics2D);
- if(this.isHover()){
- drawHover(graphics2D);
- }
- }
}
@Override
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 0558213ab..fa771beca 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersController.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersController.java
@@ -85,7 +85,17 @@ public void mouseReleased(MouseEvent e) {
treePanel.updateError(edit.getError());
}
}
- }
+ } /*else if (lastCellPressed != null) {
+ if (dragStart instanceof SkyscrapersElementView) {
+ ICommand editLine = new EditLineCommand(selection, (SkyscrapersElementView) dragStart, lastCellPressed);
+ if (editLine.canExecute()) {
+ editLine.execute();
+ getInstance().getHistory().pushChange(editLine);
+ } else {
+ treePanel.updateError(editLine.getError());
+ }
+ }
+ }*/
}
}
dragStart = null;
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 533437d67..8df3a18a8 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersElementView.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersElementView.java
@@ -16,7 +16,30 @@ public SkyscrapersElementView(SkyscrapersCell cell) {
@Override
public void drawElement(Graphics2D graphics2D) {
- graphics2D.setStroke(new BasicStroke(1));
+ /*SkyscrapersCell cell = (SkyscrapersCell) puzzleElement;
+ SkyscrapersType type = cell.getType();
+ graphics2D.setStroke(new BasicStroke(0));
+ if (type == SkyscrapersType.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.setColor(Color.BLACK);
+ graphics2D.draw(new Rectangle2D.Double(location.x + 0.5f, location.y + 0.5f, size.width - 1, size.height - 1));
+ } else if (type == SkyscrapersType.TREE) {
+ graphics2D.drawImage(SkyscrapersView.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 if (type == SkyscrapersType.GRASS) {
+ graphics2D.drawImage(SkyscrapersView.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 if (type == SkyscrapersType.TENT) {
+ graphics2D.drawImage(SkyscrapersView.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);
+ }*/
+
+ graphics2D.setStroke(new BasicStroke(1));
graphics2D.setColor(BACKGROUND_COLOR);
graphics2D.fillRect(location.x, location.y, size.width, size.height);
graphics2D.setColor(BORDER_COLOR);
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 dac09bd16..96a41378f 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersExporter.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersExporter.java
@@ -6,8 +6,8 @@
public class SkyscrapersExporter extends PuzzleExporter {
- public SkyscrapersExporter(Skyscrapers skyscrapers) {
- super(skyscrapers);
+ public SkyscrapersExporter(Skyscrapers treeTent) {
+ super(treeTent);
}
@Override
@@ -30,7 +30,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) {
org.w3c.dom.Element axisEast = newDocument.createElement("axis");
axisEast.setAttribute("side", "east");
- for (SkyscrapersClue clue : board.getEastClues()) {
+ for (SkyscrapersClue clue : board.getRowClues()) {
org.w3c.dom.Element clueElement = newDocument.createElement("clue");
clueElement.setAttribute("value", String.valueOf(clue.getData()));
clueElement.setAttribute("index", SkyscrapersClue.colNumToString(clue.getIndex()));
@@ -40,7 +40,7 @@ protected org.w3c.dom.Element createBoardElement(Document newDocument) {
org.w3c.dom.Element axisSouth = newDocument.createElement("axis");
axisSouth.setAttribute("side", "south");
- for (SkyscrapersClue clue : board.getSouthClues()) {
+ for (SkyscrapersClue clue : board.getRowClues()) {
org.w3c.dom.Element clueElement = newDocument.createElement("clue");
clueElement.setAttribute("value", String.valueOf(clue.getData()));
clueElement.setAttribute("index", String.valueOf(clue.getIndex()));
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersImporter.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersImporter.java
index c4c909172..68979881a 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersImporter.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersImporter.java
@@ -9,8 +9,8 @@
import java.awt.*;
public class SkyscrapersImporter extends PuzzleImporter {
- public SkyscrapersImporter(Skyscrapers skyscrapers) {
- super(skyscrapers);
+ public SkyscrapersImporter(Skyscrapers treeTent) {
+ super(treeTent);
}
/**
@@ -35,74 +35,78 @@ public void initializeBoard(int rows, int columns) {
public void initializeBoard(Node node) throws InvalidFileFormatException {
try {
if (!node.getNodeName().equalsIgnoreCase("board")) {
- throw new InvalidFileFormatException("Skyscrapers 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("Skyscrapers 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");
-
-
- SkyscrapersBoard skyscrapersBoard = null;
-
+ SkyscrapersBoard treeTentBoard = null;
if (!boardElement.getAttribute("size").isEmpty()) {
int size = Integer.valueOf(boardElement.getAttribute("size"));
- skyscrapersBoard = new SkyscrapersBoard(size);
+ treeTentBoard = new SkyscrapersBoard(size);
}
-
- if (skyscrapersBoard == null) {
- throw new InvalidFileFormatException("Skyscraper Importer: invalid board dimensions");
+ 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 SkyscrapersBoard(width, height);
+ }
}
- int size = skyscrapersBoard.getSize();
+ if (treeTentBoard == null) {
+ throw new InvalidFileFormatException("TreeTent Importer: invalid board dimensions");
+ }
+ int width = treeTentBoard.getWidth();
+ int height = treeTentBoard.getHeight();
for (int i = 0; i < elementDataList.getLength(); i++) {
- SkyscrapersCell cell = (SkyscrapersCell) puzzle.getFactory().importCell(elementDataList.item(i), skyscrapersBoard);
+ SkyscrapersCell cell = (SkyscrapersCell) puzzle.getFactory().importCell(elementDataList.item(i), treeTentBoard);
Point loc = cell.getLocation();
if (cell.getData() != 0) {
cell.setModifiable(false);
cell.setGiven(true);
}
- skyscrapersBoard.setCell(loc.x, loc.y, cell);
+ treeTentBoard.setCell(loc.x, loc.y, cell);
}
- for (int y = 0; y < size; y++) {
- for (int x = 0; x < size; x++) {
- if (skyscrapersBoard.getCell(x, y) == null) {
- SkyscrapersCell cell = new SkyscrapersCell(0, new Point(x, y), size);
- cell.setIndex(y * size + x);
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ if (treeTentBoard.getCell(x, y) == null) {
+ SkyscrapersCell cell = new SkyscrapersCell(0, new Point(x, y), width);
+ cell.setIndex(y * height + x);
cell.setModifiable(true);
- skyscrapersBoard.setCell(x, y, cell);
+ treeTentBoard.setCell(x, y, cell);
}
}
}
NodeList axes = boardElement.getElementsByTagName("axis");
if (axes.getLength() != 2) {
- throw new InvalidFileFormatException("Skyscraper Importer: cannot find axes");
+ throw new InvalidFileFormatException("TreeTent Importer: cannot find axes");
}
Element axis1 = (Element) axes.item(0);
Element axis2 = (Element) axes.item(1);
if (!axis1.hasAttribute("side") || !axis1.hasAttribute("side")) {
- throw new InvalidFileFormatException("Skyscraper 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("Skyscraper Importer: axes must be different and be {east | 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() != skyscrapersBoard.getHeight() || southClues.getLength() != skyscrapersBoard.getWidth()) {
- throw new InvalidFileFormatException("Skyscraper Importer: there must be same number of clues as the dimension of the board");
+ 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++) {
@@ -110,9 +114,15 @@ public void initializeBoard(Node node) throws InvalidFileFormatException {
int value = Integer.valueOf(clue.getAttribute("value"));
//int index = SkyscrapersClue.colStringToColNum(clue.getAttribute("index"));
int index = Integer.valueOf(clue.getAttribute("index"));
+ /*if (index - 1 < 0 || index - 1 > treeTentBoard.getHeight()) {
+ throw new InvalidFileFormatException("TreeTent Importer: clue index out of bounds");
+ }
- skyscrapersBoard.getWestClues().set(/*index - 1*/i, new SkyscrapersClue(index, i, SkyscrapersType.CLUE_WEST));
- skyscrapersBoard.getEastClues().set(/*index - 1*/i, new SkyscrapersClue(value, i, SkyscrapersType.CLUE_EAST));
+ if (treeTentBoard.getRowClues().get(index - 1) != null) {
+ throw new InvalidFileFormatException("TreeTent Importer: duplicate clue index");
+ }*/
+ treeTentBoard.getRow().set(/*index - 1*/i, new SkyscrapersClue(index, index, SkyscrapersType.CLUE_WEST));
+ treeTentBoard.getRowClues().set(/*index - 1*/i, new SkyscrapersClue(value, index, SkyscrapersType.CLUE_EAST));
}
for (int i = 0; i < southClues.getLength(); i++) {
@@ -120,35 +130,29 @@ public void initializeBoard(Node node) throws InvalidFileFormatException {
int value = Integer.valueOf(clue.getAttribute("value"));
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");
+ }
- skyscrapersBoard.getNorthClues().set(/*index - 1*/i, new SkyscrapersClue(index, i, SkyscrapersType.CLUE_NORTH));
- skyscrapersBoard.getSouthClues().set(/*index - 1*/i, new SkyscrapersClue(value, i, SkyscrapersType.CLUE_SOUTH));
+ if (treeTentBoard.getColClues().get(index - 1) != null) {
+ throw new InvalidFileFormatException("TreeTent Importer: duplicate clue index");
+ }*/
+ treeTentBoard.getCol().set(/*index - 1*/i, new SkyscrapersClue(index, index, SkyscrapersType.CLUE_NORTH));
+ treeTentBoard.getColClues().set(/*index - 1*/i, new SkyscrapersClue(value, index, SkyscrapersType.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++) {
- skyscrapersBoard.getLines().add((SkyscrapersLine) puzzle.getFactory().importCell(linesList.item(i), skyscrapersBoard));
- }
- }
-
- //Initialize present flags
- NodeList flagList = boardElement.getElementsByTagName("flags");
- if(flagList.getLength()==1){
- Element flags = (Element) flagList.item(0);
- if(flags.hasAttribute("dupe")){
- skyscrapersBoard.setDupeFlag(Boolean.parseBoolean(flags.getAttribute("dupe")));
- }
- if(flags.hasAttribute("view")){
- skyscrapersBoard.setViewFlag(Boolean.parseBoolean(flags.getAttribute("view")));
+ treeTentBoard.getLines().add((SkyscrapersLine) puzzle.getFactory().importCell(linesList.item(i), treeTentBoard));
}
}
- puzzle.setCurrentBoard(skyscrapersBoard);
+ puzzle.setCurrentBoard(treeTentBoard);
}
catch (NumberFormatException e) {
- throw new InvalidFileFormatException("Skyscraper Importer: unknown value where integer expected");
+ throw new InvalidFileFormatException("TreeTent Importer: unknown value where integer expected");
}
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersLineView.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersLineView.java
index 02daa7a11..2f0f30afd 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersLineView.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersLineView.java
@@ -24,6 +24,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.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/skyscrapers/SkyscrapersType.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersType.java
index 1fdd668c1..3340af8bf 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersType.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersType.java
@@ -1,7 +1,7 @@
package edu.rpi.legup.puzzle.skyscrapers;
public enum SkyscrapersType {
- UNKNOWN(0), Number(1), ANY(2), CLUE_NORTH(-1), CLUE_EAST(-2), CLUE_SOUTH(-3), CLUE_WEST(-4);
+ UNKNOWN(0), Number(1), GRASS(2), TENT(3), CLUE_NORTH(-1), CLUE_EAST(-2), CLUE_SOUTH(-3), CLUE_WEST(-4);
public int value;
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersView.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersView.java
index b12867eda..e165686bb 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersView.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/SkyscrapersView.java
@@ -1,9 +1,9 @@
package edu.rpi.legup.puzzle.skyscrapers;
import edu.rpi.legup.controller.BoardController;
-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.TreeElement;
import edu.rpi.legup.ui.boardview.ElementView;
import edu.rpi.legup.ui.boardview.GridBoardView;
import org.apache.logging.log4j.LogManager;
@@ -16,8 +16,21 @@
public class SkyscrapersView extends GridBoardView {
private final static Logger LOGGER = LogManager.getLogger(SkyscrapersView.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) {
+ LOGGER.error("Failed to open TreeTent images");
+ }
+ }
private ArrayList lineViews;
+
private ArrayList northClues;
private ArrayList eastClues;
private ArrayList southClues;
@@ -50,11 +63,12 @@ public SkyscrapersView(SkyscrapersBoard board) {
}
for (int i = 0; i < gridSize.height; i++) {
- SkyscrapersClueView row = new SkyscrapersClueView(board.getWestClues().get(i));
+ //SkyscrapersClueView row = new SkyscrapersClueView(new SkyscrapersClue(i, i, SkyscrapersType.CLUE_WEST));
+ SkyscrapersClueView row = new SkyscrapersClueView(board.getRow().get(i));
row.setLocation(new Point(0, (i + 1) * elementSize.height));
row.setSize(elementSize);
- SkyscrapersClueView clue = new SkyscrapersClueView(board.getEastClues().get(i));
+ SkyscrapersClueView clue = new SkyscrapersClueView(board.getRowClues().get(i));
clue.setLocation(new Point((gridSize.height + 1) * elementSize.height, (i + 1) * elementSize.height));
clue.setSize(elementSize);
@@ -63,11 +77,12 @@ public SkyscrapersView(SkyscrapersBoard board) {
}
for (int i = 0; i < gridSize.width; i++) {
- SkyscrapersClueView col = new SkyscrapersClueView(board.getNorthClues().get(i));
+ //SkyscrapersClueView col = new SkyscrapersClueView(new SkyscrapersClue(i, i, SkyscrapersType.CLUE_NORTH));
+ SkyscrapersClueView col = new SkyscrapersClueView(board.getCol().get(i));
col.setLocation(new Point((i + 1) * elementSize.width, 0));
col.setSize(elementSize);
- SkyscrapersClueView clue = new SkyscrapersClueView(board.getSouthClues().get(i));
+ SkyscrapersClueView clue = new SkyscrapersClueView(board.getColClues().get(i));
clue.setLocation(new Point((i + 1) * elementSize.width, (gridSize.width + 1) * elementSize.width));
clue.setSize(elementSize);
@@ -114,10 +129,22 @@ public ElementView getElement(Point point) {
return null;
}
+ public ArrayList getLineViews() {
+ return lineViews;
+ }
+
public ArrayList getNorthClues() {
return northClues;
}
+ public ArrayList getEastClues() {
+ return eastClues;
+ }
+
+ public ArrayList getSouthClues() {
+ return southClues;
+ }
+
public ArrayList getWestClues() {
return westClues;
}
@@ -131,57 +158,26 @@ protected Dimension getProperSize() {
}
/**
- * Sets the board associated with this view
+ * Called when the tree element has changed.
*
- * @param board board
+ * @param treeElement tree element
*/
@Override
- public void setBoard(Board board) {
- if (this.board != board) {
- this.board = board;
-
- if (board instanceof CaseBoard) {
- setCasePickable();
- }
- else {
- for (ElementView elementView : elementViews) {
- elementView.setPuzzleElement(board.getPuzzleElement(elementView.getPuzzleElement()));
- elementView.setShowCasePicker(false);
- }
- for (SkyscrapersClueView clueView : northClues) {
- clueView.setPuzzleElement(board.getPuzzleElement(clueView.getPuzzleElement()));
- clueView.setShowCasePicker(false);
- }
- for (SkyscrapersClueView clueView : westClues) {
- clueView.setPuzzleElement(board.getPuzzleElement(clueView.getPuzzleElement()));
- clueView.setShowCasePicker(false);
- }
- }
- }
- }
-
- @Override
- protected void setCasePickable() {
- CaseBoard caseBoard = (CaseBoard) board;
- Board baseBoard = caseBoard.getBaseBoard();
-
- for (ElementView elementView : elementViews) {
- PuzzleElement puzzleElement = baseBoard.getPuzzleElement(elementView.getPuzzleElement());
- elementView.setPuzzleElement(puzzleElement);
- elementView.setShowCasePicker(true);
- elementView.setCaseRulePickable(caseBoard.isPickable(puzzleElement, null));
+ public void onTreeElementChanged(TreeElement treeElement) {
+ super.onTreeElementChanged(treeElement);
+ SkyscrapersBoard treeTentBoard;
+ if (board instanceof CaseBoard) {
+ treeTentBoard = (SkyscrapersBoard) ((CaseBoard) board).getBaseBoard();
}
- for (SkyscrapersClueView clueView : northClues) {
- PuzzleElement puzzleElement = baseBoard.getPuzzleElement(clueView.getPuzzleElement());
- clueView.setPuzzleElement(puzzleElement);
- clueView.setShowCasePicker(true);
- clueView.setCaseRulePickable(caseBoard.isPickable(puzzleElement, null));
+ else {
+ treeTentBoard = (SkyscrapersBoard) board;
}
- for (SkyscrapersClueView clueView : westClues) {
- PuzzleElement puzzleElement = baseBoard.getPuzzleElement(clueView.getPuzzleElement());
- clueView.setPuzzleElement(puzzleElement);
- clueView.setShowCasePicker(true);
- clueView.setCaseRulePickable(caseBoard.isPickable(puzzleElement, null));
+
+ lineViews.clear();
+ for (SkyscrapersLine line : treeTentBoard.getLines()) {
+ SkyscrapersLineView lineView = new SkyscrapersLineView(line);
+ lineView.setSize(elementSize);
+ lineViews.add(lineView);
}
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/TODO.md b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/TODO.md
new file mode 100644
index 000000000..76c86b32f
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/TODO.md
@@ -0,0 +1,11 @@
+## TODO
+
+- Implement board class (`SkyscrapersBoard.java`)
+- Implement clues class (`SkyscrapersClue.java`)
+- Implement cell generation (`SkyscrapersCellFactory.java`)
+- Implement puzzle exporter (`SkyscrapersExporter.java`)
+- Add way to interact with puzzle (`SkyscrapersCellController.java`)
+- Add vision (`SkyscrapersVision.java`, `SkyscrapersVisionView.java`)
+- Puzzle GUI (`SkyscrapersView.java`, `SkyscrapersElementView.java`, `SkyscrapersClueView.java`)
+- Determine if puzzle is solved
+- Add rules (see Sudoku and the powerpoint)
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
deleted file mode 100644
index 01a1557b0..000000000
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/CellForNumberCaseRule.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package edu.rpi.legup.puzzle.skyscrapers.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.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;
-
-public class CellForNumberCaseRule extends CaseRule {
- public CellForNumberCaseRule() {
- 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");
- }
-
- private Integer selectedNumber;
-
- @Override
- public CaseBoard getCaseBoard(Board board) {
- SkyscrapersBoard currentBoard = (SkyscrapersBoard) board.copy();
- currentBoard.setModifiable(false);
- CaseBoard caseBoard = new CaseBoard(currentBoard, this);
- for (SkyscrapersClue data : currentBoard.getWestClues()) {
- //System.out.println(data.getType());
- caseBoard.addPickableElement(data);
- }
- for (SkyscrapersClue data : currentBoard.getNorthClues()) {
- //System.out.println(data.getType());
- caseBoard.addPickableElement(data);
- }
-
- //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 getCasesFor(Board board, PuzzleElement puzzleElement, Integer number){
- ArrayList cases = new ArrayList<>();
-
- SkyscrapersClue clue = (SkyscrapersClue) puzzleElement;
- SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board;
-
- 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);
- newCase.setModClue((SkyscrapersClue)newCase.getPuzzleElement(clue));
-
- //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();
- passed = passed && ViewRule.checkContradictionAt(newCase,newCell)!=null;
- }
- if(passed){
- cases.add(newCase);
- }
-
-
- }
- return cases;
- }
-
- @Override
- public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
- return getCasesFor(board,puzzleElement,selectedNumber);
- }
-
- @Override
- public String checkRuleRaw(TreeTransition transition) {
- List childTransitions = transition.getParents().get(0).getChildren();
- SkyscrapersBoard oldBoard = (SkyscrapersBoard) transition.getParents().get(0).getBoard();
- if (childTransitions.size() == 0) {
- return "This case rule must have at least one child.";
- }
-
- //find changed row/col
- SkyscrapersClue modClue = ((SkyscrapersBoard)childTransitions.get(0).getBoard()).getmodClue();
-
- //System.out.println(modClue.getType());
- //System.out.println(modClue.getClueIndex());
- if(childTransitions.size() != getCasesFor(oldBoard,modClue,(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.");
- return "Only one cell should be modified.";
- }
- SkyscrapersCell newCell = (SkyscrapersCell) newBoard.getModifiedData().iterator().next();
- if(newCell.getType() != SkyscrapersType.Number){
- //System.out.println("Changed value should be a number.");
- return "Changed value should be a number.";
- }
- }
- return null;
- }
-
- @Override
- public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElement) {
- return checkRuleRaw(transition);
- }
-}
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 c0508bf67..a7df882ff 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
@@ -16,7 +16,7 @@ public class DuplicateNumberContradictionRule extends ContradictionRule {
public DuplicateNumberContradictionRule() {
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");
+ "edu/rpi/legup/images/skyscrapers/DuplicateNumber.png");
}
/**
@@ -29,8 +29,7 @@ public DuplicateNumberContradictionRule() {
*/
@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;
+ SkyscrapersCell cell = (SkyscrapersCell) puzzleElement;
SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board;
Point loc = cell.getLocation();
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 ef8f72711..9a9c0bf8e 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
@@ -8,9 +8,7 @@
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 {
@@ -18,7 +16,7 @@ public class ExceedingVisibilityContradictionRule extends ContradictionRule {
public ExceedingVisibilityContradictionRule() {
super("SKYS-CONT-0002", "Exceeding Visibility",
"More skyscrapers are visible than there should be.",
- "edu/rpi/legup/images/skyscrapers/contradictions/ExceedingVisibility.png");
+ "edu/rpi/legup/images/skyscrapers/ExceedingVisibility.png");
}
/**
@@ -34,106 +32,92 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
SkyscrapersCell cell = (SkyscrapersCell) puzzleElement;
SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board;
Point loc = cell.getLocation();
-
- //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
- int max = 0;
- int count = 0;
- List row = skyscrapersboard.getRowCol(loc.y,SkyscrapersType.Number,true);
- if(row.size()==skyscrapersboard.getWidth()){
- //from west border
- for(SkyscrapersCell c : row){
- if (c.getData() > max) {
- System.out.print(c.getData());
- //System.out.println(cell.getData());
- max = c.getData();
- count++;
- }
- }
- if (count > west) {
- return null;
- }
+ Set candidates = new HashSet();
- max = 0;
- count = 0;
- //from east border
- Collections.reverse(row);
- for(SkyscrapersCell c : row){
- if (c.getData() > max) {
- System.out.print(c.getData());
- //System.out.println(cell.getData());
- max = c.getData();
- count++;
- }
- }
- if (count > east) {
- return null;
- }
- }
-
- //check column
- List col = skyscrapersboard.getRowCol(loc.x,SkyscrapersType.Number,false);
- if(col.size()==skyscrapersboard.getHeight()){
- //from north border
- max = 0;
- count = 0;
- for(SkyscrapersCell c : col){
- System.out.println(c.getData());
- if (c.getData() > max) {
+ //check row
+ int west = skyscrapersboard.getRow().get(loc.y).getData();
+ int east = skyscrapersboard.getRowClues().get(loc.y).getData();
+ int north = skyscrapersboard.getCol().get(loc.x).getData();
+ int south = skyscrapersboard.getColClues().get(loc.x).getData();
+ int max = 0;
+ int count = 0;
+ boolean complete = true;
+ for (int i = 0; i < skyscrapersboard.getWidth(); i++) {
+ SkyscrapersCell c = skyscrapersboard.getCell(i, loc.y);
+ if (c.getType() == SkyscrapersType.Number && c.getData() > max) {
+ //System.out.print(c.getData());
+ //System.out.println(cell.getData());
+ max = c.getData();
+ count++;
+ }
+ if (c.getType() == SkyscrapersType.UNKNOWN) {
+ complete = false;
+ }
+ }
+ if (count > west && complete == true) {
+ return null;
+ }
- //System.out.println(cell.getData());
- max = c.getData();
- count++;
- }
- }
- if (count > north) {
- return null;
- }
+ max = 0;
+ count = 0;
+ complete = true;
+ for (int i = skyscrapersboard.getWidth() - 1; i >= 0; i--) {
+ SkyscrapersCell c = skyscrapersboard.getCell(i, loc.y);
+ if (c.getType() == SkyscrapersType.Number && c.getData() > max) {
+ //System.out.print(c.getData());
+ //System.out.println(cell.getData());
+ max = c.getData();
+ count = count + 1;
+ }
+ if (c.getType() == SkyscrapersType.UNKNOWN) {
+ complete = false;
+ }
+ }
+ if (count > east && complete == true) {
+ return null;
+ }
- //from south border
- max = 0;
- count = 0;
- Collections.reverse(col);
- for(SkyscrapersCell c : col){
- System.out.println(c.getData());
- if (c.getData() > max) {
+ // check column
+ max = 0;
+ count = 0;
+ complete = true;
+ for (int i = 0; i < skyscrapersboard.getHeight(); i++) {
+ SkyscrapersCell c = skyscrapersboard.getCell(loc.x, i);
+ if (c.getType() == SkyscrapersType.Number && c.getData() > max) {
+ //System.out.print(c.getData());
+ //System.out.println(cell.getData());
+ max = c.getData();
+ count = count + 1;
+ }
+ if (c.getType() == SkyscrapersType.UNKNOWN) {
+ complete = false;
+ }
+ }
+ if (count > north && complete == true) {
+ return null;
+ }
+
+ max = 0;
+ count = 0;
+ complete = true;
+ for (int i = skyscrapersboard.getHeight() - 1; i >= 0; i--) {
+ SkyscrapersCell c = skyscrapersboard.getCell(loc.x, i);
+ if (c.getType() == SkyscrapersType.Number && c.getData() > max) {
+ //System.out.print(c.getData());
+ //System.out.println(cell.getData());
+ max = c.getData();
+ count = count + 1;
+ }
+ if (c.getType() == SkyscrapersType.UNKNOWN) {
+ complete = false;
+ }
+ }
+ if (count > south && complete == true) {
+ return null;
+ }
- //System.out.println(cell.getData());
- max = c.getData();
- count++;
- }
- }
- if (count > south) {
- return null;
- }
- }
-
//System.out.print("Does not contain a contradiction at this index");
return super.getNoContradictionMessage();
}
-
- /**
- * Checks whether the Skyscraper cell has a contradiction using this rule
- *
- * @param board board to check contradiction
- * @return null if the Skyscraper cell contains a contradiction, otherwise error message
- */
- @Override
- 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)
- String checkStr = checkContradictionAt(board, skyscrapersBoard.getCell(i,i));
- if (checkStr == null) {
- return checkStr;
- }
- }
- return "No instance of the contradiction " + this.ruleName + " here";
- }
-
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularNumberBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/FixedMaxBasicRule.java
similarity index 63%
rename from src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularNumberBasicRule.java
rename to src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/FixedMaxBasicRule.java
index 248998e84..85b6fe62d 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularNumberBasicRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/FixedMaxBasicRule.java
@@ -9,14 +9,17 @@
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell;
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType;
-import java.util.ArrayList;
+import java.awt.Point;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
-public class LastSingularNumberBasicRule extends BasicRule {
+public class FixedMaxBasicRule extends BasicRule {
- public LastSingularNumberBasicRule() {
- 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");
+ public FixedMaxBasicRule() {
+ super("SKYS-BASC-0001", "Fixed Max",
+ "If the sum of two opposing edges is n+1, the maximum number appears at a position k spaces away from the edge, where k is the number at that edge.",
+ "edu/rpi/legup/images/skyscrapers/FixedMax.png");
}
/**
@@ -34,28 +37,38 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
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";
+ 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);
- NumberForCellCaseRule caseRule = new NumberForCellCaseRule();
- ArrayList candidates = caseRule.getCases(initialBoard,puzzleElement);
- initialBoard.setDupeFlag(dupeTemp);
- initialBoard.setViewFlag(viewTemp);
+ SkyscrapersBoard emptyCase = initialBoard.copy();
+ emptyCase.getPuzzleElement(finalCell).setData(0);
+ Point loc = finalCell.getLocation();
+ int north = initialBoard.getCol().get(loc.x).getData();
+ int south = initialBoard.getColClues().get(loc.x).getData();
+ int west = initialBoard.getRow().get(loc.y).getData();
+ int east = initialBoard.getRowClues().get(loc.y).getData();
+ int max = initialBoard.getHeight();
+ System.out.println(north);
+ System.out.println(south);
+ if (north + south != max + 1 && west + east != max + 1) {
+ System.out.println("111");
+ return super.getInvalidUseOfRuleMessage() + ": Opposing clues must add up to max";
+ }
- //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.";
+ if (finalCell.getData() != initialBoard.getWidth()) {
+ return super.getInvalidUseOfRuleMessage() + ": Modified cells must be the max";
+ }
+
+ if (north + south == max + 1 && loc.y + 1 == north) {
+ return null;
}
- return super.getInvalidUseOfRuleMessage() + ":This cell is not forced.";
+ if (west + east == max + 1 && loc.x + 1 == west) {
+ return null;
+ }
+
+ return super.getInvalidUseOfRuleMessage() + ": This cell is not forced.";
+
}
private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) {
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 fb3764a2b..ef0968710 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
@@ -8,9 +8,7 @@
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 {
@@ -18,7 +16,7 @@ public class InsufficientVisibilityContradictionRule extends ContradictionRule {
public InsufficientVisibilityContradictionRule() {
super("SKYS-CONT-0003", "Insufficient Visibility",
"Less skyscrapers are visible than there should be.",
- "edu/rpi/legup/images/skyscrapers/contradictions/InsufficientVisibility.png");
+ "edu/rpi/legup/images/skyscrapers/InsufficientVisibility.png");
}
/**
@@ -35,104 +33,91 @@ public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
SkyscrapersBoard skyscrapersboard = (SkyscrapersBoard) board;
Point loc = cell.getLocation();
- //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();
+ Set candidates = new HashSet();
- //check row
- int max = 0;
- int count = 0;
- java.util.List row = skyscrapersboard.getRowCol(loc.y,SkyscrapersType.Number,true);
- if(row.size()==skyscrapersboard.getWidth()){
- //from west border
- for(SkyscrapersCell c : row){
- if (c.getData() > max) {
- System.out.print(c.getData());
- //System.out.println(cell.getData());
- max = c.getData();
- count++;
- }
- }
- if (count < west) {
- return null;
- }
+ //check row
+ int west = skyscrapersboard.getRow().get(loc.y).getData();
+ int east = skyscrapersboard.getRowClues().get(loc.y).getData();
+ int north = skyscrapersboard.getCol().get(loc.x).getData();
+ int south = skyscrapersboard.getColClues().get(loc.x).getData();
+ int max = 0;
+ int count = 0;
+ boolean complete = true;
+ for (int i = 0; i < skyscrapersboard.getWidth(); i++) {
+ SkyscrapersCell c = skyscrapersboard.getCell(i, loc.y);
+ if (c.getType() == SkyscrapersType.Number && c.getData() > max) {
+ //System.out.print(c.getData());
+ //System.out.println(cell.getData());
+ max = c.getData();
+ count++;
+ }
+ if (c.getType() == SkyscrapersType.UNKNOWN) {
+ complete = false;
+ }
+ }
+ if (count < west && complete == true) {
+ return null;
+ }
- max = 0;
- count = 0;
- //from east border
- Collections.reverse(row);
- for(SkyscrapersCell c : row){
- if (c.getData() > max) {
- System.out.print(c.getData());
- //System.out.println(cell.getData());
- max = c.getData();
- count++;
- }
- }
- if (count < east) {
- return null;
- }
- }
+ max = 0;
+ count = 0;
+ complete = true;
+ for (int i = skyscrapersboard.getWidth() - 1; i >= 0; i--) {
+ SkyscrapersCell c = skyscrapersboard.getCell(i, loc.y);
+ if (c.getType() == SkyscrapersType.Number && c.getData() > max) {
+ //System.out.print(c.getData());
+ //System.out.println(cell.getData());
+ max = c.getData();
+ count = count + 1;
+ }
+ if (c.getType() == SkyscrapersType.UNKNOWN) {
+ complete = false;
+ }
+ }
+ if (count < east && complete == true) {
+ return null;
+ }
- //check column
- List col = skyscrapersboard.getRowCol(loc.x,SkyscrapersType.Number,false);
- if(col.size()==skyscrapersboard.getHeight()){
- //from north border
- max = 0;
- count = 0;
- for(SkyscrapersCell c : col){
- System.out.println(c.getData());
- if (c.getData() > max) {
+ // check column
+ max = 0;
+ count = 0;
+ complete = true;
+ for (int i = 0; i < skyscrapersboard.getHeight(); i++) {
+ SkyscrapersCell c = skyscrapersboard.getCell(loc.x, i);
+ if (c.getType() == SkyscrapersType.Number && c.getData() > max) {
+ //System.out.print(c.getData());
+ //System.out.println(cell.getData());
+ max = c.getData();
+ count = count + 1;
+ }
+ if (c.getType() == SkyscrapersType.UNKNOWN) {
+ complete = false;
+ }
+ }
+ if (count < north && complete == true) {
+ return null;
+ }
- //System.out.println(cell.getData());
- max = c.getData();
- count++;
- }
- }
- if (count < north) {
- return null;
- }
+ max = 0;
+ count = 0;
+ complete = true;
+ for (int i = skyscrapersboard.getHeight() - 1; i >= 0; i--) {
+ SkyscrapersCell c = skyscrapersboard.getCell(loc.x, i);
+ if (c.getType() == SkyscrapersType.Number && c.getData() > max) {
+ //System.out.print(c.getData());
+ //System.out.println(cell.getData());
+ max = c.getData();
+ count = count + 1;
+ }
+ if (c.getType() == SkyscrapersType.UNKNOWN) {
+ complete = false;
+ }
+ }
+ if (count < south && complete == true) {
+ return null;
+ }
- //from south border
- max = 0;
- count = 0;
- Collections.reverse(col);
- for(SkyscrapersCell c : col){
- System.out.println(c.getData());
- if (c.getData() > max) {
-
- //System.out.println(cell.getData());
- max = c.getData();
- count++;
- }
- }
- if (count < south) {
- return null;
- }
- }
-
//System.out.print("Does not contain a contradiction at this index");
return super.getNoContradictionMessage();
}
-
- /**
- * Checks whether the Skyscraper cell has a contradiction using this rule
- *
- * @param board board to check contradiction
- * @return null if the Skyscraper cell contains a contradiction, otherwise error message
- */
- @Override
- 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)
- String checkStr = checkContradictionAt(board, skyscrapersBoard.getCell(i,i));
- if (checkStr == null) {
- return checkStr;
- }
- }
- return "No instance of the contradiction " + this.ruleName + " here";
- }
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastCellBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastCellBasicRule.java
new file mode 100644
index 000000000..524c36319
--- /dev/null
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastCellBasicRule.java
@@ -0,0 +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.BasicRule;
+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;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class LastCellBasicRule extends BasicRule {
+
+ public LastCellBasicRule() {
+ super("SKYS-BASC-0002", "Last Cell",
+ "A certain number must go in a certain cell, because that cell is the last place that number can appear in that row/column.",
+ "edu/rpi/legup/images/skyscrapers/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";
+ }
+
+ SkyscrapersBoard emptyCase = initialBoard.copy();
+ emptyCase.getPuzzleElement(finalCell).setData(0);
+ Point loc = finalCell.getLocation();
+
+ Set candidates = new HashSet();
+ for (int i = 1; i <= initialBoard.getWidth(); i++) {
+ candidates.add(i);
+ }
+
+ //check row
+ for (int i = 0; i < initialBoard.getWidth(); i++) {
+ SkyscrapersCell c = initialBoard.getCell(i, loc.y);
+ if (i != loc.x && c.getType() == SkyscrapersType.Number) {
+ candidates.remove(c.getData());
+ //System.out.print(c.getData());
+ //System.out.println(finalCell.getData());
+ }
+ }
+ if (candidates.size() == 1) {
+ Iterator it = candidates.iterator();
+ if (it.next() == finalCell.getData()) {
+ return null;
+ }
+ return super.getInvalidUseOfRuleMessage() + ": Wrong number in the cell.";
+ }
+
+ candidates.clear();
+ for (int i = 1; i <= initialBoard.getWidth(); i++) {
+ candidates.add(i);
+ }
+
+ // check column
+ for (int i = 0; i < initialBoard.getHeight(); i++) {
+ SkyscrapersCell c = initialBoard.getCell(loc.x, i);
+ if (i != loc.y && c.getType() == SkyscrapersType.Number) {
+ candidates.remove(c.getData());
+ //System.out.print(c.getData());
+ //System.out.println(finalCell.getData());
+ }
+ }
+ if (candidates.size() == 1) {
+ Iterator it = candidates.iterator();
+ if (it.next() == 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(0);
+ 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;
+ }
+ }
+}
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularCellBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastNumberBasicRule.java
similarity index 58%
rename from src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularCellBasicRule.java
rename to src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastNumberBasicRule.java
index 727559083..a4f36cd04 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastSingularCellBasicRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastNumberBasicRule.java
@@ -9,14 +9,17 @@
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell;
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType;
-import java.util.ArrayList;
+import java.awt.Point;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
-public class LastSingularCellBasicRule extends BasicRule {
+public class LastNumberBasicRule extends BasicRule {
- public LastSingularCellBasicRule() {
- 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");
+ public LastNumberBasicRule() {
+ super("SKYS-BASC-0003", "Last Number",
+ "A certain cell must contain a certain number since that number is the only one that can possibly appear in that cell.",
+ "edu/rpi/legup/images/skyscrapers/LastNumber.png");
}
/**
@@ -38,41 +41,45 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
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);
+ SkyscrapersBoard emptyCase = initialBoard.copy();
+ emptyCase.getPuzzleElement(finalCell).setData(0);
+ Point loc = finalCell.getLocation();
- System.out.println(XCandidates.size());
- System.out.println(YCandidates.size());
+ Set candidates = new HashSet();
+ for (int i = 1; i <= initialBoard.getWidth(); i++) {
+ candidates.add(i);
+ }
- //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;
+ //check row
+ for (int i = 0; i < initialBoard.getWidth(); i++) {
+ SkyscrapersCell c = initialBoard.getCell(i, loc.y);
+ if (i != loc.x && c.getType() == SkyscrapersType.Number) {
+ candidates.remove(c.getData());
+ //System.out.print(c.getData());
+ //System.out.println(finalCell.getData());
+ }
}
- 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.";
+ // check column
+ for (int i = 0; i < initialBoard.getHeight(); i++) {
+ SkyscrapersCell c = initialBoard.getCell(loc.x, i);
+ if (i != loc.y && c.getType() == SkyscrapersType.Number) {
+ candidates.remove(c.getData());
+ //System.out.print(c.getData());
+ //System.out.println(finalCell.getData());
}
- return ": No case for this cell.";
}
- return ": This cell is not forced.";
+
+ DuplicateNumberContradictionRule duplicate = new DuplicateNumberContradictionRule();
+ if (candidates.size() == 1 && duplicate.checkContradictionAt(emptyCase, finalCell) != null) {
+ Iterator it = candidates.iterator();
+ if (it.next() == 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) {
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleCellBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleCellBasicRule.java
deleted file mode 100644
index d28ed6cbd..000000000
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleCellBasicRule.java
+++ /dev/null
@@ -1,117 +0,0 @@
-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.BasicRule;
-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 LastVisibleCellBasicRule extends BasicRule {
-
- public LastVisibleCellBasicRule() {
- 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(0);
- 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;
- }
- }
-}
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NEdgeBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NEdgeBasicRule.java
index 3bea76813..d5c58220e 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NEdgeBasicRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NEdgeBasicRule.java
@@ -19,7 +19,7 @@ public class NEdgeBasicRule extends BasicRule {
public NEdgeBasicRule() {
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");
+ "edu/rpi/legup/images/skyscrapers/NEdge.png");
}
/**
@@ -46,16 +46,16 @@ public String checkRuleRawAt(TreeTransition transition, PuzzleElement puzzleElem
Point loc = finalCell.getLocation();
int max = initialBoard.getHeight();
- if (initialBoard.getWestClues().get(loc.y).getData() == max && finalCell.getData() == loc.x + 1) {
+ if (initialBoard.getRow().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) {
+ if (initialBoard.getRowClues().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) {
+ if (initialBoard.getCol().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) {
+ if (initialBoard.getColClues().get(loc.x).getData() == max && finalCell.getData() == max - loc.y) {
return null;
}
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleNumberBasicRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/OneEdgeBasicRule.java
similarity index 63%
rename from src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleNumberBasicRule.java
rename to src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/OneEdgeBasicRule.java
index 7a4a7210a..f883d7cee 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/LastVisibleNumberBasicRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/OneEdgeBasicRule.java
@@ -9,14 +9,17 @@
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell;
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType;
-import java.util.ArrayList;
+import java.awt.Point;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
-public class LastVisibleNumberBasicRule extends BasicRule {
+public class OneEdgeBasicRule extends BasicRule {
- public LastVisibleNumberBasicRule() {
- 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");
+ public OneEdgeBasicRule() {
+ super("SKYS-BASC-0005", "One Edge",
+ "If you have a 1 on an edge, put n in the adjacent square.",
+ "edu/rpi/legup/images/skyscrapers/OneEdge.png");
}
/**
@@ -30,33 +33,48 @@ public LastVisibleNumberBasicRule() {
*/
@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";
+ 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(false);
- initialBoard.setViewFlag(true);
- NumberForCellCaseRule caseRule = new NumberForCellCaseRule();
- ArrayList candidates = caseRule.getCases(initialBoard,puzzleElement);
- initialBoard.setDupeFlag(dupeTemp);
- initialBoard.setViewFlag(viewTemp);
+ SkyscrapersBoard emptyCase = initialBoard.copy();
+ emptyCase.getPuzzleElement(finalCell).setData(0);
+ Point loc = finalCell.getLocation();
- //check if given value is the only remaining value
- if(candidates.size() == 1){
- if(candidates.get(0).getPuzzleElement(puzzleElement).getData() == finalCell.getData()){
+ if (loc.x != 0 && loc.x != initialBoard.getWidth() - 1 && loc.y != 0 && loc.y != initialBoard.getHeight() - 1) {
+ return super.getInvalidUseOfRuleMessage() + ": Modified cells must be on the edge";
+ }
+
+ if (finalCell.getData() != initialBoard.getWidth()) {
+ return super.getInvalidUseOfRuleMessage() + ": Modified cells must be the max";
+ }
+
+ if (loc.x == 0 && initialBoard.getRow().get(loc.y).getData() == 1) {
+ return null;
+ }
+ else {
+ if (loc.x == initialBoard.getWidth() - 1 && initialBoard.getRowClues().get(loc.y).getData() == 1) {
return null;
}
- return super.getInvalidUseOfRuleMessage() + ": Wrong number in the cell.";
+ else {
+ if (loc.y == 0 && initialBoard.getCol().get(loc.x).getData() == 1) {
+ return null;
+ }
+ else {
+ if (loc.y == initialBoard.getHeight() - 1 && initialBoard.getColClues().get(loc.x).getData() == 1) {
+ return null;
+ }
+ else {
+ return "This cell is not forced.";
+ }
+ }
+ }
}
- return super.getInvalidUseOfRuleMessage() + ":This cell is not forced.";
+
}
private boolean isForced(SkyscrapersBoard board, SkyscrapersCell cell) {
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PossibleContentsCaseRule.java
similarity index 75%
rename from src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java
rename to src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PossibleContentsCaseRule.java
index abf6a10b0..eb106ec05 100644
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/NumberForCellCaseRule.java
+++ b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PossibleContentsCaseRule.java
@@ -9,18 +9,17 @@
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersCell;
import edu.rpi.legup.puzzle.skyscrapers.SkyscrapersType;
-import java.awt.*;
+import java.awt.Point;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
+import java.util.*;
-public class NumberForCellCaseRule extends CaseRule {
+public class PossibleContentsCaseRule extends CaseRule {
- public NumberForCellCaseRule() {
- 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");
+ public PossibleContentsCaseRule() {
+ super("SKYS-CASE-0001", "Possible Contents",
+ "Each blank cell is could have height of 1 to n.",
+ "edu/rpi/legup/images/skyscrapers/PossibleContents.png");
}
@Override
@@ -53,27 +52,31 @@ public ArrayList getCases(Board board, PuzzleElement puzzleElement) {
Set candidates = new HashSet();
for (int i = 1; i <= skyscrapersboard.getWidth(); i++) {
- Board newCase = board.copy();
- PuzzleElement newCell = newCase.getPuzzleElement(puzzleElement);
- newCell.setData(i);
- newCase.addModifiedData(newCell);
+ candidates.add(i);
+ }
- //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();
- passed = passed && ViewRule.checkContradictionAt(newCase,newCell)!=null;
+ for (int i = 0; i < skyscrapersboard.getWidth(); i++) {
+ SkyscrapersCell c = skyscrapersboard.getCell(i, loc.y);
+ if (c.getType() == SkyscrapersType.Number) {
+ candidates.remove(c.getData());
}
- //how should unresolved be handled? should it be?
- if(passed){
- cases.add(newCase);
+ }
+ for (int i = 0; i < skyscrapersboard.getHeight(); i++) {
+ SkyscrapersCell c = skyscrapersboard.getCell(loc.x, i);
+ if (c.getType() == SkyscrapersType.Number) {
+ candidates.remove(c.getData());
}
}
+ Iterator it = candidates.iterator();
+ while (it.hasNext()) {
+ Board case1 = board.copy();
+ PuzzleElement data = case1.getPuzzleElement(puzzleElement);
+ data.setData(it.next());
+ case1.addModifiedData(data);
+ cases.add(case1);
+ }
+
return cases;
}
@@ -90,9 +93,6 @@ public String checkRuleRaw(TreeTransition transition) {
//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()){
- return "Wrong number of children.";
- }
//TreeTransition case1 = childTransitions.get(0);
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
deleted file mode 100644
index 1d96b3ed6..000000000
--- a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/PreemptiveVisibilityContradictionRule.java
+++ /dev/null
@@ -1,193 +0,0 @@
-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.Queue;
-import java.util.LinkedList;
-import java.util.List;
-
-public class PreemptiveVisibilityContradictionRule extends ContradictionRule {
-
- public PreemptiveVisibilityContradictionRule() {
- 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
- *
- * @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
- */
- @Override
- public String checkContradictionAt(Board board, PuzzleElement puzzleElement) {
- SkyscrapersBoard skyscrapersBoard = (SkyscrapersBoard) board;
- SkyscrapersCell cell = (SkyscrapersCell) puzzleElement;
- Point loc = cell.getLocation();
-
- //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
- Queue rowQ = new LinkedList<>();
- rowQ.add(skyscrapersBoard);
- Queue colQ = new LinkedList<>();
- colQ.add(skyscrapersBoard);
-
- // 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
- for(int i = 0; i < skyscrapersBoard.getWidth(); i++) {
- int num = i + 1;
-
- //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
-
- //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) {
- exists = true;
- break;
- }
- }
-
- if(exists) {
- rowQ.add(temp);
- }
- 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);
-
- //reset flags
- temp.setDupeFlag(dupeTemp);
- temp.setViewFlag(viewTemp);
-
- //add all row cases to row queue
- for (Board k : rows) {
- rowQ.add((SkyscrapersBoard) k);
- }
- }
- }
-
- //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
-
- //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) {
- exists = true;
- break;
- }
- }
-
- if(exists){
- colQ.add(temp);
- }
- 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);
-
- //reset flags
- temp.setDupeFlag(dupeTemp);
- temp.setViewFlag(viewTemp);
-
- //add all row cases to row queue
- for(Board k : cols) {
- colQ.add((SkyscrapersBoard) k);
- }
- }
- }
- }
-
- String rowTooFew;
- String rowTooMany;
- boolean rowContradiction = true;
- //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?
- 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
- }
-
- String colTooFew;
- String colTooMany;
- boolean colContradiction = true;
- while(colQ.size()>0) {
- SkyscrapersBoard fullCol = colQ.poll();
-
- //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
- colContradiction = colContradiction && (colTooFew == null || colTooMany == null);
- }
-
- //if every possible permutation results in contradictions return null, else no contradiction
- if(rowContradiction || colContradiction) {
- return null;
- }
- return super.getNoContradictionMessage();
- }
-
- /**
- * Checks whether the tree node has a contradiction using this rule
- *
- * @param board board to check contradiction
- * @return null if the tree node contains a contradiction, otherwise error message
- */
- @Override
- 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)
- String checkStr = checkContradictionAt(board, skyscrapersBoard.getCell(i,i));
- if (checkStr == null) {
- return checkStr;
- }
- }
- return "No instance of the contradiction " + this.ruleName + " here";
- }
-
-
-
-}
diff --git a/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/Skyscrapers Ruleset.pdf b/src/main/java/edu/rpi/legup/puzzle/skyscrapers/rules/Skyscrapers Ruleset.pdf
deleted file mode 100644
index 3ff35c2fe9eca703566e225aff879c8029337faa..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 194684
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