class Board
{
public:
Board()
: remains(81)
{
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j)
{
matrix[i][j] = 0;
memory[i][j] = allSet;
}
}
Board(unsigned seed)
: remains(81)
{
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j)
{
matrix[i][j] = 0;
memory[i][j] = allSet;
}
std::srand(seed);
_random_fill();
}
void set(unsigned row, unsigned col, unsigned val, bool advanced = false)
{
matrix[row][col] = val;
if (matrix[row][col])
{
Blank.elim(row, col, val);
--remains;
}
if (advanced)
_update(row, col);
}
unsigned unset(unsigned row, unsigned col)
{
unsigned val = matrix[row][col];
if (val)
{
Blank.cancel(row, col, val);
++remains;
}
matrix[row][col] = 0;
return val;
}
bitfield mask_check(unsigned i, unsigned j, bitfield mask)
{
return Blank.possible(i, j) & mask & memory[i][j];
}
bitfield house_check(unsigned i, unsigned j, bool advanced = false)
{
bitfield house_hidden = allSet;
unsigned row_base = i / 3 * 3;
unsigned col_base = j / 3 * 3;
for (unsigned row = row_base; row < row_base + 3; ++row)
for (unsigned col = col_base; col < col_base + 3; ++col)
{
if ((row == i && col == j) || matrix[row][col])
continue;
house_hidden &= advanced ? ~memory[row][col] : ~Blank.possible(row, col);
}
return house_hidden;
}
bitfield row_check(unsigned i, unsigned j, bool advanced = false)
{
bitfield row_hidden = allSet;
for (unsigned col = 0; col < 9; ++col)
if (!matrix[i][col] && col != j)
row_hidden &= advanced ? ~memory[i][col] : ~Blank.possible(i, col);
return row_hidden;
}
bitfield col_check(unsigned i, unsigned j, bool advanced = false)
{
bitfield col_hidden = allSet;
for (unsigned row = 0; row < 9; ++row)
if (!matrix[row][j] && row != i)
col_hidden &= advanced ? ~memory[row][j] : ~Blank.possible(row, j);
return col_hidden;
}
bitfield decide(bitfield & possible, bitfield & house,
bitfield & row, bitfield & col)
{
if (bitCount(possible) == 1)
return possible;
bitfield check1 = possible & house;
if (bitCount(check1) == 1)
return check1;
bitfield check2 = possible & row;
if (bitCount(check2) == 1)
return check2;
bitfield check3 = possible & col;
if (bitCount(check3) == 1)
return check3;
bitfield check = check1 & check2;
if (bitCount(check) == 1)
return check;
check = check1 & check3;
if (bitCount(check) == 1)
return check;
check = check2 & check3;
if (bitCount(check) == 1)
return check;
check &= check1;
if (bitCount(check) == 1)
return check;
return 0;
}
void hidden_fill()
{
bool again;
do
{
again = false;
for (unsigned i = 0; i < 9; ++i)
{
for (unsigned j = 0; j < 9; ++j)
{
if (matrix[i][j]) continue;
bitfield possible = Blank.possible(i, j);
bitfield house = house_check(i, j);
bitfield row = row_check(i, j);
bitfield col = col_check(i, j);
bitfield to_check = decide(possible, house, row, col);
if (to_check)
{
set(i, j, numFor(to_check));
again = true;
}
}
}
}
while (again);
}
bitfield candidate_check(unsigned i, unsigned j)
{
bitfield row_locked(0), col_locked(0), row_i(0), col_j(0);
unsigned row_base = i / 3 * 3;
unsigned col_base = j / 3 * 3;
unsigned total_count = 0;
for (unsigned row = row_base; row < row_base + 3; ++row)
{
if (row == i)
{
for (unsigned col = col_base; col < col_base + 3; ++col)
{
if (matrix[row][col])
continue;
row_i |= memory[row][col];
}
}
else
{
for (unsigned col = col_base; col < col_base + 3; ++col)
{
if (matrix[row][col])
continue;
row_locked |= memory[row][col];
++total_count;
}
}
}
if (total_count && total_count == bitCount(row_locked))
memory[i][j] &= ~row_locked;
bitfield pointing = row_i & ~row_locked;
if (pointing)
for (unsigned col = 0; col < 9; ++col)
{
if (matrix[i][col] || (col >= col_base && col < col_base + 3))
continue;
memory[i][col] &= ~pointing;
}
total_count = 0;
for (unsigned col = col_base; col < col_base + 3; ++col)
{
if (col == j)
{
for (unsigned row = row_base; row < row_base + 3; ++row)
{
if (matrix[row][col])
continue;
col_j |= memory[row][col];
}
}
else
{
for (unsigned row = row_base; row < row_base + 3; ++row)
{
if (matrix[row][col])
continue;
col_locked |= memory[row][col];
++total_count;
}
}
}
if (total_count && total_count == bitCount(col_locked))
memory[i][j] &= ~col_locked;
pointing = col_j & ~col_locked;
if (pointing)
for (unsigned row = 0; row < 9; ++row)
{
if (matrix[row][j] || (row >= row_base && row < row_base + 3))
continue;
memory[row][j] &= ~pointing;
}
for (unsigned col = 0; col < 9; ++col)
{
if (matrix[i][col] || (col >= col_base && col < col_base + 3))
continue;
row_i &= ~memory[i][col];
}
if (row_i)
{
for (unsigned r = row_base; r < row_base + 3; ++r)
for (unsigned c = col_base; c < col_base + 3; ++c)
{
if (r == i || matrix[r][c])
continue;
memory[r][c] &= ~row_i;
}
}
for (unsigned row = 0; row < 9; ++row)
{
if (matrix[row][j] || (row >= row_base && row < row_base + 3))
continue;
col_j &= ~memory[row][j];
}
if (col_j)
{
for (unsigned r = row_base; r < row_base + 3; ++r)
for (unsigned c = col_base; c < col_base + 3; ++c)
{
if (c == j || matrix[r][c])
continue;
memory[r][c] &= ~col_j;
}
}
return memory[i][j];
}
void advanced_fill()
{
bool again;
unsigned sum;
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j)
if (!matrix[i][j])
memory[i][j] &= Blank.possible(i, j);
do
{
again = false;
sum = 0;
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j)
sum += memory[i][j];
for (unsigned i = 0; i < 9; ++i)
{
for (unsigned j = 0; j < 9; ++j)
{
if (matrix[i][j]) continue;
bitfield possible = candidate_check(i, j);
//print_possible();
bitfield house = house_check(i, j, true);
bitfield row = row_check(i, j, true);
bitfield col = col_check(i, j, true);
bitfield to_check = decide(possible, house, row, col);
if (to_check)
set(i, j, numFor(to_check), true);
}
}
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j)
sum -= memory[i][j];
if (sum) again = true;
}
while (again);
}
unsigned remaining()
{
return remains;
}
bool findMin(unsigned& row, unsigned& col)
{
bool found = false;
unsigned count = 10;
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j)
{
if (!matrix[i][j] && (bitCount(Blank.possible(i, j)
& memory[i][j])) < count)
{
count = bitCount(Blank.possible(i, j) & memory[i][j]);
row = i;
col = j;
found = true;
}
}
return found;
}
bool backtrack(unsigned depth)
{
unsigned row, col;
if (!findMin(row, col))
if (!depth)
return true;
else
return false;
// Iterate through the possible values this cell could have
unsigned num = 1;
bitfield mask = bitFor(num);
while (mask != maskMax)
{
if (mask_check(row, col, mask))
{
set(row, col, num);
if (backtrack(depth-1))
return true;
unset(row, col);
}
// Advance to the next number
mask *= 2;
num++;
}
return false;
}
unsigned value(unsigned i, unsigned j)
{
return matrix[i][j];
}
bool assert(unsigned i, unsigned j, unsigned val)
{
return matrix[i][j] == val;
}
void print_possible()
{
for (unsigned i = 0; i < 9; ++i)
{
for (unsigned j = 0; j < 9; ++j)
{
output << memory[i][j] << " ";
}
output << std::endl;
}
output << std::endl;
}
void print_board(std::ostream & out)
{
for (unsigned i = 0; i < 9; ++i)
{
for (unsigned j = 0; j < 9; ++j)
{
out << matrix[i][j] << " ";
}
out << std::endl;
}
out << std::endl;
}
private:
unsigned matrix[9][9];
bitfield memory[9][9];
unsigned remains;
BlankList Blank;
static unsigned numFor(bitfield bit)
{
unsigned num = 0;
while (bit)
{
bit >>= 1;
++num;
}
return num;
}
void _update(unsigned row, unsigned col)
{
unsigned row_base = row / 3 * 3;
unsigned col_base = col / 3 * 3;
unsigned r, c;
for (unsigned i = 0; i < 9; ++i)
{
if (!matrix[row][i])
memory[row][i] &= Blank.possible(row, i);
if (!matrix[i][col])
memory[i][col] &= Blank.possible(i, col);
r = row_base + i / 3;
c = col_base + i % 3;
if (r != row && c != col && !matrix[r][c])
memory[r][c] &= Blank.possible(r, c);
}
}
bool _fill(bool is_big, unsigned block, unsigned num)
{
if (is_big)
{
if (num == 10)
return true;
if (block == 9)
return _fill(is_big, 0, num + 1);
}
if (block == 9)
return true;
static unsigned look_up[] =
{
0, 1, 2,
9, 10, 11,
18, 19, 20
};
static unsigned base[] =
{
0, 3, 6,
27, 30, 33,
54, 57, 60
};
unsigned place;
bitfield available = allSet;
while (available)
{
while (true)
{
place = std::rand() % 9;
if (available & bitFor(place + 1))
break;
}
available &= ~bitFor(place + 1);
unsigned loc = base[block] + look_up[place];
unsigned row = loc / 9, col = loc % 9;
if (!matrix[row][col] &&
(bitFor(num) & Blank.possible(row, col)))
{
set(row, col, num);
if (_fill(is_big, block + 1, num))
return true;
unset(row, col);
}
}
return false;
}
void _random_fill()
{
for (unsigned i = 1; i <= 5; ++i)
_fill(false, 0, i);
if (!_fill(true, 0, 6))
std::cout << "Error" << std::endl;
}
};
class Holes
{
public:
Holes(Board & board)
: puzzle(board)
{}
void digHoles(difficulty level)
{
static unsigned look_up[] =
{
0, 1, 2,
9, 10, 11,
18, 19, 20
};
static unsigned base[] =
{
0, 3, 6,
27, 30, 33,
54, 57, 60
};
for (unsigned i = 0; i < 9; ++i)
{
unsigned array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
unsigned diff = _random_by_level(level);
std::random_shuffle(array, array + 9);
for (unsigned j = 0; j < diff; ++j)
{
unsigned loc = base[i] + look_up[array[j]];
unsigned row = loc / 9, col = loc % 9;
_valid_dig(row, col, level);
}
}
}
Board& to_play()
{
return puzzle;
}
private:
Board puzzle;
unsigned _random_by_level(difficulty level)
{
unsigned random = 5;
switch (level)
{
case EASY:
random = std::rand() % 7 + 3;
break;
case MEDIUM:
random = std::rand() % 5 + 3;
break;
case DIFFICULT:
random = std::rand() % 5 + 4;
break;
case EVIL:
random = std::rand() % 5 + 5;
break;
default:
break;
}
return random;
}
void _valid_dig(unsigned i, unsigned j, difficulty level)
{
unsigned val = puzzle.unset(i, j);
if (level == EASY)
{
Board bd = puzzle;
bd.hidden_fill();
if (bd.remaining())
{
puzzle.set(i, j, val);
return;
}
}
for (unsigned num = 1; num <= 9; ++num)
{
if (num != val &&
puzzle.mask_check(i, j, bitFor(num)))
{
Board bd = puzzle;
bd.set(i, j, num);
bd.hidden_fill();
bd.advanced_fill();
if (bd.backtrack(bd.remaining()))
{
puzzle.set(i, j, val);
return;
}
}
}
}
};
class Sudoku
{
public:
Sudoku(const char * name, bool play = false)
{
std::ifstream in(name);
unsigned num = 0;
for (unsigned i = 0; i < 9; ++i)
{
for (unsigned j = 0; j < 9; ++j)
{
in >> num;
_board.set(i, j, num);
}
}
_board.print_board(std::cout);
_answer = _board;
/* if (_solve())
{
if (!play)
{
std::cout << "The answer is:" << std::endl;
_answer.print_board(std::cout);
}
}
else
std::cout << "The sudoku is not solvable!" << std::endl;*/
solve();
}
Sudoku(difficulty level, std::ostream & out)
{
generate(level, out);
}
void generate(difficulty level, std::ostream & out)
{
_answer = Board(static_cast<unsigned>(std::time(0)));
while (true)
{
Holes game(_answer);
game.digHoles(level);
Board bd = game.to_play();
bd.hidden_fill();
if (level > EASY && !bd.remaining())
continue;
bd.advanced_fill();
if (level > MEDIUM && !bd.remaining())
continue;
if (level > DIFFICULT && bd.remaining() < 30)
continue;
_board = game.to_play();
break;
}
_board.print_board(out);
}
void play(unsigned& row, unsigned& col, unsigned& val)
{
if (_board.mask_check(row, col, bitFor(val)))
if (_answer.assert(row, col, val))
{
_board.set(row, col, val);
system("cls");
_board.print_board(std::cout);
}
else
std::cout << "You've chosen the wrong number.\n";
else
std::cout << "Your play violated the rules.\n";
}
bool is_complete()
{
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j)
if (!_answer.assert(i, j, _board.value(i, j)))
return false;
return true;
}
private:
Board _board;
Board _answer;
bool _solve()
{
_answer.hidden_fill();
if (_answer.backtrack(_answer.remaining()))
return true;
else
return false;
}
void solve()
{
//std::ofstream out("Sudoku.out");
_answer.hidden_fill();
_answer.advanced_fill();
_answer.backtrack(_answer.remaining());
_answer.print_board(std::cout);
}
};