Merge pull request #4121 from Adam-/lightbox

puzzle solver: add lightbox solver
This commit is contained in:
Adam
2018-07-01 10:54:50 -04:00
committed by GitHub
9 changed files with 641 additions and 5 deletions

View File

@@ -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;

View File

@@ -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),

View File

@@ -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");
}
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}