Here's a quick Monday morning puzzle.
You have a 14x14 rectangular game board except that the last 7 fields of the last row are missing. Each field has a lamp, and a button that toggles the lamps on that field and each of its neighbours in a cardinal direction, altogether at most five lamps. At the start, all lights are lit. Find out which buttons to push to unlight all lights.
Why I like this puzzle is:
brute forcing won't work, but there's an intermediate algorithm that's fast enough for this board size but easier to code than the general algorithm that solves this for larger board sizes.
Solution:
Update: here's an example. Suppose we have a 3x4 board with the last 1 field of the last row missing. At the start, it looks like this, all lamps lit:
****
****
***
Now we press the button on the bottom left field so three lights go off:
****
.***
..*
then press the button above that so two lights turn back on but two lights go off:
.***
*.**
*.*
now press the second button in the bottom row:
.***
****
.*.
now the button above that one:
..**
...*
...
finally press the top right button:
....
....
...
and all the lights are off, so we've solved this small board.
Re: Lights out puzzle
by salva (Abbot) on Nov 28, 2011 at 11:26 UTC

Perl may not be the right tool to solve that problem.
A generic solution using GNUProlog (that has a very fast finite domain constraint solver):
It solves any problem where N < 20 in a few seconds.  [reply] [d/l] 

This is a nice solution.
I too was thinking that perl might not be the best tool for solving this, but for an entirely different reason.
I wasn't thinking of this puzzle as a constraint satisfaction problem. Of course not, since it's
which is what my second solution uses.
But once you mentioned it, viewing as a constraint satisfaction problem also makes sense. After all,
Update: for reference, the last time salva has surprised me with a nice solution using a finite domain constraint solver was Re^4: Seven by seven farming puzzle.
Update: I ran the solution for (20, 20, 2). Your prolog solution took two and a half minutes (I have modified the printing part somewhat, but used GNU prolog). My perl solution took 40 seconds. So my opinion is that this prolog+finitedomain solution is fast enough. (Update: the same solution ran in SWI prolog is riddiculously slow though.)
 [reply] 
Re: Lights out puzzle (perl solution)
by ambrus (Abbot) on Nov 28, 2011 at 21:41 UTC

Here's a solution written in perl, then some explanation on how it works.
 [reply] [d/l] [select] 

Now quick someone bribe zentara to put a TK interface to this... and I'll get nothing done for the next week. :)
 [reply] 
Re: Lights out puzzle
by marto (Bishop) on Nov 28, 2011 at 09:48 UTC

My immediate reaction would be to press the button on the wall socket/power source, no power to the board, no lights :P
 [reply] 
Re: Lights out puzzle
by choroba (Chancellor) on Nov 28, 2011 at 18:09 UTC

Here's a quick Monday morning puzzle.
Quick?? I spent several hours on it, not being able to come with anything better then this:
It's a bit randomized, but usually runs under 2 seconds on my machine. Run it with a filename as an argument to check the solution saved in the file.
Update: Removed forgotten debugging line.
Update2: Readmore changed to spoiler.
 [reply] [d/l] 

Here are some comments on how it works:
The code clears all the lines except for the last one (clean) the simple way: if there is a light, click underneath. The last line (or, better to say, broken line, i.e. the last line plus the remaining half of the previous one) is then solved halfrandomly. At the beginning, I cache how clicking on the top line influences the last line, but only for one click on the line (i.e. I only know what the last line will be after having one light lit). Therefore, I have to click randomly until I get a cached position that I can solve. This works well for size 14, but the time doubles for each +2 in size, so size 20 is already too slow. Caching more positions could be added easily (like clicking two times), but I am not sure how much time it would take to cache all possible combinations on the first line.
Because the order of clicks is not important, I keep a separate map of the board with 0 for the even clicks and 1 for the odd ones. This separate board is the output of the program.
 [reply] [d/l] 

sub show {
my $board = shift;
print "\e[H";
for my $row (@$board) {
return unless defined $row;
print map $_ ? '*' : defined $_ ? '.' : '', @$row;
print "\e[K\n";
}
print "\e[J";
use Time::HiRes "sleep";
sleep(6e3);
} # show
sub toggle {
my ($board, $x, $y) = @_;
my $old = $board>[$y][$x];
return unless defined $old;
$board>[$y][$x] = $old eq 1 ? 0 : 1;
} # toggle
and now I can see the lights being chased down to the bottom of the board. Looks nice.
 [reply] [d/l] 

Yes, in fact, I did something similar for debugging :)
 [reply] 
Re: Lights out puzzle
by Ratazong (Monsignor) on Nov 28, 2011 at 10:02 UTC

Good Monday morning also to you, ambrus!
Lights out is really nice. Especially the simplicity of the solution: if it is solvable (not all boardconfigurations are), it takes at maximum n*m turns on an nbym board. However when I try it manually, I need many, many more (if I ever finish it) ...
Rata (who's only adventure into VBforExcelprogramming was a 5x5  version of this game)
 [reply] 
Re: Lights out puzzle (nonperl solution)
by ambrus (Abbot) on Nov 29, 2011 at 14:38 UTC

Here's a nonperl solution, with explanation.
For larger boards, this one is much faster than my program above. (You could try (29, 30, 2) or (39, 40, 2) as large examples where there's a unique button combination this program finds very quickly but that would take ages to found with the previous program.)
 [reply] [d/l] [select] 

Now solving a linear equation over GF(2) is something apparently very few libraries can do
That's quite easy to implement, so easy that, well... see Algorithm::GaussianElimination::GF2.
Using that module, the Lights On problem gets reduced to:
use strict;
use warnings;
use Algorithm::GaussianElimination::GF2;
use 5.010;
(@ARGV >= 1 and @ARGV <= 2) or die "Usage:\n $0 len [width]\n\n";
my ($len, $w) = @ARGV;
unless (defined $w) {
$w = int sqrt($len);
$w++ unless $w * $w == $len;
}
my $a = Algorithm::GaussianElimination::GF2>new;
for my $ix (0..$len1) {
my $eq = $a>new_equation;
$eq>b(1);
$eq>a($ix, 1);
my $up = $ix  $w;
$eq>a($up, 1) if $up >= 0;
my $down = $ix + $w;
$eq>a($down, 1) if $down < $len;
my $left = $ix  1;
$eq>a($left, 1) if $left % $w + 1 != $w;
my $right = $ix + 1;
$eq>a($right, 1) if $right % $w and $right < $len;
}
my ($sol, @base0) = $a>solve;
if ($sol) {
my @sol = @$sol;
while (@sol) {
my @row = splice @sol, 0, $w;
say "@row";
}
for my $sol0 (@base0) {
say "sol0:";
my @sol0 = @$sol0;
while (@sol0) {
my @row = splice @sol0, 0, $w;
say "@row";
}
}
}
else {
say "no solution found"
}
On my computer the 14x147 problem gets solved in 0.06 seconds.  [reply] [d/l] 

