Print all the numbers from 0-100 in the right order using the Danish way of counting

How they count

  • Like English, they have dedicated words for 0-20, 30, 40 and 100
  • Instead of saying twenty-one and twenty-two, they say one and twenty and two and twenty
  • Starting with fifty they say multiples of 10 as n*20

    50 = half third times twenty = half way to the 3rd multiple of 20
    60 = three times twenty
    70 = half fourth times twenty
    80 = four times twenty
    90 = half fifth times twenty

    So for instance, 55 would be five and half third times twenty.

Expected output

one and twenty
two and twenty
three and twenty
four and twenty
five and twenty
six and twenty
seven and twenty
eight and twenty
nine and twenty
one and thirty
two and thirty
three and thirty
four and thirty
five and thirty
six and thirty
seven and thirty
eight and thirty
nine and thirty
one and forty
two and forty
three and forty
four and forty
five and forty
six and forty
seven and forty
eight and forty
nine and forty
half third times twenty
one and half third times twenty
two and half third times twenty
three and half third times twenty
four and half third times twenty
five and half third times twenty
six and half third times twenty
seven and half third times twenty
eight and half third times twenty
nine and half third times twenty
three times twenty
one and three times twenty
two and three times twenty
three and three times twenty
four and three times twenty
five and three times twenty
six and three times twenty
seven and three times twenty
eight and three times twenty
nine and three times twenty
half fourth times twenty
one and half fourth times twenty
two and half fourth times twenty
three and half fourth times twenty
four and half fourth times twenty
five and half fourth times twenty
six and half fourth times twenty
seven and half fourth times twenty
eight and half fourth times twenty
nine and half fourth times twenty
four times twenty
one and four times twenty
two and four times twenty
three and four times twenty
four and four times twenty
five and four times twenty
six and four times twenty
seven and four times twenty
eight and four times twenty
nine and four times twenty
half fifth times twenty
one and half fifth times twenty
two and half fifth times twenty
three and half fifth times twenty
four and half fifth times twenty
five and half fifth times twenty
six and half fifth times twenty
seven and half fifth times twenty
eight and half fifth times twenty
nine and half fifth times twenty
one hundred


  • You may use any separator to separate the numbers
  • Due to a typo in the original specification, you may use forth instead of fourth.
  • You may write a function or write to std-out
  • Standard loopholes apply
  • This is codegolf; shortest code in bytes win!
  • 2
    \$\begingroup\$ Related. \$\endgroup\$
    – Adám
    Sep 8, 2016 at 10:45
  • 5
    \$\begingroup\$ Why all the spaces? 55 is femoghalvtredsindstyve in Danish, not fem og halv tred sinds tyve. \$\endgroup\$
    – Adám
    Sep 8, 2016 at 10:48
  • 14
    \$\begingroup\$ The expected output looks decidedly non-Danish to me. (And 55 is femoghalvtreds, not femoghalvtredsinstyve unless you're being deliberately archaic). \$\endgroup\$ Sep 8, 2016 at 10:53
  • 9
    \$\begingroup\$ @Adám I decided to use English rather than Danish words to make the challenge more accessible, and we don't contract words in English. \$\endgroup\$
    – BlackCap
    Sep 8, 2016 at 10:54
  • 6
    \$\begingroup\$ @BlackCap: Some words do become contracted over time. For instance, it is screenshot, not screen shot. \$\endgroup\$ Sep 8, 2016 at 11:02

18 Answers 18


JavaScript (ES6), 347 336 326 325 308 bytes

for(a=btoa`...`.split(i=0);i<101;i++)alert(i<13?a[i]:i<20?(a[i]||a[i-10])+"teen":i>99?"one hundred":(i%10?a[i%10]+" and ":"")+(i<30?"twenty":i<40?"thirty":i<50?"forty":(i%20>9?"half "+["third","forth","fifth"][i/20-2|0]:a[i/20|0])+" times twenty"))

Before running, replace the ... with the result of running this code:


Or you could just use the uncompressed version:

for(a="zero0one0two0three0four0five0six0seven0eight0nine0ten0eleven0twelve0thir00fif000eigh".split(i=0);i<101;i++)alert(i<13?a[i]:i<20?(a[i]||a[i-10])+"teen":i>99?"one hundred":(i%10?a[i%10]+" and ":"")+(i<30?"twenty":i<40?"thirty":i<50?"forty":(i%20>9?"half "+["third","forth","fifth"][i/20-2|0]:a[i/20|0])+" times twenty"))

Still probably not optimal. 11 bytes saved in part by @Titus.

  • \$\begingroup\$ I was wrong. that´s a reasonable way to golf the exceptions. \$\endgroup\$
    – Titus
    Sep 8, 2016 at 1:11
  • \$\begingroup\$ -7 bytes: (x%20>9?"half ":"")+[third,forth,fifth][x/20-2.5|0] instead of (x%20>9?"half "+[third,forth,fifth][x/20-2.5|0]:f(x/20|0)) \$\endgroup\$
    – Titus
    Sep 8, 2016 at 1:30
  • \$\begingroup\$ @Titus If I understand what you mean, that generates incorrect output for 60, 61, ..., 69, 80, 81... (e.g. third times twenty instead of three times twenty) \$\endgroup\$ Sep 8, 2016 at 2:00
  • \$\begingroup\$ Oh I was missing that difference. You´re right. But get rid of the recursion; that will make way for a little more golfing. \$\endgroup\$
    – Titus
    Sep 8, 2016 at 2:21
  • \$\begingroup\$ @Titus Thanks for the tip. I didn't notice it, but recursion was actually saving me exactly 0 bytes over non-recursion. I've switched and golfed some more now. \$\endgroup\$ Sep 8, 2016 at 3:13

Fourier, 7028 bytes

The bounty will go to Paul Schmitz's answer

This was golfed programmatically using issacg's golfing program


Try it online!

  • \$\begingroup\$ Here's a suggestion: simply print the output. It consists of 1989 characters that use the same number of bytes. \$\endgroup\$
    – DavidC
    Sep 8, 2016 at 15:01
  • 2
    \$\begingroup\$ @DavidC As far as I know this is how you "simply print the output" in Fourier. There are no string literals if that's what you meant. \$\endgroup\$ Sep 8, 2016 at 15:17
  • \$\begingroup\$ @DavidC Martin is right, strings don't exist in Fourier \$\endgroup\$
    – Beta Decay
    Sep 8, 2016 at 15:39
  • \$\begingroup\$ My goodness, very strange language it seems! \$\endgroup\$
    – DavidC
    Sep 8, 2016 at 15:49
  • \$\begingroup\$ I got 7020 bytes. pastebin.com/WGtHSGFT \$\endgroup\$ Sep 9, 2016 at 6:46

JavaScript (ES6), non-competing

I decided to do what the title actually asked, and counted to 100 på dansk. This is based on ETHproductions' answer. It is 292 bytes (286 if you use alert instead)


  • \$\begingroup\$ To be fair, you should append instyve to every number that ends in s. \$\endgroup\$
    – Adám
    Sep 8, 2016 at 10:51
  • 1
    \$\begingroup\$ @Adám: Why so? The -sinstyve is etymology, not actual Danish as currently spoken. \$\endgroup\$ Sep 8, 2016 at 10:54
  • \$\begingroup\$ Yeah, but the English OP does include it, otherwise it should say 55 would be five and half third t. \$\endgroup\$
    – Adám
    Sep 8, 2016 at 11:54

///, 434 bytes

/(/\/\///D/\/7(7/ and (2/twenty(4/ times (_/half ([/42
O*Y*&*)*F*X*#*^*-*&[OGYG&G)GFGXG#G^G-G_!h[O%Y%&%)%F%X%#%^%-%)[OHYH&H)HFHXH#H^H-H$OAYA&A)AFAXA#A^A-AO hundred

Try it online!


PHP, 397 375 372 381 386 365 bytes

This was too funny to be ignored. It can possibly be golfed further.

zero_<?=join(_,$a=[one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen,nineteen])._;foreach([twenty,thirty,forty]as$t)for($i=-2;$i++<8;)echo($i<0?'':$c[]="$a[$i] and ").$t._;foreach([third,three,fourth,four,fifth]as$k=>$t)for($i=-2;$i++<8;)echo$c[$i],($k&1?'':'half '),"$t times twenty_";?>one hundred
  • It uses underscore as the separator
  • 10 to 19 are still hardcoded; any way to compute them doesn´t give as much as the join.

Mathematica 251 238 230 bytes

This now presents the output in the format of a list, to save 8 more bytes.

c@s_:=s<>" times twenty";f@n_:=Which[n<21∨{30,40,100}~MemberQ~n,IntegerName@n,n==50,c@"half third",n==60,c@"three",n==70,c@"half forth",n==80,c@"four",n==90,c@"half fifth",3>2,NumberExpand@n/.{t_,u_}:>f@u<>" plus "<>f@t];f/@0~Range~100
  • \$\begingroup\$ I'm really jealous of that IntegerName function \$\endgroup\$
    – BlackCap
    Sep 8, 2016 at 9:35
  • \$\begingroup\$ Yeah, it does a good amount of the work. NumberExpand is also useful for decomposing a number (in any base). `NumberExpand[943]-> {900,40,3} \$\endgroup\$
    – DavidC
    Sep 8, 2016 at 10:41

C (gcc), 445 426 452 449 444 439 bytes

*t[]={0,0,"twenty","thirty","fourty",[10]="one hundred","third","fourth","fifth"},*o[101]={"zero","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"};i,p;main(j){for(;i<'e';i++)p=i%10,o[i]?puts(o[i]):printf("%s%s%s%s%s%s\n",p?o[p]:t,p?" and ":t,!t[j]&j%2?"half ":t,t[j]?t:j%2?t[j/2+9]:o[j/2],t[j]?t:" times ",t[j=i/10]?:t[2]);}

Try it online!

19 22 27 bytes shaved off thanks to @ceilingcat, but 26 bytes were added again, 3 to prevent a segfault (o[] really has to have 101 entries), and upon checking the rules again I noticed we had to print out all numbers from 0 to 100, not just provide a function that printed one number.


char *t[] = {0, 0, "twenty", "thirty", "fourty", 0, 0, 0, 0, 0, "one hundred", "third", "fourth", "fifth"};
char *o[101] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
                "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
int i = 0;
int j = 0;
int p = 0;

  for(; i < 101; i++) {
    p = i % 10;
               p ? o[p] : "",
               p ? " and " : "",
               !t[j] & j % 2 ? "half " : "",
               t[j] ? "" : j % 2 ? t[j / 2 + 9] : o[j / 2],
               t[j] ? "" : " times ",
               t[j = i / 10] ? : t[2]

Haskell, 308 291 285 bytes

w=words;q x=map(++x);m=w"thir four fif six seven eigh nine";t=w"zero one two three four five six seven eight nine ten eleven twelve"++q"teen"m++q"ty"(do b<-"twen":take 2m++q" times twen"["half third",t!!3,"half fourth",t!!4,"half fifth"];b:q b(q" and ".take 9$tail t))++["one hundred"]

Readable version:

w   = words
m   = w "thir four fif six seven eigh nine"
q x = map (++x)

t = w "zero one two three four five six seven eight nine ten eleven twelve"
 ++ q "teen" m 
 ++ q "ty" (do b <- "twen" : take 2 m
                     ++ q " times twen"
                          ["half third",t!!3,"half fourth",t!!4,"half fifth"]
               b:q b(q" and ".take 9$tail t)
 ++ ["one hundred"]

Also 285

w=words;m=w"thir four fif six seven eigh nine";x!l=map(++x)l
t  = w"zero one two three four five six seven eight nine ten eleven twelve"
  ++ "teen"!m
  ++ "ty"!(
  do x<-"twen":take 2m++" times twen"!
         ["half third",t!!3,"half fourth",t!!4,"half fifth"]
     x:x!(" and "!take 9(tail t)))
  ++ ["one hundred"]

It might not look much different, but it represents hours of factorization that eventually brought me full circle. I think I have done this before..

  • \$\begingroup\$ Damn, Nordic-related challenge and so there already is a fp solution I can hardly improve on (fp being quite popular in the Nordics, no?) \$\endgroup\$ Sep 8, 2016 at 19:19
  • \$\begingroup\$ @LeifWillerts I don't know anyone else who do fp, nor do they teach it in schools- sadly. You could try Lisp, it has format nil "~R" which converts numbers to their English text representation \$\endgroup\$
    – BlackCap
    Sep 8, 2016 at 19:44
  • \$\begingroup\$ Why do you suggest that Lisp? Well, I have been taught FP in Germany by a professor who had spent a lot of time at Chalmers in Sweden, and in here in Copenhagen they teach it on quite a high level and there is an active community in the city. Erlang was famously developed by Ericsson in Sweden. Where are you and what do you do? \$\endgroup\$ Sep 9, 2016 at 22:02
  • 1
    \$\begingroup\$ Why is it non-competing? Just because you are OP doesn't mean non-competing AFAIK. Mods correct me if I'm wrong though... \$\endgroup\$ Sep 11, 2016 at 13:25
  • 1
    \$\begingroup\$ @EriktheGolfer Can someone confirm that? I thought competing in my own challenge sounded a bit cheesy.. \$\endgroup\$
    – BlackCap
    Sep 11, 2016 at 15:47

PHP, 333 328 321 bytes

@ETHproductions´s expression ported to PHP and golfed down. I am surprised that PHP can beat JavaScript without any builtins.

I guess the mightiest builtins are the implicit typecasts:

  • I need no quotes for most of the strings, that alone is worth 12 bytes;
  • and it allows me to use an array directly instead of splitting a string.
  • the array indexing is implicitly typecasting any floats to integer, saving 6 bytes.

BUT: I need $s (21 of them) to tell PHP that it´s a variable.

So it´s still unclear where the 15 bytes actually come from. I didn´t golf away that much. Or did I? ETH caught up.

<?$a=[zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,'',fifteen,'','',eighteen];for($n=-1;$n++<99;)echo$n>19?($n%10?$a[$n%10].' and ':'').($n>49?($n%20>9?"half ".[third,forth,fifth][$n/20-2.5]:$a[$n/20]).' times twenty':[twen,thir,'for'][$n/10-2].ty):($a[$n]?:$a[$n%10].teen),_;?>one hundred
  • \$\begingroup\$ Beating you now ;) \$\endgroup\$ Sep 8, 2016 at 3:22

Fourier, 7020 bytes


This is an improved version of Beta Decays program.


05AB1E, 127 123 120 115 bytes

“¡×€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š—¿áÓÁωª†ìdßàŒšdï¿dŸ¯een¥Šd“¤'…§:#©`…«¹¿œÖƒ#“‰ª„í¦ƒ†ì³ä“#ε…ÿ„Æ«¹NÈi„Š£ ì]«vyTG®Nè'€ƒ‚yª]„€µ°¡»

Try it online!

“¡× (...) Šd“         # dictionary string "zero one two ... sixd sevend eighteen nined"
¤                     # get the last letter ("d") without popping 
 '…§                  # dictionary string "teen"
    :                 # replace (changes all "d" to "teen" in the initial string)
     #                # split on spaces
      ©               # save this list to the register
       `              # dump all items on the stack
…«¹¿œÖƒ               # dictionary string "twenty thirty fourty"
       #              # split on spaces
“‰ª„í¦ƒ†ì³ä“          # dictionary string "third three fourth four fifth"
            #         # split on spaces
ε              ]      # for each:
 …ÿ„Æ«¹               #  append " times twenty"
       NÈi     ]      #  if the iteration count is even:
          „Š£ ì       #   prepend "half "
                «     # merge those two lists ([20, 30, 40] and [50, 60, 70, 80, 90])
v            ]        # for y in this list of names:
 y                    #  put y on the stack
  TG         ]        #  for N from 1 to 9:
    ®Nè               #   get the Nth element in the register
       '€ƒ‚           #   append "and"
           yª         #   append y
„€µ°¡                 # dictionary string "one hundred"
     »                # join the stack with newlines
  • \$\begingroup\$ That's 230 bytes, with 115 wide (16-bit) characters. \$\endgroup\$
    – John Tromp
    Apr 4, 2022 at 7:54
  • 1
    \$\begingroup\$ @JohnTromp no, that’s 115 8-bit characters. See 05AB1E’s codepage. \$\endgroup\$
    – Grimmy
    Apr 5, 2022 at 10:53
  • \$\begingroup\$ Ok; I stand corrected. \$\endgroup\$
    – John Tromp
    Apr 6, 2022 at 11:08

JavaScript (ES6), 346 bytes

Only a small idea to ETHproductions' solution: Replace f(..) with a[..] to be able to call f recursively to concat the output.

f=x=>(a="1one1two1three1four1five1six1seven1eight1nine1ten1eleven1twelve1thir11fif111eigh".split(1),x<1?"zero":f(x-1)+(x<13?a[x]:x<20?(a[x]||a[x-10])+"teen":x>99?"one hundred":(x%10?a[x%10]+" and ":"")+(x<50?"twen1thir1for".split(1)[x/10-2|0]+"ty":(x%20>9?"half "+"third1forth1fifth".split(1)[x/20-2.5|0]:a[x/20|0])+" times twenty")))+"\n"

Still far away from optimal...


Python 2, 359 349 345 Bytes

a='one two three four five six seven eight nine'.split()
c=['ten','eleven','twelve']+[i+'teen'for i in['thir',a[3],'fif',a[5],a[6],'eigh',a[8]]]
p=' times twenty'
h='half '
for i in x:f+=[i];f+=[b+' and '+i for b in a] 
for i in f+['one hundred']:print i


Create a list of the first 9 numbers.
Create a list of the next 10 numbers.
Create a list of the endings - twenty, thirty, forty, half third times twenty etc
Join the first two lists with zero
Append to the list each of the numbers from 50 onwards.
Print out list

Ungolfed code:

endings=['twenty','thirty','forty','half third times twenty','three times twenty','half forth times twenty','four times twenty','half fifth times twenty']
for ending in endings:
    for number in firstNumbers:
        joined.append(number + 'and' + ending)
joined.append('one hundred')
for line in joined:
    print line
  • \$\begingroup\$ Some golfing: teen line - remove space after in; move q into the only place it is used; do for i in f+['one hundred']:print i \$\endgroup\$ Sep 8, 2016 at 18:38
  • 1
    \$\begingroup\$ @JonathanAllan The score actually measured it with the q='and' - I'd noticed, just forgot to change it here! Thanks! \$\endgroup\$
    – Tim
    Sep 8, 2016 at 21:54

Java 8 7, 512 490 + 19(import) bytes

Needs an import import java.util.*;

<T>void y(List<T>l,T...a){for(T t:a)l.add(t);}List x(){String b="teen",c="twenty",d="half ",e=" times "+c;String[]a={"zero","one","two","three","four","five","six","seven","eight","nine"},f={c,"thirty","fourty",d+"third"+e,a[3]+e,d+"fourth"+e,a[4]+e,d+"fifth"+e};List<String>g=new ArrayList<>(Arrays.asList(a));y(g,"ten","eleven","twelve","thir"+b,a[4]+b,"fif"+b,a[6]+b,a[7]+b,"eigh"+b,a[9]+b);for(String h:f){y(g,h);for(int i=1;i<=9;i++)y(g,(a[i]+" and "+h));}y(g,"one hundred");return g;}


<T> void y(List<T> l, T... a) {
    for (T t : a) {

List x() {
    String b = "teen", c = "twenty", d = "half ", e = " times " + c;
    String[] a = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"},
        f = {c, "thirty", "fourty", d + "third" + e, a[3] + e, d + "fourth" + e, a[4] + e, d + "fifth" + e};
    List<String> g = new ArrayList<>(Arrays.asList(a));
    y(g, "ten", "eleven", "twelve", "thir" + b, a[4] + b, "fif" + b, a[6] + b, a[7] + b, "eigh" + b, a[9] + b);

    for (String h : f) {
        y(g, h);
        for (int i = 1; i <= 9; i++) {
            y(g, (a[i] + " and " + h));

    y(g, "one hundred");
    return g;

To run this, simply call <instance>.x();. This now returns the list containing all numbers.

Try it here!


Python 2, with num2words, 206 bytes

Even with num2words it takes quite a few bytes!

This is a full program.

from num2words import num2words as w
for i in range(1,101):d=i/10;e=w(i).split('-');print' and '.join(e[1:]+[10>d>4 and((d%2 and'half '+{5:'third',7:'forth',9:'fifth'}[d]or w(d/2))+' times twenty')or e[0]])

Here is a mocked version on ideone
(By mocked I mean that since the online interpreter does not have num2words I replaced w with a lambda which looks up num2word's output in a list)

ungolfed and with 'fourth' rather than the allowed 'forth' (which saves a byte):

from num2words import num2words
for i in range(1,101):
    d = i / 10 # i div 10
    e = num2words(i).split('-') # i in English words with a "-" separator, split into parts
    if d > 4 and d < 10:
        if d % 2:
            p = 'half '+ {5:'third', 7:'fourth', 9:'fifth'}[d] + ' times twenty'
            p = num2words(d / 2) + ' times twenty'
        p = e[0]
    print' and '.join(e[1:]+[p])

Note that the separator used by num2words(100) is a space, whereas for the other numbers it is a "-", so we don't need to do anything fancy for that case other than stop it from being "five times twenty".


If the challenge were to actually produce the numbers in Danish one could take the lang_DK.py from the github page and use:

from num2words import*
[num2words(i,lang='dk')for i in range(1,101)]

for 68 bytes, yielding:

['et', 'to', 'tre', 'fire', 'fem', 'seks', 'syv', 'otte', 'ni', 'ti', 'elleve', 'tolv', 'tretten', 'fjorten', 'femten', 'seksten', 'sytten', 'atten', 'nitten', 'tyve', 'enogtyve', 'toogtyve', 'treogtyve', 'fireogtyve', 'femogtyve', 'seksogtyve', 'syvogtyve', 'otteogtyve', 'niogtyve', 'tredive', 'enogtredive', 'toogtredive', 'treogtredive', 'fireogtredive', 'femogtredive', 'seksogtredive', 'syvogtredive', 'otteogtredive', 'niogtredive', 'fyrre', 'enogfyrre', 'toogfyrre', 'treogfyrre', 'fireogfyrre', 'femogfyrre', 'seksogfyrre', 'syvogfyrre', 'otteogfyrre', 'niogfyrre', 'halvtreds', 'enoghalvtreds', 'tooghalvtreds', 'treoghalvtreds', 'fireoghalvtreds', 'femoghalvtreds', 'seksoghalvtreds', 'syvoghalvtreds', 'otteoghalvtreds', 'nioghalvtreds', 'treds', 'enogtreds', 'toogtreds', 'treogtreds', 'fireogtreds', 'femogtreds', 'seksogtreds', 'syvogtreds', 'otteogtreds', 'niogtreds', 'halvfjerds', 'enoghalvfjerds', 'tooghalvfjerds', 'treoghalvfjerds', 'fireoghalvfjerds', 'femoghalvfjerds', 'seksoghalvfjerds', 'syvoghalvfjerds', 'otteoghalvfjerds', 'nioghalvfjerds', 'firs', 'enogfirs', 'toogfirs', 'treogfirs', 'fireogfirs', 'femogfirs', 'seksogfirs', 'syvogfirs', 'otteogfirs', 'niogfirs', 'halvfems', 'enoghalvfems', 'tooghalvfems', 'treoghalvfems', 'fireoghalvfems', 'femoghalvfems', 'seksoghalvfems', 'syvoghalvfems', 'otteoghalvfems', 'nioghalvfems', 'ethundrede']

PHP , 318 Bytes

for($i=~0;$i++<100;)echo([0=>zero,10=>ten,eleven,twelve,thirteen,15=>fifteen,18=>eighteen,100=>"one hundred"][$i]??["",one,two,three,four,five,six,seven,eight,nine][$i%10].($i>20&&$i%10?" and ":"").["",teen,twenty,thirty,forty,"half third",three,"half fourth",four,"half fifth"][$i/10].($i>49?" times twenty":"")).",";

first pick with the Null coalescing operator ?? the exceptions.

this version with 314 Bytes is without the , at the end

zero<?php for($i=0;$i++<100;)echo",".([10=>ten,eleven,twelve,thirteen,15=>fifteen,18=>eighteen][$i]??["",one,two,three,four,five,six,seven,eight,nine][$i%10].($i>20&&$i%10?" and ":"").["",teen,twenty,thirty,forty,"half third",three,"half fourth",four,"half fifth"][$i/10].($i>49?" times twenty":""));?>,one hundred

Bash (using rev and sed), 299 276 bytes

I'm using bash's curly braces-expansion. However the braces are expanded in the wrong order, so I print all the words in reverted order and then fix the order of the letters using rev. After that, I still need some adjustments using sed:

printf '%s\n' orez {,{neet,yt{newt,riht,rof},ytnewt\ semit\ {drihtX,eerht,htruofX,ruof,htfifX}}Y}{,eno,owt,eerht,ruof,evif,xis,neves,thgie,enin} derdnuh\ eno |rev |sed -r 's,^Yte,t,;s,^Y,,;12s,.*,eleven,;13s,o.*,elve,;1,20{s,reeY,ir,;s,veY,f,;s,(t|)Y,,};s,Y, and ,;s,X,half ,'

A bit less unreadable:

printf '%s\n' orez {,{neet,yt{newt,riht,rof},\
ytnewt\ semit\ {drihtX,eerht,htruofX,ruof,htfifX}}Y}\
{,eno,owt,eerht,ruof,evif,xis,neves,thgie,enin} \
    derdnuh\ eno \
    |rev \
    |sed -r 's,^Yte,t,;
            s,Y, and ,;
            s,X,half ,'

ink, 286 273 bytes

-c>9 and c<20:
{&one|two|three|four|five|six|seven|eight|nine}{c>9: and {t}}
~temp t="{twenty|thirty|forty|{&half {third|fourth|fifth}|{three|four}} times twenty}"
{c<99:->c}one hundred

Try it online!

  • -13 bytes by removing a useless "five times twenty" case, special-casing zero to be able to simplify the mod check, and simplifying the teens (which now also include ten)

Ink has sequences - they look like {a|b|c} and evaluate to a different value each time, until there's no next value at which point they stick with the last one. By combining and nesting these, we can get pretty advanced with very little in the way of actual conditionals.

A sequence that begins with {& instead of just { is a cycle - those loop and that's how we count units and how we alternate between "half nth times twenty" and "n times twenty" for the tens.

We keep track of the name for the tens in a variable t which we only update every tenth pass through the loop. On the passes where we update the variable, we print only the variable, on other passes we use cycles to print the unit followed by and {t}.
With a handful exceptions - below ten we skip printing the tens (no three and zero) and the teens are irregular enough that they get a sequence all to themselves.

c is a labelled gather. Gathers by themselves don't do anything, but they can be diverted to as a form of control flow, and they keep track of how many times they've been visited - we use this readcount to special-case the teens, to know when we need to update the tens variable, and to know when to stop looping, wrap everything up and print one hundred.

I know I could save a byte by using "forth" instead of "fourth", but I'm choosing not to.


zero // Print "zero"
- (c)
- c > 9 and c < 20:
    // The teens get a sequence of their own because they don't fit into the other numbers' pattern.
- c % 10: // Otherwise, unless we're meant to print a multiple of ten
    // Print the unit - this is a cycle, so it loops when it's been run through nine times.
    {c > 9:<> and {t}} // If we're past nine (and, since we didn't enter the "teens" section earlier, past nineteen), also print " and " and the contents of the variable t.
- else:
    // Set the variable t to the multiple of ten we want. Note the cycle to alternate between "half nth" and "n"
  ~ temp t="{zero|ten|twenty|thirty|forty|{&half {third|fourth|fifth}|{three|four}} times twenty}"

    {t} // Print the contents of t
{c < 99: -> c} // If we've done all this fewer than a hundred times, we go back to the top.
one hundred // Print "one hundred"
// Out of content, end of program

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.