5
\$\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\$
  • \$\begingroup\$ Can you justify why this isn't a duplicate of question 1? Do the answers there demonstrably not find the shortest solution? \$\endgroup\$ – Peter Taylor Feb 4 '14 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 '14 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\$ – John Dvorak Feb 4 '14 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\$ – Peter Taylor Feb 4 '14 at 10:12
  • \$\begingroup\$ @JanDvorak the minimum size is 5x5 \$\endgroup\$ – Teun Pronk Feb 4 '14 at 10:13
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\$
  • \$\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 '14 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\$ – johnchen902 Feb 5 '14 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 '14 at 7:26
  • \$\begingroup\$ @Josh Unfortunately, no. \$\endgroup\$ – johnchen902 Feb 5 '14 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\$
  • \$\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 '14 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 '14 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 '14 at 14:39
  • \$\begingroup\$ an input of n, (a number followed by a comma) causes it to go into infinite loop. \$\endgroup\$ – Braden Best Feb 11 '14 at 2:43
  • \$\begingroup\$ @B1KMusic Coordinates are separated by whitespace, not a comma. \$\endgroup\$ – Oberon Feb 11 '14 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.