|
楼主 |
发表于 2014-7-9 12:32:05
|
显示全部楼层
本帖最后由 andalousie 于 2014-7-11 16:12 编辑
新的测试代码,部分。
- 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);
- }
- };
复制代码 |
|