Some time ago, /r/ProgrammerHumor was flooding with phone number inputs. In the linked thread, you can find one based on the "Lights off" game. If you click a cell, it will flip, and all neighbouring cells will also flip. In this particular implementation, this propagates through the walls. We can represent a number as a 5x4 matrix of booleans. So if you start from a matrix that's all zeros, clicking the top left cell should leave you with the following:
1, 1, 0, 1,
1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 0
The representation of all numbers is in the file numbers.h
below. The question is whether all numbers can be reached, starting from "all lights off" (all values are zero).
The author noted that he had a Python implementation that runs in 5 minutes. This seemed ridiculously long to me and I was curious to compare the timing of his Python implementation to a C implementation, so I wrote it. My C isn't very good, though, so comments are very welcome!
numbers.h:
char numbers[][20] =
{
// zero
{
1, 1, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 1
},
// one
{
0, 0, 0, 1,
0, 0, 1, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1
},
// two
{
1, 1, 1, 1,
0, 0, 0, 1,
1, 1, 1, 1,
1, 0, 0, 0,
1, 1, 1, 1
},
// three
{
1, 1, 1, 1,
0, 0, 0, 1,
1, 1, 1, 1,
0, 0, 0, 1,
1, 1, 1, 1
},
// four
{
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 1,
0, 0, 0, 1,
0, 0, 0, 1
},
// five
{
1, 1, 1, 1,
1, 0, 0, 0,
1, 1, 1, 1,
0, 0, 0, 1,
1, 1, 1, 1
},
// six
{
1, 1, 1, 1,
1, 0, 0, 0,
1, 1, 1, 1,
1, 0, 0, 1,
1, 1, 1, 1,
},
// seven
{
1, 1, 1, 1,
0, 0, 0, 1,
0, 0, 1, 0,
0, 1, 0, 0,
1, 0, 0, 0
},
// eight
{
1, 1, 1, 1,
1, 0, 0, 1,
1, 1, 1, 1,
1, 0, 0, 1,
1, 1, 1, 1
},
// nine
{
1, 1, 1, 1,
1, 0, 0, 1,
1, 1, 1, 1,
0, 0, 0, 1,
0, 0, 0, 1
}
};
phone-number-bruteforce.c:
#include "stdio.h"
#include "string.h"
#include "numbers.h"
void print_num(int in) {
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 4; ++j) {
int nbit = 4*i+j;
printf("%d", (in & (1 << nbit)) >> nbit);
}
printf("\n");
}
}
void print_char(char *in) {
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 4; ++j) {
int n = 4*i+j;
printf("%d", in[n]);
}
printf("\n");
}
}
int shift(int index, int shift) {
// Note: NOT the same as (index + shift) / 4, due to rounding
int row = (5 + index / 4 + shift / 4) % 5;
int col = (4 + index + shift) % 4;
return row * 4 + col;
}
char* click(char *in, int click) {
in[click] ^= 1;
in[shift(click, 1)] ^= 1;
in[shift(click, -1)] ^= 1;
in[shift(click, 4)] ^= 1;
in[shift(click, -4)] ^= 1;
return in;
}
int compare_numbers(char *in) {
for (int i = 0; i < 10; ++i) {
if (!memcmp(numbers[i], in, 20)) {
return i;
}
}
return -1;
}
int main() {
for (int i = 0; i < (1 << 20); ++i) {
int index = i;
char new[20] = {0};
for (int j = 0; j < 20; ++j) {
if (index & 1) {
click(new, j);
}
index /= 2;
}
int found = compare_numbers(new);
if (found >= 0) {
printf("Found %d!\n", found);
print_num(i);
}
}
}
I tried to save each number in one int
(since I only need 20 bits), but I couldn't figure out the index calculations. This is the working version using an array of char
s.