# Four is the magic number

I didn't check the sandbox before posting this challenge - it looks like this challenge was proposed by Cᴏɴᴏʀ O'Bʀɪᴇɴ.

Given an integer input, write a program that prints the "four is a magic number" riddle

• Four is the magic number
• Five is four and four is the magic number
• Six is three and three is five and five is four and four is the magic number
• Eleven is six and six is three and three is five and five is four and four is the magic number
• Five Hundred is eleven and eleven is six and six is three and three is five and five is four and four is the magic number

If you already know the riddle, or are too lazy to solve it anxious to find out what the riddle is, here's an explanation

The next number is the number of letters in the previous number. So, for example, five has four letters, so the next number is four.

six has three letters, so the next number is 3, and three has five letters, so the next number is 5, and five has four letters, so the next number is 4

The reason the riddle ends at four is because four has four letters, and four is four and four is four and four is four... (four is the magic number)

## Test Cases

0 =>
Zero is four and four is the magic number
1 =>
One is three and three is five and five is four and four is the magic number
2 =>
Two is three and three is five and five is four and four is the magic number
3 =>
Three is five and five is four and four is the magic number
4 =>
Four is the magic number
5 =>
Five is four and four is the magic number
6 =>
Six is three and three is five and five is four and four is the magic number
7 =>
Seven is five and five is four and four is the magic number
8 =>
Eight is five and five is four and four is the magic number
9 =>
Nine is four and four is the magic number
10 =>
Ten is three and three is five and five is four and four is the magic number
17 =>
Seventeen is nine and nine is four and four is the magic number
100 =>
One Hundred is ten and ten is three and three is five and five is four and four is the magic number
142 =>
One Hundred Forty Two is eighteen and eighteen is eight and eight is five and five is four and four is the magic number
1,000 =>
One Thousand is eleven and eleven is six and six is three and three is five and five is four and four is the magic number
1,642 =>
One Thousand Six Hundred Forty Two is twenty nine and twenty nine is ten and ten is three and three is five and five is four and four is the magic number
70,000 =>
Seventy Thousand is fifteen and fifteen is seven and seven is five and five is four and four is the magic number
131,072 =>
One Hundred Thirty One Thousand Seventy Two is thirty seven and thirty seven is eleven and eleven is six and six is three and three is five and five is four and four is the magic number
999,999 =>
Nine Hundred Ninety Nine Thousand Nine Hundred Ninety Nine is fifty and fifty is five and five is four and four is the magic number


## Rules

• The input may either be taken from STDIN or as an argument to a function
• The input will be a positive number between 0 and 999,999
• The input will only contain numbers (it will follow the regex ^[0-9]+) • The input can either be taken as an integer or a string • When converted to a word string, spaces and hyphens should not be included in the count (100 [One Hundred] is 10 characters, not 11. 1,742 [One thousand Seven hundred Forty-Two] is 31 characters, not 36) • When converted to a string, 100 should be One Hundred, not A Hundred or Hundred, 1000 should be One Thousand, not A Thousand or Thousand. • When converted to a string 142 should be One Hundred Forty Two, not One Hundred and Forty Two • The output is case-insensitive, and should follow the format "N is K and K is M and M is ... and four is the magic number" (unless the input is 4, in which case the output should simply be "four is the magic number") • The output can use numbers instead of letters ("5 is 4 and 4 is the magic number" instead of "five is four and four is the magic number") as long as your program is always consistent • The output can either be the return value of a function, or printed to STDOUT • Standard loopholes apply • This is , so the shortest program in bytes wins. Good luck! ## Bonus -30 bytes if the program works when the input is between -999,999 and 999,999. Negative numbers, when converted to words, just have "negative" in front of them. For example -4 is "Negative Four", Negative Four is twelve and twelve is six and six is three and three is five and five is four and four is the magic number -150 bytes if the program does not use any built-in functions for generating the string representation of the number ## Leaderboard This is a Stack Snippet that generates both a leaderboard and an overview of winners by language. To ensure your answer shows up, please start your answer with a headline using the following Markdown template ## Language Name, N bytes  Where N is the size, in bytes, of your submission If you want to include multiple numbers in your header (for example, striking through old scores, or including flags in the byte count), just make sure that the actual score is the last number in your header ## Language Name, <s>K</s> X + 2 = N bytes  var QUESTION_ID=67344;var OVERRIDE_USER=20634;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a,language:a,link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(-?\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i; body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px} <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> • Is there a maximum possible input? – Arcturus Dec 22 '15 at 4:57 • In the future, please also check the Sandbox to see if someone else had your idea. – El'endia Starman Dec 22 '15 at 5:23 • @El'endiaStarman Alright, I added some text at the top of the challenge linking to that post – Jojodmo Dec 22 '15 at 5:28 • Your built in function bonus should be more like -150 to -200 bytes. – TanMath Jan 2 '16 at 6:44 • I'm just gonna throw this out there - even the most insanely optimized number to name converters are barely going to cost less than 150 bytes for most languages, as it stands the -150 is more of a trap than a bonus. – ricdesi Mar 2 '16 at 21:16 ## 12 Answers ## Bash + common utilities (including bsd-games), 123 - 30 = 93 bytes for((n=1;n-4;n=m)){
m=number -l -- $n|sed 's/nus/&&/;s/\W//g' s+="$n is $[m=${#m}] and "
}
echo $s 4 is the magic number  Luckily the output from the bsd-games number utility is almost exactly what we need. Output numbers are all written numerically and not in words as per the 8th bullet point: $ ./4magic.sh 131072
131072 is 37 and 37 is 11 and 11 is 6 and 6 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
$./4magic.sh -4 -4 is 12 and 12 is 6 and 6 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number$


# C, 263 261 bytes - 180 = 81

char*i="jmmonnmoonmpprrqqsrrjjddeeecdd",x;f(n,c){return!n?n:n<0?f(-n,8):n<100?c+i[n<20?n:n%10]-i[20+n/10]:f(n/1000,8)+f(n/100%10,7)+f(n/100%10,0)+c;}main(int c,char**v){for(c=atoi(*++v);c-4;c=x)printf("%d is %d and ",c,x=c?f(c,0)):4;puts("4 is the magic number");}


Inspired by the answer from Cole Cameron. I thought I might be able to do better without the macro definition. Although I eventually managed, it did take some squeezing to achieve!

It requires a host character set with consecutive letters (so ASCII is okay, but EBCDIC won't work). That's for the pair of lookup tables. I chose j as the zero character, and took advantage of needing two lookups, so I could subtract one from the other rather than having to subtract my zero from both.

## Commented version:

char*i=
"jmmonnmoon"                /* 0 to 9 */
"mpprrqqsrr"                /* 10 to 19 */
"jjddeeecdd";               /* tens */
char x;                /* current letter count */

f(n,c){
return
!n?n                        /* zero - return 0 (ignore c) */
:n<0?f(-n,8)                /* negative n (only reached if c==0) */
:n<100?c+i[n<20?n:n%10]-i[20+n/10] /* lookup tables */
:
f(n/1000,8)               /* thousand */
+ f(n/100%10,7)             /* hundred */
+ f(n%100,0)                /* rest */
+ c;                        /* carry-in */
}
main(int c, char**v)
{
for(c=atoi(*++v);c-4;c=x)
printf("%d is %d and ",c,x=c?f(c,0):4);
puts("4 is the magic number");
}


There's an obvious extension to support millions, by replacing f(n/1000,8) with f(n/1000000,7)+f(n/1000%1000,8).

## Test output

0 is 4 and 4 is the magic number
1 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
2 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
3 is 5 and 5 is 4 and 4 is the magic number
4 is the magic number
5 is 4 and 4 is the magic number
6 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
7 is 5 and 5 is 4 and 4 is the magic number
8 is 5 and 5 is 4 and 4 is the magic number
9 is 4 and 4 is the magic number
10 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
17 is 9 and 9 is 4 and 4 is the magic number
100 is 10 and 10 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
142 is 18 and 18 is 8 and 8 is 5 and 5 is 4 and 4 is the magic number
1000 is 11 and 11 is 6 and 6 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
1642 is 29 and 29 is 10 and 10 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
70000 is 15 and 15 is 7 and 7 is 5 and 5 is 4 and 4 is the magic number
131072 is 37 and 37 is 11 and 11 is 6 and 6 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number
999999 is 50 and 50 is 5 and 5 is 4 and 4 is the magic number


## Mathematica, 156 - 30 = 126 bytes

a=ToString;({a@#," is ",a@#2," and "}&@@@Partition[NestWhileList[#~IntegerName~"Words"~StringCount~LetterCharacter&,#,#!=4&],2,1])<>"4 is the magic number"&


I'm simply surprised that this uses strings and isn't ridiculously long.

## Swift 2, 408 419 - 30 = 389 Bytes

I would be able to get rid of 176 bytes if it Swift wasn't so verbose with regular expressions (removing hyphens and spaces) *glares at Apple*

func c(var s:Int)->String{var r="";while(s != 4){r+="\(s)";let f=NSNumberFormatter();f.numberStyle=NSNumberFormatterStyle.SpellOutStyle;let v=f.stringFromNumber(s)!;s=v.stringByReplacingOccurrencesOfString("[- ]",withString:"",options:NSStringCompareOptions.RegularExpressionSearch,range:Range<String.Index>(start:v.startIndex,end:v.endIndex)).utf8.count+(s<0 ?3:0);r+=" is \(s) and "};return r+"4 is the magic number"}


This can be tested on swiftstub.com, here

I ran a little for loop, and it turns out that 100003 is the number between 0 and 999999 has the longest string result, which has 6 iterations, and is

100003 is 23 and 23 is 11 and 11 is 6 and 6 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number

### Ungolfed

func a(var s: Int) -> String{
var r = ""
while(s != 4){
r+="\(s)"

let f = NSNumberFormatter()
f.numberStyle = NSNumberFormatterStyle.SpellOutStyle
let v = f.stringFromNumber(s)!
s = v.stringByReplacingOccurrencesOfString(
"[- ]",
withString: "",
options: NSStringCompareOptions.RegularExpressionSearch,
range: Range<String.Index>(start: v.startIndex, end: v.endIndex)
).utf8.count + (s < 0 ? 3 : 0)

r+=" is \(s) and "
}
return r+"4 is the magic number"
}

• NSStringCompareOptions.RegularExpressionSearch And I thought JS's String.fromCharCode was verbose. :P – ETHproductions Dec 22 '15 at 19:53
• Python and Ruby: string.replace. Swift: String.stringByReplacingOccurrencesOfString – cat Dec 26 '15 at 5:16

# Haskell, 285 - 180 = 105 Bytes

In fact, there is no built-in at all for displaying number. I still dissatisfied with the score. Feel free to comment. I will experiment further, though. Still the score is better than Swift's score

c n|n<0=8+c(-n)|n>999=r 1000+8|n>99=7+r 100|n>19=r 10+2-g[30..59]+g[20..29]|n>15=r 10-1|2>1=[0,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7]!!n where{g=fromEnum.elem n;r k=c(mod n k)+c(div n k)}
m 4="4 is the magic number"
m 0="0 is 4 and "++m 4
m n=show n++" is "++show(c n)++" and "++m(c n)


usage

m 7
"7 is 5 and 5 is 4 and 4 is the magic number"
m 999999
"999999 is 50 and 50 is 5 and 5 is 4 and 4 is the magic number"


Explanation.

m is trivial enough, however, the c is not. c is the function to count the number of character the english name of number.

c n |n<0=8+c(-n) -- Add word "negative" in front of it, the length is 8
|n>999=r 1000+8 -- the english name for number with form xxx,yyy is xxx thousand yyy
|n>99=7+r 100 -- the english name for number with form xyy is x hundred yy
|n>19=r 10+2-g[30..59]+g[20..29] -- the english name for number with form xy with x more
-- than 1 is x-ty. However *twoty>twenty,
-- *threety>thirty, *fourty>forty, *fivety>fifty.
|n>10=r 10-1-g(15:18:[11..13]) -- the english name for number with form 1x is x-teen.
-- However, *oneteen>eleven, *twoteen>twelve,
-- *threeteen>thirteen, *fiveteen>fifteen,
-- *eightteen>eighteen
|2>1=[0,3,3,5,4,4,3,5,5,4,3]!!n -- for number 0-10, the length is memorized. 0 is 0
-- because it is omitted. Input zero is handled
-- separately. If we defined 0 to be 4, then
-- 20 => twenty zero.
where g   =fromEnum.elem n      -- Check if n is element of argument array, if true, 1 else 0
r k=c(mod n k)+c(div n k) -- Obvious.

• Oh yea? Well, Swift has... uhm... a higher score... (I'm not very good at comebacks) – Jojodmo Dec 31 '15 at 21:36

# C, 268 - 180 = 88 bytes

#define t(x,o)n<x?o:f(n/x)+(n%x?f(n%x):0)
char*i="4335443554366887798866555766";f(n){return t(1000,t(100,n<20?n<0?8+f(-n):i[n]-48:i[n/10+18]-48+(n%10?f(n%10):0))+7)+8;}main(n){for(scanf("%d",&n);n^4;n=f(n))printf("%d is %d and ",n,f(n));puts("4 is the magic number");}


Try it here.

## Ungolfed

/* Encode number length in string (shorter representation than array) */
char*i="4335443554366887798866555766";

f(n)
{
return n < 1000
? n < 100
? n < 20
? n < 0
? 8 + f(-n) /* "Negative x" */
: i[n] - 48 /* "x" */
: i[n/10+18] + (n%10 ? f(n%10) : 0) /* 20-99 */
: f(n/100) + (n%100 ? f(n%100) : 0) + 7 /* x hundred y */
: f(n/1000) + (n%1000 ? f(n%1000) : 0) + 8; /* x thousand y */
}

main(n)
{
/* Keep printing until you get to the magic number */
for(scanf("%d",&n);n^4;n=f(n))
printf("%d is %d and ",n,f(n));
puts("4 is the magic number");
}


## Java, 800 - 150 = 650 bytes

class G{static String e="",i="teen",j="ty",k="eigh",y="thir",d="zero",l="one",n="two",m="three",h="four",s="five",c="six",t="seven",b=k+"t",g="nine",D="ten",L="eleven",N="twelve",M=y+i,H=h+i,S="fif"+i,C=c+i,T=t+i,B=k+i,G=g+i,o="twen"+j,p=y+j,q="for"+j,r="fif"+j,u=c+j,v=t+j,w=k+j,x=g+j,A=" ",O=" hundred ",z,E;public static void main(String a[]){z=e;int l=new Integer(a);do{E=a(l,1,e);l=E.replace(A,e).length();z=z+E+" is "+a(l,1,e)+" and ";}while(l!=4);System.out.print(z+h+" is the magic number");}static String a(int P,int _,String Q){String[]f={e,l,n,m,h,s,c,t,b,g,D,L,N,M,H,S,C,T,B,G,e,D,o,p,q,r,u,v,w,x};int R=20,X=10,Y=100,Z=1000;return P==0?(_>0?d:e):(P<R?f[P]+Q:(P<Y?(f[R+(P/X)]+" "+a(P%X,0,e)).trim()+Q:(P<Z?a(P/Y,0,O)+a(P%Y,0,e)+Q:a(P/Z,0," thousand ")+a((P/Y)%X,0,O)+a(P%Y,0,e)+Q)));}}


### De-golfed

class G {

static String e="",i="teen",j="ty",k="eigh",y="thir",d="zero",l="one",n="two",m="three",h="four",s="five",c="six",t="seven",b=k+"t",g="nine",D="ten",L="eleven",N="twelve",M=y+i,H=h+i,S="fif"+i,C=c+i,T=t+i,B=k+i,G=g+i,o="twen"+j,p=y+j,q="for"+j,r="fif"+j,u=c+j,v=t+j,w=k+j,x=g+j,A=" ",O=" hundred ",z,E;

public static void main(String a[]){
z = e;
int l = new Integer(a);
do {
E = a(l,1,e);
l = E.replace(A,e).length();
z = z+E+" is "+a(l,1,e)+" and ";
} while(l!=4);
System.out.println(z+h+" is the magic number");
}

static String a(int P,int _,String Q) {
String[] f = {e,l,n,m,h,s,c,t,b,g,D,L,N,M,H,S,C,T,B,G,e,D,o,p,q,r,u,v,w,x};
int R=20,X=10,Y=100,Z=1000;
return P==0?(_>0?d:e):(P<R?f[P]+Q:(P<Y?(f[R+(P/X)]+" "+a(P%X,0,e)).trim()+Q:(P<Z?a(P/Y,0,O)+a(P%Y,0,e)+Q:a(P/Z,0," thousand ")+ a((P/Y)%X,0,O)+a(P%Y,0,e)+Q)));
}
}

• I know it's been more than a year, but you can remove some parenthesis in that ternary assignment as well as change ==0 to <1. So: return P<1?_>0?d:e:P<R?f[P]+Q:P<Y?(f[R+(P/X)]+" "+a(P%X,0,e)).trim()+Q:P<Z?a(P/Y,0,O)+a(P%Y,0,e)+Q:a(P/Z,0," thousand ")+a((P/Y)%X,0,O)+a(P%Y,0,e)+Q; (- 10 bytes) – Kevin Cruijssen Feb 22 '17 at 14:20

## QC, 265 - 30 - 150 = 85 bytes

(✵1:oaT%=ta100%=ha100/⌋T%=X[0 3 3 5 4 4 3 5 5 4 3 6 6 8 8 7 7 9 8 8]=Y[6 6 5 5 5 7 6 6]=a0≟4a20<Xt☌YtT/⌋2-☌Xo☌+▲▲hXh☌7+0▲+)(❆1:na0<8*=ba‖1000/⌋=ca1000%=nbb✵8+0▲a✵++){I4≠:EEI" is "++=II❆=EEI" and "++=E!}E"4 is the magic number"+


Test suite

Ungolfed:

(✵1:
oaT%=                                        # ones
ta100%=                                      # tens
ha100/⌋T%=                                   # hundreds
X[0 3 3 5 4 4 3 5 5 4 3 6 6 8 8 7 7 9 8 8]=  # length of "zero", "one", "two", ..., "nineteen"
Y[6 6 5 5 5 7 6 6]=                          # length of "twenty", ..., "ninety"
a0≟
4
a20<
Xt☌
YtT/⌋2-☌ Xo☌ +
▲
▲
hXh☌7+0▲+)

(❆1:
na0<8*=                 # if negative, add 8
ba‖1000/⌋=              # split aaaaaa into bbbccc
ca1000%=
n bb✵8+0▲ a✵ ++)

{I4≠:EEI" is "++=II❆=EEI" and "++=E!}E"4 is the magic number"+

• If you're not using a built-in function for getting the length of the number, so you can actually subtract another 150 from your score – Jojodmo Jan 7 '16 at 15:18

## JavaScript, 382 - 150 - 30 = 202 bytes

var o=[0,3,3,5,4,4,3,5,5,4],f=s=>(s==1?[3,6,6,8,8,7,7,9,8,8][s]:o[s]+(s.length>1?[0,3,6,6,5,5,5,7,6,6][s]:0))+(s.length==3?(7+o[s]-(o[s]==0?7:0)):0),l=n=>{var s=(""+n).split("").reverse();return f(s.slice(0,3))+(s.length>3?(f(s.slice(3,6))+8):0)};(n=>{var s="";while(n!=4){s+=n+" is ";n=n>=0?l(n):(l(-n)+8);s+=n+" and ";}console.log(s+"4 is the magic number");})()


The input is given as the parameter to the Immediately-Invoked Function Expression.

Test input:

999999 ->
999999 is 50 and 50 is 5 and 5 is 4 and 4 is the magic number
17 ->
17  is 9 and 9 is 4 and 4 is the magic number
-404 ->
-404 is 23 and 23 is 11 and 11 is 6 and 6 is 3 and 3 is 5 and 5 is 4 and 4 is the magic number


De-golfed:

// array of the lengths of digits in ones place:
// one is 3, two is 3, three is 5, etc... zero is a special case
// and is assigned zero length because zero is never written out in a number name
var o=[0,3,3,5,4,4,3,5,5,4],

// function that computes the length of a substring of the input
// because the input is 6 digits, it can be broken into two 3 digit subsections
// each of which can have it's length calculated separately
f=s=>
(
s==1? // check for if the tens digit is a one
// when the tens is a one, pull the string length from an array that represents
// ten, eleven, twelve, thirteen, etc...
[3,6,6,8,8,7,7,9,8,8][s]
:
// when the tens digit is not a one, add the ones digit normally and...
o[s]
+
// add the tens digit length from the array that represents
// zero, ten, twenty, thirty, forty, fifty, sixty, seventy, eighty, ninety
(s.length>1?[0,3,6,6,5,5,5,7,6,6][s]:0)
)
+
(
s.length==3? // check if the length is 3 and weren't not accidentally trying to do something wierd with a minus sign
// if so, then we have to add a hundred (7 characters) to the length and the
// length of the ones digit that is in the hundreds place like
// 'one' hundred or 'two' hundred
(7+o[s]-
(
// also, if the hundreds place was a zero, subtract out those 7 characters
// that were added because 'hundred' isn't added if there's a zero in its
// place
o[s]==0?
7
:
0
)
)
:
// if the length wasn't 3, then don't add anything for the hundred
0
),

// function that computes the length of the whole six digit number
l=n=>{
// coerce the number into a string and then reverse the string so that the
// ones digit is the zeroth element instead of last element
var s=(""+n).split("").reverse();
return
// calculate the character length of the first 3 characters
// like in the number 999888, this does the '888'
f(s.slice(0,3))
+
// then if there actually are any characters after the first 3
(s.length>3?
// parse the character length of the second 3 characters
(f(s.slice(3,6))+8)
:
0
)
};
// lastly is the Immediately-Invoked Function Expression
(n=>{
var s="";
// as long as we haven't reached four, just keep going through the loop
while(n!=4){
s+=n+" is ";
n=n>=0?l(n):(l(-n)+8) // this handles negatives by only passing positive values to l and then just adding 8 onto the length for negatives
s+=n+" and ";
}
// finally just say that '4 is the magic number'
console.log(s+"4 is the magic number");
})(999999)


# Python 641-150 = 501 bytes

At least it isn't longer than Java! It is based on this except using strings.

EDIT: I forgot about 0 and that I need to say "5 is 4", not skip to "4 is the magic number" - that added a bit to the score.

w={0:"zero",1:"one",2:"two",3:"three",4:"four",5:"five",6:"six",7:"seven",8:"eight",9:"nine",10:"ten",11:"eleven",12:"twelve",13:"thirteen",14:"fourteen",15:"fifteen",16:"sixteen",17:"seventeen",18:"eighteen",19:"nineteen",20:"twenty",30:"thirty",40:"forty",50:"fifty",60:"sixty",70:"seventy",80:"eighty",90:"ninety"}
s=""
def i(n):
global s
e=""
o=n%10
t=n%100
h=n/100%10
th=n/1000
if th:
e+=i(th)
e+='thousand'
if h:
e+=w[h]
e+='hundred'
if t:
if t<20 or o==0:
e+=w[t]
else:
e+=w[t-o]
e+=w[o]
if len(e)==4:s+="4 is the magic number";print s
else: s+="%d is %d and "%(n,len(e));i(len(e))
In=input()
i(In)


Try it here!

• You don't have to display the name, right? – Akangka Jan 4 '16 at 12:00
• This is incorrect. i(5) prints 4 is the magic number, instead of 5 is 4 and 4 is the magic number. – mbomb007 Mar 2 '16 at 19:54

# Moo, 182 176/192 188 bytes - 30 = 146/158

188 byte version:

u=$string_utils;s="";i=args;while(i-4)j=u:english_number(i);s=s+j+(s?" and "+j|"")+" is ";i=length(u:strip_chars(j,"- "}));endwhile;return s+(s?"four and "|"")+"four is the magic number"  176 byte implementation-dependent version: s="";i=args;while(i-4)j=#20:english_number(i);s=s+j+(s?" and "+j|"")+" is ";i=length(#20:strip_chars(j," -"));endwhile;return s+(s?"four and "|"")+"four is the magic number"  Both are functions. ## PHP, 168 - 30 = 138 bytes function m($i){$e=strlen(preg_replace('/[^a-z-]/','',(new NumberFormatter("en",5))->format($i)));echo($i==$e?"":"$i is$e and "),($e==4?"4 is the magic number":m($e));}