Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Code Golf: Four is magic

by deMize (Monk)
on Jul 12, 2010 at 23:20 UTC ( [id://849126]=perlmeditation: print w/replies, xml ) Need Help??

Question: Originally found here: http://stackoverflow.com/questions/3230978/code-golf-four-is-magic, I'm curious if anyone here could do better

The puzzle

A little puzzle I heard while I was in high school went something like this...

  • The questioner would ask me to give him a number;
  • On hearing the number, the questioner would do some sort of transformation on it repeatedly (for example, he might say ten is three) until eventually arriving at the number 4 (at which point he would finish with four is magic).
  • Any number seems to be transformable into four eventually, no matter what.

The goal was to try to figure out the transformation function and then be able to reliably proctor this puzzle yourself.

The solution

The transformation function at any step was to

  • Take the number in question,
  • Count the number of letters in its English word representation, ignoring a hyphen or spaces or "and" (e.g., "ten" has 3 letters in it, "thirty-four" has 10 letters in it, "one hundred forty-three" has 20 letters in it).
  • Return that number of letters.

For all of the numbers I have ever cared to test, this converges to 4. Since "four" also has four letters in it, there would be an infinite loop here; instead it is merely referred to as magic by convention to end the sequence.

The challenge

Your challenge is to create a piece of code that will read a number from the user and then print lines showing the transformation function being repeatedly applied until "four is magic" is reached.

Specifically:

  1. Solutions must be complete programs in and of themselves. They cannot merely be functions which take in a number-- factor in the input.
  2. Input must be read from standard input. (Piping from "echo" or using input redirection is fine since that also goes from stdin)
  3. The input should be in numeric form.
  4. For every application of the transformation function, a line should be printed: a is b., where a and b are numeric forms of the numbers in the transformation.
  5. Full stops (periods) ARE required!
  6. The last line should naturally say, 4 is magic..
  7. The code should produce correct output for all numbers from 0 to 99.

Examples:

> 4
4 is magic.

> 12
12 is 6.
6 is 3.
3 is 5.
5 is 4.
4 is magic.

> 42
42 is 8.
8 is 5.
5 is 4.
4 is magic.

> 0
0 is 4.
4 is magic.

> 99
99 is 10.
10 is 3.
3 is 5.
5 is 4.
4 is magic.

The winner is the shortest submission by source code character count which is also correct.

BONUS

You may also try to write a version of the code which prints out the ENGLISH NAMES for the numbers with each application of the transformation function. The original input is still numeric, but the output lines should have the word form of the number.

I'm considering these a separate category for bonus competition with regard to the challenge, so if you go for this, don't worry about your code being longer than the numeric version.

Feel free to submit one solution for each version.




Demize

Replies are listed 'Best First'.
Re: Code Golf: Four is magic
by duelafn (Parson) on Jul 13, 2010 at 03:45 UTC

    Well, I'm not much of a golfer, but here is a proof of concept (at a whopping 258 strokes) that goes up to 999 nonillion... using spelling in Lingua::EN::Numbers (limiting to 0..99 is too boring)

    # Update: 222 strokes by using a bareword and (for the fun of it) supp +ort up to undecillion 10^36 (costs no extra chars due to bareword tri +ck) for f in 0 4 12 99 1024 1000024 999999999999999999999999999999999; do +echo $f | \ perl -E'@x=a33544355436688779880066555766=~/./g;$_=<>;chop;while(($a=$ +_)-4){split//,b999aabb87780;$x=4*!$_;$x+=hex(pop@_)*!!-$&+!!$1*($x[$1 +]+7)+$x[$2+20]+$x[$3]while s/(.??)([^1]?)(1?.)$//;say"$a is $x.";$_=$ +x}say"4 is magic."' ; \ echo; done # Update: 224 strokes by including the suggested =~/./g shortcut and m +oving output around a bit perl -E'@x="033544355436688779880066555766"=~/./g;$_=<>;chop;while(($a +=$_)-4){split//,"99aabb87780";$x=4*!$_;$x+=hex(pop@_)*!!-$&+!!$1*($x[ +$1]+7)+$x[$2+20]+$x[$3]while s/(.??)([^1]?)(1?.)$//;say"$a is $x.";$_ +=$x}say"4 is magic."' # Update: 229 strokes by moving some conditionals into the regex perl -E'@x=split//,"033544355436688779880066555766";$_=<>;chop;print;w +hile($_-4){split//,"99aabb87780";$x=4*!$_;$x+=hex(pop@_)*!!-$&+!!$1*( +$x[$1]+7)+$x[$2+20]+$x[$3]while s/(.??)([^1]?)(1?.)$//;say" is $x.";p +rint$_=$x}say" is magic."' # Update: Ah, ha! 239 strokes: !!-$& will do it perl -E'@x=split//,"0335443554366887798866555766";$_=<>;chop;print;whi +le($_-4){split//,"99aabb87780";$x=4*!$_;$x+=hex(pop@_)*!!-$&+!!$1*($x +[$1]+7)+($2>1?$x[$2+18]+$x[$3]:$x[$2.$3])while s/(.??)(.?)(.)$//;say" + is $x.";print$_=$x}say" is magic."' # Update: 242 strokes, and works :), stealing some ideas from haarg & +thundergnat perl -E'@x=split//,"0335443554366887798866555766";$_=<>;chop;print;whi +le($_-4){split//,"99aabb87780";$x=4*!$_;$x+=hex(pop@_)*!!(0+$&)+!!$1* +($x[$1]+7)+($2>1?$x[$2+18]+$x[$3]:$x[$2.$3])while s/(.??)(.?)(.)$//;s +ay" is $x.";print$_=$x}say" is magic."' # Update: Down to 258 strokes perl -E'@x=split//,"0335443554366887798866555766";$_=<>;chop;print;whi +le($_!=4){split//,"99aabb87780";$_?do{$x=0;while(s/(.??)(.?)(.)$//){$ +x+=hex(pop@_)*(0+$&?1:0)+($1?$x[$1]+7:0)+($2>1?$x[$2+18]+$x[$3]:$x[$2 +.$3])}}:($x=4);say" is $x.";print$_=$x}say" is magic."' # 261 strokes: perl -E'@x=split//,"0335443554366887798866555766";$_=<>;chop;print;whi +le($_!=4){@m=split//,"99aabb87780";$_?do{$x=0;while(s/(.??)(.?)(.)$// +){$x+=hex(pop@m)*(0+$&?1:0)+($1?$x[$1]+7:0)+($2>1?$x[$2+18]+$x[$3]:$x +[$2.$3])}}:($x=4);say" is $x.";print$_=$x}say" is magic."' 999999999999999999999999999999999 is 321. 321 is 21. 21 is 9. 9 is 4. 4 is magic.

    Good Day,
        Dean

      A couple small improvements:
      perl -E'@x=split//,"0335443554366887798866555766";$_+=<>;print;while($ +_!=4){split//,"99aabb87780";$_?do{$x=0;$x+=hex(pop)*!!$&+($1&&$x[$1]+ +7)+($2>1?$x[$2+18]+$x[$3]:$x[$2.$3])while s/(.??)(.?)(.)$//}:($x=4);s +ay" is $x.";print$_=$x}say" is magic."'

        That actually has problems with large numbers (> native integer ?) Once it gets over 64 bits on my machine it converts to scientific notation... which throws off the conversion.

        Never mind. Broken

        Here's my whack at it - 232 strokes

        perl -E'@x=split//,"4335443554366887798866555766";$_=<>;chop;print;whi +le($_-4){split//,"99aabb87780";$x=0;$x+=hex(pop)*!!$&+($1&&$x[$1]+7)+ +($2>1?$x[$2+18]+$x[$3]:$x[$2.$3])while s/(.??)(.?)(.)$//;say" is $x." +;print$_=$x}say" is magic."' __END__ 999999999999999999999999999999999 999999999999999999999999999999999 is 231. 231 is 19. 19 is 8. 8 is 5. 5 is 4. 4 is magic.

      A modest improvement on your 229:
      227 strokes

      perl -E'@x="033544355436688779880066555766"=~/./g;$_=<>;chop;print;whi +le($_-4){split//,"99aabb87780";$x=4*!$_;$x+=hex(pop@_)*!!-$&+!!$1*($x +[$1]+7)+$x[$2+20]+$x[$3]while s/(.??)([^1]?)(1?.)$//;say" is $x.";pri +nt$_=$x}say" is magic."'
Re: Code Golf: Four is magic
by Limbic~Region (Chancellor) on Jul 13, 2010 at 00:09 UTC
    deMize,
    I know you are intentionally limiting input from 0 .. 99 to avoid ambiguity in the spelling of larger numbers. On the other hand, if you decided on a standard You could extend the challenge to golfing the implementation of the spelling AND the 4 is magic.

    Cheers - L~R

      I should say, that I this is not my puzzle. I merely copy/pasted it from the embedded link. I take no credit for this, despite how fun it is to do.

      So far what we came up with is 139 chars:
      @u=split'','4335043554366887798866555766';$_=<>;chop;print"$_ is ".($_=$_<20?$u[$_]:$u[$_/10+18]+($_%10?$u[$_%10]:0)or"magic").".\n"while$_
      depending on the rules of golf '\n' could be substituted for an actual linebreak.


      Demize
Re: Code Golf: Four is magic
by thundergnat (Deacon) on Jul 14, 2010 at 16:53 UTC

    Update: 122 Just realized that there is no requirement to output to STDOUT, so output to STDERR instead and knock off another character.

    #234567890123456789012345678901234567890123456789012345678901234567890 +1234567890123456789012345678901234567890123456789012 @u="0335443554366887798866555766"=~/./g;$_+=<>;warn"$_ is ",$_=$_-4?$_ +<20?$u[$_]||4:$u[chop]+$u[$_+18]:magic,".\n"until/a/

    Update: 123

    #234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123 @u='0335443554366887798866555766'=~/./g;$_+=<>;print"$_ is ",$_=$_-4?$ +_<20?$u[$_]||4:$u[chop]+$u[$_+18]:magic,".\n"until/a/

    121 124 strokes

    Update 2 Whoops. Broken for zero. Add three strokes.

    # 12345678901234567890123456789012345678901234567890123456789012345 +67890123456789012345678901234567890123456789012345678901234 perl -E'@u="0335443554366887798866555766"=~/./g;$_+=<>;say"$_ is ",$_= +$_-4?$_<20?$u[$_]||4:$u[chop]+$u[18+$_]:magic,"."while/\d/'

    or alternately, also 124 strokes:

    #234567890123456789012345678901234567890123456789012345678901234567890 +123456789012345678901234567890123456789012345678901234 @u='0335443554366887798866555766'=~/./g;$_=pop;print"$_ is ",$_=$_-4?$ +_<20?$u[$_]||4:$u[chop]+$u[$_+18]:magic,".\n"until/\D/

    Updated: Argh. posted wrong (broken) version. Try again.

    # 12345678901234567890123456789012345678901234567890123456789012345 +67890123456789012345678901234567890123456789012345678901 perl -E'@u="0335443554366887798866555766"=~/./g;$_+=<>;say"$_ is ",$_= +$_-4?$_<20?$u[$_]:$u[chop]+$u[18+$_]:magic,"."while/\d/'

    or alternately, also 121 strokes:

    #234567890123456789012345678901234567890123456789012345678901234567890 +123456789012345678901234567890123456789012345678901 @u='0335443554366887798866555766'=~/./g;$_=pop;print"$_ is ",$_=$_-4?$ +_<20?$u[$_]:$u[chop]+$u[$_+18]:magic,".\n"until/\D/
Re: Code Golf: Four is magic
by deMize (Monk) on Jul 14, 2010 at 02:22 UTC
    144 chars:
    @u=split//,'4335443554366887798866555766';$_=<>;chop;print"$_ is ".($_=$_-4?$_<20?$u[$_]:$u[$_/10+18]+($_%10&&$u[$_%10]):0or magic).".\n"while$_


    Demize
      125 chars:
      @u='4335443554366887798866555766'=~/./g;$_=pop;print"$_ is ",$_=$_-4?$_<20?$u[$_]:$u[$_/10+18]+$u[$_%10]:magic,".\n"until/\D/


      Demize

        That is broken for 30, 40, 50, etc.

Re: Code Golf: Four is magic
by TedPride (Priest) on Jul 15, 2010 at 06:32 UTC
    @d=split//,'4335443554366887798866555766';$n=int<STDIN>;while($n!=4){p +rint"$n is ";$n=$n<20?$d[$n]:$d[$n/10+18]+($n%10==0?0:$d[$n%10]);prin +t"$n.\n";}print"4 is magic.\n";
    125 characters, or 123 if you eliminate that last line break. Looks remarkably like some of the other submissions here, but I didn't cheat and look at anyone else's solutions first - guess there just aren't many ways to do this while keeping it short.
Re: Code Golf: Four is magic
by thundergnat (Deacon) on Jul 15, 2010 at 13:56 UTC

    A version that returns the English names of the input 1-2 digit number.

    Update: Hmmm. I just noticed on the stackoverflow page that they clarified that the numbers should be spelled out in both the left AND right columns. Phooey.

    Another update: And now there's some further stipulation that there be a separator(space, hyphen, whatever) between spelled words and the input number must come in through STDIN, not as a passed parameter, so no pop @ARGV.

    Update: 283

    @p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);@n=("\x8",One,Two,Three,Four,Fi +ve,@p[3..6],Ten,Eleven,Twelve,map$_.teen,@p);s/u//for@m=map$_.ty,Twen +,@p;$n[8].=t;sub n{$n=shift;$n?$n<20?$n[$n]:"$m[$n/10-2]-$n[$n%10]":Z +ero}$p+=<>;warn$m=n($p)," is ",$_=$p-4?n$p=()=$m=~/\w/g:magic,".\n"un +til/c/
    0
    Zero is Four.
    Four is magic.
    
    40
    Forty is Five.
    Five is Four.
    Four is magic.
    
    67
    Sixty-Seven is Ten.
    Ten is Three.
    Three is Five.
    Five is Four.
    Four is magic.
    
    83
    Eighty-Three is Eleven.
    Eleven is Six.
    Six is Three.
    Three is Five.
    Five is Four.
    Four is magic.
    
    

    ##### Versions that don't spell out right column. #####

    Update:Sigh. Apparently I'm blind. Using duelafns suggestion, modifying the end conditional and some other minor tweaks.

    256

    @p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);@n=("",One,Two,Three,Four,Five, +@p[3..6],Ten,Eleven,Twelve,map($_.teen,@p),map$_.ty,Twen,@p);$n[22]=~ +s/u//;$n[8].=t;$_+=<>;print$z=$_?$_<20?$n[$_]:$n[$_/10+18].$n[$_%10]: +Zero," is ",$_=$_-4?length$z:magic,".\n"until/a/

    or

    perl -E'@p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);@n=("",One,Two,Three,Fo +ur,Five,@p[3..6],Ten,Eleven,Twelve,map($_.teen,@p),map$_.ty,Twen,@p); +$n[22]=~s/u//;$n[8].=t;$_+=<>;say$z=$_?$_<20?$n[$_]:$n[$_/10+18].$n[$ +_%10]:Zero," is ",$_=$_-4?length$z:magic,"."until/a/'

    Previous versions

    Proof of concept. Should be lots of room for improvement.

    Update: whoops. Fixed for fourteen/forty. Curse you, irregular number names!

    384 strokes.

    @u='0335443554366887798866555766'=~/./g;sub n{shift;@p=(qw/thir four f +if six seven eigh nine/);@n=('',qw/one two three four five/,@p[3..6], +qw/ten eleven twelve/);push@n,$_.'teen'for@p;push@n,'twenty',;push@n, +$_.'ty'for@p;$n[8].='t';$n[22]=~s/u//;$t=$_?$_<20?$n[$_]:$n[$_/10+18] +.$n[$_%10]:'zero'}$_=pop;print n($_)," is ",$_=$_-4?$_<20?$u[$_]||4:$ +u[chop]+$u[18+$_]:magic,".\n"while/\d/
    C:\test>magic.pl 0
    zero is 4.
    four is magic.
    
    C:\test>magic.pl 1
    one is 3.
    three is 5.
    five is 4.
    four is magic.
    
    C:\test>magic.pl 14
    fourteen is 8.
    eight is 5.
    five is 4.
    four is magic.
    
    C:\test>magic.pl 15
    fifteen is 7.
    seven is 5.
    five is 4.
    four is magic.
    
    C:\test>magic.pl 18
    eighteen is 8.
    eight is 5.
    five is 4.
    four is magic.
    
    C:\test>magic.pl 44
    fortyfour is 9.
    nine is 4.
    four is magic.
    
    C:\test>magic.pl 77
    seventyseven is 12.
    twelve is 6.
    six is 3.
    three is 5.
    five is 4.
    four is magic.
    
    C:\test>magic.pl 80
    eighty is 6.
    six is 3.
    three is 5.
    five is 4.
    four is magic.
    
    C:\test>magic.pl 99
    ninetynine is 10.
    ten is 3.
    three is 5.
    five is 4.
    four is magic.
    

      So, um, what's @u still doing in there? :)

      Update: Removing @u, using do{} instead of a sub, and applying the "say" cheat gives 261 260 (until/m/) strokes

      #123456789 123456789 123456789 123456789 123456789 123456789 12345 +6789 123456789 123456789 123456789_123456789 123456789 123456789 1234 +56789 123456789 123456789 123456789 123456789 123456789 123456789_123 +456789 123456789 123456789 123456789 123456789 123456789 for f in 0 4 12 99; do perl -E'$_=pop;say$z=do{@p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);@n=("", +One,Two,Three,Four,Five,@p[3..6],Ten,Eleven,Twelve,map($_.teen,@p),ma +p$_.ty,Twen,@p);$n[22]=~s/u//;$n[8].=t;$_?$_<20?$n[$_]:$n[$_/10+18].$ +n[$_%10]:Zero}," is ",$_=$_-4?length$z:magic,"."until/m/' $f ; \ echo; done

      Good Day,
          Dean

        Ummm........ Wasting about 30 strokes? Apparently I have very selective blindness...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://849126]
Approved by BrowserUk
Front-paged by Limbic~Region
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (11)
As of 2024-03-28 09:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found