Merge pull request #4121 from Adam-/lightbox
puzzle solver: add lightbox solver
This commit is contained in:
@@ -86,6 +86,7 @@ public class WidgetID
|
||||
public static final int MOTHERLODE_MINE_GROUP_ID = 382;
|
||||
public static final int EXPERIENCE_DROP_GROUP_ID = 122;
|
||||
public static final int PUZZLE_BOX_GROUP_ID = 306;
|
||||
public static final int LIGHT_BOX_GROUP_ID = 322;
|
||||
public static final int NIGHTMARE_ZONE_GROUP_ID = 202;
|
||||
public static final int BLAST_FURNACE_GROUP_ID = 474;
|
||||
public static final int WORLD_MAP_GROUP_ID = 595;
|
||||
@@ -479,6 +480,21 @@ public class WidgetID
|
||||
static final int VISIBLE_BOX = 4;
|
||||
}
|
||||
|
||||
static class LightBox
|
||||
{
|
||||
static final int LIGHT_BOX = 1;
|
||||
static final int LIGHT_BOX_WINDOW = 2;
|
||||
static final int LIGHT_BULB_CONTAINER = 3;
|
||||
static final int BUTTON_A = 8;
|
||||
static final int BUTTON_B = 9;
|
||||
static final int BUTTON_C = 10;
|
||||
static final int BUTTON_D = 11;
|
||||
static final int BUTTON_E = 12;
|
||||
static final int BUTTON_F = 13;
|
||||
static final int BUTTON_G = 14;
|
||||
static final int BUTTON_H = 15;
|
||||
}
|
||||
|
||||
static class DialogSprite
|
||||
{
|
||||
static final int SPRITE = 0;
|
||||
|
||||
@@ -310,6 +310,19 @@ public enum WidgetInfo
|
||||
|
||||
PUZZLE_BOX(WidgetID.PUZZLE_BOX_GROUP_ID, WidgetID.PuzzleBox.VISIBLE_BOX),
|
||||
|
||||
LIGHT_BOX(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.LIGHT_BOX),
|
||||
LIGHT_BOX_CONTENTS(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.LIGHT_BULB_CONTAINER),
|
||||
LIGHT_BOX_BUTTON_A(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.BUTTON_A),
|
||||
LIGHT_BOX_BUTTON_B(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.BUTTON_B),
|
||||
LIGHT_BOX_BUTTON_C(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.BUTTON_C),
|
||||
LIGHT_BOX_BUTTON_D(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.BUTTON_D),
|
||||
LIGHT_BOX_BUTTON_E(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.BUTTON_E),
|
||||
LIGHT_BOX_BUTTON_F(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.BUTTON_F),
|
||||
LIGHT_BOX_BUTTON_G(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.BUTTON_G),
|
||||
LIGHT_BOX_BUTTON_H(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.BUTTON_H),
|
||||
|
||||
LIGHT_BOX_WINDOW(WidgetID.LIGHT_BOX_GROUP_ID, WidgetID.LightBox.LIGHT_BOX_WINDOW),
|
||||
|
||||
NIGHTMARE_ZONE(WidgetID.NIGHTMARE_ZONE_GROUP_ID, 1),
|
||||
|
||||
RAIDS_POINTS_INFOBOX(WidgetID.RAIDS_GROUP_ID, WidgetID.Raids.POINTS_INFOBOX),
|
||||
|
||||
@@ -25,16 +25,40 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.inject.Provides;
|
||||
import java.util.Arrays;
|
||||
import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.MenuOptionClicked;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetID;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import static net.runelite.api.widgets.WidgetInfo.LIGHT_BOX_BUTTON_A;
|
||||
import static net.runelite.api.widgets.WidgetInfo.LIGHT_BOX_BUTTON_B;
|
||||
import static net.runelite.api.widgets.WidgetInfo.LIGHT_BOX_BUTTON_C;
|
||||
import static net.runelite.api.widgets.WidgetInfo.LIGHT_BOX_BUTTON_D;
|
||||
import static net.runelite.api.widgets.WidgetInfo.LIGHT_BOX_BUTTON_E;
|
||||
import static net.runelite.api.widgets.WidgetInfo.LIGHT_BOX_BUTTON_F;
|
||||
import static net.runelite.api.widgets.WidgetInfo.LIGHT_BOX_BUTTON_G;
|
||||
import static net.runelite.api.widgets.WidgetInfo.LIGHT_BOX_BUTTON_H;
|
||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.puzzlesolver.lightbox.Combination;
|
||||
import net.runelite.client.plugins.puzzlesolver.lightbox.LightBox;
|
||||
import net.runelite.client.plugins.puzzlesolver.lightbox.LightboxSolution;
|
||||
import net.runelite.client.plugins.puzzlesolver.lightbox.LightboxSolver;
|
||||
import net.runelite.client.plugins.puzzlesolver.lightbox.LightboxState;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Puzzle Solver"
|
||||
)
|
||||
@Slf4j
|
||||
public class PuzzleSolverPlugin extends Plugin
|
||||
{
|
||||
@Inject
|
||||
@@ -43,11 +67,13 @@ public class PuzzleSolverPlugin extends Plugin
|
||||
@Inject
|
||||
private PuzzleSolverOverlay overlay;
|
||||
|
||||
@Provides
|
||||
PuzzleSolverConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(PuzzleSolverConfig.class);
|
||||
}
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
private LightboxState lightbox;
|
||||
private LightboxState[] changes = new LightboxState[LightBox.COMBINATIONS_POWER];
|
||||
private Combination lastClick;
|
||||
private boolean lastClickInvalid;
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
@@ -60,4 +86,156 @@ public class PuzzleSolverPlugin extends Plugin
|
||||
{
|
||||
overlayManager.remove(overlay);
|
||||
}
|
||||
|
||||
@Provides
|
||||
PuzzleSolverConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(PuzzleSolverConfig.class);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onWidgetClicked(MenuOptionClicked menuOptionClicked)
|
||||
{
|
||||
int widgetId = menuOptionClicked.getWidgetId();
|
||||
if (TO_GROUP(widgetId) != WidgetID.LIGHT_BOX_GROUP_ID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Combination combination;
|
||||
if (widgetId == LIGHT_BOX_BUTTON_A.getId())
|
||||
{
|
||||
combination = Combination.A;
|
||||
}
|
||||
else if (widgetId == LIGHT_BOX_BUTTON_B.getId())
|
||||
{
|
||||
combination = Combination.B;
|
||||
}
|
||||
else if (widgetId == LIGHT_BOX_BUTTON_C.getId())
|
||||
{
|
||||
combination = Combination.C;
|
||||
}
|
||||
else if (widgetId == LIGHT_BOX_BUTTON_D.getId())
|
||||
{
|
||||
combination = Combination.D;
|
||||
}
|
||||
else if (widgetId == LIGHT_BOX_BUTTON_E.getId())
|
||||
{
|
||||
combination = Combination.E;
|
||||
}
|
||||
else if (widgetId == LIGHT_BOX_BUTTON_F.getId())
|
||||
{
|
||||
combination = Combination.F;
|
||||
}
|
||||
else if (widgetId == LIGHT_BOX_BUTTON_G.getId())
|
||||
{
|
||||
combination = Combination.G;
|
||||
}
|
||||
else if (widgetId == LIGHT_BOX_BUTTON_H.getId())
|
||||
{
|
||||
combination = Combination.H;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastClick != null)
|
||||
{
|
||||
lastClickInvalid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastClick = combination;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameTick(GameTick event)
|
||||
{
|
||||
Widget lightboxWidget = client.getWidget(WidgetInfo.LIGHT_BOX_CONTENTS);
|
||||
if (lightboxWidget == null)
|
||||
{
|
||||
if (lightbox != null)
|
||||
{
|
||||
lastClick = null;
|
||||
lastClickInvalid = false;
|
||||
lightbox = null;
|
||||
Arrays.fill(changes, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// get current state from widget
|
||||
LightboxState lightboxState = new LightboxState();
|
||||
int index = 0;
|
||||
for (Widget light : lightboxWidget.getDynamicChildren())
|
||||
{
|
||||
boolean lit = light.getItemId() == LightBox.LIGHT_BULB_ON;
|
||||
lightboxState.setState(index / LightBox.WIDTH, index % LightBox.HEIGHT, lit);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (lightboxState.equals(lightbox))
|
||||
{
|
||||
return; // no change
|
||||
}
|
||||
|
||||
log.debug("Lightbox changed!");
|
||||
|
||||
LightboxState prev = lightbox;
|
||||
lightbox = lightboxState;
|
||||
|
||||
if (lastClick == null || lastClickInvalid)
|
||||
{
|
||||
lastClick = null;
|
||||
lastClickInvalid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
LightboxState diff = lightboxState.diff(prev);
|
||||
changes[lastClick.ordinal()] = diff;
|
||||
|
||||
log.debug("Recorded diff for {}", lastClick);
|
||||
lastClick = null;
|
||||
|
||||
// try to solve
|
||||
LightboxSolver solver = new LightboxSolver();
|
||||
solver.setInitial(lightbox);
|
||||
int idx = 0;
|
||||
for (LightboxState state : changes)
|
||||
{
|
||||
if (state != null)
|
||||
{
|
||||
Combination combination = Combination.values()[idx];
|
||||
solver.setSwitchChange(combination, state);
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
|
||||
LightboxSolution solution = solver.solve();
|
||||
if (solution != null)
|
||||
{
|
||||
log.debug("Got solution: {}", solution);
|
||||
}
|
||||
|
||||
// Set solution to title
|
||||
Widget lightbox = client.getWidget(WidgetInfo.LIGHT_BOX);
|
||||
if (lightbox != null)
|
||||
{
|
||||
Widget title = lightbox.getChild(1);
|
||||
if (solution != null && solution.numMoves() > 0)
|
||||
{
|
||||
title.setText("Light box - Solution: " + solution);
|
||||
}
|
||||
else if (solution != null)
|
||||
{
|
||||
title.setText("Light box - Solution: solved!");
|
||||
}
|
||||
else
|
||||
{
|
||||
title.setText("Light box - Solution: unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver.lightbox;
|
||||
|
||||
public enum Combination
|
||||
{
|
||||
A, B, C, D, E, F, G, H;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver.lightbox;
|
||||
|
||||
public class LightBox
|
||||
{
|
||||
public static final int WIDTH = 5;
|
||||
public static final int HEIGHT = 5;
|
||||
public static final int COMBINATIONS_POWER = 8;
|
||||
public static final int LIGHT_BULB_ON = 20357;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver.lightbox;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LightboxSolution
|
||||
{
|
||||
private int solution;
|
||||
|
||||
public void flip(Combination c)
|
||||
{
|
||||
solution ^= (1 << c.ordinal());
|
||||
}
|
||||
|
||||
public int numMoves()
|
||||
{
|
||||
int count = 0;
|
||||
int cur = solution;
|
||||
for (int i = 0; i < Combination.values().length; ++i)
|
||||
{
|
||||
count += cur & 1;
|
||||
cur >>= 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (Combination combination : Combination.values())
|
||||
{
|
||||
if (((solution >>> combination.ordinal()) & 1) != 0)
|
||||
{
|
||||
stringBuilder.append(combination.name());
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver.lightbox;
|
||||
|
||||
public class LightboxSolver
|
||||
{
|
||||
private LightboxState initial;
|
||||
private final LightboxState[] switches = new LightboxState[LightBox.COMBINATIONS_POWER];
|
||||
|
||||
static boolean isBitSet(int num, int bit)
|
||||
{
|
||||
return ((num >>> bit) & 1) != 0;
|
||||
}
|
||||
|
||||
private static boolean isSolved(LightboxState s)
|
||||
{
|
||||
for (int i = 0; i < LightBox.WIDTH; ++i)
|
||||
{
|
||||
for (int j = 0; j < LightBox.HEIGHT; ++j)
|
||||
{
|
||||
if (!s.getState(i, j))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public LightboxSolution solve()
|
||||
{
|
||||
LightboxSolution solution = null;
|
||||
outer:
|
||||
for (int i = 0; i < Math.pow(2, LightBox.COMBINATIONS_POWER); ++i)
|
||||
{
|
||||
LightboxState s = initial;
|
||||
|
||||
for (int bit = 0; bit < LightBox.COMBINATIONS_POWER; ++bit)
|
||||
{
|
||||
if (isBitSet(i, bit))
|
||||
{
|
||||
// this switch is unknown, so this can't be a valid answer
|
||||
if (switches[bit] == null)
|
||||
{
|
||||
continue outer;
|
||||
}
|
||||
|
||||
s = s.diff(switches[bit]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isSolved(s))
|
||||
{
|
||||
LightboxSolution sol = new LightboxSolution(i);
|
||||
if (solution == null || sol.numMoves() < solution.numMoves())
|
||||
{
|
||||
solution = sol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
public void setInitial(LightboxState initial)
|
||||
{
|
||||
this.initial = initial;
|
||||
}
|
||||
|
||||
public void setSwitchChange(Combination combination, LightboxState newState)
|
||||
{
|
||||
switches[combination.ordinal()] = newState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver.lightbox;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public class LightboxState
|
||||
{
|
||||
private final boolean[][] state = new boolean[LightBox.WIDTH][LightBox.HEIGHT];
|
||||
|
||||
public void setState(int x, int y, boolean s)
|
||||
{
|
||||
state[x][y] = s;
|
||||
}
|
||||
|
||||
public boolean getState(int x, int y)
|
||||
{
|
||||
return state[x][y];
|
||||
}
|
||||
|
||||
public LightboxState diff(LightboxState other)
|
||||
{
|
||||
LightboxState newState = new LightboxState();
|
||||
|
||||
for (int i = 0; i < LightBox.WIDTH; ++i)
|
||||
{
|
||||
for (int j = 0; j < LightBox.HEIGHT; ++j)
|
||||
{
|
||||
newState.state[i][j] = state[i][j] ^ other.state[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.puzzlesolver.lightbox;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
|
||||
public class LightboxSolverTest
|
||||
{
|
||||
private static final int[] INITIAL = new int[]{
|
||||
1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0,
|
||||
0, 1, 1, 1, 0,
|
||||
0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1
|
||||
};
|
||||
|
||||
private static final int[] A = new int[]{
|
||||
0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 1
|
||||
};
|
||||
|
||||
private static final int[] B = new int[]{
|
||||
0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0,
|
||||
1, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 1,
|
||||
};
|
||||
|
||||
private static final int[] C = new int[]{
|
||||
0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
};
|
||||
|
||||
private static final int[] D = new int[]{
|
||||
1, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1,
|
||||
1, 1, 0, 1, 1,
|
||||
0, 1, 1, 0, 0,
|
||||
1, 0, 0, 1, 1,
|
||||
};
|
||||
|
||||
private static final int[] E = new int[]{
|
||||
1, 0, 0, 1, 0,
|
||||
1, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 1,
|
||||
};
|
||||
|
||||
private static final int[] F = new int[]{
|
||||
1, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 1, 1, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
private static final int[] G = new int[]{
|
||||
1, 0, 0, 1, 1,
|
||||
1, 1, 1, 0, 0,
|
||||
0, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
1, 1, 0, 0, 0,
|
||||
};
|
||||
|
||||
private static final int[] H = new int[]{
|
||||
1, 0, 1, 1, 1,
|
||||
1, 1, 1, 0, 0,
|
||||
0, 1, 1, 1, 0,
|
||||
1, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
private static LightboxState fromArray(int[] array)
|
||||
{
|
||||
LightboxState s = new LightboxState();
|
||||
|
||||
assert array.length == 25;
|
||||
for (int i = 0; i < array.length; ++i)
|
||||
{
|
||||
s.setState(i / 5, i % 5, array[i] != 0);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
LightboxSolver solver = new LightboxSolver();
|
||||
|
||||
solver.setInitial(fromArray(INITIAL));
|
||||
solver.setSwitchChange(Combination.A, fromArray(A));
|
||||
solver.setSwitchChange(Combination.B, fromArray(B));
|
||||
solver.setSwitchChange(Combination.C, fromArray(C));
|
||||
solver.setSwitchChange(Combination.D, fromArray(D));
|
||||
solver.setSwitchChange(Combination.E, fromArray(E));
|
||||
solver.setSwitchChange(Combination.F, fromArray(F));
|
||||
solver.setSwitchChange(Combination.G, fromArray(G));
|
||||
solver.setSwitchChange(Combination.H, fromArray(H));
|
||||
|
||||
LightboxSolution solution = solver.solve();
|
||||
|
||||
LightboxSolution expected = new LightboxSolution();
|
||||
expected.flip(Combination.A);
|
||||
expected.flip(Combination.B);
|
||||
expected.flip(Combination.D);
|
||||
expected.flip(Combination.E);
|
||||
expected.flip(Combination.F);
|
||||
expected.flip(Combination.G);
|
||||
|
||||
assertEquals(expected, solution);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user