use List::Util qw(any);

print 'Enter pool size, puzzle size, attempts allowed: '; 
($pool,$length,$tries) = split /\s+/, <>;
$length =  4 if $length eq '' or $length < 3 or $length > 11;
$pool   =  6 if $pool   eq '' or $pool   < 2 or $pool   > 21;
$tries  = 10 if $tries  eq '' or $tries  < 7 or $tries  > 21;

@valid  = sort { -1 + 2*int(rand 2) } ('A' .. 'T')[0..$pool-1];
@puzzle = @valid[0..$length-1];

$black = '';
$white = '';

while () {
    header();
    print "$_\n" for @guesses;
    lose() if  @guesses == $tries;
    @guess = get_guess();
    next unless is_valid(@guess);
    $score = score(\@puzzle, \@guess);
    win() if $score eq join ' ', ($black) x $length;
    push @guesses, join(' ', @guess) . ':: ' . $score;
}

sub score {
    local *puzzle = shift;
    local *guess  = shift;
    my @score;
    for $i (0..$length-1) {
        if    (     $puzzle[$i] eq $guess[$i]) { push @score, $black }
        elsif (any {$puzzle[$i] eq $_} @guess) { push @score, $white }
        else                                   { push @score, '-'    }
    }
    join ' ', reverse sort @score;
}

sub header {
    $num = $tries - @guesses;
    print  "Valid letter, but wrong position:  - Correct letter and position: \n";
    print  "Guess the $length element sequence containing the letters " . join(', ', sort @valid) . "\n";
    printf "Repeats are not allowed. You have $num guess%s remaining\n", $num > 1 ? 'es' : '';
}

sub get_guess { print 'Your guess?: '; $g = <>; return split /\s*/, uc $g }

sub is_valid { $length == @_ }

sub win  { print 'You win! The correct answer is: ' . join(' ',@puzzle) . "\n"; exit }

sub lose { print 'Too bad, you ran out of guesses. The solution was: ' . join(' ',@puzzle) . "\n"; exit }