1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
#include <vector>
#include <algorithm>
#include <set>
constexpr std::size_t SZ_BOARD = 9 ; // board is SZ_BOARD x SZ_BOARD
constexpr std::size_t SZ_GRID = 3 ; // a sub-grid is SZ_GRID x SZ_GRID
constexpr int EMPTY = 0 ; // 0 is used to indicate an unfilled cell
// filled cells contain the number, unfilled cells contain EMPTY
using board_t = std::vector< std::vector<int> > ;
// return an empty vector if row_num is invalid
std::vector<int> row( const board_t& board, std::size_t row_num )
{ return row_num < SZ_BOARD ? board[row_num] : std::vector<int>{} ; }
// return the nine cells forming column col_num
// return an empty vector if col_num is invalid
std::vector<int> col( const board_t& board, std::size_t col_num )
{
std::vector<int> column ;
if( col_num < SZ_BOARD ) for( const auto& row : board ) column.push_back( row[col_num] ) ;
return column ;
}
// return the nine cells forming the sub-grid
// sub-grids are numbered 0 .. 8 starting with the top-left-grid
// return an empty vector if grid_num is invalid
std::vector<int> sub_grid( const board_t& board, std::size_t grid_num )
{
std::vector<int> grid ;
if( grid_num < SZ_BOARD )
{
const std::size_t start_row = SZ_GRID * (grid_num/SZ_GRID) ;
const std::size_t start_col = SZ_GRID * (grid_num%SZ_GRID) ;
for( auto row = start_row ; row < (start_row+SZ_GRID) ; ++row )
for( auto col = start_col ; col < (start_col+SZ_GRID) ; ++col )
grid.push_back( board[row][col] ) ;
}
return grid ;
}
// verify that there are no invalid entries in the segment
// partial == true: no invalid entries so far (segment may contain empty cells)
// partial == false (default): all cells must be filled (no empty cells)
bool verify_segment( std::vector<int> segment, bool partial = false )
{
if( segment.size() != SZ_BOARD ) return false ; // invalid segment size
// if partial == true, move all EMPTY cells to the end of the back of the sequence
// end: the non-empty values are up to (not including) end
const auto end = partial ? std::remove( std::begin(segment), std::end(segment), EMPTY ) :
std::end(segment) ;
const auto begin = std::begin(segment) ;
// return true if: all non-empty numbers are within range [1,9]
// and no number is repeated (size of set == number of non-empty cells)
return std::all_of( begin, end, [] ( int v ) { return v > 0 && v < 10 ; } ) &&
std::set<int>( begin, end ).size() == std::distance(begin,end) ;
}
// verify that there are no invalid entries in the board
// partial == true: no invalid entries so far (segments may contain empty cells)
// partial == false (default): all cells must be filled (no empty cells)
bool verify_board( const board_t& board, bool partial = false )
{
for( std::size_t i = 0 ; i < SZ_BOARD ; ++i )
{
if( !verify_segment( row( board, i ), partial ) ) return false ;
if( !verify_segment( col( board, i ), partial ) ) return false ;
if( !verify_segment( sub_grid( board, i ), partial ) ) return false ;
}
return true ;
}
|