views:

728

answers:

4

I am trying to create a solvability function for a game algorithm. Basically a function that returns true or false for a given game it if is solvable or not.

The game is Buttonia.com (which does not implement the algorithm as yet), a type of lights-out game. Basically You have a grid of buttons, each of which, when pressed, will change the state of some of it's neighbors. Currently I generate a random game configuration and then apply heuristics as far as possible. The rest is decided by brute force search.

My progress so far was to create a system of equations to model the game. As each button needs to change state an odd number of times to end up in a down state, It's equation would be this:

button_A = 1 - (button_1 + button_2 + ... + button_X) % 2

Where button_1 through button_X are the states of the buttons with an effect on button_A. Some buttons may be immediately resolved, if they are not dependent on others. For the rest, I try one configuration until I get a conflict and then back track.

Currently this algorithm is practical for smaller configurations of games. I've tested it from 3x3 games up to sizes of 10x10. Where 6x6 is near an upper limit for practical play.

The equations hugely cut down the search space from brute-force, making it practical. There might be a purely mathematical way of solving the system of equations.


Sample 3x3 game in ascii (from buttonia.com/?game=2964):

||#
-o-
+#|

Legend:
o = affect only self
- = affect left and right neighbors
| = affect above and below neighbors
+ = affect left, right, above and below neighbors
# = affect all 8 surrounding neighbors

Solution, press these: (0,0), (2,0), (1, 2), (0, 1), (1, 1), (2,1)

Equations for this game:

Button_0_0 = 1 - (0) % 2
Button_1_0 = 1 - (Button_2_0) % 2
Button_2_0 = 1 - (0) % 2
Button_0_1 = 1 - (Button_0_0 + Button_0_2 + Button_1_2) % 2
Button_1_1 = 1 - (Button_1_0 + Button_2_0 + Button_0_1 + Button_2_1 + Button_1_2) % 2
Button_2_1 = 1 - (Button_2_0 + Button_1_2 + Button_2_2) % 2
Button_0_2 = 1 - (Button_1_2) % 2
Button_1_2 = 1 - (Button_0_2) % 2
Button_2_2 = 1 - (Button_1_2) % 2

Potential solution:

Changing the mathematical functions to avoid the need for the modulus lets us move the terms on the left side to the right, creating the neat matrix setup we need for the Gaussian method. So the first two equations would respectively convert to:

-1 = -1*B00 +  0*B10 +  0*B20 +  0*B01 +  0*B11 +  0*B21 +  0*B02 +  0*B12 +  0*B22
-1 =  0*B00 + -1*B10 + -1*B20 +  0*B01 +  0*B11 +  0*B21 +  0*B02 +  0*B12 +  0*B22

Discussed solution here: http://stackoverflow.com/questions/1216176/gaussian-elimination-with-custom-operators

Getting closer. Almost ready to post full solution: http://stackoverflow.com/questions/1248216/inverting-binary-networks

+2  A: 

Instead of starting with a random state, why not generate the starting position by flipping random switches, i.e. work backwards from a solved state to a starting state. That way you only generate solvable puzzles.

Matt Howells
By random state, I mean random game. The starting state is always all buttons up, with the target state always all buttons down. Since the states are symmetrical, it does not make a difference if u start with all up or all down. The solution is always a bit-map (on/off map) of which buttons need to be pressed and which do not.
Killroy
I see, so you are just trying to determine if a given grid NxM is solvable?
Matt Howells
Yes. As it happens, my current solvability algorithm also returns the solution. Basically I want to ensure I only present solvable games to the player.
Killroy
+3  A: 

This is a system of linear equations over F2, the field containing the two elements 0 and 1.

You can solve it just like normal linear equations, but you have to do the arithmetic modulo 2.

Edit: Linear algebra for this case works exactly like for real numbers, except that you have to replace the operations:

  • Addition and subtraction become exclusive or, i.e. 0 + 0 = 0, 0 + 1 = 1, 1 + 1 = 0.

  • Multiplication becomes AND: 0 * 0 = 0, 0 * 1 = 0, 1 * 1 = 1

  • Division is only possible by one: 0 / 1 = 0, 1 / 1 = 1.

All the coefficients in your equations and the possible values of unknowns are either 0 or 1.

So the modulo is not slapped on the outside of the equations like you wrote, it is implicit in the operations.

If your system of equations is not solvable you'll get an equation 0 = 1, which is obviously not solvable.

starblue
The modulo is exactly what threw me off. How can I solve them despite the modulo? Especially if they might not be solvable!
Killroy
http://en.wikipedia.org/wiki/Chinese_remainder_theorem
fortran
hmmmm... I thought the Chinese Remainder Theorem was the needed tool to solve it, but reviewing it I realise that it's about a different problem (my discrete mathematics lessons are a little bit rusty now :-s)
fortran
You only need the Chinese Remainder Theorem to compute inverses in bigger finite fields, in this case it is trivial.
starblue
It looks like this might do it. I will implement the simultaneous equation algorithm (any recommendations?) And likely accept this answer if it works!
Killroy
@starblue: I would have thought the most common use of the chinese remainder theorem was computing divisors in an infinite field, i.e the field of integers
Mitch Wheat
A: 

As this is not a time-limited problem (well, assuming it can be done in less than a day), I would probably go for a depth-limited breadth-first search, taking each possible move on a level and then each move that follows on from each move.

It will be slow, however it is almost guaranteed to find an answer, if there is one!

Ed Woodcock
It is solvable. I even have extensive statistics on it. My current implementation can find a solvable 6x6 in an average of about 400ms with a max time of 1300ms in Javascript under Chrome 3. The problem is the algorithm will not scale well to larger game configrations. A truly arithmetic solution very well might!
Killroy
Fair enough, if you intend to make the search space much larger it won't scale well, agreed. Answer effectively retracted =]
Ed Woodcock
Also, it is highly time constrained, since I have to solve this problem each time a player wants to play a new game, while they are waiting. And this might happen in resource limited devices, such as a mobile phone.
Killroy
A 10x10 takes over 15 seconds to solve with the current implementation, which I think is a bit too long for usability reasons.
Killroy
Is this really a problem though? Why not build a huge library of known solvable puzzles at the server side, and just farm them out? If you hand them out randomly, and the library is large enough, you have effectively memoized the solver's task. This would avoid the need entirely for a solver to run in javascript at the client side.
ire_and_curses
Oh, I was under the impression that the games only changed once a day, my bad! agreed with ire though, pre-solved puzzles would make sense, you could quickly build up a library if it only takes 15s to solve one, and storing them is trivial, if you store in some sort of matrix format.
Ed Woodcock
The website was build a long time before I had the idea of the simultaneous equations. We planned to use a community voting algorithm to remove "bad" games. That's horrible of course and I want the solver. Even for mobile phone application usage the current algorithm is workable, since games over 6x6 may be too hard to play. I've never played one larger then 6x6. This is mostly a theoretical question.
Killroy
+1  A: 

This looks almost like a system of linear equations (except the mod 2), so you might be able to adapt one of the normal techniques for solving those - e.g. row reduction of the system in matrix form (wikipedia).

Jon
Thanks I will look into those. The problem is the modulus! Perhaps I can eliminate it somehow, but I don't know how.
Killroy