ASCII Maya Numbers

21

1

Write a program or function which, given a positive integer as input, outputs the representation of that integer in Maya numerals.

Maya numerals

Maya numerals is a vigesimal system (base 20) using only 3 symbols :

  • < > for Zero (The correct symbol is some sort of shell that can't easily be represented using ASCII).
  • . for One
  • ---- for Five

Numbers are written vertically in powers of 20, and numbers between 0 and 19 are written as stacks of fives and ones. You shall refer to the Wikipedia article for more details.

As an example, here are the numbers between 0 and 25, separated by commas:

                                                                                 .    ..  ...  ....
                                                        .    ..  ...  .... ---- ---- ---- ---- ----  .    .    .    .    .    .
                               .    ..  ...  .... ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
<  >, .  , .. ,... ,....,----,----,----,----,----,----,----,----,----,----,----,----,----,----,----,<  >, .  , .. ,... ,....,----

Inputs

  • Inputs always are positive integers between 0 and 2147483647 (2^31 - 1).
  • You may take the input from STDIN, as a command line argument, function parameter or anything similar.

Outputs

  • Each line is at most 4 characters long. < > and ---- should always be printed as given here (4 characters long each).
  • Ones(.) must be centered on the line. If there are 1 or 3 ., since perfect horizontal alignment is impossible, it does not matter whether they are one column to the left or one column to the right or the center.
  • There must be exactly one empty line between different powers of 20, regardless of the height of the stacks in the power of 20s. For example, the correct output for 25 and 30 are :

            .
     .
           ----
    ----   ----
    
  • No leading or trailing lines allowed.

  • Outputs must be printed exactly like they are in the examples given.

Test cases

  • Each individual number between 0 and 25 given as example above.

  • Input: 42

Output:

 .. 

 .. 
  • Input: 8000

Output:

 .  

<  >

<  >

<  >
  • Input: 8080

Output:

 .  

<  >

....

<  >
  • input: 123456789

Output:

 .  

... 
----
----
----

 .  
----
----

 .. 
----
----

 .  

....
----
----
----

....
----
  • Input: 31415

Output:

... 

... 
----
----
----

----
----

----
----
----
  • Input: 2147483647

Output:

 .  

... 
----
----

 .  
----
----

 .  

----
----
----

....
----

 .. 

 .. 
----

Scoring

This is , so the shortest code in bytes wins.

Fatalize

Posted 2015-08-04T16:12:15.810

Reputation: 32 976

15 and 20 appear to be identical. – isaacg – 2015-08-04T16:16:24.793

@isaacg Thanks, I actually had 15 appearing both at the right spot and also between 19 and 20. Fixed. – Fatalize – 2015-08-04T16:19:09.707

@Fatalize Does the output need to be printed (i.e. STDOUT) or can my function just return the output? – rink.attendant.6 – 2015-08-04T17:52:33.010

@rink.attendant.6 Must be printed exactly like they are in the post. – Fatalize – 2015-08-04T18:23:12.980

Is it ok if 1 is one column to the right, but 3 is one column to the left? – aragaer – 2015-08-06T16:45:58.063

@aragaer yes it's fine – Fatalize – 2015-08-06T16:51:44.947

And another one - is it ok to have a trailing newline? Basically we're operating lines here, so it would make sense if the last line was actually a line. – aragaer – 2015-08-06T17:18:08.827

@aragaer The "No trailing or leading lines" rule has been included since the beginning of the challenge, so to be fair to other participants I can't remove it. So no – Fatalize – 2015-08-06T17:22:17.207

For "digits" that are multiples of 5, I'm assuming that an extra blank line isn't acceptable: That is, for the number 35, there must be exactly one blank line between the line with the single dot, and the first of the three lines of dashes. Correct? – MtnViewMark – 2015-08-10T01:03:36.057

@MtnViewMark correct – Fatalize – 2015-08-10T05:50:00.423

Is it possible to return a 2D list of lines? (Jelly solution) – user202729 – 2018-04-06T02:45:19.593

Answers

3

Pyth, 41 bytes

j+bbm|jb_m.[\ 4kc:*d\.*5\.*4\-4"<  >"jQ20

Try it online: Demonstration

Explanation:

                                     jQ20   convert input to base 20
    m                                       map each value d to:
                  *d\.                         string of d points
                 :    *5\.*4\-                 replace 5 points by 4 -s
                c             4                split into groups of 4
         m.[\ 4k                               center each group
        _                                      invert order
      jb                                       join by newlines
     |                         "<  >"          or if 0 use "<  >"
j+bb                                        join by double newlines

Jakube

Posted 2015-08-04T16:12:15.810

Reputation: 21 462

5

Perl, 125 117 bytes

$-=<>;{$_=($-%20?(""," .
"," ..
","...
","....
")[$-%5]."----
"x($-/5&3):"<  >
").$_;($-/=20)&&($_=$/.$_,redo)}print

Thanks to Dom Hastings for helping me save 8 bytes.

samgak

Posted 2015-08-04T16:12:15.810

Reputation: 1 577

1Hey samgak, a couple more byte saving changes, rather than redo,if(int($i/=20)) you can use ~~($i/=20)&&redo. ~~ converts to int - you could also use 0| at the beginning (or |0 at the end). Also replacing substr(".... ... .. . ",20-$i%5*5,5) with (' .', ' ..','...','.'x4)[$i%5-1].$/ seems to work ok, but I haven't tested all the test cases... If those work, you're down to 114... If I think of anything else to share I'll let you know! – Dom Hastings – 2015-08-05T10:59:57.130

1Thinking about it, if you only ever want to have an integer and ignore the remainder, you can use the magic variable $- which will always truncate to an int... might save a few more! – Dom Hastings – 2015-08-05T11:47:09.140

1@DomHastings thanks, the int conversion trick saves a couple of bytes, and getting rid of substr saves another 4. The newlines need to go inside the string constants because there has to be no newline in the case where there are no dots. – samgak – 2015-08-05T11:47:13.173

1@DomHastings indeed it does, thanks again! I guess that means I have to get rid of my end of the world joke – samgak – 2015-08-05T11:48:49.660

4

Mathematica 185 182 171 153

With 18 bytes saved thanks to Arcinde's suggestion to use anonymous functions,

c=Column;c[If[#>0,{q,r}=#~QuotientRemainder~5;c@{{""," ."," .."," ...","...."}[[r+1]],c@{{""},{d="----"},{d,d},{d,d,d}}[[q+1]]},"< >"]&/@#~IntegerDigits~20]&

Example

c[If[# > 0, {q, r} = #~QuotientRemainder~5; c@{{"", " .", " ..", " ...", "...."}[[r + 1]], c@{{""}, {d = "----"}, {d, d}, {d, d, d}}[[q + 1]]}, "< >"] & /@ #~IntegerDigits~20] &[31415]

output


Checking

The decimal number, 31415, expressed in base 20. Mathematica employs lower case for this.

BaseForm[31415, 20]

base 20


The decimal digits corresponding to the above base 20 number.

IntegerDigits[31415,20]

{3, 18, 10, 15}


Another example

IntegerDigits[2147483607, 20]

{1, 13, 11, 1, 15, 9, 0, 7}

c[If[# > 0, {q, r} = #~QuotientRemainder~5;c@{{"", " .", " ..", " ...","...."}[[r + 1]], c@{{""}, {d = "----"}, {d, d}, {d, d, d}}[[q + 1]]},"< >"] & /@ #~IntegerDigits~20] &[2147483607]

ex2

DavidC

Posted 2015-08-04T16:12:15.810

Reputation: 24 524

c=Column;c[If[#>0,{q,r}=#~QuotientRemainder~5;c@{{""," ."," .."," ...","...."}[[r+1]],c@{{""},{d="----"},{d,d},{d,d,d}}[[q+1]]},"< >"]&/@#~IntegerDigits~20]& using anonymous functions. – jcai – 2015-08-05T12:48:23.190

@Arcinde, Thanks. Good old anonymous functions. – DavidC – 2015-08-05T13:04:40.720

4

JavaScript ES6, 143 bytes

Loads of bytes added because need to console.log, could save another 23 bytes without it.

n=>console.log((d=(x,s='',l=1,j=x/l|0)=>s+(j>19?d(x,s,l*20)+`

`:'')+((j=j%20)?(' '+`.`.repeat(j%5)).slice(-4)+`
----`.repeat(j/5):'<  >'))(n))

George Reith

Posted 2015-08-04T16:12:15.810

Reputation: 2 424

3

JavaScript (ES6), 157 bytes

The newlines are significant and are counted as 1 byte each. Since printing to STDOUT is required, console.log cost me a few bytes there.

f=i=>console.log([...i.toString(20)].map(j=>(!(j=parseInt(j,20))||j%5?[`<  >`,` .`,` ..`,`...`,`....`][j%5]+`
`:'')+`----
`.repeat(j/5)).join`
`.slice(0,-1))

Demo

For demonstration purposes I'll write an ES5 version so it works in all browsers:

// Snippet stuff
console.log = function(x) {
  O.innerHTML = x;
}
document.getElementById('I').addEventListener('change', function() {
  f(this.valueAsNumber);
}, false);

// Actual function
f = function(i) {
  console.log(i.toString(20).split('').map(function(j) {
    return (! (j = parseInt(j, 20)) || j % 5 ? ['<  >', ' .', ' ..', '...', '....'][j % 5] + '\n' : '') + '----\n'.repeat(j / 5);
  }).join('\n').slice(0,-1));
}
<input type=number min=0 max=2147483647 value=0 id=I>

<pre><output id=O></output></pre>

rink.attendant.6

Posted 2015-08-04T16:12:15.810

Reputation: 2 776

Does the last .join need parenthesis? – Downgoat – 2015-08-04T20:25:45.483

137 bytes: http://pastebin.com/3Zgg4qtX

– Downgoat – 2015-08-04T21:14:40.070

@vihan That doesn't output anything, it just returns. – rink.attendant.6 – 2015-08-04T21:21:07.377

didn't know that was a requirement as input can be through a function. http://pastebin.com/0pS0XtJa is 3 bytes shorter

– Downgoat – 2015-08-04T21:23:13.353

2

CJam, 82 76 bytes

li{_K%[""" .
"" ..
""...
""....
"]1$5%='-4*N+2$5/3&*+"<  >
"?N+L+:L;K/}h;L);

My first CJam program, basically just a transliteration of my Perl answer to CJam.

Try online

Multi-line with comments:

li            # read input
{             # start of do-while loop
  _K%         # check if this base-20 digit is a zero
    [""" .
    "" ..
    ""...
    ""....
    "]1$5%=   # push dots for 1s onto stack
    '-4*N+2$5/3&*+    # push lines for 5s onto stack

    "<  >
    "         # push zero on stack
  ?           # ternary if test (for digit equals zero)
  N+L+:L;     # pre-concatenate string with output plus newline
  K/          # divide by 20
}h            # end of do while loop
;L);          # push output string on stack, chop off trailing newline

samgak

Posted 2015-08-04T16:12:15.810

Reputation: 1 577

2

Python 2.x, 142 bytes:

def m(n):
 h=[[""," "*(2-n%5/2)+"."*(n%5)+"\n"][n%5!=0]+"----\n"*(n%20/5),"<  >\n"][n%20==0]
 n/=20
 if n>0:
  h=m(n)+"\n\n"+h
 return h[:-1]

Example:

>>> print m(2012)
----

<  >

 ..
----
----
>>> 

Edit: trailing line...

Locoluis

Posted 2015-08-04T16:12:15.810

Reputation: 741

I have a few improvements to suggest. First, change [n%20==0] to [n%20<1]. Second, change [[""," "*(2-n%5/2)+"."*(n%5)+"\n"][n%5!=0] to h=[(" "*(2-a/2)+"."*a+"\n")*(a>0)+"----\n"*(n%20/5),"< >\n"][n%20<1] with a=n%5, which moves all the n%5s out, and changes the conditional to *(a>0) which returns an empty string at a==0 for the same effect. – Sherlock9 – 2015-12-31T13:30:24.617

Finally, put a, h, and n on one line, like so: a=n%5;h=[(" "*(2-a/2)+"."*a+"\n")*(a>0)+"----\n"*(n%20/5),"< >\n"][n%20<1];n/=20. All this should leave you with 131 bytes. – Sherlock9 – 2015-12-31T14:01:34.087

1

PHP, 220 bytes

Same approach as my JavaScript answer. PHP has built-in functions for everything.

Takes 1 input from the command line (i.e. STDIN), as seen with $argv[1]:

<?=rtrim(implode("\n",array_map(function($j){return(!($j=base_convert($j,20,10))||$j%5?['<  >', ' .', ' ..', '...', '....'][$j%5]."\n":'').str_repeat("----\n",$j/5);},str_split(base_convert($argv[1],10,20)))));

rink.attendant.6

Posted 2015-08-04T16:12:15.810

Reputation: 2 776

1

C - 149

f(v){v/20&&(f(v/20),puts("\n"));if(v%=20)for(v%5&&printf("%3s%s","...."+4-v%5,v/5?"\n":""),v/=5;v--;v&&puts(""))printf("----");else printf("<  >");}

Uses recursion to print most significant numbers first. Then either prints zero or prints all dots with one clever printf and all fives in a loop. I am not sure if I can avoid using if-else here.

The downside of clever printf is that 1 and 3 are not aligned to each other:

Result for 23 is:

  .

...

119 incorrect solution - trailing newline

f(v){v/20&&(f(v/20),puts(""));if(v%=20)for(v%5&&printf("%3s\n","...."+4-v%5),v/=5;v--;)puts("----");else puts("<  >");}

aragaer

Posted 2015-08-04T16:12:15.810

Reputation: 431

146 bytes. – Jonathan Frech – 2018-12-27T04:34:44.173

1

PHP, 202 192 bytes

function m($n){return(($c=($n-($r=$n%20))/20)?m($c)."\n":"").
($r?(($q=$r%5)?substr(" .   .. ... ....",$q*4-4,4)."\n":"").
str_repeat("----\n",($r-$q)/5):"<  >\n");}
echo rtrim(m($argv[1]),"\n");

It gets the input from the first command line argument.

The complete source code, with comments and tests, is available on github.

axiac

Posted 2015-08-04T16:12:15.810

Reputation: 749

\n is two characters - but a newline in the middle of a string is only one. – fisharebest – 2015-09-11T12:50:53.300

1

Python 2, 114 bytes

This answer is based on Jakube's Pyth answer and Locoluis's Python 2 answer.

def f(n):d,m=divmod(n%20,5);h=[" "*(2-m/2)+"."*m+"\n----"*d,"<  >"][n%20<1];n/=20;return(f(n)+"\n\n"if n else"")+h

Sherlock9

Posted 2015-08-04T16:12:15.810

Reputation: 11 664

0

Jelly, 50 49 47 bytes

b5µṪ”.x⁶;$L<3Ɗ¡ṭ⁾--;UW¤ẋ$Ẏ$L¡Ṛø“<  >”WµẸ?
b20Ç€

Try it online!

... is now left aligned thanks to user202729's point.

When you trick yourself into thinking < > is a palindrome...

dylnan

Posted 2015-08-04T16:12:15.810

Reputation: 4 993

Why do you right-align ...... – user202729 – 2018-04-06T02:43:22.327

@user202729 For . and .. there needs to be a space so I put one for ... too. Is there a shorter way? – dylnan – 2018-04-06T02:46:55.877

I think that according to the challenge spec ... should not be right-aligned. Just change <4 to <3? – user202729 – 2018-04-06T03:02:51.200

@user202729 You’re right, I think I misread the spec. I don’t think it specifies for ... but I can change it to <2 – dylnan – 2018-04-06T04:03:38.760