aboutsummaryrefslogtreecommitdiff
path: root/challenge-025/duncan-c-white/perl5/v3.pl
blob: 8f4c67e8aeeab1e7c0da5a37de77e634bd55b8e0 (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
#!/usr/bin/perl
#
# Challenge 1: "Generate a longest sequence of the following "English Pokemon"
#     names where each name starts with the last letter of the previous name:
# 
#         audino bagon baltoy banette bidoof braviary bronzor carracosta
#         charmeleon cresselia croagunk darmanitan deino emboar emolga
#         exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
#         jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
#         lumineon lunatone machamp magnezone mamoswine nosepass petilil
#         pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
#         registeel relicanth remoraid rufflet sableye scolipede scrafty
#         seaking sealeo silcoon simisear snivy snorlax spoink starly
#         tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
#         wartortle whismur wingull yamask"
# 
# My notes: Clearly defined, nice, potentially tricky, let's do it.
# 
# optimization v3: instead of cloning the used set to modify it,
#		   modify it, pass it, and then change it back        21.1s
# optimization v2: instead of recalculating the "used set" each time,
#		   pass it around, modifying it as we go              28.8s
# optimization v1: baseline code before starting to optimize:         32.6s.
#

use v5.10;	# to get "say"
use strict;
use warnings;
use Function::Parameters;
#use Data::Dumper;

my $debug = @ARGV>0;

my @words = qw(audino bagon baltoy banette bidoof braviary bronzor carracosta
	charmeleon cresselia croagunk darmanitan deino emboar emolga
	exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
	jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
	lumineon lunatone machamp magnezone mamoswine nosepass petilil
	pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
	registeel relicanth remoraid rufflet sableye scolipede scrafty
	seaking sealeo silcoon simisear snivy snorlax spoink starly
	tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
	wartortle whismur wingull yamask);
#@words = qw(hello ollie excellent thanks shelter runaround set to);

my %sw;	# hash from letter to list of words starting with that letter.

foreach my $word (@words)
{
	$word =~ /^(.)/;
	my $letter = $1;
	$sw{$letter} //= [];
	push @{$sw{$letter}}, $word;
}

#die Dumper \%sw;

my @longseq = ();	# longest sequence found so far..

# search for sequences starting with each word in turn..
foreach my $sw (@words)
{
	findseq( $sw, {}, () );
}

my $longest = @longseq;

print "\nlongest sequence is length $longest: @longseq\n";
exit 0;


#
# findseq( $currw, $used, @seq );
#	Find all sequences of words from $currw onwards,
#	given that we've already visited words in @seq,
#	(the same info, as a set, is in %$used)
#	and update the global @longseq if any sequences
#	we find are longer than that.
#
fun findseq( $currw, $used, @seq )
{
	push @seq, $currw;		  # extend @seq sequence

	$used->{$currw}++;		  # update $used set

	$currw =~ /(.)$/;		  # find the last letter of currw
	my $lastletter = $1;

	my $nextw = $sw{$lastletter};     # all words starting with lastletter
	if( defined $nextw )              # if there are any, try each word
	{
		foreach my $nextword (@$nextw)
		{
			findseq( $nextword, $used, @seq )
				unless $used->{$nextword};
		}
	} else				  # @seq is finished
	{
		#print "found sequence @seq\n";
		my $len = @seq;
		if( $len > @longseq )
		{
			print "longest seq so far (len $len): @seq\n" if $debug;
			@longseq = @seq;
		}
	}
	delete $used->{$currw};
}