use strict;
use warnings;
no warnings 'uninitialized';
use feature 'say';
use constant True => 1;
use List::Util qw(head uniq);

sub GraphNodeColor {
    my(%OneMany, %NodeColor, %NodePool, @ColorPool);
    my(@data) = @_;

    for (@data) {
        my($a,$b) = @$_;
        push @{$OneMany{$a}}, $b;
        push @{$OneMany{$b}}, $a;
    }

    @ColorPool = 0 .. -1 + scalar %OneMany;
    $NodePool{$_} = True for keys %OneMany;

    if ($OneMany{''}) { 
        delete $NodePool{$_} for @{$OneMany{''}};
        delete $NodePool{''};
    }

    while (%NodePool) {
        my $color = shift @ColorPool;
        my %TempPool = %NodePool;

        while (my $n = head 1, sort keys %TempPool) {
            $NodeColor{$n} = $color;
            delete $TempPool{$n};
            delete $TempPool{$_} for @{$OneMany{$n}} ; 
            delete $NodePool{$n};
        }

        if ($OneMany{''}) { 
            $NodeColor{$_} = head 1, sort values %NodeColor for @{$OneMany{''}};
        }
    }
    %NodeColor
}

my @DATA = (
    [ [1,2],[2,3],[3,1],[4,undef],[5,undef],[6,undef] ],
    [ [1,6],[1,7],[1,8],[2,5],[2,7],[2,8],[3,5],[3,6],[3,8],[4,5],[4,6],[4,7] ],
    [ [1,4],[1,6],[1,8],[3,2],[3,6],[3,8],[5,2],[5,4],[5,8],[7,2],[7,4],[7,6] ],
    [ [1,6],[7,1],[8,1],[5,2],[2,7],[2,8],[3,5],[6,3],[3,8],[4,5],[4,6],[4,7] ]
);

for my $d (@DATA) {
    my %result = GraphNodeColor @$d;

    my($graph,$colors);
    $graph  .= '(' . join(' ', @$_) . '), ' for @$d;
    $colors .= ' ' . $result{$$_[0]} . '-' . ($result{$$_[1]} // '') . '   ' for @$d;

    say 'Graph : ' . $graph =~ s/,\s*$//r;
    say 'Colors: ' . $colors;
    say 'Nodes : ' . keys %result;
    say 'Edges : ' . @$d;
    say 'Unique: ' . uniq values %result;
    say '';
}