8
\$\begingroup\$

I have posted here my working and accepted solution to the graphical editor programming challenge (detailed here) for your review.

The program recognizes the following image editing commands:

  • I M N: Creates a new table M × N (up to 250 × 250) with white (O) pixels.
  • C: Clears the table to white.
  • L X Y C: Colors the pixel with coordinates (X, Y) in colour C. (A "colour" is a single character.)
  • V X Y1 Y2 C: Draws the vertical segment in the column X between the rows Y1 and Y2 inclusive in colour C.
  • H X1 X2 Y C: Draws the horizontal segment in the row Y between the columns X1 and X2 inclusive in colour C.
  • K X1 Y1 X2 Y2 C: Draws the filled rectangle in colour C. (X1, Y1) is the upper left corner, (X2, Y2) is the lower right corner of the rectangle.
  • F X Y C: Fills the region with the colour C, starting with (X, Y) and including any neighbouring pixels with a common side and the same colour.
  • S Name: Writes the picture in the file Name.
  • X: Terminates the session.
// graphical_editor.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream> //provides access to cout and cin 
#include <string> //Always import <string> if piping std input to a string in .net 
#include <vector>
#include <fstream>

using std::cin; 
using std::cout; 
using std::string;
using std::vector;
using std::ofstream;

//This is where we store the pixels of the image
static vector<vector <string>> image_array;

//our definition of an X,Y coordinate pair. 
typedef struct point {
    int x_coordinate, y_coordinate;
};

void initialise_image();
void clear_image(); 
void save_image(string file_name);
int get_image_width();
int get_image_height();
void color_pixel(int x, int y, string color);
void color_point(point p, string color);
void color_vertical_line(int x, int y1, int y2, string color);
void color_horizontal_line(int x1, int x2, int y, string color);
void color_box(int x1, int x2, int y1, int y2, string color);
void flood_fill(point p, string color);
void add_matching_neighbours(point p, string original_color, string new_color, vector<point> &points_queue);

int main()
{
    //myfile.open("example.txt");
    char command; //first letter of a given line 
    while (cin >> command) {
        //application terminates when command is X
        if (command==('X')) {
            return 0;
        } else if (command==('I')) {
            initialise_image();
        }
        else if (command=='S') {
            string file_name;
            cin >> file_name;
            save_image(file_name);
        }
        else if (command=='L') {
            string color;
            point p;
            cin >> p.x_coordinate >> p.y_coordinate >> color;
            color_point(p, color);
        }
        else if (command=='V') {
            string color;
            int x, y1, y2;
            cin >> x >> y1 >> y2 >> color;
            color_vertical_line(x, y1, y2, color);
        }
        else if (command=='H') {
            string color;
            int x1, x2, y;
            cin >> x1 >> x2 >> y >> color;
            color_horizontal_line(x1, x2, y, color);
        }
        else if (command=='K') {
            string color;
            int x1, x2, y1, y2;
            cin >> x1 >> y1 >> x2 >> y2 >> color;
            color_box(x1, y1, x2, y2, color);
        }
        else if (command== 'F') {
            string color;
            point p;
            cin >> p.x_coordinate >> p.y_coordinate >> color;
            flood_fill(p, color);
        }
        else if (command == 'C') {
            clear_image();
        }
    }

    return 0;
}

/* This function creates a blank image size width by height
where width and height are read from standard input respectively.*/
void initialise_image()
{
    /*read parameters height and width*/
    int width, height; 
    cin >> width >> height;

    /*first we create a vector of vectors (numRows+1)x(numColumns matrix+1). */
    image_array.clear(); 
    for (int i = 0; i < width+ 1; i++) {
        image_array.push_back(vector<string>());
    }

    /*then we initialize each element of it one by one*/
    for (int colNo = 0; colNo < width + 1; colNo++) {
        for (int rowNo = 0; rowNo < height + 1; rowNo++) {
            image_array[colNo].push_back("O");
        }

    }
}
 /* resets all pixels of the image to color "O"*/
void clear_image() {
    /*we initialize each element of it one by one*/
    for (int y = 1; y < get_image_height()+1 ; y++) {
        for (int x = 1; x < get_image_width()+1; x++) {
            image_array[x][y] = "O";
        }
    }
}

/* saves the image in filename where filename is read from stdin*/
void save_image(string file_name) {
    cout << file_name << "\n";
    for (int y = 1; y < get_image_height()+1; y++) {
        for (int x = 1; x < get_image_width()+1; x++) {
            cout << image_array[x][y] ;
        }
        cout << "\n";
    }

}


int get_image_width() {
    return image_array.size()-1;

}

int get_image_height() {
    return image_array[0].size()-1;
}

//colors the pixel at point p.x_coordinate, p.y_coordinate in color color. 
void color_point(point p, string color) {
    color_pixel(p.x_coordinate,p.y_coordinate, color);
}

void color_pixel(int x, int y, string color) {
    image_array[x][y] = color;
}


void color_vertical_line(int x, int y1, int y2, string color) {
    int y_adjustment; 
    if (y1 > y2) {
        y_adjustment = -1;
    }
    else {
        y_adjustment = 1; 
    }

    int y = y1; 
    while (y != y2+y_adjustment) {
        color_pixel(x, y, color);
        y += y_adjustment; 
    }
}

void color_horizontal_line(int x1, int x2, int y, string color) {
    int x_adjustment;
    if (x1 > x2) {
        x_adjustment = -1;
    }
    else {
        x_adjustment = 1;
    }

    int x = x1;
    while (x != x2 + x_adjustment) {
        color_pixel(x, y, color);
        x += x_adjustment;
    }
}

//colors the box drawn between point x1, y1 and x2, y2. 
void color_box(int x1, int y1, int x2, int y2, string color) {
    int x_adjustment;
    if (x1 > x2) {
        x_adjustment = -1;
    }
    else {
        x_adjustment = 1;
    }

    int y_adjustment;
    if (y1 > y2) {
        y_adjustment = -1;
    }
    else {
        y_adjustment = 1;
    }


    int x = x1;
    int y = y1;

    while (x != x2 + x_adjustment) {
        while (y != y2 + y_adjustment) {
            color_pixel(x, y, color);
            y += y_adjustment;
        }
        x += x_adjustment;
        y = y1;
    }

}


string get_point_color(point p) {
    return image_array[p.x_coordinate][p.y_coordinate];
}

//fills all pixels that share a border and color with p the color color. 
void flood_fill(point p, string color) {

    //we will be using a queue to store points that have been colored but whose neighbours are yet to be. 
    vector <point> points_queue;

    //first we add the point p to our queue
    points_queue.push_back(p);
    string original_color = get_point_color(p);
    point current_point; 
    string final_color = ""; 

    //if the original color of a point is the same as the new color then we return. Prevents infinite loop. 
    if (original_color.compare(color) == 0) {
        return;
    }


    while (points_queue.size() > 0) {
        //get element in front of queue for processing and remove it from queue. 
        current_point = points_queue[0];
        points_queue.erase(points_queue.begin());

        //if the point shares a color with the original point then color it in the new color. 
        if (get_point_color(current_point).compare(original_color) == 0) {
            color_point(current_point, color);
        }

        // add it's neighbours to the queue who's color matches original_color. 
        add_matching_neighbours(current_point, original_color, color, points_queue);

    }
}

//check if coordinates for point p lie in our image. 
bool is_valid_point(point p) {
    if (p.x_coordinate >= 1 && p.x_coordinate < get_image_width() + 1 && p.y_coordinate >= 1 && p.y_coordinate < get_image_height() + 1) {
        return true;
    }
    else {
        return false; 
    }
}


//checks all direct neighbours of p(north, south, east, west) and adds
//those whose color is the original color to points_queue after coloring them. 
void add_matching_neighbours(point p, string original_color, string new_color, vector<point> &points_queue) {
    point left_neighbour, right_neighbour, upper_neighbour, lower_neighbour;
    left_neighbour.x_coordinate = p.x_coordinate - 1;
    left_neighbour.y_coordinate = p.y_coordinate;
    if (is_valid_point(left_neighbour) && get_point_color(left_neighbour).compare(original_color) == 0) {
        points_queue.push_back(left_neighbour);
        color_point(left_neighbour, new_color);
    }

    right_neighbour.x_coordinate = p.x_coordinate + 1;
    right_neighbour.y_coordinate = p.y_coordinate;
    if (is_valid_point(right_neighbour) && get_point_color(right_neighbour).compare(original_color) == 0) {
        points_queue.push_back(right_neighbour);
        color_point(right_neighbour, new_color);
    }

    upper_neighbour.x_coordinate = p.x_coordinate;
    upper_neighbour.y_coordinate = p.y_coordinate + 1;
    if (is_valid_point(upper_neighbour) && get_point_color(upper_neighbour).compare(original_color) == 0) {
        points_queue.push_back(upper_neighbour);
        color_point(upper_neighbour, new_color);
    }

    lower_neighbour.x_coordinate = p.x_coordinate;
    lower_neighbour.y_coordinate = p.y_coordinate - 1;

    if (is_valid_point(lower_neighbour) && get_point_color(lower_neighbour).compare(original_color) == 0) {
        points_queue.push_back(lower_neighbour);
        color_point(lower_neighbour, new_color);
    }

}
\$\endgroup\$
  • 1
    \$\begingroup\$ "A "colour" is a single character" then why use string everywhere in your code? \$\endgroup\$ – I'll add comments tomorrow Oct 30 '16 at 14:58
3
\$\begingroup\$

Here are several things that may help you improve your code.

Isolate platform-specific code

If you must have stdafx.h, consider wrapping it so that the code is portable:

#ifdef WINDOWS
#include "stdafx.h"
#endif

In this case, with only a single file, there's no advantage to having it, so I'd recommend simply deleting that line.

Eliminate spurious typedef

The code currently contains this:

typedef struct point {
    int x_coordinate, y_coordinate;
};

However, in C++, the typedef is not needed since a struct definition creates a new type. Simply omit the word typedef here.

Use objects

Almost all of the functions in the code operate on a single global variable named image_array. This strongly suggests an object instead in which the image_array is a class and most of the functions are member functions instead of standalone C-style functions.

Use a switch instead of long if ...else chain

The command procesing is much easier to see and understand if a switch statement is used instead of the long if...else chain. The default case can then be used for unrecognized commands. On my machine, this also makes the code slightly faster.

Use the appropriate data type

The description of the problem says that a color is a single character, but it's defined as a std::string in most of the code. It seems to me that a more appropriate choice would be to define a Color type and use that. I'd probably do this:

using Color = char;

However, if there's some reason you must use a std::string for this, you could use this:

using Color = std::string;

The advantage here is that it is easy to understand the intended usage if the functions are declared using syntax like this:

void add_matching_neighbours(point p, Color original_color, Color new_color, vector<point> &points_queue);

Eliminate unused variables

Unused variables are a sign of poor code quality, so eliminating them should be a priority. In this code, final_color gets set but is never actually used. My compiler also tells me that. Your compiler is probably also smart enough to tell you that, if you ask it to do so.

Choose easier names

The point struct is quite simple, but the names for the coordinates are x_coordinate and y_coordinate. While those are fine, descriptive names, I think they're overly long. I'd be inclined to simply name them x and y instead and save a lot of typing and shorten some really long lines that are currently within the code.

Use for instead of while where appropriate

Within the color_box function is this code:

int x = x1;
int y = y1;

while (x != x2 + x_adjustment) {
    while (y != y2 + y_adjustment) {
        color_pixel(x, y, color);
        y += y_adjustment;
    }
    x += x_adjustment;
    y = y1;
}

This can be much simplified and also easier to understand by using a for loop instead of while:

for (int x = x1; x != x2 + x_adjustment; x += x_adjustment) {
    for (int y = y1; y != y2 + y_adjustment; y += y_adjustment) {
        color_pixel(x, y, color);
    }
}

Name useful constants

In the existing code, the value "0" is used multiple times to represent the color "white". I'd recommend formalizing that equivalence by naming the constants.

static const Color white{'0'};

In this case, I've defined it as a single char per my previous suggestion.

Think carefully about memory allocation

The code for initialise_array contains theres three lines:

for (int i = 0; i < width+ 1; i++) {
    image_array.push_back(vector<Color>());
}

The creates each column as an empty vector, forcing the vector to resize (probably more than once) as items are added to the vector. Since we already know the size, we can eliminate a lot of reallocations by initializing the std::vector to the known correct size as we create it:

for (int i = 0; i < width+ 1; i++) {
    image_array.push_back(vector<Color>(height+1));
}

Even better, we do the same thing to the outer vector and pass in an initialized vector:

image_array.reserve(width+1);
for (int i = 0; i < width+ 1; i++) {
    image_array.push_back(vector<Color>(height+1, white));
}

Perform bounds checking

If we construct an image that is 64x32 using I 64 32 then attempt to create a filled box with the command L 65 20 +, the x dimension of 65 is out of bounds. Unfortunately, the program doesn't seem to notice that and attempts to use the out of bounds and crashes.

Don't repeat yourself

Here's one way to rewrite the add_matching_neighbors to reduce the repetition.

void Image::add_matching_neighbours(const point &p, Color original_color, 
         Color new_color, vector<point> &points_queue) {
    const point neighbours[4]{ {p.x - 1, p.y},     // left
                    {p.x + 1, p.y},     // right
                    {p.x,     p.y + 1}, //upper
                    {p.x,     p.y - 1}, //lower
    };
    for (const auto &neigh : neighbours) {
        if (is_valid_point(neigh) && get_point_color(neigh) == original_color) {
            points_queue.push_back(neigh);
            color_point(neigh, new_color);
        }
    }
}

Omit return 0

When a C or C++ program reaches the end of main the compiler will automatically generate code to return 0, so there is no need to put return 0; explicitly at the end of main.

Note: when I make this suggestion, it's almost invariably followed by one of two kinds of comments: "I didn't know that." or "That's bad advice!" My rationale is that it's safe and useful to rely on compiler behavior explicitly supported by the standard. For C, since C99; see ISO/IEC 9899:1999 section 5.1.2.2.3:

[...] a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0.

For C++, since the first standard in 1998; see ISO/IEC 14882:1998 section 3.6.1:

If control reaches the end of main without encountering a return statement, the effect is that of executing return 0;

All versions of both standards since then (C99 and C++98) have maintained the same idea. We rely on automatically generated member functions in C++, and few people write explicit return; statements at the end of a void function. Reasons against omitting seem to boil down to "it looks weird". If, like me, you're curious about the rationale for the change to the C standard read this question. Also note that in the early 1990s this was considered "sloppy practice" because it was undefined behavior (although widely supported) at the time.

So I advocate omitting it; others disagree (often vehemently!) In any case, if you encounter code that omits it, you'll know that it's explicitly supported by the standard and you'll know what it means.

\$\endgroup\$
2
\$\begingroup\$

I've tried to review your code, and I have the following comments.

Pro:
All in all the code is well structured and the naming is easy to understand.

The comments are helpful

The separation of user interaction and processing is good

Contra:

Missing

  • helpful prompts

  • error handling and messages. The processing functions should return a status value so the UI can inform the user if something went wrong.


Below I've reentered all your code with some inline comments and modifications (All begins with // HH or // HH TODO):

// graphical_editor.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream> //provides access to cout and cin 
#include <string> //Always import <string> if piping std input to a string in .net 
#include <vector>
#include <fstream>

using std::cin;
using std::cout;
using std::string;
using std::vector;
using std::ofstream;


// HH you could typedef Color to quickly change the type
typedef char Color;
// HH The black and white colors:
const Color white = '0';
const Color black = ' ';

// HH compare function is easy to change if Color changes to other type
int compare_colors(Color c1, Color c2)
{
  if (c1 == c2)
    return 0;
  if (c1 < c2)
    return -1;
  return 1;
}


//This is where we store the pixels of the image
// static vector<vector <string>> image_array; // HH: One char == one pixel so use char instead of string
vector<vector <Color>> image_array;

//our definition of an X,Y coordinate pair. 
/*typedef*/ struct point { // HH: typedef ignored because no variable is defined
  // int x_coordinate, y_coordinate; // HH unnecessarily long names
  int x, y;
};

/* You could have done it like this: 
typedef struct _point {                       
  int x, y;
} point;
*/


void initialise_image(int width, int height);
void clear_image();
void print_image(); // HH Prints the image to the console
void save_image(string file_name);
int get_image_width();
int get_image_height();
void color_pixel(int x, int y, Color color);
void color_point(point p, Color color);
void color_vertical_line(int x, int y1, int y2, Color color);
void color_horizontal_line(int x1, int x2, int y, Color color);
void color_box(int x1, int x2, int y1, int y2, Color color);
void flood_fill(point p, Color color);
void add_matching_neighbours(point p, Color original_color, Color new_color, vector<point> &points_queue);

int main()
{
  //myfile.open("example.txt");
  char command; //first letter of a given line 

  // HH: A switch() may be better here than the else if sequence
  do {
    cout << "Enter Command [ I, S, L, V, H, K, F, C, X ] ";
    cin >> command;

    // HH TODO: Change the loop so that the user can't draw on an uninitialized image

    switch (command)
    {
    case 'X':
    case 'x': // HH: Allow for lower case letters as well
      return 0;
    case 'I':
    case 'i':
      // HH Here you have the input dialog inside the function but elsewhere it's in this loop. Be consistent
      // initialise_image();
      /*read parameters height and width*/
      cout << "Initialize Image enter Width and Height: ";
      int width, height;
      cin >> width >> height;
      initialise_image(width, height);
      break;
    case 'S':
    case 's':
    {
      cout << "Enter File Name: ";
      string file_name;
      cin >> file_name;
      save_image(file_name);
    }
    break;
    case 'L':
    case 'l':
    {
      // HH TODO: User friendly prompt
      Color color;
      point p;
      cin >> p.x >> p.y >> color;
      color_point(p, color);
    }
    break;
    case 'V':
    case 'v':
    {
      // HH TODO: User friendly prompt
      Color color;
      int x, y1, y2;
      cin >> x >> y1 >> y2 >> color;
      color_vertical_line(x, y1, y2, color);
    }
    break;
    case 'H':
    case 'h':
    {
      // HH TODO: User friendly prompt
      Color color;
      int x1, x2, y;
      cin >> x1 >> x2 >> y >> color;
      color_horizontal_line(x1, x2, y, color);
    }
      break;
    case 'K':
    case 'k':
    {
      // HH TODO: User friendly prompt
      Color color;
      int x1, x2, y1, y2;
      cin >> x1 >> y1 >> x2 >> y2 >> color;
      color_box(x1, y1, x2, y2, color);
    }
      break;
    case 'F':
    case 'f':
    {
      // HH TODO: User friendly prompt
      Color color;
      point p;
      cin >> p.x >> p.y >> color;
      flood_fill(p, color);
    }
      break;
    case 'C':
    case 'c':
      // HH TODO: User friendly prompt and accept
      clear_image();
      break;
    default:
      cout << "Invalid input - try again...";
      break;
    }

    print_image(); // HH Printf the image after every command to see the result
  } while (true);

  return 0;
}

/* This function creates a blank image size width by height
where width and height are read from standard input respectively.*/
void initialise_image(int width, int height)
{
  /*first we create a vector of vectors (numRows+1)x(numColumns matrix+1). */
  image_array.clear();
  for (int i = 0; i < width + 1; i++) {
    image_array.push_back(vector<Color>());
  }

  /*then we initialize each element of it one by one*/
  for (int colNo = 0; colNo < width + 1; colNo++) {
    for (int rowNo = 0; rowNo < height + 1; rowNo++) {
      image_array[colNo].push_back(white);
    }

  }
}
/* resets all pixels of the image to color "O"*/
void clear_image() {
  /*we initialize each element of it one by one*/
  for (int y = 1; y < get_image_height() + 1; y++) {
    for (int x = 1; x < get_image_width() + 1; x++) {
      image_array[x][y] = white;
    }
  }
}

void print_image()
{
  system("cls");
  for (int y = 1; y < get_image_height() + 1; y++) {
    for (int x = 1; x < get_image_width() + 1; x++) {
      cout << image_array[x][y];
    }
    cout << "\n";
  }
}

/* saves the image in filename where filename is read from stdin*/
void save_image(string file_name) {
  cout << file_name << "\n";
  for (int y = 1; y < get_image_height() + 1; y++) {
    for (int x = 1; x < get_image_width() + 1; x++) {
      cout << image_array[x][y];
    }
    cout << "\n";
  }

}


int get_image_width() {
  return image_array.size() - 1;

}

int get_image_height() {
  return image_array[0].size() - 1;
}

//colors the pixel at point p.x, p.y in color color. 
void color_point(point p, Color color) {
  color_pixel(p.x, p.y, color);
}

void color_pixel(int x, int y, Color color) {
  image_array[x][y] = color;
}


void color_vertical_line(int x, int y1, int y2, Color color) {
  // HH TODO: Validation of input
  int y_adjustment;
  if (y1 > y2) {
    y_adjustment = -1;
  }
  else {
    y_adjustment = 1;
  }

  int y = y1;
  while (y != y2 + y_adjustment) {
    color_pixel(x, y, color);
    y += y_adjustment;
  }
}

void color_horizontal_line(int x1, int x2, int y, Color color) {
  // HH TODO: Validation of input 
  int x_adjustment;
  if (x1 > x2) {
    x_adjustment = -1;
  }
  else {
    x_adjustment = 1;
  }

  int x = x1;
  while (x != x2 + x_adjustment) {
    color_pixel(x, y, color);
    x += x_adjustment;
  }
}

//colors the box drawn between point x1, y1 and x2, y2. 
void color_box(int x1, int y1, int x2, int y2, Color color) { // HH Why not two points as arguments instead of for coordinates?
  // HH TODO: Validation of input
  int x_adjustment;
  if (x1 > x2) {
    x_adjustment = -1;
  }
  else {
    x_adjustment = 1;
  }

  int y_adjustment;
  if (y1 > y2) {
    y_adjustment = -1;
  }
  else {
    y_adjustment = 1;
  }


  int x = x1;
  int y = y1;

  while (x != x2 + x_adjustment) {
    while (y != y2 + y_adjustment) {
      color_pixel(x, y, color);
      y += y_adjustment;
    }
    x += x_adjustment;
    y = y1;
  }

}


Color get_point_color(point p) {
  return image_array[p.x][p.y];
}

//fills all pixels that share a border and color with p the color color. 
void flood_fill(point p, Color color) {
  // HH TODO: Validation of input

  //we will be using a queue to store points that have been colored but whose neighbours are yet to be. 
  vector <point> points_queue;

  //first we add the point p to our queue
  points_queue.push_back(p);
  Color original_color = get_point_color(p);
  point current_point;
  Color final_color = black;

  //if the original color of a point is the same as the new color then we return. Prevents infinite loop. 
  if (compare_colors(original_color, color) == 0) {
    return;
  }


  while (points_queue.size() > 0) {
    //get element in front of queue for processing and remove it from queue. 
    current_point = points_queue[0];
    points_queue.erase(points_queue.begin());

    //if the point shares a color with the original point then color it in the new color. 
    if (compare_colors(get_point_color(current_point), original_color) == 0) {
      color_point(current_point, color);
    }

    // add it's neighbours to the queue who's color matches original_color. 
    add_matching_neighbours(current_point, original_color, color, points_queue);

  }
}

//check if coordinates for point p lie in our image. 
bool is_valid_point(point p) {
  if (p.x >= 1 && p.x < get_image_width() + 1 && p.y >= 1 && p.y < get_image_height() + 1) {
    return true;
  }
  else {
    return false;
  }
}


//checks all direct neighbours of p(north, south, east, west) and adds
//those whose color is the original color to points_queue after coloring them. 
void add_matching_neighbours(point p, Color original_color, Color new_color, vector<point> &points_queue) {
  point left_neighbour, right_neighbour, upper_neighbour, lower_neighbour;
  left_neighbour.x = p.x - 1;
  left_neighbour.y = p.y;
  if (is_valid_point(left_neighbour) && compare_colors(get_point_color(left_neighbour), original_color) == 0) {
    points_queue.push_back(left_neighbour);
    color_point(left_neighbour, new_color);
  }

  right_neighbour.x = p.x + 1;
  right_neighbour.y = p.y;
  if (is_valid_point(right_neighbour) && compare_colors(get_point_color(right_neighbour), original_color) == 0) {
    points_queue.push_back(right_neighbour);
    color_point(right_neighbour, new_color);
  }

  upper_neighbour.x = p.x;
  upper_neighbour.y = p.y + 1;
  if (is_valid_point(upper_neighbour) && compare_colors(get_point_color(upper_neighbour), original_color) == 0) {
    points_queue.push_back(upper_neighbour);
    color_point(upper_neighbour, new_color);
  }

  lower_neighbour.x = p.x;
  lower_neighbour.y = p.y - 1;

  if (is_valid_point(lower_neighbour) && compare_colors(get_point_color(lower_neighbour), original_color) == 0) {
    points_queue.push_back(lower_neighbour);
    color_point(lower_neighbour, new_color);
  }

}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.