ASCII Art Mayan Numerals

14

1

This challenge is simple. Given a number, output a ascii-art representation of the number, using the Mayan Base-20 numeral system.

What is the Mayan system?

The Mayans used base 20 to store numbers, so the first position was the 1s place, the next the 20s place, then the 400s, etc.

So Mayan number 1 is 1 in base 10, but 10 is actually 20 in base 10, 207 is 807 in base 10, etc..

And they represented their numbers as pictographs, with a special symbol for 0.

 -------------------
|    |    |    |    |
|    |    |    |    |
|-------------------|
|                   |
|                   |
 ------------------- 

That was their zero. (at least the half picascii half my artisticness ascii art version)

That is a real picture of the mayan zero symbol.1

This was their five:

--------------------------------
|                              |
--------------------------------

And a 4:

 ----   ----   ----   ----  
|    | |    | |    | |    | 
|    | |    | |    | |    | 
 ----   ----   ----   ----  

Finally, to put it together:

 ----   ----   ----  
|    | |    | |    | 
|    | |    | |    | 
 ----   ----   ----  
--------------------------------
|                              |
--------------------------------
--------------------------------
|                              |
--------------------------------

So they have x//5 bars, and x%5 dots on top of the bars. And if x=0, they use the shell/loaf instead of a blank space.

For more images, try the Wikimedia Commons page of Maya number images.

But this is only for numbers up to 19. We aren't allowed to have more than 4 bars and 4 dots in a single 'story'... So we go up!

The output for 20 is:

 ----
|    |
|    |
 ----



 -------------------
|    |    |    |    |
|    |    |    |    |
|-------------------|
|                   |
|                   |
 ------------------- 

Note this would normally be invalid, because is has a 1 and a 0 at the same time. But the 3 (note that, your answer needs at least 3) newlines before the 0 mean a new place value.

The bottom story has dots, meaning 1, and bars meaning 5. But it actually has dots meaning 20^0 and bars meaning 20^0 * 5.

Each story goes up a power. The second story dots mean 20 (20^1) and 100 (20^1 * 5).

So the number 506 can be represented as:

 ----  
|    | 
|    | 
 ----  




--------------------------------
|                              |
--------------------------------




 ----  
|    | 
|    | 
 ----  
--------------------------------
|                              |
--------------------------------

This is (20^0) * 1 + (20^0 * 5) * 1 + (20^1 * 5) * 1 + (20^2) * 1 = 1 + 5 + 100 + 400 = 506.

Your mission, should you choose not or choose to (it doesn't matter), is to output a ascii art representation of the base-10 number.

Other Rules:

  • Leading/trailing space is okay, as long as the dots, bars, and shells are intact.
  • The bars, dots, and shells must be exactly what the test cases have. No resizing.
  • Leading '0's are okay. (leading shells on the output)
  • You don't have to have exactly 3 newlines between each place value or story, just at least 3.

Test Cases:

15

--------------------------------
|                              |
--------------------------------
--------------------------------
|                              |
--------------------------------
--------------------------------
|                              |
--------------------------------  

12

 ----   ----  
|    | |    | 
|    | |    | 
 ----   ----  
--------------------------------
|                              |
--------------------------------
--------------------------------
|                              |
--------------------------------



4

 ----   ----   ----   ----  
|    | |    | |    | |    | 
|    | |    | |    | |    | 
 ----   ----   ----   ----  


0

 -------------------
|    |    |    |    |
|    |    |    |    |
|-------------------|
|                   |
|                   |
 ------------------- 


24

 ----  
|    | 
|    | 
 ----  




 ----   ----   ----   ----  
|    | |    | |    | |    | 
|    | |    | |    | |    | 
 ----   ----   ----   ----  



33



 ----  
|    |  
|    | 
 ----  




 ----   ----   ----  
|    | |    | |    | 
|    | |    | |    | 
 ----   ----   ----  
--------------------------------
|                              |
--------------------------------
--------------------------------
|                              |
--------------------------------



20



 ----  
|    | 
|    | 
 ----  




 -------------------
|    |    |    |    |
|    |    |    |    |
|-------------------| 
|                   |
|                   |
 -------------------  

1: They also used the heads of gods for the symbols, but for this challenge the shell/bread/zelda chest will be used.

Rɪᴋᴇʀ

Posted 2016-04-29T00:15:07.207

Reputation: 7 410

but for this challenge the shell/bread will be used.. Not shell, not bread. LOZ link to the past chest. – Bald Bantha – 2016-04-29T00:19:10.390

https://www.youtube.com/watch?v=69AyYUJUBTg – Bald Bantha – 2016-04-29T00:21:18.403

@epicTCK .... that is actually remarkably like it... – Rɪᴋᴇʀ – 2016-04-29T00:24:13.677

1Related. – Martin Ender – 2016-04-29T07:00:53.553

Answers

4

Ruby, 223 180 177 179 bytes

Anonymous function, returns a multiline string.

Forgot to add some extra spacing that was needed, and also the recursion. Also golfed a bit more by shifting things around.

f=->n{s=?|;e=' ';n<20?(n<1?[t=e+d=?-*19,a=s+(e*4+s)*4,a,s+d+s,b=s+e*19+s,b,t]:((r=n%5)>0?[t=" ----  "*r,m="|    | "*r,m,t]:[])+[a=?-*32,s+e*30+s,a]*(n/5))*$/:f[n/20]+$/*5+f[n%20]}

Value Ink

Posted 2016-04-29T00:15:07.207

Reputation: 10 608

You are the golfiest. Congrats! – Rɪᴋᴇʀ – 2016-06-18T14:54:06.780

6

Python 3.5, 404 400 392 312 311 308 290 281 285 281 bytes:

(Thanks to Adnan for a tip on saving 9 bytes(290->281) and Neil for a tip on saving 4 bytes(285->281)!)

def u(z):
 p=[];P=print;S,N,M,X=' -|\n'
 while not p or z:p+=[z%20];z=z//20
 E=lambda i:(S+N*4+S)*i+X+((M+S*4+M)*i+X)*2+(S+N*4+S)*i+X;F=N*32+X+M+S*30+M+X+N*32+X;[P(S+N*19+S+X+M+((S*4+M)*4+X+M)*2+N*19+M+X+(M+S*19+M+X)*2+S+N*19+S+X*3)if y<1else P(E(y%5)+F*(y//5)+X*3)for y in p[::-1]]

Try it online! (Ideone)

Analysis

For the purposes of this analysis, we will use the character set 0123456789ABCDEFGHIJ to represent each digit in base 20.

So, I could have gone and converted base 10 into base 20 using one of two algorithms I have. The first algorithm I thought of using is what I call the powers algorithm. This is not the one that I used in the code though as it would have made it way longer than it should have been, so I'm not going to talk about this one. However, I did create a python script that converts any integer in base 10 into any other base provided using this method, which you can use here on repl.it. The one I used instead for this challenge is what I call the division algorithm, which I think is explained pretty good here. But basically what happens is that it takes the base 10 number provided and divides it by the base it needs to convert the number to, which in this case is 20, until the remainder is either 0 or 1. It then takes the quotiant and remainder, in that order, from the last division operation, and then all the other remainders from the other division operations in the order from last to first. All these digits are then joined together, and that joined sequence reversed is your base 10 number in base 20! To illustrate this, assume you want to convert the base 10 number 431 to base 20. So, what we would do is this:

[]=list we will put all remainders and the last quotient in
R = Remainder

1. 431/20 = 21 R11 [B (B=11 in base 20)]
2. 21/20 = 1 R1 [Add the remainder and quotient: B11]

Then, finally we would take the list we have, which in this case contains B11, and reverse it so that we now have 11B. In doing this, we have finally got our final answer! 431 in base 10 converted to base 20 is 11B, which can be confirmed using my Python script that uses the powers algorithm which I already shared a link to above, but I will do it again here. Here is one that also uses the division algorithm described in this answer and returns the same answer as the powers one.

This entire process is essentially what happens in my script in this while loop: while not p or z:p+=[z%20];z=z//20. The only difference is that numbers >9 are not represented as letters but instead as themselves.

Moving on, after the base 10 number has been converted to base 20, for each digit in the base 20 integer, which we will call g, g mod 5 dots are printed out and then g//5 bars are printed out. Then the program prints 3 blank lines and moves on to the next digit. However, if the digit is 0, then a single "loaf" is printed out followed by 3 new lines, and then the program moves onto the next digit. So, taking the base 20 number 11B, we go to the first digit. The first digit is 1, and therefore it would print 0 bars since 1//5=0, and 1 dot since 1%5=1. So, we would first get this:

 ---- 
|    |
|    |
 ---- 

and then 3 new lines. Moving onto the the second digit, we also see that it is 1, so it would output the same thing:

 ---- 
|    |
|    |
 ---- 

and also 3 new lines. Finally, moving onto the last digit, we see that it's a B. Since B=11 in base 20, the program would output 1 dot since 11%5=1 and 2 bars since 11//5=2. So now, we get this:

 ---- 
|    |
|    |
 ---- 
--------------------------------
|                              |
--------------------------------
--------------------------------
|                              |
--------------------------------

Finally, putting all this together, we get this:

 ---- 
|    |
|    |
 ---- 




 ---- 
|    |
|    |
 ---- 




 ---- 
|    |
|    |
 ---- 
--------------------------------
|                              |
--------------------------------
--------------------------------
|                              |
--------------------------------

And, that's the mayan numeral for 431! You finally have your base 10 number represented in base 20 Mayan numerals.

Note: You may or may not have noticed that lambda function in my code. Regardless, this function is used for the creation of the dots since multiple dots must be output next to each other.

R. Kap

Posted 2016-04-29T00:15:07.207

Reputation: 4 730

I'm not sure if it's possible, but can you do S,N,M,X=' -|\n' instead of S,N,M,X=' ','-','|','\n'? – Adnan – 2016-04-29T10:53:05.647

@Adnan that is possible. – Rɪᴋᴇʀ – 2016-04-29T14:46:43.613

@Adnan Really? Wow, I did not know that. Thanks! – R. Kap – 2016-04-29T16:38:52.273

401 contains an inside zero. – Neil – 2016-04-30T07:27:21.180

@Neil Oh, right. Thanks for the heads-up. It's fixed now. – R. Kap – 2016-04-30T09:27:09.780

Rather than adding the J variable, can you use the fact that p is an empty list on the first time through the loop? – Neil – 2016-04-30T09:42:40.577

@Neil Yeah, I guess I can. Back to 281 bytes now! :) – R. Kap – 2016-04-30T10:08:56.177

I thought spaces were needed between the "dots"? Good job on the explanation though, and enjoy your bounty :D – Value Ink – 2016-06-19T04:16:51.687

Also, because of bool-to-int conversion and what-not, it is perfectly fine to do (not p)+z instead of not p or z! You might also be able to leverage this tip from the Python golf tips page for the last printing step

– Value Ink – 2016-06-19T04:36:45.603

3

Python 3, 243 bytes

s,v,h,x=' |-\n';P=print
t=s+h*19+s+x
def m(n):
 n//20and m(n//20);r=n%20
 if r:
  for a,b,f in[(r%5*' ----  ',r%5*'|    | ',1),('-'*32,'|'+' '*30+'|',r//5)]:P(*((a,b,b,a)*f),sep=x)
 else:P(t+2*(v+(4*s+v)*4+x)+v+h*19+v+x+2*(v+s*19+v+x)+t)
 P(x)

Discussion

n//20and m(n//20) calls m() recursively if there are higher powers of 20 to be handled. The recursion is done before printing the current place value, so that higher powers get printed first.

If the current place value is non-zero (r!=0), the for a,b,f-loop prints the units and then the fives. a is the first/forth row and b is the second/third row. The trick is in the print(*((a,b,b,a)*f),sep=x). For the units, f = 1 resulting in print(*(a,b,b,a),sep=x), which prints the 4 rows that make up the units symbols (x is a '\n'). For the fives, f = the number of fives to print (r//5), so the tuple (a,b,b,a) gets multiplied (i.e., repeated) by the number of fives to print. If f = 2, we get print(*(a,b,b,a,a,b,b,a),sep=x), which prints two symbols for five.

If the current place value is 0, then the zero symbol is printed.

RootTwo

Posted 2016-04-29T00:15:07.207

Reputation: 1 749

I did have to reward the bounty to R. Kap, but this might deserve it's own bounty! Nice job! – Rɪᴋᴇʀ – 2016-06-22T01:03:31.993

2

Python, 411 bytes

w,m=input(),[]
for i in[20**i for i in range(int(w**0.25))][::-1]:m.append(w/i);w=w%i
for i in m or[0]:print(lambda x,y='\n',w=' ----  ',z='|    | ':w*(x%5)+y+z*(x%5)+y+z*(x%5)+y+w*(x%5)+y+('-'*32+'\n|'+' '*30+'|\n'+'-'*32+y)*(x/5)if x else''' -------------------
|    |    |    |    |
|    |    |    |    |
|-------------------|
|                   |
|                   |
 ------------------- ''')(i),'\n\n\n'

I created this to generate test cases, you can use it as a benchmark. Sorta golfed.

Rɪᴋᴇʀ

Posted 2016-04-29T00:15:07.207

Reputation: 7 410

You could take off 26 bytes by removing whitespace, and another 4 by doing s=math.sqrt and calling s(s(w)) instead of math.sqrt(math.sqrt(w)) – James – 2016-04-29T00:32:17.427

@DrGreenEggsandHamDJ thanks. I don't think I got 26 bytes off from whitespace though? – Rɪᴋᴇʀ – 2016-04-29T00:37:13.340

Oh, sorry, counting error I meant 25. Also, w**0.25 is even better than s(s(w)). Although it got longer? – James – 2016-04-29T00:39:42.617

@DrGreenEggsandHamDJ yeah, I somehow lost the shell zero string in transit from file to answer. – Rɪᴋᴇʀ – 2016-04-29T00:40:33.750

2

JavaScript (ES6), 254 bytes

f=(n,r=(s,n=19)=>s.repeat(n))=>(n>19?f(n/5>>2)+`


`:``)+(n%5?`${r(s=` ----  `,n%5)}
${t=r(`|    | `,n%5)}
${t}
${s}
`:``)+r(`${s=r(`-`,32)}
|${r(` `,30)}|
${s}
`,n/5&3)+(n%20?``:` ${s=r(`-`)}
${t=r(`|    `,4)}|
${t}|
|${s}|
|${t=r(` `)}|
|${t}|
 ${s}
`)

Neil

Posted 2016-04-29T00:15:07.207

Reputation: 95 035

I can't get this to work? It errors with Missing } in template expression. I don't know very much js, how can I fix it? – Rɪᴋᴇʀ – 2016-04-29T20:51:47.620

@EᴀsᴛᴇʀʟʏIʀᴋ My bad, I moved some code around and accidentally pasted it in the wrong place. It's fixed now. – Neil – 2016-04-29T21:34:15.030

1

Python 3, 213 bytes

Came up with an even shorter version using a different approach:

s,v,h,x=' |-\n'
t=s+h*19+s
k=4*s+v
w=v+4*k
y=v+s*19+v
a=' ----  '
b=v+k+s
c=h*32
d=v+s*30+v
m=lambda n:m(n//20)+([n%5*a,n%5*b,n%5*b,n%5*a][:n%5*4]+n%20//5*[c,d,d,c]if n%20else[t,w,w,v+h*19+v,y,y,t])+[x,x]if n else[]

explanation

The first 9 lines or so, build up strings that are used to make the symbols

s,v,h,x = ' |-\n'
k = '    |'

    # parts for a unit
a = ' ----  '
b = '|    | '

    # parts for a five
c = '--------------------------------'
d = '|                              |'

    # parts for a zero
t = ' ------------------- '
w = '|    |    |    |    |'
y = '|                   |'

The core of the solution is the recursive function m, which builds a list of strings, one string for each line in the output. Schematically, m looks like:

m(n//20) + (ones + fives if n%20 else zero) + [x,x] if n else []

m can be rewritten like:

def m(n):
  if n:
    ans = m(n//20)                             # process high digits first

    if n%20:                                   # if there is a base-20 digit
      ans += [n%5*a,n%5*b,n%5*b,n%5*a][:n%5*4] # add strings for the 'ones' if any
      ans += n%20//5 * [c, d, d, c]            # add strings for the 'fives' if any

    else:
      ans += [t,w,w,v+h*19+v,y,y,t]            # otherwise, add strings for a `zero`

    ans += [x,x]                               # blank lines between digit groups

  else:
    ans = []                                   # base case

  return ans

The recursive call m(n//20) comes first so that the most significant digits are done first.

[n%5*a,n%5*b,n%5*b,n%5*a] are the string for ones symbols. a is the top row for a single symbol. n%5 is the number of one symbols for this digit. So, n%5*a is a string for the top (and bottom) row of n%5 ones. Similarly, 'n%5*b` is a string for the 2nd (and 3rd) row.

The expression [:n%5*4] acts like an if to avoid extra blank lines in the output if there aren't any 'ones' to output. It's not needed, but makes the output look better.

n%20//5 is the number of symbols for five that are needed. [c,d,d,c] are the strings to make one symbol for five.

[t,w,w,v+h*19+v,y,y,t] are the strings to make the zero symbol

[x,x] puts at least three blank lines between groups of Mayan digits

RootTwo

Posted 2016-04-29T00:15:07.207

Reputation: 1 749

Can you give an explanation on how this works? – Rɪᴋᴇʀ – 2016-08-05T23:16:47.773