6
\$\begingroup\$

Intro

I guess most people are familiar with the game Lights Off, but in case someone isn't, here is a short description:

You start with an NxN grid where each cell in the grid is a light. For this example N=5. There are 2 ways the game can start: either all of the lights are on, or some lights are off. The goal is to turn off all of the lights. If you toggle a light, the lights left, right, above and below it will toggle with it.

All Lights on

O O O O O  
O O O O O  
O O O O O  
O O O O O  
O O O O O

Toggled cells

Toggled(0,0) | Toggled(1,2)| Toggled(2,4)
X X O O O    |  O O X O O  |  O O O O O
X O O O O    |  O X X X O  |  O O O O X
O O O O O    |  O O X O O  |  O O O X X
O O O O O    |  O O O O O  |  O O O O X
O O O O O    |  O O O O O  |  O O O O O

Task

Make an interactive game of Lights Off with as little code as possible.

Requirements

There is a setup phase and a play phase.

The setup phase takes user input to determine the grid size (minimum size of 5) and whether the grid starts with all of the lights on. If the grid should not start with all of the lights on, lights must be selected randomly to start off: at least 1 and at most 20% of the lights.

In the play phase, the grid is displayed to the user and moves are taken as input. The application could use a windowed GUI with lights toggled by clicking, or a text UI which takes typed input of the coordinates of the cell to toggle.

When the user reaches a solved state (all lights off), the application must notify them that they have solved the puzzle, and show how many moves it took.

The use of external resources is not allowed.

If there is anything unclear or missing please let me know :)

Related questions

\$\endgroup\$
10
  • \$\begingroup\$ Can you justify why this isn't a duplicate of question 1? Do the answers there demonstrably not find the shortest solution? \$\endgroup\$ Feb 4, 2014 at 10:03
  • \$\begingroup\$ Question 1 requires the input of a full grid where the program will find the solution for you, where in this question the program will create a grid for the user to solve. \$\endgroup\$
    – Teun Pronk
    Feb 4, 2014 at 10:05
  • \$\begingroup\$ do we need to generate a solvable puzzle? Does every puzzle need to be possible to generate? If the size is 2x2, do we really need to start in the solved state? \$\endgroup\$ Feb 4, 2014 at 10:11
  • 1
    \$\begingroup\$ If the interesting bit is unchanged and the new bit is as trivial as that, I don't think it adds value to the site. \$\endgroup\$ Feb 4, 2014 at 10:12
  • \$\begingroup\$ @JanDvorak the minimum size is 5x5 \$\endgroup\$
    – Teun Pronk
    Feb 4, 2014 at 10:13

3 Answers 3

3
\$\begingroup\$

APL (101)

00{⎕←'XO'[1+⍵]⋄1∨.=,⍵:(⍺+1)∇⍵≠(⍳⍴⍵)∊⎕∘+¨Z,⌽¨Z←0∘.,¯1 0 1⋄'SOLVED',⍺}⎕{⍺:⍵ ⍵⍴1⋄~(⍵ ⍵⍴⍳V)∊V?⍨⌊.2×V←⍵*2}⎕

The first input is the size, the second input is the start value (0=some off, 1=on). Coordinates are 1-based.

      0{⎕←'XO'[1+⍵]⋄1∨.=,⍵:(⍺+1)∇⍵≠(⍳⍴⍵)∊⎕∘+¨Z,⌽¨Z←0∘.,¯1 0 1⋄'SOLVED',⍺}⎕{⍺:⍵ ⍵⍴1⋄~(⍵ ⍵⍴⍳V)∊V?⍨⌊.2×V←⍵*2}⎕
⎕:
      5
⎕:
      1
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO
⎕:
      2 2
OXOOO
XXXOO
OXOOO
OOOOO
OOOOO
⎕:
\$\endgroup\$
3
\$\begingroup\$

C++, 564 bytes

#include <iostream>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <vector>
using namespace std;int main(){int n,p,s=0,y,i=0,b;cin>>n>>b;if(n<5)n=5;vector<int>m(n*n,1);srand(time(0));if(b)for(int&c:m)c=rand()<RAND_MAX/6;for(;i<n*n;i++)cout<<m[i]<<(-~i%n?"":"\n");while(find(m.begin(),m.end(),1)!=m.end()){cin>>p>>y;p+=y*n;if(p<0||p>=n*n)continue;m[p]=!m[p];if(p%n)m[p-1]=!m[p-1];if(p%n+1<n)m[p+1]=!m[p+1];if(p>=n)m[p-n]=!m[p-n];if(p+n<n*n)m[p+n]=!m[p+n];for(i=0;i<n*n;i++)cout<<m[i]<<(-~i%n?"":"\n");s++;}cout<<"Solved in "<<s<<" steps."<<endl;}

In setup phase, the user should input the grid size first. Then if the grid should starts with all of the lights on, the user should input 0; otherwise 1.

In play phase, the user should input the 0-based coordinates of the cell to toggle until all lights off.

Original code:

#include <iostream>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <vector>
using namespace std;
int main() {
    int n, p, s = 0, y, i = 0, b;
    cin >> n >> b;
    if(n < 5) n = 5;
    vector<int> m(n * n, 1);
    srand(time(0));
    if (b) for (int& c : m) c = rand() < RAND_MAX / 6;
    for (; i < n * n; i++) cout << m[i] << (-~i % n ? "" : "\n");
    while (find(m.begin(), m.end(), 1) != m.end()) {
        cin >> p >> y;
        p += y * n;
        if (p < 0 || p >= n * n) continue;
        m[p] = !m[p];
        if (p % n) m[p - 1] = !m[p - 1];
        if (p % n + 1 < n) m[p + 1] = !m[p + 1];
        if (p >= n) m[p - n] = !m[p - n];
        if (p + n < n * n) m[p + n] = !m[p + n];
        for (i = 0; i < n * n; i++) cout << m[i] << (-~i % n ? "" : "\n");
        s++;
    }
    cout << "Solved in " << s << " steps." << endl;
}
\$\endgroup\$
4
  • \$\begingroup\$ Nice answer. You can save a few characters by dropping the #include <ctime> and initializing your random number generator with the address of one of your locals; ex srand(&n);. That should be random enough to produce good results. \$\endgroup\$
    – Josh
    Feb 5, 2014 at 1:10
  • \$\begingroup\$ @Josh &n is fixed on my machine. srand((int)&m[0]); is better but I think it is implementation-defined. \$\endgroup\$ Feb 5, 2014 at 5:02
  • \$\begingroup\$ What if you declared your variables at global scope? Would that add any randomness in to their addresses? \$\endgroup\$
    – Josh
    Feb 5, 2014 at 7:26
  • \$\begingroup\$ @Josh Unfortunately, no. \$\endgroup\$ Feb 5, 2014 at 7:49
3
\$\begingroup\$

C - 365 characters

#define a for(y=0;y<w*w;y++)
*k,i,w,x,y,c=0;main(){scanf("%i %i",&w,&i);k=malloc(4*w*w+8*w)+4*w;i&=1;srand(k);a k[y]=i||ra
nd()<6553;i^=1;for(;;){x=0;a{putchar(k[y]?79:88);x|=k[y]!=i;!((y+1)%w)&&putchar(10);}if(!x&&c
)return printf("won in %i",c);putchar(62);scanf("%i %i",&x,&y);k[x*w-w+y]^=x>0;k[x*w+y-1]^=y>
0;k[x*w+w+y]^=x<w-1;k[x*w+y+1]^=y<w-1;k[x*w+y]^=1;c++;}}

In setup phase, it asks the user for two integers: table size and starting state (0 for off and 1 for on), respectively.

After that, before every move, it will print the grid, then prompt (>) the user for 0-based xy coordinates of the point.

\$\endgroup\$
6
  • \$\begingroup\$ This is beautiful. You blew the C answer I was working on out of the water. I did notice that your solution seems to segafault on input 0 0 due to the code k[x*w+y-1]. \$\endgroup\$
    – Josh
    Feb 5, 2014 at 1:06
  • \$\begingroup\$ Additionally, as per the spec, if the user specifies 'lights off', there is supposed to be at least one light randomly turned on. \$\endgroup\$
    – Josh
    Feb 5, 2014 at 1:09
  • \$\begingroup\$ The random part should work. Not sure about your segfault, @Josh, so I added two lines in the grid memory. What OS and compiler are you using? It isn't segfaulting on W7x64. \$\endgroup\$
    – Oberon
    Feb 5, 2014 at 14:39
  • \$\begingroup\$ an input of n, (a number followed by a comma) causes it to go into infinite loop. \$\endgroup\$ Feb 11, 2014 at 2:43
  • \$\begingroup\$ @B1KMusic Coordinates are separated by whitespace, not a comma. \$\endgroup\$
    – Oberon
    Feb 11, 2014 at 15:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.