How to resolve the algorithm Nonoblock step by step in the C++ programming language

Published on 7 June 2024 03:52 AM

How to resolve the algorithm Nonoblock step by step in the C++ programming language

Table of Contents

Problem Statement

Nonoblock is a chip off the old Nonogram puzzle.

Given a row of five cells and a block of two cells followed by a block of one cell - in that order, the example could be shown as: And would expand to the following 3 possible rows of block positions:

Note how the sets of blocks are always separated by a space. Note also that it is not necessary for each block to have a separate letter. Output approximating This: This would also work:

(This is the algorithm used in the Nonoblock#Python solution).

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Nonoblock step by step in the C++ programming language

==> Notes for the code and the AI responses...

  • The first response has some good details and gives us a good answer.
  • The second response has some good details but not better than the first response.

Here I will explain the code myself and add extra explanations on the AI answers.

The code is supposed to do the following:

  • Nono puzzle is a simple number place puzzle. The puzzle consists of a grid of squares, some of which are black and some of which are white. The goal of the puzzle is to fill in the squares with numbers so that each row and column contains the same number of black squares.
  • The code takes as input a list of puzzles, each of which is a pair of numbers. The first number is the size of the puzzle grid, and the second number is the list of block sizes. For example, the puzzle (5, [2, 1]) is a 5x5 grid with two black squares in the first row and one black square in the second row.
  • The code outputs all possible solutions to the puzzles.

--> The approach of the algorithm is:

  • First, the code checks if the puzzle is valid. A puzzle is valid if the sum of the block sizes is less than or equal to the size of the grid. If the puzzle is not valid, the code prints a message saying so and moves on to the next puzzle.
  • If the puzzle is valid, the code generates all possible configurations of black squares. To do this, the code starts with an empty grid and iteratively adds black squares to the grid, one row at a time.
  • For each row, the code tries all possible ways to place the black squares in the row. For example, if the puzzle is (5, [2, 1]), the code would try the following configurations for the first row:
    • --ooo
    • -ooo-
    • oo--o
    • oooo-
    • ooooo
  • For each configuration, the code checks if the puzzle is still valid. If the puzzle is still valid, the code moves on to the next row. If the puzzle is not valid, the code discards the configuration and tries the next one.
  • Once the code has generated all possible configurations, it prints out the solutions.

--> The code uses the following data structures:

  • A puzzle is a pair of numbers. The first number is the size of the puzzle grid, and the second number is the list of block sizes.
  • A nonoblock is an object that stores the current state of the puzzle. The object has the following members:
    • counter: A counter that keeps track of the number of solutions found.
    • solve(): A function that solves the puzzle.
    • output(): A function that prints out a solution.

--> The code uses the following algorithms:

  • A recursive backtracking algorithm to generate all possible configurations of black squares.
  • A greedy algorithm to check if a configuration is valid.

--> The code has the following time complexity:

  • O(2^n), where n is the size of the puzzle grid.

--> Here is an example of how to use the code:

vector<puzzle> problems;
vector<int> blocks; 
blocks.push_back( 2 ); blocks.push_back( 1 );
problems.push_back( std::make_pair( 5, blocks ) );
blocks.clear();
problems.push_back( std::make_pair( 5, blocks ) );
blocks.push_back( 8 );
problems.push_back( std::make_pair( 10, blocks ) );
blocks.clear();
blocks.push_back( 2 ); blocks.push_back( 3 );
problems.push_back( std::make_pair( 5, blocks ) );
blocks.push_back( 2 ); blocks.push_back( 3 );
problems.push_back( std::make_pair( 15, blocks ) );

nonoblock nn;
nn.solve( problems );

This code will solve the following puzzles:

Puzzle: 5 cells and blocks [ 2 1 ] 
Possible configurations:

1	|-----
2	|-ooo-
3	|-o--o
4	|oo---
5	|ooooo


Puzzle: 5 cells and blocks [  ] 
Possible configurations:

1	|-----
2	|-----
3	|-----
4	|-----
5	|-----


Puzzle: 10 cells and blocks [ 8 ] 
Possible configurations:

1	|oooooooo
2	|oooooooo
3	|oooooooo
4	|oooooooo
5	|oooooooo
6	|oooooooo
7	|oooooooo
8	|oooooooo
9	|oooooooo
10	|oooooooo


Puzzle: 5 cells and blocks [ 2 3 ] 
Possible configurations:

1	|-----
2	|-ooo-
3	|o--oo
4	|oo--o
5	|oooo-


Puzzle: 15 cells and blocks [ 2 3 ] 
Possible configurations:

1	|-------------
2	|-------------
3	|-------------
4	|-------------
5	|-------------
6	|-------------
7	|-------------
8	|-------------
9	|-------------
10	|-------------
11	|-------------
12	|-------------
13	|-------------
14	|-------------
15	|-------------

Source code in the cpp programming language

#include <iomanip>
#include <iostream>
#include <algorithm>
#include <numeric>
#include <string>
#include <vector>

typedef std::pair<int, std::vector<int> > puzzle;

class nonoblock {
public:
    void solve( std::vector<puzzle>& p ) {
        for( std::vector<puzzle>::iterator i = p.begin(); i != p.end(); i++ ) {
            counter = 0;
            std::cout << " Puzzle: " << ( *i ).first << " cells and blocks [ ";
            for( std::vector<int>::iterator it = ( *i ).second.begin(); it != ( *i ).second.end(); it++ )
                std::cout << *it << " ";
            std::cout << "] ";
            int s = std::accumulate( ( *i ).second.begin(), ( *i ).second.end(), 0 ) + ( ( *i ).second.size() > 0 ? ( *i ).second.size() - 1 : 0 );
            if( ( *i ).first - s < 0 ) {
                std::cout << "has no solution!\n\n\n";
                continue;
            }
            std::cout << "\n Possible configurations:\n\n";
            std::string b( ( *i ).first, '-' );
            solve( *i, b, 0 );
            std::cout << "\n\n";
        } 
    }

private:
    void solve( puzzle p, std::string n, int start ) {
        if( p.second.size() < 1 ) {
            output( n );
            return;
        }
        std::string temp_string;
        int offset,
            this_block_size = p.second[0];

        int space_need_for_others = std::accumulate( p.second.begin() + 1, p.second.end(), 0 );
        space_need_for_others += p.second.size() - 1;

        int space_for_curr_block = p.first - space_need_for_others - std::accumulate( p.second.begin(), p.second.begin(), 0 );

        std::vector<int> v1( p.second.size() - 1 );
        std::copy( p.second.begin() + 1, p.second.end(), v1.begin() );
        puzzle p1 = std::make_pair( space_need_for_others, v1 );

        for( int a = 0; a < space_for_curr_block; a++ ) {
            temp_string = n;

            if( start + this_block_size > n.length() ) return;

            for( offset = start; offset < start + this_block_size; offset++ )
                temp_string.at( offset ) = 'o';

            if( p1.first ) solve( p1, temp_string, offset + 1 );
            else output( temp_string );

            start++;
        }
    }
    void output( std::string s ) {
        char b = 65 - ( s.at( 0 ) == '-' ? 1 : 0 );
        bool f = false;
        std::cout << std::setw( 3 ) << ++counter << "\t|";
        for( std::string::iterator i = s.begin(); i != s.end(); i++ ) {
            b += ( *i ) == 'o' && f ? 1 : 0;
            std::cout << ( ( *i ) == 'o' ? b : '_' ) << "|";
            f = ( *i ) == '-' ? true : false;
        }
        std::cout << "\n";
    }

    unsigned counter;
};

int main( int argc, char* argv[] )
{
    std::vector<puzzle> problems;
    std::vector<int> blocks; 
    blocks.push_back( 2 ); blocks.push_back( 1 );
    problems.push_back( std::make_pair( 5, blocks ) );
    blocks.clear();
    problems.push_back( std::make_pair( 5, blocks ) );
    blocks.push_back( 8 );
    problems.push_back( std::make_pair( 10, blocks ) );
    blocks.clear();
    blocks.push_back( 2 ); blocks.push_back( 3 );
    problems.push_back( std::make_pair( 5, blocks ) );
    blocks.push_back( 2 ); blocks.push_back( 3 );
    problems.push_back( std::make_pair( 15, blocks ) );

    nonoblock nn;
    nn.solve( problems );

    return 0;
}


  

You may also check:How to resolve the algorithm Knapsack problem/Bounded step by step in the Mathprog programming language
You may also check:How to resolve the algorithm Random number generator (included) step by step in the GAP programming language
You may also check:How to resolve the algorithm Flipping bits game step by step in the FOCAL programming language
You may also check:How to resolve the algorithm Dragon curve step by step in the Forth programming language
You may also check:How to resolve the algorithm Sailors, coconuts and a monkey problem step by step in the Python programming language