Skip to content

Commit

Permalink
add constexpr example with builtin array and some doc
Browse files Browse the repository at this point in the history
  • Loading branch information
valpo committed Aug 20, 2015
1 parent f02eb90 commit 1623bc5
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 1 deletion.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ endif()

add_subdirectory(classic)
add_subdirectory(constexpr)
add_subdirectory(constexpr_arr)
add_subdirectory(qt)

12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ This is a quick shot implementation of a sudoku solver, used at starting point f
## constexpr
This is the compile time variant. Works for me with clang 3.6, needs C++14 (constexpr using "if" and loops).

## constexpr_arr
This is a modification of the constexpr example using builtin array instead of std::array. We had a
longer discussion in our local c++ user group about the fact, that c++14 removed the implicit const
from constexpr methods. This is the result of our search for a use case. And it simplifies the
implemention by removing the template-gymnastics used in the constexpr example to "modify" values
in a std::array. Courtesy goes to [Arne Metz](http://arne-mertz.de/category/cpp/new-features/)

## qt
This is just a graphical frontend to demonstrate the problem and visualize how backtracking works.

See also [my blog](http://www.valpo.de/?p=190)

# Compiler
Examples tested with clang (3.6 and current version from svn) and gcc 5.2.1. Clang needs around 5 minutes to
compile one constexpr example and uses around 100MB of memory. gcc needs around 388GB of memory for the
constexpr example, so do not forget to add some memory before compiling.
1 change: 0 additions & 1 deletion constexpr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
aux_source_directory(. SRC_LIST)
# -ftemplate-backtrace-limit=0
add_executable(constexpr_sudoku ${SRC_LIST})
#target_link_libraries(constexpr_sudoku c++ c++abi)


5 changes: 5 additions & 0 deletions constexpr_arr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
aux_source_directory(. SRC_LIST)
# -ftemplate-backtrace-limit=0
add_executable(constexpr_arr_sudoku ${SRC_LIST})


162 changes: 162 additions & 0 deletions constexpr_arr/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
//#include <tuple>
//#include <type_traits>
#include <utility>
#include <array>
#include <limits>

#include <iostream>

using std::cout;
using std::endl;

constexpr int sqrt_impl(int i, int val)
{
return i*i == val ? i : sqrt_impl(i-1,val);
}
constexpr int sqrt(int i)
{
return sqrt_impl(i,i);
}

// sudoku (== matrix) class
template<typename T, size_t N>
class SudokuT
{
private:
public:
T data[N*N];
constexpr unsigned operator()(size_t row, size_t col) const {
return row*N+col >= N*N ? 0
: data[row*N+col];
}
constexpr SudokuT<T,N> replace(size_t row, size_t col, T val) {
data[row*N+col] = val;
return *this;
}
constexpr size_t dimension() const { return N; }
};

using Sudoku = SudokuT<unsigned, 9ul>;
using Cell = std::pair<size_t, size_t>;

std::ostream& operator<<(std::ostream& os, const Sudoku& s) {
os << "+------------------+\n";
for(size_t i=0; i< s.dimension(); ++i) {
os << "|";
for(size_t j=0; j< s.dimension(); ++j) {
os << s(i,j) << " ";
}
os << "|\n";
}
os << "+------------------+\n";
return os;
}

std::ostream& operator<<(std::ostream& os, const Cell& c)
{
os << '(' << c.first << ',' << c.second << ')';
return os;
}

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 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);
}
}
// 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);
}

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 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 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 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 = Sudoku(s).replace(n.first,n.second,i);
const auto res = solve(ns);
if (finished(res) && valid(res)) return res;
}
return s;
}
}

int main()
{
constexpr Sudoku sudoku{
{
9, 5, 0, 0, 2, 0, 0, 0, 0,
0, 7, 8, 5, 0, 0, 0, 0, 0,
0, 6, 0, 4, 0, 0, 0, 0, 0,
0, 9, 0, 7, 3, 0, 0, 5, 0,
8, 0, 0, 0, 0, 0, 0, 0, 2,
0, 1, 0, 0, 8, 5, 0, 6, 0,
0, 0, 0, 0, 0, 6, 0, 8, 0,
0, 0, 0, 0, 0, 8, 7, 9, 0,
0, 0, 0, 0, 7, 0, 0, 3, 1,
}
};
cout << sudoku << endl;
constexpr Sudoku res = solve(sudoku);
cout << res << endl;
return valid(res) && finished(res) ? 0 : 1;
}

0 comments on commit 1623bc5

Please sign in to comment.