#include <iostream>
#include <vector>
#include <utility>
#include <fstream>
#include <string>
#include <sstream>
#include <iterator>
#include <map>
#include <set>
#include <algorithm>
#include <functional>

using namespace std;

typedef std::pair<int,int> cell;

enum island_status {COMPLETE,INCOMPLETE};
enum color {WHITE = -2, BLACK = -1 };

class island
{
public:
	std::set<cell> cells;
	island_status status;
};
class nurikabe
{
	std::vector<std::vector<int>> grid;
	std::map<int,island*> islands;
	unsigned int l1,l2;	
	void color_black(cell);
public:
	nurikabe();
	nurikabe(std::string);
	void solve();
	void print();
	void find_islands();
	unsigned int any_complete_island();
	int fill_adjacent(cell);
};



void nurikabe::solve()
{
	find_islands();
	unsigned int i = 0;
	do
	{
		i = 0;
		i += any_complete_island();
		cout<<i<<" islands complete";
	}while(i != 0);

}

void nurikabe::find_islands()
{
	int i,j;
	for(i = 0;i < l1; ++i)
	{
		for(j = 0;j < l2; ++j)
		{
			if( grid[i][j] > 0)
				{
					islands[grid[i][j]] = new island;
					islands[grid[i][j]]->status = INCOMPLETE;
					islands[grid[i][j]]->cells.insert(make_pair(i,j));
			}
		}
	}
}
unsigned int nurikabe::any_complete_island()
{
	int i =0;
	auto it = islands.cbegin();
	auto end = islands.cend();
	for( ;it != end ; ++it)
	{
		auto & an_island = (*it).second;
		if( an_island->status == INCOMPLETE && (*it).first == an_island->cells.size() )
		{
			++i;
			an_island->status = COMPLETE;
			for_each(an_island->cells.cbegin(),an_island->cells.cend(),std::bind(&nurikabe::fill_adjacent,this));
		}
	};
	return i;
}

int nurikabe::fill_adjacent(cell c)
{
	color_black(make_pair(c.first,c.second+1));
	color_black(make_pair(c.first+1,c.second));
	color_black(make_pair(c.first,c.second-1));
	color_black(make_pair(c.first-1,c.second));

	return 0;
}

void nurikabe::color_black(cell c)
{
	if(grid[c.first][c.second] != WHITE)
		grid[c.first][c.second] = BLACK;
}
nurikabe::nurikabe(string filename)
{
	fstream input (filename);
	string aline;
	
	unsigned int size =0;
	while(input)
	{
		getline(input,aline);
		if(aline.size() > 0)
		{
			istringstream line(aline);
			istream_iterator<int> begin(line), end;
			grid.push_back(vector<int>(begin,end));
		}
	}
	l2 = grid[0].size();
	l1 = grid.size();
}

void nurikabe::print()
{
	//print out the puzzle
	for( auto i = grid.cbegin();i != grid.cend();i++)
	{
		cout<<endl;
		auto row = *i;
		for( auto j = row.cbegin();j != row.cend();j++)
		{
			cout<<*j<<",";
		}
	}
	cout<<"\n"<<islands.size()<<" Islands present.";
}
int main()
{
	nurikabe mynurikabe("D:\\Nurikabe.txt");
	mynurikabe.solve();
	mynurikabe.print();
	return 0;
}