CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Fun With Perl: Perl Golf:
Perl Golf: Phonobulizer

 



Coderifous
journeyman

Oct 25, 2001, 4:46 PM

Post #1 of 10 (35249 views)
Perl Golf: Phonobulizer Can't Post

Admittedly, "Phonobulize" is a word I created, but I think it's cooler than saying "numerize". And appropriate too. Cool

My Inspiration:
My phone number sucks. No mathematical reason or rhyme to it... but what if I could tell people to call me at: how-cool rather than 469-2665. (It's not my real phone number)

The challenge:
A script that takes up to 10 digits as input, and outputs to a file containing all possible "phonobulized" conversions.

The Rules:
0 and 1 on the phone keypad are to equal 0 and 1, respectively. For all the other digits, there are three possible letter values as defined by your phone's keypad. All possible combinations must be outputted: That's the main reason I limited input to 10 digits. To much more than that and the output flows in astounding quantity.

Hint: Attached is the HoA that I used:





mhx
Enthusiast / Moderator

Oct 26, 2001, 2:27 AM

Post #2 of 10 (35241 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

Well, that's my first shot. It's 134 characters:

Code
sub _{my$a=shift;local$_=shift;defined||return print"$a\n";$_<2?_( 
$a.$_,@_):do{$_=3*$_+91;_($a.chr,@_)for$_..$_+2}}_('',<>=~/(\d)/g)

It reads the phone number from standard input and writes all phonobulized versions to standard output. Works with an unlimited number of digits.

-- Marcus


Code
s$$ab21b8d15c3d97bd6317286d$;$"=547269736;split'i',join$,,map{chr(($*+= 
($">>=1)&1?-hex:hex)+0140)}/./g;$"=chr$";s;.;\u$&;for@_[0,2];print"@_,"



Coderifous
journeyman

Oct 26, 2001, 8:59 AM

Post #3 of 10 (35238 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

Marcus... you sicken me. Needless to say you destroyed my codes par.

I want a full report on how that rediculously efficient code works, because I understand about 10 percent of it. And I want to know how long it took you to figure that out. Then if I don't like the answers you give me, I'm going to cry like a little baby until my wife bars me from visiting this website.

--jim



Coderifous
journeyman

Oct 26, 2001, 2:30 PM

Post #4 of 10 (35232 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

MARCUS!!! YOU SUCK!!!! Smile

After running your code, and wonderful code it is, I realized that you have made a fatal mistake! You have yet to pass the Phonobulizer quiz, because your code returns letters that are missing from an actual phone key pad. Atleast from my keypad... is the "Q" on phones in Germany? Also: where is the "Y" when I use the number 9? I disovered this while useing the number 7448 as input, and it didn't return one of my favorite dirty words that start with an "s". Now, you will more than likely fix this w/ minor modification. But then you will truly be phonobulizing.

Looking forward to your next post...

--jim

PS - The other kids can play too...



mhx
Enthusiast / Moderator

Oct 26, 2001, 2:44 PM

Post #5 of 10 (35232 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

Jim, I'm really sorry if my solution sickens you. I didn't want that.

So here's my explanation for the code, I hope that makes it a bit clearer. First of all, I've added some line breaks and whitespace to the code to make it a bit more readable:

Code
sub _ 
{
my $a = shift;
local $_ = shift;
defined || return print "$a\n";
$_ < 2 ? _( $a.$_, @_ )
: do {
$_=3*$_+91;
_( $a.chr, @_ ) for $_..$_+2
}
}

_( '', <> =~ /(\d)/g )

Next, I'm going to give the subroutine a cool name (although I personally find the underscore is really cool as a subroutine name) and replace the ?: section by an if/else section, just to make it even more readable:

Code
sub phone 
{
my $a = shift;
local $_ = shift;
defined || return print "$a\n";
if( $_ < 2 ) {
phone( $a.$_, @_ )
}
else {
$_=3*$_+91;
phone( $a.chr, @_ ) for $_..$_+2
}
}

phone( '', <> =~ /(\d)/g )

Now, one can almost immediately see that this is a recursive algorithm. It's started in the last line by calling phone() with an empty string and all digits entered by the user. <> reads in one line and the regular expression transforms that line into a list containing all digits.
The heart of that algorithm is obviously the phone() subroutine. In that subroutine, $a is always the string that is assembled to contain the phonobulized version of the phone number. In the first call, $a will be the empty string and $_ will be the first of the digits:

Code
  my $a    = shift; 
local $_ = shift;

I'll explain the next line later and first go to the if/else section:

Code
  if( $_ < 2 ) { 
phone( $a.$_, @_ )
}
else {
$_=3*$_+91;
phone( $a.chr, @_ ) for $_..$_+2
}

Depending on whether the first digit is less than 2 or not, two different blocks need to be executed. In case of a 0 or 1, we only need to add the digit to the string and enter the next recursion level by calling the phone() subroutine again with the new string and all remaining digits. (Remember we shifted the string and the first digit off @_, so it holds all remaining digits.) But if the first digit is 2 or greater, we need to replace it by three consecutive letters. Fortunately enough, the characters are sorted in the ASCII set, and since the lowercase letters start at 97 (a) and our digit ($_) is at least 2, the three letters of interest start at (91+3*$_). We now call phone() again recursively from within a loop over the ASCII values of the three letters. The new string passed to the next recursion level is a concatenation of the old string and the character that corresponds to the current ASCII code stored in $_, which is the default argument to the chr function.
Now, when does the recursion stop? As we've seen, with each level of recursion there's one digit shifted off the list. So at a certain level, there's no more digits and thus $_ will become undef. That's when the following line becomes interesting:

Code
  defined || return print "$a\n";

Since $_ is also the default argument to defined, the return statement will be executed when we've run out of digits. But before returning from the subroutine, we have to print out the string we've assembled, and this string is still stored in $a. As we don't call phone(), the recursion has reached its end.

If you're familiar with recursion, this shouln't be too hard to understand. If you're not it may be, uh, quite hard.

To answer your other questions: I read your post shortly after I got up. Then I went shopping with my mom and that's where I made up most of the algorithm. It was clear to me from the beginning that it had to be recursive. I also had the idea of using $_=3*$_+91 to get the letters corresponding to a digit while being in town. Back home, coding those ideas took about 15 minutes and compressing the code took another 15 minutes. So, considering that I spent a total of 30 minutes thinking about the solution, you can say that it took me about an hour to come up with the above code.

I'm pretty sure there's still room for improvements. I'd guess about 120 characters should be possible. However, I hope you find the above explanations helpful and I also hope you won't be crying to much as you'll see that there's really nothing special about the code.

-- Marcus


Code
s$$ab21b8d15c3d97bd6317286d$;$"=547269736;split'i',join$,,map{chr(($*+= 
($">>=1)&1?-hex:hex)+0140)}/./g;$"=chr$";s;.;\u$&;for@_[0,2];print"@_,"



Coderifous
journeyman

Oct 26, 2001, 3:04 PM

Post #6 of 10 (35230 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

Hey Marcus, I didn't really mean it when I said you suck. I feel bad now...

Thanks for breaking it all down for me, I really like learning the stuff that boggles me. And your stuff does boggle me. What a wonderful thing: I'm learning so much from this forum. I'm putting it on my Resume.

As far as forgetting the "Q" and "Y" thing, it's really not the point of the challenge anyway... just a small technicality. You figured out the recursion and that was (for me) the real challenge.

Thanks again.Smile
--jim



mhx
Enthusiast / Moderator

Oct 26, 2001, 3:07 PM

Post #7 of 10 (35230 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

Well, ok, you got me. Wink

I've not been thinking enough before coding my solution. But, there's a Q on german phones, and there's also a Y and a Z. Actually, here's the german phone mapping:

Code
0 => 0 
1 => 1
2 => abc
3 => def
4 => ghi
5 => jkl
6 => mno
7 => pqrs
8 => tuv
9 => wxyz

Unfortunately, the fix isn't that minor, and so my code grew to 168 characters:

Code
sub _{my$a=shift;local$_=shift;defined||return print"$a\n";$_<2?_($a.$_,@_):do{$n=2 
;$n+=$_%2if$_>6;$_=3*$_+91;$_++if$_>112;_($a.chr,@_)for$_..$_+$n}}_('',<>=~/(\d)/g)

This code implements the mapping as it is on german phones. (I once owned an american phone and as far as I can recall it wasn't different, but feel free to correct me if I'm wrong on that.)

-- Marcus


Code
s$$ab21b8d15c3d97bd6317286d$;$"=547269736;split'i',join$,,map{chr(($*+= 
($">>=1)&1?-hex:hex)+0140)}/./g;$"=chr$";s;.;\u$&;for@_[0,2];print"@_,"



Coderifous
journeyman

Oct 26, 2001, 3:14 PM

Post #8 of 10 (35228 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

Well, I don't know that there is an ANSI standard supplied to phone manufacturers on what letters go on what numbers in America, but on the phone I was sitting next too when I coded mine, the mapping was what you saw in my HoA attachment on the first post.

Personally I think the German phones make more sense... why exclude a letter if you don't really have too?

I don't know if all US phones omit those two letters: Q and Z I'll do a little survey to find out...

Until then my friendSmile

--jim



randor
User

Oct 31, 2001, 4:40 AM

Post #9 of 10 (35215 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

my phone has ALL letters, and i am in new york

I Hope this helps...

perl programmers don't die.. they just start writing a new script.


mhx
Enthusiast / Moderator

Oct 31, 2001, 7:03 AM

Post #10 of 10 (35214 views)
Re: Perl Golf: Phonobulizer [In reply to] Can't Post

Yes, it helps. Wink

-- Marcus


Code
s$$ab21b8d15c3d97bd6317286d$;$"=547269736;split'i',join$,,map{chr(($*+= 
($">>=1)&1?-hex:hex)+0140)}/./g;$"=chr$";s;.;\u$&;for@_[0,2];print"@_,"


 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives