aboutsummaryrefslogtreecommitdiff
path: root/challenge-161/alexander-pankoff/perl/ch-2.pl
blob: 374f797e0a85b6f9b6f423b48c9b00592cac75da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw'say state signatures';
no warnings qw'experimental::signatures';

# Task 2: Pangrams
# Submitted by: Ryan J Thompson
#
# A pangram is a sentence or phrase that uses every letter in the English
# alphabet at least once. For example, perhaps the most well known pangram is:
#
# the quick brown fox jumps over the lazy dog
#
# Using the provided dictionary, so that you don’t need to include individual
# copy, generate at least one pangram.
#
# Your pangram does not have to be a syntactically valid English sentence (doing
# so would require far more work, and a dictionary of nouns, verbs, adjectives,
# adverbs, and conjunctions). Also note that repeated letters, and even repeated
# words, are permitted.

# BONUS: Constrain or optimize for something interesting (completely up to you),
# such as:
#
# * Shortest possible pangram (difficult)
# * Pangram which contains only abecedarian words (see challenge 1)
# * Pangram such that each word "solves" exactly one new letter. For example,
#   such a pangram might begin with (newly solved letters in bold):
#     a ah hi hid die ice tea ...
# * What is the longest possible pangram generated with this method? (All
#   solutions will contain 26 words, so focus on the letter count.)
# * Pangrams that have the weirdest (PG-13) Google image search results
# Anything interesting goes!

use FindBin    ();
use File::Spec ();
use List::Util qw(any max);

use lib $FindBin::RealBin;

use DictReader qw(read_dict);
use My::List::Util qw(group_by);

package challenge1 {
    ## we want to reuse `is_abecedarian` from challenge 1

    BEGIN {
        require File::Spec->catfile( $FindBin::Bin, 'ch-1.pl' );
    }
}

run() unless caller();

sub run() {
    my @dict = read_dict();

    say find_pangram_naive(@dict);
    say find_pangram_most_new_chars_used(@dict);

    my @abecedarian = grep ( challenge1::is_abecedarian($_), @dict );

    say find_pangram_naive(@abecedarian);
    say find_pangram_most_new_chars_used(@abecedarian);
}

sub find_pangram_naive(@dict) {
    ## Walks the dict in order. As soon as we  encounter a word with unused
    ## chars it is added to the pangram.

    my @unused = 'a' .. 'z';
    my @pangram;
    for my $word (@dict) {
        my @new_chars = grep { contains( $word, $_ ) } @unused;
        push @pangram, $word if @new_chars;
        @unused = without( \@unused, \@new_chars );
        if ( !@unused ) {
            return join( " ", @pangram );
        }
    }

    die "No pangram found";
}

sub find_pangram_most_new_chars_used(@dict) {
    ## In every step we find words with the most unused characters and add the
    ## shorted to the pangram.

    my @unused = 'a' .. 'z';

    my @pangram;
    while (@unused) {
        my $cur = find_word_with_most_unused_chars( \@dict, \@unused );
        @unused = without( \@unused, [ explode($cur) ] );
        push @pangram, $cur;
    }

    return join( " ", @pangram );
}

sub find_word_with_most_unused_chars ( $dict, $unused ) {
    my $words_by_unused = group_by(
        sub ($word) {
            scalar grep { contains( $word, $_ ) } @$unused;
        },
        @$dict
    );

    my $shortest = ( sort { length $a <=> length $b }
          @{ $words_by_unused->{ max( keys %$words_by_unused ) } } )[0];

    return $shortest;
}

sub contains ( $word, $char ) {
    return $word =~ m/\Q$char\E/;
}

sub without ( $as, $bs ) {
    grep {
        my $a = $_;
        !any { $_ eq $a } @$bs
    } @$as;
}

sub explode($str) {
    split( m//, $str );
}