/*
Sudoku Puzzle generator
(C) Copyright 2007
John Ryland <jryland@invertedlogic.com>
ALL RIGHTS RESERVED
*/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
int boxTab[81] = {
1,1,1,2,2,2,3,3,3,
1,1,1,2,2,2,3,3,3,
1,1,1,2,2,2,3,3,3,
4,4,4,5,5,5,6,6,6,
4,4,4,5,5,5,6,6,6,
4,4,4,5,5,5,6,6,6,
7,7,7,8,8,8,9,9,9,
7,7,7,8,8,8,9,9,9,
7,7,7,8,8,8,9,9,9
};
unsigned int selected[81];
unsigned int possible[81];
void prettyPrint()
{
for (int i = 0; i < 81; i++) {
if (i % 27 == 0)
printf("-------------\n");
if (i % 3 == 0)
printf("|");
printf("%i", selected[i]);
if (i % 9 == 8)
printf("|\n");
}
printf("-------------\n");
}
int onlyOne(int val)
{
for (unsigned int j = 0; j < 9; j++)
if (val == (0x1u << j))
return j + 1;
return 0;
}
void addValue(int pos, unsigned int val)
{
unsigned int mask = 0x1u << (val-1);
if ( (possible[pos] & mask) == 0 )
return;
possible[pos] = ~mask;
selected[pos] = val;
for (int i = 0; i < 81; i++)
if ( !selected[i] ) {
if ( pos/9 == i/9 || pos%9 == i%9 || boxTab[pos] == boxTab[i] ) {
possible[i] &= ~mask;
for (unsigned int j = 0; j < 9; j++)
if (possible[i] == (0x1u << j))
addValue(i, j + 1);
}
}
}
/*
// Broken - seems it can't work to do it this way
void init()
{
for (int i = 0; i < 81; i++) {
possible[i] = 0x1FFu;
selected[i] = 0;
}
for (int pos = 0; pos < 81; pos++) {
assert(possible[pos]);
unsigned int possibles = possible[pos];
unsigned int bitCount = 0;
unsigned int vals[10] = { 0 };
for (unsigned int bit = 0; possibles; bit++, possibles >>= 1) {
if (possibles & 1) {
vals[bitCount] = bit + 1;
bitCount++;
}
}
assert(bitCount >= 1);
assert(bitCount <= 9);
bitCount--;
unsigned int off = 0;
if (bitCount)
off = rand() % (bitCount+1);
assert(off >= 0);
assert(off <= 8);
unsigned int val = vals[off];
//unsigned int val = (bitCount-1) ? vals[rand() % (bitCount - 1)] : vals[0];
assert(val >= 1);
assert(val <= 9);
unsigned int mask = 0x1u << (val-1);
assert(mask);
assert(possible[pos] & mask);
//mask = ~mask;
selected[pos] = val;
if (pos != 80)
for (int i = pos + 1; i < 81; i++)
if ( pos/9 == i/9 || pos%9 == i%9 || boxTab[pos] == boxTab[i] ) {
assert(possible[i]);
//assert(possible[i] & mask);
if (!(possible[i] & mask)) {
printf("pos: %u i: %u mask: %u\n", pos, i, mask);
}
possible[i] &= ~mask;
assert(possible[i]);
for (unsigned int j = 0; j < 9; j++)
if (possible[i] == (0x1u << j)) {
for (int i2 = pos + 1; i2 < 81; i2++)
if ( i/9 == i2/9 || pos%9 == i2%9 || boxTab[i] == boxTab[i2] ) {
possible[i2] &= ~(1<<j);
assert(possible[i2]);
}
}
}
}
}
*/
bool addNumbers()
{
for (int i = 0; i < 81; i++) {
if ( !possible[i] )
return false;
while ( selected[i] == 0 )
addValue(i, (rand() % 9) + 1);
}
return true;
}
void init()
{
for (int i = 0; i < 81; i++) {
possible[i] = 0x1FFu;
selected[i] = 0;
}
addNumbers();
}
bool checkValid()
{
for (int j = 0; j < 81; j++)
for (int i = 0; i < 81; i++)
if (i != j && selected[i] && selected[j])
if ( j/9 == i/9 || j%9 == i%9 || boxTab[j] == boxTab[i] )
if ( selected[i] == selected[j] )
return false;
return true;
}
unsigned int puzzleVals[81];
unsigned int puzzleMask[81];
void solverAddValue(int pos, unsigned int val)
{
unsigned int mask = 0x1u << (val-1);
if ( (puzzleMask[pos] & mask) == 0 )
return;
puzzleMask[pos] = ~mask;
puzzleVals[pos] = val;
for (int i = 0; i < 81; i++)
if ( !puzzleVals[i] ) {
if ( pos/9 == i/9 || pos%9 == i%9 || boxTab[pos] == boxTab[i] ) {
puzzleMask[i] &= ~mask;
for (unsigned int j = 0; j < 9; j++)
if (puzzleMask[i] == (0x1u << j))
solverAddValue(i, j + 1);
}
}
}
bool isSolved()
{
for (int j = 0; j < 81; j++)
for (int i = 0; i < 81; i++)
if (i != j)// && puzzleVals[i] && puzzleVals[j])
if ( j/9 == i/9 || j%9 == i%9 || boxTab[j] == boxTab[i] )
if ( puzzleVals[i] == puzzleVals[j] )
return false;
return true;
}
bool canSolve()
{
for (int i = 0; i < 81; i++) {
puzzleVals[i] = selected[i];
puzzleMask[i] = 0x1FFu;
}
for (int i = 0; i < 81; i++) {
if ( puzzleVals[i] ) {
for (int j = 0; j < 81; j++)
if ( !puzzleVals[j] ) {
if ( j/9 == i/9 || j%9 == i%9 || boxTab[j] == boxTab[i] )
puzzleMask[j] &= ~(1 << (puzzleVals[i] - 1));
} else {
puzzleMask[j] = ~(1 << (puzzleVals[i] - 1)); // 0;
}
}
}
for (int i = 0; i < 81; i++)
if ( !puzzleVals[i] ) {
for (unsigned int j = 0; j < 9; j++)
if (puzzleMask[i] == (0x1u << j))
solverAddValue(i, j + 1);
}
return isSolved();
}
bool canRemoveCell(int i)
{
int oldSelected = selected[i];
selected[i] = 0;
bool ret = canSolve();
selected[i] = oldSelected;
return ret;
}
int removeZigZag[81] = {
41,51,31,33,49,81, 1,61,21,
63,19,79, 3,71,11, 9,73,25,
57,55,27,75, 7,65,17,54,78,
4,28,48,24,34,58,36,76,52,
60, 6,46,22,30,44,68,38,14,
12,20,62,70,42,50,40,32,45,
77,37, 5,13,29,69,53,15,47,
67,35,16,56,66,26,43,59,39,
23,72,80,10, 2, 8,64,18,74
};
int main(int argc, char* argv[])
{
unsigned int type = 0; // 0 - random, 1 - daily, 2 - specific seed
unsigned int difficulty = 0; // 0 - easy, 1 - medium, 2 - hard, 3 - test
unsigned int seed = time(0);
if (argc >= 1) {
for (int arg = 1; arg < argc; arg++) {
const char* argStr = argv[arg];
if (strcmp(argStr,"daily")==0) { type = 1; seed = time(0) / (60*60*24); }
else if (strcmp(argStr,"easy")==0) { difficulty = 0; }
else if (strcmp(argStr,"medium")==0) { difficulty = 1; }
else if (strcmp(argStr,"hard")==0) { difficulty = 2; }
else if (strcmp(argStr,"test")==0) { difficulty = 3; }
else { type = 2; seed = atoi(argv[arg]); }
}
}
// printf("%u\n", seed);
const char* types[3] = { "random", "daily", "specific" };
const char* difficulties[4] = { "easy", "medium", "hard", "test" };
printf("{\n");
printf(" \"type\" : \"%s\",\n \"difficulty\" : \"%s\",\n \"id\" : %u,\n \"solution\" : \"",
types[type], difficulties[difficulty], seed);
srand(seed);
int tries = 0;
do {
init();
tries++;
} while (!checkValid());
for (int i = 0; i < 81; i++)
printf("%i",selected[i]);
printf("\",");
printf("\n");
// prettyPrint();
// printf("tried: %i times\n", tries);
// printf("%s\n", checkValid()?"valid":"invalid");
int numRemoved = 0;
for (int i = 0; i < 81; i++) {
int j = removeZigZag[i] - 1;
if (canRemoveCell(j)) {
numRemoved++;
selected[j] = 0;
// prettyPrint();
if (difficulty == 3 && numRemoved >= 2) // test
break;
if (difficulty == 0 && numRemoved >= 40) // easy
break;
if (difficulty == 1 && numRemoved >= 48) // medium
break;
}
}
printf(" \"clues\" : \"");
for (int i = 0; i < 81; i++)
printf("%i",selected[i]);
printf("\"");
printf("\n");
printf("}\n");
return 0;
}