#include <set>
#include <string>
#include <fstream>
#include <iostream>
#include <cassert>
// ======================================================================================
enum SolutionResult {
// The position has been solved OK.
SR_SOLVED,
// The current position in invalid.
// For that reason, it is useless to even attempt to solve it.
SR_INVALID,
// The current position is valid in its current state, but there
// exists no complete solution that would uphold the sudoku rules.
SR_UNSOLVABLE
};
// ======================================================================================
class Sudoku {
protected:
// 0 = Empty cell
short values[9][9];
// Returns whether all the rows are currently valid,
// i.e. whether no rows contain any duplicate values.
bool checkValidRows() {
for (short row = 0; row < 9; row++) {
std::set<short> valuesInRow;
for (short col = 0; col < 9; col++) {
short val = this->values[row][col];
if (!val) continue;
if (valuesInRow.find(val) != valuesInRow.end()) {
return false;
}
valuesInRow.insert(val);
}
}
return true;
}
// Returns whether all the columns are currently valid,
// i.e. whether no columns contain any duplicate values.
bool checkValidCols() {
for (short col = 0; col < 9; col++) {
std::set<short> valuesInCol;
for (short row = 0; row < 9; row++) {
short val = this->values[row][col];
if (!val) continue;
if (valuesInCol.find(val) != valuesInCol.end()) {
return false;
}
valuesInCol.insert(val);
}
}
return true;
}
// Returns whether all the partial squares are currently valid,
// i.e. whether no 3x3 square contains a duplicate value.
bool checkValidSquares() {
for (short squareX = 0; squareX < 3; squareX++) {
for (short squareY = 0; squareY < 3; squareY++) {
std::set<short> valuesInSquare;
for (short m = 0; m < 3; m++) {
for (short n = 0; n < 3; n++) {
short val = this->values[squareX*3+m][squareY*3+n];
if (val == 0) continue;
if (valuesInSquare.find(val) != valuesInSquare.end()) {
return false;
}
valuesInSquare.insert(val);
}
}
}
}
return true;
}
// Returns whether the current position is valid, i.e., whether its rows, columns,
// and squares are all valid and do not contain a duplicate value.
bool checkValid() {
return this->checkValidRows() && this->checkValidCols() && this->checkValidSquares();
}
public:
Sudoku() {
// Start with a blank position.
for (short row = 0; row < 9; row++) {
for (short col = 0; col < 9; col++) {
this->values[row][col] = 0;
}
}
}
Sudoku (const short values[9][9]) {
for (short row = 0; row < 9; row++) {
for (short col = 0; col < 9; col++) {
// Values that are not between [0 .. 9]
// are discarded and replaced with zeroes.
short val = values[row][col];
if (val >= 0 && val <= 9) {
this->values[row][col] = val;
}
else {
this->values[row][col] = 0;
}
}
}
}
// This is the solver method.
// The way to solution is a standard backtrack exercise.
//
// For the next empty space, we put the lowest possible value in, and recursively call the solver
// to see whether it can complete all the other spaces in a valid manner – in which case, we are done.
// In case that no possible value in the chosen space leads to a valid and complete solution, we clear
// the space entirely and declare the position as unsolvable. In recursion terms, this means that
// we need to attempt to put another value to the previous space, and so on.
SolutionResult solve() {
// Check that the situation is valid.
if (!this->checkValid()) return SR_INVALID;
// For the next empty space:
for (short row = 0; row < 9; row++) {
for (short col = 0; col < 9; col++) {
if (this->values[row][col] > 0) continue;
// Put an arbitrary value into the space:
for (short val = 1; val <= 9; val++) {
this->values[row][col] = val;
// Recursively call the solver and see whether it can complete all
// the other spaces in the same manner. In case that it can, we're done.
if (this->solve() == SR_SOLVED) {
return SR_SOLVED;
}
}
// We tried all the possible values, and none has lead to a complete and
// valid solution. Clear the space, and return that the position is unsolvable.
this->values[row][col] = 0;
return SR_UNSOLVABLE;
}
}
// There are no more empty spaces.
// We're done.
return SR_SOLVED;
}
// Formatted output.
friend std::ostream& operator<< (std::ostream &os, const Sudoku& s) {
for (short row = 0; row < 9; row++) {
os << std::endl;
for (short col = 0; col < 9; col++) {
os << ' ';
if (s.values[row][col] > 0) {
os << s.values[row][col];
} else {
os << '.';
}
if (col == 2 || col == 5) {
os << " |";
}
}
if (row == 2 || row == 5) {
os << std::endl << " ------+-------+------";
}
}
os << std::endl;
return os;
}
//
static void runUnitTests();
};
// ======================================================================================
int main (int argc, char* argv[])
{
short pos[9][9] = {
{0, 0, 4, 0, 0, 0, 0, 0, 0},
{6, 0, 2, 1, 0, 0, 0, 0, 0},
{1, 0, 8, 3, 4, 2, 5, 6, 7},
{0, 0, 9, 7, 0, 0, 4, 2, 3},
{4, 0, 6, 8, 0, 0, 0, 0, 1},
{7, 1, 3, 9, 2, 0, 8, 0, 0},
{0, 0, 0, 5, 3, 0, 2, 8, 4},
{0, 0, 0, 4, 1, 0, 6, 0, 0},
{3, 0, 0, 0, 0, 6, 1, 0, 0}
};
// Let's test the entire unit.
Sudoku::runUnitTests();
// Let's solve the particular position above:
Sudoku s (pos);
std::cout << s << std::endl;
std::cout << "Solver starts, please wait..." << std::endl;
switch (s.solve()) {
case SR_SOLVED:
std::cout << "Solution: " << std:: endl;
std::cout << s << std::endl;
break;
case SR_INVALID:
std::cout << "The position is not valid." << std:: endl;
break;
case SR_UNSOLVABLE:
std::cout << "The position cannot be solved." << std:: endl;
break;
}
std::cout << "Press any key to exit...";
getchar();
return 0;
}
// ======================================================================================
void Sudoku::runUnitTests() {
short dataZeroes[9][9] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0}
};
short dataValidPos1[9][9] = {
{5, 3, 4, 6, 7, 8, 9, 1, 2},
{6, 7, 2, 1, 9, 5, 3, 4, 8},
{1, 9, 8, 3, 4, 2, 5, 6, 7},
{8, 5, 9, 7, 6, 1, 4, 2, 3},
{4, 2, 6, 8, 5, 3, 7, 9, 1},
{7, 1, 3, 9, 2, 4, 8, 5, 6},
{9, 6, 1, 5, 3, 7, 2, 8, 4},
{2, 8, 7, 4, 1, 9, 6, 3, 5},
{3, 4, 5, 2, 8, 6, 1, 7, 9}
};
short dataValidPos2[9][9] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{6, 0, 2, 1, 0, 0, 0, 0, 0},
{1, 0, 8, 3, 4, 2, 5, 6, 7},
{0, 0, 9, 7, 0, 0, 4, 2, 3},
{4, 0, 6, 8, 0, 0, 0, 0, 1},
{7, 1, 3, 9, 2, 0, 8, 0, 0},
{0, 0, 0, 5, 3, 0, 2, 8, 4},
{0, 0, 0, 4, 1, 0, 6, 0, 0},
{3, 0, 0, 0, 0, 6, 1, 0, 0}
};
short dataInvalidRows[9][9] = {
{5, 3, 4, 6, 7, 8, 9, 1, 5},
{6, 7, 2, 1, 9, 5, 3, 4, 8},
{1, 9, 8, 3, 4, 2, 0, 6, 7},
{8, 5, 9, 7, 6, 1, 4, 2, 3},
{4, 2, 6, 8, 5, 3, 7, 9, 1},
{7, 1, 3, 9, 2, 4, 8, 5, 6},
{9, 6, 1, 5, 3, 7, 2, 8, 4},
{2, 8, 7, 4, 1, 9, 6, 3, 0},
{3, 4, 5, 2, 8, 6, 1, 7, 9}
};
short dataInvalidCols[9][9] = {
{5, 3, 4, 6, 7, 8, 9, 1, 2},
{6, 7, 2, 1, 9, 0, 3, 4, 8},
{1, 9, 8, 3, 4, 2, 5, 6, 7},
{8, 5, 9, 7, 6, 1, 4, 2, 3},
{4, 2, 6, 8, 5, 3, 7, 9, 1},
{7, 1, 3, 9, 2, 4, 8, 5, 6},
{9, 6, 1, 5, 3, 7, 2, 8, 4},
{2, 8, 7, 4, 1, 9, 6, 3, 5},
{5, 4, 0, 2, 8, 6, 1, 7, 9}
};
short dataInvalidSquares[9][9] = {
{5, 3, 4, 6, 7, 8, 9, 1, 2},
{6, 5, 2, 1, 9, 0, 3, 4, 8},
{1, 9, 8, 3, 4, 2, 5, 6, 7},
{8, 0, 9, 7, 6, 1, 4, 2, 3},
{4, 2, 6, 8, 5, 3, 7, 9, 1},
{7, 1, 3, 9, 2, 4, 8, 5, 6},
{9, 6, 1, 5, 3, 7, 2, 8, 4},
{2, 8, 7, 4, 1, 9, 6, 3, 5},
{3, 4, 5, 2, 8, 6, 1, 7, 9}
};
Sudoku zeroes (dataZeroes);
Sudoku validPos1 (dataValidPos1);
Sudoku validPos2 (dataValidPos2);
Sudoku invalidRows (dataInvalidRows);
Sudoku invalidCols (dataInvalidCols);
Sudoku invalidSquares (dataInvalidSquares);
std::cout << "Unit tests start..." << std::endl;
assert(zeroes.checkValidRows());
assert(zeroes.checkValidCols());
assert(zeroes.checkValidSquares());
assert(zeroes.checkValid());
assert(zeroes.solve() == SR_SOLVED);
assert(validPos1.checkValidRows());
assert(validPos1.checkValidCols());
assert(validPos1.checkValidSquares());
assert(validPos1.checkValid());
assert(validPos1.solve() == SR_SOLVED);
assert(validPos2.checkValidRows());
assert(validPos2.checkValidCols());
assert(validPos2.checkValidSquares());
assert(validPos2.checkValid());
assert(validPos2.solve() == SR_SOLVED);
assert(validPos2.values[0][0] == 5);
assert(validPos2.values[0][1] == 3);
assert(validPos2.values[0][2] == 4);
assert(validPos2.values[0][3] == 6);
assert(validPos2.values[0][4] == 7);
assert(validPos2.values[0][5] == 8);
assert(validPos2.values[0][6] == 9);
assert(validPos2.values[0][7] == 1);
assert(validPos2.values[0][8] == 2);
assert(!invalidRows.checkValidRows());
assert( invalidRows.checkValidCols());
assert( invalidRows.checkValidSquares());
assert(!invalidRows.checkValid());
assert( invalidRows.solve() == SR_INVALID);
assert( invalidCols.checkValidRows());
assert(!invalidCols.checkValidCols());
assert( invalidCols.checkValidSquares());
assert(!invalidCols.checkValid());
assert( invalidCols.solve() == SR_INVALID);
assert( invalidSquares.checkValidRows());
assert( invalidSquares.checkValidCols());
assert(!invalidSquares.checkValidSquares());
assert(!invalidSquares.checkValid());
assert( invalidSquares.solve() == SR_INVALID);
std::cout << "All unit tests OK." << std::endl;
}
CiNpbmNsdWRlIDxzZXQ+CiNpbmNsdWRlIDxzdHJpbmc+CgojaW5jbHVkZSA8ZnN0cmVhbT4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y2Fzc2VydD4KCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgplbnVtIFNvbHV0aW9uUmVzdWx0IHsKCiAgICAvLyBUaGUgcG9zaXRpb24gaGFzIGJlZW4gc29sdmVkIE9LLgogICAgU1JfU09MVkVELAoKICAgIC8vIFRoZSBjdXJyZW50IHBvc2l0aW9uIGluIGludmFsaWQuCiAgICAvLyBGb3IgdGhhdCByZWFzb24sIGl0IGlzIHVzZWxlc3MgdG8gZXZlbiBhdHRlbXB0IHRvIHNvbHZlIGl0LgogICAgU1JfSU5WQUxJRCwKCiAgICAvLyBUaGUgY3VycmVudCBwb3NpdGlvbiBpcyB2YWxpZCBpbiBpdHMgY3VycmVudCBzdGF0ZSwgYnV0IHRoZXJlIAogICAgLy8gZXhpc3RzIG5vIGNvbXBsZXRlIHNvbHV0aW9uIHRoYXQgd291bGQgdXBob2xkIHRoZSBzdWRva3UgcnVsZXMuCiAgICBTUl9VTlNPTFZBQkxFCgp9OwoKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCmNsYXNzIFN1ZG9rdSB7Cgpwcm90ZWN0ZWQ6CgogICAgLy8gMCA9IEVtcHR5IGNlbGwKICAgIHNob3J0IHZhbHVlc1s5XVs5XTsKCiAgICAvLyBSZXR1cm5zIHdoZXRoZXIgYWxsIHRoZSByb3dzIGFyZSBjdXJyZW50bHkgdmFsaWQsIAogICAgLy8gaS5lLiB3aGV0aGVyIG5vIHJvd3MgY29udGFpbiBhbnkgZHVwbGljYXRlIHZhbHVlcy4KICAgIGJvb2wgY2hlY2tWYWxpZFJvd3MoKSB7CgogICAgICAgIGZvciAoc2hvcnQgcm93ID0gMDsgcm93IDwgOTsgcm93KyspIHsKCiAgICAgICAgICAgIHN0ZDo6c2V0PHNob3J0PiB2YWx1ZXNJblJvdzsKICAgICAgICAgICAgZm9yIChzaG9ydCBjb2wgPSAwOyBjb2wgPCA5OyBjb2wrKykgewogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBzaG9ydCB2YWwgPSB0aGlzLT52YWx1ZXNbcm93XVtjb2xdOwogICAgICAgICAgICAgICAgaWYgKCF2YWwpIGNvbnRpbnVlOwoKICAgICAgICAgICAgICAgIGlmICh2YWx1ZXNJblJvdy5maW5kKHZhbCkgIT0gdmFsdWVzSW5Sb3cuZW5kKCkpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgdmFsdWVzSW5Sb3cuaW5zZXJ0KHZhbCk7CgogICAgICAgICAgICB9CgogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIHRydWU7CgogICAgfQoKICAgIC8vIFJldHVybnMgd2hldGhlciBhbGwgdGhlIGNvbHVtbnMgYXJlIGN1cnJlbnRseSB2YWxpZCwgCiAgICAvLyBpLmUuIHdoZXRoZXIgbm8gY29sdW1ucyBjb250YWluIGFueSBkdXBsaWNhdGUgdmFsdWVzLgogICAgYm9vbCBjaGVja1ZhbGlkQ29scygpIHsKCiAgICAgICAgZm9yIChzaG9ydCBjb2wgPSAwOyBjb2wgPCA5OyBjb2wrKykgewoKICAgICAgICAgICAgc3RkOjpzZXQ8c2hvcnQ+IHZhbHVlc0luQ29sOwogICAgICAgICAgICBmb3IgKHNob3J0IHJvdyA9IDA7IHJvdyA8IDk7IHJvdysrKSB7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIHNob3J0IHZhbCA9IHRoaXMtPnZhbHVlc1tyb3ddW2NvbF07CiAgICAgICAgICAgICAgICBpZiAoIXZhbCkgY29udGludWU7CgogICAgICAgICAgICAgICAgaWYgKHZhbHVlc0luQ29sLmZpbmQodmFsKSAhPSB2YWx1ZXNJbkNvbC5lbmQoKSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICB2YWx1ZXNJbkNvbC5pbnNlcnQodmFsKTsKCiAgICAgICAgICAgIH0KCiAgICAgICAgfQoKICAgICAgICByZXR1cm4gdHJ1ZTsKCiAgICB9CgogICAgLy8gUmV0dXJucyB3aGV0aGVyIGFsbCB0aGUgcGFydGlhbCBzcXVhcmVzIGFyZSBjdXJyZW50bHkgdmFsaWQsIAogICAgLy8gaS5lLiB3aGV0aGVyIG5vIDN4MyBzcXVhcmUgY29udGFpbnMgYSBkdXBsaWNhdGUgdmFsdWUuCiAgICBib29sIGNoZWNrVmFsaWRTcXVhcmVzKCkgewoKICAgICAgICBmb3IgKHNob3J0IHNxdWFyZVggPSAwOyBzcXVhcmVYIDwgMzsgc3F1YXJlWCsrKSB7CiAgICAgICAgZm9yIChzaG9ydCBzcXVhcmVZID0gMDsgc3F1YXJlWSA8IDM7IHNxdWFyZVkrKykgewoKICAgICAgICAgICAgc3RkOjpzZXQ8c2hvcnQ+IHZhbHVlc0luU3F1YXJlOwogICAgICAgICAgICBmb3IgKHNob3J0IG0gPSAwOyBtIDwgMzsgbSsrKSB7CiAgICAgICAgICAgICAgICBmb3IgKHNob3J0IG4gPSAwOyBuIDwgMzsgbisrKSB7CgogICAgICAgICAgICAgICAgICAgIHNob3J0IHZhbCA9IHRoaXMtPnZhbHVlc1tzcXVhcmVYKjMrbV1bc3F1YXJlWSozK25dOwogICAgICAgICAgICAgICAgICAgIGlmICh2YWwgPT0gMCkgY29udGludWU7CiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlc0luU3F1YXJlLmZpbmQodmFsKSAhPSB2YWx1ZXNJblNxdWFyZS5lbmQoKSkgewogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIHZhbHVlc0luU3F1YXJlLmluc2VydCh2YWwpOwoKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gdHJ1ZTsKCiAgICB9CgogICAgLy8gUmV0dXJucyB3aGV0aGVyIHRoZSBjdXJyZW50IHBvc2l0aW9uIGlzIHZhbGlkLCBpLmUuLCB3aGV0aGVyIGl0cyByb3dzLCBjb2x1bW5zLCAKICAgIC8vIGFuZCBzcXVhcmVzIGFyZSBhbGwgdmFsaWQgYW5kIGRvIG5vdCBjb250YWluIGEgZHVwbGljYXRlIHZhbHVlLgogICAgYm9vbCBjaGVja1ZhbGlkKCkgewoKICAgICAgICByZXR1cm4gdGhpcy0+Y2hlY2tWYWxpZFJvd3MoKSAmJiB0aGlzLT5jaGVja1ZhbGlkQ29scygpICYmIHRoaXMtPmNoZWNrVmFsaWRTcXVhcmVzKCk7CgogICAgfQoKcHVibGljOgoKICAgIFN1ZG9rdSgpIHsKCiAgICAgICAgLy8gU3RhcnQgd2l0aCBhIGJsYW5rIHBvc2l0aW9uLgogICAgICAgIGZvciAoc2hvcnQgcm93ID0gMDsgcm93IDwgOTsgcm93KyspIHsKICAgICAgICBmb3IgKHNob3J0IGNvbCA9IDA7IGNvbCA8IDk7IGNvbCsrKSB7CgogICAgICAgICAgICB0aGlzLT52YWx1ZXNbcm93XVtjb2xdID0gMDsKCiAgICAgICAgfQogICAgICAgIH0KCiAgICB9CgogICAgU3Vkb2t1IChjb25zdCBzaG9ydCB2YWx1ZXNbOV1bOV0pIHsKCiAgICAgICAgZm9yIChzaG9ydCByb3cgPSAwOyByb3cgPCA5OyByb3crKykgewogICAgICAgIGZvciAoc2hvcnQgY29sID0gMDsgY29sIDwgOTsgY29sKyspIHsKCiAgICAgICAgICAgIC8vIFZhbHVlcyB0aGF0IGFyZSBub3QgYmV0d2VlbiBbMCAuLiA5XSAKICAgICAgICAgICAgLy8gYXJlIGRpc2NhcmRlZCBhbmQgcmVwbGFjZWQgd2l0aCB6ZXJvZXMuCiAgICAgICAgICAgIHNob3J0IHZhbCA9IHZhbHVlc1tyb3ddW2NvbF07CiAgICAgICAgICAgIGlmICh2YWwgPj0gMCAmJiB2YWwgPD0gOSkgewogICAgICAgICAgICAgICAgdGhpcy0+dmFsdWVzW3Jvd11bY29sXSA9IHZhbDsKICAgICAgICAgICAgfSAKICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICB0aGlzLT52YWx1ZXNbcm93XVtjb2xdID0gMDsKICAgICAgICAgICAgfQoKICAgICAgICB9CiAgICAgICAgfQoKICAgIH0KCiAgICAvLyBUaGlzIGlzIHRoZSBzb2x2ZXIgbWV0aG9kLgogICAgLy8gVGhlIHdheSB0byBzb2x1dGlvbiBpcyBhIHN0YW5kYXJkIGJhY2t0cmFjayBleGVyY2lzZS4KICAgIC8vIAogICAgLy8gRm9yIHRoZSBuZXh0IGVtcHR5IHNwYWNlLCB3ZSBwdXQgdGhlIGxvd2VzdCBwb3NzaWJsZSB2YWx1ZSBpbiwgYW5kIHJlY3Vyc2l2ZWx5IGNhbGwgdGhlIHNvbHZlcgogICAgLy8gdG8gc2VlIHdoZXRoZXIgaXQgY2FuIGNvbXBsZXRlIGFsbCB0aGUgb3RoZXIgc3BhY2VzIGluIGEgdmFsaWQgbWFubmVyIOKAkyBpbiB3aGljaCBjYXNlLCB3ZSBhcmUgZG9uZS4KICAgIC8vIEluIGNhc2UgdGhhdCBubyBwb3NzaWJsZSB2YWx1ZSBpbiB0aGUgY2hvc2VuIHNwYWNlIGxlYWRzIHRvIGEgdmFsaWQgYW5kIGNvbXBsZXRlIHNvbHV0aW9uLCB3ZSBjbGVhciAKICAgIC8vIHRoZSBzcGFjZSBlbnRpcmVseSBhbmQgZGVjbGFyZSB0aGUgcG9zaXRpb24gYXMgdW5zb2x2YWJsZS4gSW4gcmVjdXJzaW9uIHRlcm1zLCB0aGlzIG1lYW5zIHRoYXQgCiAgICAvLyB3ZSBuZWVkIHRvIGF0dGVtcHQgdG8gcHV0IGFub3RoZXIgdmFsdWUgdG8gdGhlIHByZXZpb3VzIHNwYWNlLCBhbmQgc28gb24uCgogICAgU29sdXRpb25SZXN1bHQgc29sdmUoKSB7CgogICAgICAgIC8vIENoZWNrIHRoYXQgdGhlIHNpdHVhdGlvbiBpcyB2YWxpZC4KICAgICAgICBpZiAoIXRoaXMtPmNoZWNrVmFsaWQoKSkgcmV0dXJuIFNSX0lOVkFMSUQ7CgogICAgICAgIC8vIEZvciB0aGUgbmV4dCBlbXB0eSBzcGFjZToKICAgICAgICBmb3IgKHNob3J0IHJvdyA9IDA7IHJvdyA8IDk7IHJvdysrKSB7CiAgICAgICAgZm9yIChzaG9ydCBjb2wgPSAwOyBjb2wgPCA5OyBjb2wrKykgewoKICAgICAgICAgICAgaWYgKHRoaXMtPnZhbHVlc1tyb3ddW2NvbF0gPiAwKSBjb250aW51ZTsKCiAgICAgICAgICAgIC8vIFB1dCBhbiBhcmJpdHJhcnkgdmFsdWUgaW50byB0aGUgc3BhY2U6CiAgICAgICAgICAgIGZvciAoc2hvcnQgdmFsID0gMTsgdmFsIDw9IDk7IHZhbCsrKSB7CgogICAgICAgICAgICAgICAgdGhpcy0+dmFsdWVzW3Jvd11bY29sXSA9IHZhbDsKCiAgICAgICAgICAgICAgICAvLyBSZWN1cnNpdmVseSBjYWxsIHRoZSBzb2x2ZXIgYW5kIHNlZSB3aGV0aGVyIGl0IGNhbiBjb21wbGV0ZSBhbGwgCiAgICAgICAgICAgICAgICAvLyB0aGUgb3RoZXIgc3BhY2VzIGluIHRoZSBzYW1lIG1hbm5lci4gSW4gY2FzZSB0aGF0IGl0IGNhbiwgd2UncmUgZG9uZS4KICAgICAgICAgICAgICAgIGlmICh0aGlzLT5zb2x2ZSgpID09IFNSX1NPTFZFRCkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBTUl9TT0xWRUQ7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBXZSB0cmllZCBhbGwgdGhlIHBvc3NpYmxlIHZhbHVlcywgYW5kIG5vbmUgaGFzIGxlYWQgdG8gYSBjb21wbGV0ZSBhbmQgCiAgICAgICAgICAgIC8vIHZhbGlkIHNvbHV0aW9uLiBDbGVhciB0aGUgc3BhY2UsIGFuZCByZXR1cm4gdGhhdCB0aGUgcG9zaXRpb24gaXMgdW5zb2x2YWJsZS4KICAgICAgICAgICAgdGhpcy0+dmFsdWVzW3Jvd11bY29sXSA9IDA7CiAgICAgICAgICAgIHJldHVybiBTUl9VTlNPTFZBQkxFOwoKICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvLyBUaGVyZSBhcmUgbm8gbW9yZSBlbXB0eSBzcGFjZXMuIAogICAgICAgIC8vIFdlJ3JlIGRvbmUuCiAgICAgICAgcmV0dXJuIFNSX1NPTFZFRDsKCiAgICB9CgogICAgLy8gRm9ybWF0dGVkIG91dHB1dC4KICAgIGZyaWVuZCBzdGQ6Om9zdHJlYW0mIG9wZXJhdG9yPDwgKHN0ZDo6b3N0cmVhbSAmb3MsIGNvbnN0IFN1ZG9rdSYgcykgewogICAgCiAgICAgICAgZm9yIChzaG9ydCByb3cgPSAwOyByb3cgPCA5OyByb3crKykgewoKICAgICAgICAgICAgb3MgPDwgc3RkOjplbmRsOwogICAgICAgICAgICBmb3IgKHNob3J0IGNvbCA9IDA7IGNvbCA8IDk7IGNvbCsrKSB7CgogICAgICAgICAgICAgICAgb3MgPDwgJyAnOwogICAgICAgICAgICAgICAgaWYgKHMudmFsdWVzW3Jvd11bY29sXSA+IDApIHsKICAgICAgICAgICAgICAgICAgICBvcyA8PCBzLnZhbHVlc1tyb3ddW2NvbF07CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIG9zIDw8ICcuJzsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBpZiAoY29sID09IDIgfHwgY29sID09IDUpIHsKICAgICAgICAgICAgICAgICAgICBvcyA8PCAiIHwiOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgfQoKICAgICAgICAgICAgaWYgKHJvdyA9PSAyIHx8IHJvdyA9PSA1KSB7CiAgICAgICAgICAgICAgICBvcyA8PCBzdGQ6OmVuZGwgPDwgIiAtLS0tLS0rLS0tLS0tLSstLS0tLS0iOwogICAgICAgICAgICB9CgogICAgICAgIH0KCiAgICAgICAgb3MgPDwgc3RkOjplbmRsOwogICAgICAgIHJldHVybiBvczsKCiAgICB9CgogICAgLy8KICAgIHN0YXRpYyB2b2lkIHJ1blVuaXRUZXN0cygpOwoKfTsKCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgppbnQgbWFpbiAoaW50IGFyZ2MsIGNoYXIqIGFyZ3ZbXSkKewogICAgc2hvcnQgcG9zWzldWzldID0gewogICAgICAgIHswLCAwLCA0LCAwLCAwLCAwLCAwLCAwLCAwfSwKICAgICAgICB7NiwgMCwgMiwgMSwgMCwgMCwgMCwgMCwgMH0sCiAgICAgICAgezEsIDAsIDgsIDMsIDQsIDIsIDUsIDYsIDd9LAogICAgICAgIHswLCAwLCA5LCA3LCAwLCAwLCA0LCAyLCAzfSwKICAgICAgICB7NCwgMCwgNiwgOCwgMCwgMCwgMCwgMCwgMX0sCiAgICAgICAgezcsIDEsIDMsIDksIDIsIDAsIDgsIDAsIDB9LAogICAgICAgIHswLCAwLCAwLCA1LCAzLCAwLCAyLCA4LCA0fSwKICAgICAgICB7MCwgMCwgMCwgNCwgMSwgMCwgNiwgMCwgMH0sCiAgICAgICAgezMsIDAsIDAsIDAsIDAsIDYsIDEsIDAsIDB9CiAgICB9OwoKICAgIC8vIExldCdzIHRlc3QgdGhlIGVudGlyZSB1bml0LgogICAgU3Vkb2t1OjpydW5Vbml0VGVzdHMoKTsKCiAgICAvLyBMZXQncyBzb2x2ZSB0aGUgcGFydGljdWxhciBwb3NpdGlvbiBhYm92ZToKCiAgICBTdWRva3UgcyAocG9zKTsKICAgIHN0ZDo6Y291dCA8PCBzIDw8IHN0ZDo6ZW5kbDsKICAgIHN0ZDo6Y291dCA8PCAiU29sdmVyIHN0YXJ0cywgcGxlYXNlIHdhaXQuLi4iIDw8IHN0ZDo6ZW5kbDsKICAgIAogICAgc3dpdGNoIChzLnNvbHZlKCkpIHsKCiAgICBjYXNlIFNSX1NPTFZFRDoKICAgICAgICBzdGQ6OmNvdXQgPDwgIlNvbHV0aW9uOiAiIDw8IHN0ZDo6IGVuZGw7CiAgICAgICAgc3RkOjpjb3V0IDw8IHMgPDwgc3RkOjplbmRsOwogICAgICAgIGJyZWFrOwoKICAgIGNhc2UgU1JfSU5WQUxJRDoKICAgICAgICBzdGQ6OmNvdXQgPDwgIlRoZSBwb3NpdGlvbiBpcyBub3QgdmFsaWQuIiA8PCBzdGQ6OiBlbmRsOwogICAgICAgIGJyZWFrOwoKICAgIGNhc2UgU1JfVU5TT0xWQUJMRToKICAgICAgICBzdGQ6OmNvdXQgPDwgIlRoZSBwb3NpdGlvbiBjYW5ub3QgYmUgc29sdmVkLiIgPDwgc3RkOjogZW5kbDsKICAgICAgICBicmVhazsKCiAgICB9CgogICAgc3RkOjpjb3V0IDw8ICJQcmVzcyBhbnkga2V5IHRvIGV4aXQuLi4iOwogICAgZ2V0Y2hhcigpOwogICAgcmV0dXJuIDA7Cn0KCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Cgp2b2lkIFN1ZG9rdTo6cnVuVW5pdFRlc3RzKCkgewoKICAgIHNob3J0IGRhdGFaZXJvZXNbOV1bOV0gPSB7CiAgICAgICAgezAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDB9LAogICAgICAgIHswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwfSwKICAgICAgICB7MCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMH0sCiAgICAgICAgezAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDB9LAogICAgICAgIHswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwfSwKICAgICAgICB7MCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMH0sCiAgICAgICAgezAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDB9LAogICAgICAgIHswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwfSwKICAgICAgICB7MCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMH0KICAgIH07CgogICAgc2hvcnQgZGF0YVZhbGlkUG9zMVs5XVs5XSA9IHsKICAgICAgICB7NSwgMywgNCwgNiwgNywgOCwgOSwgMSwgMn0sCiAgICAgICAgezYsIDcsIDIsIDEsIDksIDUsIDMsIDQsIDh9LAogICAgICAgIHsxLCA5LCA4LCAzLCA0LCAyLCA1LCA2LCA3fSwKICAgICAgICB7OCwgNSwgOSwgNywgNiwgMSwgNCwgMiwgM30sCiAgICAgICAgezQsIDIsIDYsIDgsIDUsIDMsIDcsIDksIDF9LAogICAgICAgIHs3LCAxLCAzLCA5LCAyLCA0LCA4LCA1LCA2fSwKICAgICAgICB7OSwgNiwgMSwgNSwgMywgNywgMiwgOCwgNH0sCiAgICAgICAgezIsIDgsIDcsIDQsIDEsIDksIDYsIDMsIDV9LAogICAgICAgIHszLCA0LCA1LCAyLCA4LCA2LCAxLCA3LCA5fQogICAgfTsKCiAgICBzaG9ydCBkYXRhVmFsaWRQb3MyWzldWzldID0gewogICAgICAgIHswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwfSwKICAgICAgICB7NiwgMCwgMiwgMSwgMCwgMCwgMCwgMCwgMH0sCiAgICAgICAgezEsIDAsIDgsIDMsIDQsIDIsIDUsIDYsIDd9LAogICAgICAgIHswLCAwLCA5LCA3LCAwLCAwLCA0LCAyLCAzfSwKICAgICAgICB7NCwgMCwgNiwgOCwgMCwgMCwgMCwgMCwgMX0sCiAgICAgICAgezcsIDEsIDMsIDksIDIsIDAsIDgsIDAsIDB9LAogICAgICAgIHswLCAwLCAwLCA1LCAzLCAwLCAyLCA4LCA0fSwKICAgICAgICB7MCwgMCwgMCwgNCwgMSwgMCwgNiwgMCwgMH0sCiAgICAgICAgezMsIDAsIDAsIDAsIDAsIDYsIDEsIDAsIDB9CiAgICB9OwoKICAgIHNob3J0IGRhdGFJbnZhbGlkUm93c1s5XVs5XSA9IHsKICAgICAgICB7NSwgMywgNCwgNiwgNywgOCwgOSwgMSwgNX0sCiAgICAgICAgezYsIDcsIDIsIDEsIDksIDUsIDMsIDQsIDh9LAogICAgICAgIHsxLCA5LCA4LCAzLCA0LCAyLCAwLCA2LCA3fSwKICAgICAgICB7OCwgNSwgOSwgNywgNiwgMSwgNCwgMiwgM30sCiAgICAgICAgezQsIDIsIDYsIDgsIDUsIDMsIDcsIDksIDF9LAogICAgICAgIHs3LCAxLCAzLCA5LCAyLCA0LCA4LCA1LCA2fSwKICAgICAgICB7OSwgNiwgMSwgNSwgMywgNywgMiwgOCwgNH0sCiAgICAgICAgezIsIDgsIDcsIDQsIDEsIDksIDYsIDMsIDB9LAogICAgICAgIHszLCA0LCA1LCAyLCA4LCA2LCAxLCA3LCA5fQogICAgfTsKCiAgICBzaG9ydCBkYXRhSW52YWxpZENvbHNbOV1bOV0gPSB7CiAgICAgICAgezUsIDMsIDQsIDYsIDcsIDgsIDksIDEsIDJ9LAogICAgICAgIHs2LCA3LCAyLCAxLCA5LCAwLCAzLCA0LCA4fSwKICAgICAgICB7MSwgOSwgOCwgMywgNCwgMiwgNSwgNiwgN30sCiAgICAgICAgezgsIDUsIDksIDcsIDYsIDEsIDQsIDIsIDN9LAogICAgICAgIHs0LCAyLCA2LCA4LCA1LCAzLCA3LCA5LCAxfSwKICAgICAgICB7NywgMSwgMywgOSwgMiwgNCwgOCwgNSwgNn0sCiAgICAgICAgezksIDYsIDEsIDUsIDMsIDcsIDIsIDgsIDR9LAogICAgICAgIHsyLCA4LCA3LCA0LCAxLCA5LCA2LCAzLCA1fSwKICAgICAgICB7NSwgNCwgMCwgMiwgOCwgNiwgMSwgNywgOX0KICAgIH07CgogICAgc2hvcnQgZGF0YUludmFsaWRTcXVhcmVzWzldWzldID0gewogICAgICAgIHs1LCAzLCA0LCA2LCA3LCA4LCA5LCAxLCAyfSwKICAgICAgICB7NiwgNSwgMiwgMSwgOSwgMCwgMywgNCwgOH0sCiAgICAgICAgezEsIDksIDgsIDMsIDQsIDIsIDUsIDYsIDd9LAogICAgICAgIHs4LCAwLCA5LCA3LCA2LCAxLCA0LCAyLCAzfSwKICAgICAgICB7NCwgMiwgNiwgOCwgNSwgMywgNywgOSwgMX0sCiAgICAgICAgezcsIDEsIDMsIDksIDIsIDQsIDgsIDUsIDZ9LAogICAgICAgIHs5LCA2LCAxLCA1LCAzLCA3LCAyLCA4LCA0fSwKICAgICAgICB7MiwgOCwgNywgNCwgMSwgOSwgNiwgMywgNX0sCiAgICAgICAgezMsIDQsIDUsIDIsIDgsIDYsIDEsIDcsIDl9CiAgICB9OwoKICAgIFN1ZG9rdSB6ZXJvZXMgKGRhdGFaZXJvZXMpOwogICAgU3Vkb2t1IHZhbGlkUG9zMSAoZGF0YVZhbGlkUG9zMSk7CiAgICBTdWRva3UgdmFsaWRQb3MyIChkYXRhVmFsaWRQb3MyKTsKICAgIFN1ZG9rdSBpbnZhbGlkUm93cyAoZGF0YUludmFsaWRSb3dzKTsKICAgIFN1ZG9rdSBpbnZhbGlkQ29scyAoZGF0YUludmFsaWRDb2xzKTsKICAgIFN1ZG9rdSBpbnZhbGlkU3F1YXJlcyAoZGF0YUludmFsaWRTcXVhcmVzKTsKCiAgICBzdGQ6OmNvdXQgPDwgIlVuaXQgdGVzdHMgc3RhcnQuLi4iIDw8IHN0ZDo6ZW5kbDsKCiAgICBhc3NlcnQoemVyb2VzLmNoZWNrVmFsaWRSb3dzKCkpOwogICAgYXNzZXJ0KHplcm9lcy5jaGVja1ZhbGlkQ29scygpKTsKICAgIGFzc2VydCh6ZXJvZXMuY2hlY2tWYWxpZFNxdWFyZXMoKSk7CiAgICBhc3NlcnQoemVyb2VzLmNoZWNrVmFsaWQoKSk7CiAgICBhc3NlcnQoemVyb2VzLnNvbHZlKCkgPT0gU1JfU09MVkVEKTsKCiAgICBhc3NlcnQodmFsaWRQb3MxLmNoZWNrVmFsaWRSb3dzKCkpOwogICAgYXNzZXJ0KHZhbGlkUG9zMS5jaGVja1ZhbGlkQ29scygpKTsKICAgIGFzc2VydCh2YWxpZFBvczEuY2hlY2tWYWxpZFNxdWFyZXMoKSk7CiAgICBhc3NlcnQodmFsaWRQb3MxLmNoZWNrVmFsaWQoKSk7CiAgICBhc3NlcnQodmFsaWRQb3MxLnNvbHZlKCkgPT0gU1JfU09MVkVEKTsKCiAgICBhc3NlcnQodmFsaWRQb3MyLmNoZWNrVmFsaWRSb3dzKCkpOwogICAgYXNzZXJ0KHZhbGlkUG9zMi5jaGVja1ZhbGlkQ29scygpKTsKICAgIGFzc2VydCh2YWxpZFBvczIuY2hlY2tWYWxpZFNxdWFyZXMoKSk7CiAgICBhc3NlcnQodmFsaWRQb3MyLmNoZWNrVmFsaWQoKSk7CiAgICBhc3NlcnQodmFsaWRQb3MyLnNvbHZlKCkgPT0gU1JfU09MVkVEKTsKICAgIGFzc2VydCh2YWxpZFBvczIudmFsdWVzWzBdWzBdID09IDUpOwogICAgYXNzZXJ0KHZhbGlkUG9zMi52YWx1ZXNbMF1bMV0gPT0gMyk7CiAgICBhc3NlcnQodmFsaWRQb3MyLnZhbHVlc1swXVsyXSA9PSA0KTsKICAgIGFzc2VydCh2YWxpZFBvczIudmFsdWVzWzBdWzNdID09IDYpOwogICAgYXNzZXJ0KHZhbGlkUG9zMi52YWx1ZXNbMF1bNF0gPT0gNyk7CiAgICBhc3NlcnQodmFsaWRQb3MyLnZhbHVlc1swXVs1XSA9PSA4KTsKICAgIGFzc2VydCh2YWxpZFBvczIudmFsdWVzWzBdWzZdID09IDkpOwogICAgYXNzZXJ0KHZhbGlkUG9zMi52YWx1ZXNbMF1bN10gPT0gMSk7CiAgICBhc3NlcnQodmFsaWRQb3MyLnZhbHVlc1swXVs4XSA9PSAyKTsKCiAgICBhc3NlcnQoIWludmFsaWRSb3dzLmNoZWNrVmFsaWRSb3dzKCkpOwogICAgYXNzZXJ0KCBpbnZhbGlkUm93cy5jaGVja1ZhbGlkQ29scygpKTsKICAgIGFzc2VydCggaW52YWxpZFJvd3MuY2hlY2tWYWxpZFNxdWFyZXMoKSk7CiAgICBhc3NlcnQoIWludmFsaWRSb3dzLmNoZWNrVmFsaWQoKSk7CiAgICBhc3NlcnQoIGludmFsaWRSb3dzLnNvbHZlKCkgPT0gU1JfSU5WQUxJRCk7CgogICAgYXNzZXJ0KCBpbnZhbGlkQ29scy5jaGVja1ZhbGlkUm93cygpKTsKICAgIGFzc2VydCghaW52YWxpZENvbHMuY2hlY2tWYWxpZENvbHMoKSk7CiAgICBhc3NlcnQoIGludmFsaWRDb2xzLmNoZWNrVmFsaWRTcXVhcmVzKCkpOwogICAgYXNzZXJ0KCFpbnZhbGlkQ29scy5jaGVja1ZhbGlkKCkpOwogICAgYXNzZXJ0KCBpbnZhbGlkQ29scy5zb2x2ZSgpID09IFNSX0lOVkFMSUQpOwoKICAgIGFzc2VydCggaW52YWxpZFNxdWFyZXMuY2hlY2tWYWxpZFJvd3MoKSk7CiAgICBhc3NlcnQoIGludmFsaWRTcXVhcmVzLmNoZWNrVmFsaWRDb2xzKCkpOwogICAgYXNzZXJ0KCFpbnZhbGlkU3F1YXJlcy5jaGVja1ZhbGlkU3F1YXJlcygpKTsKICAgIGFzc2VydCghaW52YWxpZFNxdWFyZXMuY2hlY2tWYWxpZCgpKTsKICAgIGFzc2VydCggaW52YWxpZFNxdWFyZXMuc29sdmUoKSA9PSBTUl9JTlZBTElEKTsKCiAgICBzdGQ6OmNvdXQgPDwgIkFsbCB1bml0IHRlc3RzIE9LLiIgPDwgc3RkOjplbmRsOwoKfQo=