constexpr Cell next(const Sudoku& s) { for(size_t i=0; i<s.dimension(); ++i) for(size_t j=0; j<s.dimension(); ++j) if (s(i,j) == 0) return {i,j}; return {std::numeric_limits<Cell::first_type>::max(),std::numeric_limits<Cell::second_type>::max()}; }
constexpr bool finished(const Sudoku& s) { for(size_t i=0; i<s.dimension(); ++i) for(size_t j=0; j<s.dimension(); ++j) if (s(i,j) == 0) return false; return true; }
constexpr bool colValid(const Sudoku& s, size_t col, size_t pos = 0) { if (pos > s.dimension()) return true; else if (s(pos,col) == 0) return colValid(s,col,pos+1); else { for(size_t i=pos+1;i<s.dimension();++i) if (s(i,col) == s(pos,col)) return false; return colValid(s,col,pos+1); } }
constexpr bool rowValid(const Sudoku& s, size_t row, size_t pos = 0) { if (pos > s.dimension()) return true; else if (s(row,pos) == 0) return rowValid(s,row,pos+1); else { for(size_t i=pos+1;i<s.dimension();++i) if (s(row,i) == s(row,pos)) return false; return rowValid(s,row,pos+1); } }
constexpr bool quadrantValid(const Sudoku& s, size_t x, size_t y, size_t pos = 0) { if (pos > s.dimension()) return true; else if (qVal(s, x,y,pos) == 0) return quadrantValid(s, x, y, pos+1); else { for(size_t i=pos+1;i<s.dimension();++i) if (qVal(s, x,y,i) == qVal(s, x,y,pos)) return false; return quadrantValid(s,x,y,pos+1); } }
constexpr bool valid(const Sudoku& s) { for(size_t x=0;x<s.dimension();++x) { if (!rowValid(s,x)) return false; if (!colValid(s,x)) return false; } size_t qsize = sqrt(s.dimension()); for(size_t i=0; i<qsize; ++i) for(size_t j=0; j<qsize; ++j) if (!quadrantValid(s,i,j)) return false; return true; }
constexpr Sudoku solve(const Sudoku& s) { if (!valid(s)) return s; else { const Cell n{next(s)}; if (n.first == std::numeric_limits<Cell::first_type>::max()) return s; for(unsigned i=1;i<=s.dimension();++i) { const auto ns = s.replace(n.first,n.second,i); const Sudoku res = solve(ns); if (finished(res) && valid(res)) return res; } return s; } }
// return the value at offset in quadrant(x,y) constexpr unsigned qVal(const Sudoku& s, size_t x,size_t y, size_t offset = 0) { size_t qsize = sqrt(s.dimension()); return s(qsize*x + offset/qsize, qsize*y + offset % qsize); }