Distance to four

13

1

This challenge is based on this video. I recommend that you watch it before trying this challenge.

First we define a function. This function (OEIS) takes a integer n as input and outputs the number of letters in the English representation of n (without spaces or hyphens). For example "three" has 5 letters so 3 maps to 5.

As demonstrated in the video starting with any number repeating this process will eventually result in a four, which will map to itself forever.

Here is a crude directed graph showing the orbits of the numbers less than 16:

  12 11
    \|      
15 2 6 1 10 14 13
  \ \|/ /  /  /
   7 3-/  8--/
    \|   /
 9 0 5--/
  \ \|
   \-4

Your challenge is to determine the number of steps that a number will take (or the number of times this function must be applied to a number) before reaching four (i.e. the level on the directed graph pictured).

Forming english numbers

Here is a brief explanation of how one should form english words for this challenge:

The numbers one through nineteen are:

one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen

For numbers greater than nineteen the process is as follows:

If the number has a hundreds place begin with the name of digit in the hundreds place and "hundred".

e.g.

100 -> "onehundred"

If the remainder is less than twenty append the remainder's English representation.

e.g.

714 -> "sevenhundredfourteen"

Otherwise if the tens digit is not zero append the proper representation:

2-> twenty
3-> thirty
4-> forty
5-> fifty
6-> sixty
7-> seventy
8-> eighty
9-> ninety

e.g.

470 -> "fourhundredseventy"

Finally if there is a one's digit append its representation

e.g.

681 -> "sixhundredeightyone"

Further Stipulations

  • For numbers greater than one hundred you should leave out the "and" when counting the number of letters. For instance 577 is "fivehundredseventyseven" which has 23 letters.

  • Your program must accept all integers greater than 0 and less than 1,000 as input via standard methods.

  • Your program must output the number of steps required to standard output methods.

  • This is codegolf so the solution with the fewest bytes wins.

Test cases

1 -> 3
4 -> 0
7 -> 2
23 -> 5
577 -> 6
600 -> 4 

Post Rock Garf Hunter

Posted 2016-09-10T16:44:39.500

Reputation: 55 382

1Related I thought this was a dupe, but I can't find it. – James – 2016-09-10T16:51:04.073

What happened to "and"? Or rather, why leave out and?! – Jonathan Allan – 2016-09-10T19:17:06.973

@JonathanAllan cuz 'Murica – LegionMammal978 – 2016-09-10T20:18:07.747

Answers

5

JavaScript (ES6), 106 bytes

f=(n,a="03354435543668877998")=>n-4&&1+f(7*(n>99)-(-a[n/100|0]-(a[n%=100]||a[n%10])-"0066555766"[n/10|0]))

Strings seem to be the best way to encode the length, despite the numeric conversion overhead.

Neil

Posted 2016-09-10T16:44:39.500

Reputation: 95 035

Gosh, that's almost exactly what my (nearly-posted) answer looked like, only 11 bytes shorter. – ETHproductions – 2016-09-10T21:10:46.010

@ETHproductions Good thing I golfed 16 bytes off before posting it then! – Neil – 2016-09-10T21:53:59.423

2

Python, with num2words, 97 113 115 94 93 92 bytes

+16 bytes (forgot the hyphenation that num2words applies which does not actually change the results of any of the test cases, even though 23 and 577 each have a hyphen)
+2 bytes (forgot to include f= although recursive)
-20 bytes (use re)
-8 bytes thanks to @Wheat Wizard (use ~, replace n!=4 with n-4, and ...one line import >_<)
-1 byte thanks to @Cyoce (space from 4 and)

import re,num2words as w
f=lambda n:n-4and-~f(len(re.sub('\W|and','',w.num2words(n))))

Just counts up the number of steps; works for huge and negative integers too (\W finds the spaces, commas and hyphens in the num2words result):

>>> for test in (1,4,7,23,577,600,-1*2**96,3**96):
...     print('test: {0}  ->  {1}'.format(test, f(test)))
...
test: 1  ->  3
test: 4  ->  0
test: 7  ->  2
test: 23  ->  5
test: 577  ->  6
test: 600  ->  4
test: -79228162514264337593543950336  ->  4
test: 6362685441135942358474828762538534230890216321  ->  5

Here is that last case, step by step:

sixquattuordecillionthreehundredsixtytwotredecillionsixhundredeightyfiveduodecillionfourhundredfortyoneundecilliononehundredthirtyfivedecillionninehundredfortytwononillionthreehundredfiftyeightoctillionfourhundredseventyfourseptillioneighthundredtwentyeightsextillionsevenhundredsixtytwoquintillionfivehundredthirtyeightquadrillionfivehundredthirtyfourtrilliontwohundredthirtybillioneighthundredninetymilliontwohundredsixteenthousthreehundredtwentyone
fourhundredfiftyone
nineteen
eight
five

Jonathan Allan

Posted 2016-09-10T16:44:39.500

Reputation: 67 804

1Don't you need a f= before your lambda function – Post Rock Garf Hunter – 2016-09-10T20:00:25.470

@WheatWizard I do indeed, and I've done that before! – Jonathan Allan – 2016-09-10T20:01:54.593

If you import re and use re.sub("and|-| ","",num2words(n)) instead of num2words(n).replace('and','').replace(' ','').replace('-','') you can save a couple of bytes. – Post Rock Garf Hunter – 2016-09-10T20:01:56.833

@WheatWizard I was already doing that :) – Jonathan Allan – 2016-09-10T20:06:55.167

1Try import re,num2words as r instead of the two different statements. – Post Rock Garf Hunter – 2016-09-10T20:11:23.780

1n-4 is the same thing as n!=4 – Post Rock Garf Hunter – 2016-09-10T20:14:47.547

1@WheatWizard num2words is w, re is still re - note that both the module and function are called num2words – Jonathan Allan – 2016-09-10T20:18:41.547

1Ok last one, and 1+ can be replaced with and-~ to save one byte – Post Rock Garf Hunter – 2016-09-10T20:22:59.390

I'm glad I'm not the only one who forgets the f= for their recursive lambdas. – Neil – 2016-09-10T20:31:38.427

1n-4 and can become n-4and – Cyoce – 2016-09-11T07:00:51.000

1

Pyth - 54 bytes

Will try to refactor.

KjC"Y©åláóê¤"Ttl.u?<NyT@KNs+V@LKJ_jNT[Z@jC"Ckg"ThtJ7

Test Suite.

Maltysen

Posted 2016-09-10T16:44:39.500

Reputation: 25 023

1

Java, 556 295 bytes

Thanks to @KevinCruijssen for saving 261 bytes

  void int(n) {int s[]={0,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,9,8,6,9,9,11,10,6,6,5,5,7,7,6};int c=0,t=(int)Math.pow(10,(int)Math.log10(n)),v=1;while(n>0){if(n/100>0)c+=(s[n/100]+7);else {if(n>0&n<25){c+=s[n];break;}else{c+=s[(n/10)+22];}}n=n%t;t=t/10;}while(c!=4){v++;c=s[c];}System.out.print(v);}


Ungolfed:

  void int(n) {

    int s[]={0,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,9,8,6,9,9,11,10,6,6,5,5,7,7,6};
     int c=0,t=(int)Math.pow(10,(int)Math.log10(n)),v=1;
         while(n>0){
            if(n/100>0)
                c+=(s[n/100]+7);
            else {if(n>0&n<25){
                c+=s[n];
            break;
            }
            else{
                c+=s[(n/10)+22];

            }
            }
            n=n%t;
            t=t/10;
        }

        while(c!=4)
        {
            v++;
        c=s[c];
        }
System.out.print(v);
}

Numberknot

Posted 2016-09-10T16:44:39.500

Reputation: 885

I think you have a mistake in your code, because s++ isn't possible on a String-array.. :S – Kevin Cruijssen – 2016-09-12T07:46:27.490

@KevinCruijssen I declare S(counter) as a INT and STRING too....java automatically decide it is an INT. – Numberknot – 2016-09-12T07:51:21.373

Well, if I run your code in ideone or my Eclipse IDE it fails because you have two s.. Btw, you can golf your code by quite a large amount like this: int c(int n){int s[]={0,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8,6,9,9,11,10,6,5,5,5,7,6,6},c=0,t=(int)Math.pow(10,(int)Math.log10(n)),x=1;while(n>0)if(n/100>0)c+=s[n/100]+7;else{if(n>0&n<25){c+=s[n];break;}else c+=s[(n/10)+22];}n%=t;t/=10;}for(;c!=4;x++,c=s[c]);return x;} – Kevin Cruijssen – 2016-09-12T07:59:14.380

I am shocked......what happen to my code and thanks @KevinCruijssen..and i am correcting it...Thanks again. – Numberknot – 2016-09-12T08:12:35.490

Np :) I think it might be golfed some more somehow without using the if-else and break in there (but I'll leave that to someone else), but your initial code was a great base for tackling the challenge, so +1 from me. – Kevin Cruijssen – 2016-09-12T09:19:50.213

1

Mathematica, 89 bytes

Length@FixedPointList[StringLength@StringReplace[IntegerName@#,{" "->"","-"->""}]&,#]-2&

Typical Mathematica: built-in functions good, long function names bad. FixedPointList applies its first argument (a function) to the second argument repeatedly until the answer doesn't change, listing all results; the results include the original input and two copies of the repeated output, hence the -2 at the end. Mathematica's built-in IntegerName contains spaces and hyphens, so we need to get rid of those by hand.

Annoyingly, IntegerName's output contains the character "‐" (Unicode #8208) rather than normal hyphens; that's why this submission is 89 bytes rather than 88. (And I couldn't precede the code above with four spaces and have it accept the Unicode character—any help?—so the above code won't work exactly right if cut and pasted.)

Greg Martin

Posted 2016-09-10T16:44:39.500

Reputation: 13 940

1

Python 2.7, 344 216 208 bytes:

x=`input()`;c=0;y=lambda v:dict(zip(range(0,10),[0]+v));l=[3,3,5,4,4,3,5,5,4];d=y(l);e=y([3,6,6,6,5,5,7,7,6]);f=y([i+7for i in l])
while x!='4':x=`sum([q[int(r)]for q,r in zip([d,e,f],x[::-1])])`;c+=1
print c

Does not use any external libraries unlike other Python answer. Takes input through stdin and outputs to stdout.

Repl.it with All Test Cases!

Explanation

First creates 3 dictionaries with each one pairing the length of the English word representations of each number to the number it represents in the closed interval [1,9] in the ones, tens, and hundreds place, respectively. For example, the first entry in dictionary d is 1:3 as 1 is spelled one in English and has 3 letters.

Then, each digits place in some string input x is assigned to its corresponding dictionary, after which each number in each place is matched up with its value in the corresponding dictionary. For instance, suppose the input number was 23. The 20 in the tens place would be paired with dictionary e, in which it is matched with 6, and the 3 in the ones place would be paired with dictionary d, in which it is matched with 5. These matched digits are then added together to represent the length of the English representation of the number, which is assigned to x as a string and, as long as x!='4', the while loop goes on, incrementing c by 1 each time to represent the number of steps taken thus far. Therefore, 23 would correspond to 11, which would in turn correspond to 6 which would turn to 3 and then to 5 and finally to 4, resulting in 5 total steps.

Finally, once the loop finishes, c is output to stdout to represent the "Distance to Four", which in this case would be 5.

R. Kap

Posted 2016-09-10T16:44:39.500

Reputation: 4 730