4
\$\begingroup\$

This proposal had few attention for 8 months (though an answer was posted in the sandbox at that time), so I decided to post it anyway.

Introduction

Napier's bones is a calculation tool, which helps speeding up the calculation of multiplication, division and digit-by-digit square root extraction by turning n-digit-by-1-digit multiplications into table look-ups. Napier's bones consists of rods marked with the multiples of a single-digit number, and a board with a set of numbers on the left, on which the rods can be arranged. The board and the rods look like this (All appearances of the rods are in the Sample section):

Rod    Board
       +-----------------------------------------------+
       |   +------------------------------------------+|
+---+  |   |                                          ||
| 4 |  |   |                                          ||
+---+  |   |                                          ||
|0 /|  |   |                                          ||
| / |  | 1 |                                          ||
|/ 4|  |   |                                          ||
+---+  |   |                                          ||
|0 /|  |   |                                          ||
| / |  | 2 |                                          ||
|/ 8|  |   |                                          ||
+---+  |   |                                          ||
|1 /|  |   |                                          ||
| / |  | 3 |                                          ||
|/ 2|  |   |                                          ||
+---+  |   |                                          ||
|1 /|  |   |                                          ||
| / |  | 4 |                                          ||
|/ 6|  |   |                                          ||
+---+  |   |                                          ||
|2 /|  |   |                                          ||
| / |  | 5 |                                          ||
|/ 0|  |   |                                          ||
+---+  |   |                                          ||
|2 /|  |   |                                          ||
| / |  | 6 |                                          ||
|/ 4|  |   |                                          ||
+---+  |   |                                          ||
|2 /|  |   |                                          ||
| / |  | 7 |                                          ||
|/ 8|  |   |                                          ||
+---+  |   |                                          ||
|3 /|  |   |                                          ||
| / |  | 8 |                                          ||
|/ 2|  |   |                                          ||
+---+  |   |                                          ||
|3 /|  |   |                                          ||
| / |  | 9 |                                          ||
|/ 6|  |   |                                          ||
+---+  |   |                                          ||
       |   +------------------------------------------+|
       +-----------------------------------------------+

Challenge

This challenge is to write a function or program which receives a natural number as input, and outputs the arrangement of the rods, as if a calculation were in progress, on the board as an ASCII art, according to the input, having the code as short as possible. The top row of the rods will assemble that number you have inputted.

Requirements

  • The input can be an argument of the function or program, or an input from STDIN. Please indicate your choice of input format. Accepted formats are as follows:

    • An integer representing the number;
    • A string representing the number; or
    • A list of characters representing the digits of the number.
  • The output can be directly printed to STDOUT, or returned from the function as a string. Please refer to the Sample section.

  • You can assume that the input will always be a valid representation of the number, i.e. the number matches the regex [1-9][0-9]*.
  • You must support all valid inputs in the range [1, 2147483648). Larger ranges are absolutely welcomed.
  • You must leave no space around the rods.
  • Standard loopholes apply.

Sample Input/Output

Input: 1234567890

Output:

+-------------------------------------------------------+
|   +--------------------------------------------------+|
|   |+---++---++---++---++---++---++---++---++---++---+||
|   || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 0 |||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||0 /||0 /||0 /||0 /||0 /||0 /||0 /||0 /||0 /|||
| 1 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 1||/ 2||/ 3||/ 4||/ 5||/ 6||/ 7||/ 8||/ 9||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||0 /||0 /||0 /||1 /||1 /||1 /||1 /||1 /||0 /|||
| 2 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 2||/ 4||/ 6||/ 8||/ 0||/ 2||/ 4||/ 6||/ 8||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||0 /||0 /||1 /||1 /||1 /||2 /||2 /||2 /||0 /|||
| 3 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 3||/ 6||/ 9||/ 2||/ 5||/ 8||/ 1||/ 4||/ 7||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||0 /||1 /||1 /||2 /||2 /||2 /||3 /||3 /||0 /|||
| 4 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 4||/ 8||/ 2||/ 6||/ 0||/ 4||/ 8||/ 2||/ 6||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||1 /||1 /||2 /||2 /||3 /||3 /||4 /||4 /||0 /|||
| 5 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 5||/ 0||/ 5||/ 0||/ 5||/ 0||/ 5||/ 0||/ 5||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||1 /||1 /||2 /||3 /||3 /||4 /||4 /||5 /||0 /|||
| 6 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 6||/ 2||/ 8||/ 4||/ 0||/ 6||/ 2||/ 8||/ 4||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||1 /||2 /||2 /||3 /||4 /||4 /||5 /||6 /||0 /|||
| 7 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 7||/ 4||/ 1||/ 8||/ 5||/ 2||/ 9||/ 6||/ 3||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||1 /||2 /||3 /||4 /||4 /||5 /||6 /||7 /||0 /|||
| 8 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 8||/ 6||/ 4||/ 2||/ 0||/ 8||/ 6||/ 4||/ 2||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   ||0 /||1 /||2 /||3 /||4 /||5 /||6 /||7 /||8 /||0 /|||
| 9 || / || / || / || / || / || / || / || / || / || / |||
|   ||/ 9||/ 8||/ 7||/ 6||/ 5||/ 4||/ 3||/ 2||/ 1||/ 0|||
|   |+---++---++---++---++---++---++---++---++---++---+||
|   +--------------------------------------------------+|
+-------------------------------------------------------+

Victory Condition

This is a , so the shortest code wins.

\$\endgroup\$
3
  • \$\begingroup\$ Can you link to the original Sandbox post? \$\endgroup\$
    – Neil
    Sep 22, 2018 at 10:49
  • \$\begingroup\$ @Neil codegolf.meta.stackexchange.com/a/14555/71546 (Now deleted sandbox post) \$\endgroup\$ Sep 22, 2018 at 11:27
  • \$\begingroup\$ Ah yes, I seem to have outgolfed myself quite handily, thanks! \$\endgroup\$
    – Neil
    Sep 22, 2018 at 12:13

4 Answers 4

2
\$\begingroup\$

Charcoal, 78 bytes

B⁺⁷×⁵Lθ⁴³↓↘↘P↓⭆⁹◧I⊕ι⁴↗↗B⁺²×⁵Lθ⁴¹↘Fθ«B⁵¦³↘→←ι↙FE⁹×Iι⊕κ«UR⁵↘↘I÷κχ↘↑I﹪κχ↑↙³»M⁵±³⁸

Try it online! Link is to verbose version of code. Explanation:

B⁺⁷×⁵Lθ⁴³↓↘↘

Draw the outer box.

P↓⭆⁹◧I⊕ι⁴↗↗

Pad the digits 1-9 and print them vertically.

B⁺²×⁵Lθ⁴¹↘

Draw the inner box.

Fθ«

Loop over the bones.

B⁵¦³↘→←ι↙

Draw the small box at the top of the bone with the current digit.

FE⁹×Iι⊕κ«

Multiply the current digit with the digits 1-9 and loop over the result.

UR⁵↘↘I÷κχ↘↑I﹪κχ↑↙³»

Draw a square and insert the digits of the product and the diagonal line.

M⁵±³⁸

Move to the start of the next bone.

\$\endgroup\$
3
  • \$\begingroup\$ Nice answer! Didn't realize that Move(:DownRight);Move(:DownRight); / ↘↘ is actually shorter than Move(2, :DownRight); / M²↘ in this case. Btw, is Move with two num inputs not in the github docs yet? Never seen Move(5, Negate(38)); / M⁵±³⁸ before.. \$\endgroup\$ Sep 21, 2018 at 11:59
  • 1
    \$\begingroup\$ @KevinCruijssen I've corrected the documentation; it used to have the wrong succinct code and only one verbose alias. \$\endgroup\$
    – Neil
    Sep 21, 2018 at 12:11
  • \$\begingroup\$ Ah, so it's an alias for Jump when using two num inputs. I see. That makes sense. \$\endgroup\$ Sep 21, 2018 at 12:14
2
\$\begingroup\$

Python 2, 424 314 304 305 303 298 bytes

n=map(int,input());l=len(n)
a,b='+'+'-'*5*-~l+'+','|   +'+'-'*5*l+'+|'
x='+---+'*l
y='|   |%s||\n'
j=''.join
print'\n'.join([a,b,j([(y+'| %s |%s||\n'+y+y)%(j('|%d /|'%(c*i/10)for c in n),i,'| / |'*l,j('|/ %d|'%(c*i%10)for c in n),x),3*y%(x,j('| %s |'%c for c in n),x)][i<1]for i in range(10))+b,a])

Try it online!

-2 bytes, thanks to Kevin Cruijssen

\$\endgroup\$
2
  • \$\begingroup\$ That was quick, and with just 1 additional byte. +1 from me! Oh, and one small thing to golf: (3*y)% can be 3*y%. \$\endgroup\$ Sep 21, 2018 at 8:02
  • \$\begingroup\$ @KevinCruijssen Thanks :) \$\endgroup\$
    – TFeld
    Sep 21, 2018 at 8:08
2
\$\begingroup\$

JavaScript (ES8), 250 241 bytes

Takes input as an array of digit characters of any size.

s=>[...'0123'.padEnd(40,2456)+210].map((v,y)=>`+----0-+,|   +0+|,71||,72||,73||,| 6 |4||,75||`.split`,`[v].replace(/\d/g,n=>[Y=y>>2,'|   |'][n-6]||s.map(X=>`-----+---+| ${X} ||${X*Y/10|0} /|| / ||/ ${X*Y%10}|`.substr(n*5,5)).join``)).join`
`

Try it online!

How?

The board consists of 43 rows of 7 distinct types, which are represented below with an ID in \$[0..6]\$:

00: +---------------+ --> 0 >--- outer board header
01: |   +----------+| --> 1 >--- inner board header
02: |   |+---++---+|| --> 2 \___ rod header
03: |   || X || X ||| --> 3 /
04: |   |+---++---+|| --> 2 \
05: |   ||X /||X /||| --> 4  \__ first row
06: | X || / || / ||| --> 5  /
07: |   ||/ X||/ X||| --> 6 /
..  .               .
..  .               .
36: |   |+---++---+|| --> 2 \
37: |   ||X /||X /||| --> 4  \__ last row
38: | X || / || / ||| --> 5  /
39: |   ||/ X||/ X||| --> 6 /
40: |   |+---++---+|| --> 2 >--- rod footer
41: |   +----------+| --> 1 >--- inner board footer
42: +---------------+ --> 0 >--- outer board footer

The code '0123'.padEnd(40,2456)+210 (see this tip) generates the following string of 43 row IDs over which we are going to iterate:

"0123245624562456245624562456245624562456210"

Each ID is replaced with a temporary encoded string which, in turn, contains other IDs in \$[0..7]\$:

 ID | String
----+------------
  0 | "+----0-+"
  1 | "|   +0+|"
  2 | "71||"
  3 | "72||"
  4 | "73||"
  5 | "| 6 |4||"
  6 | "75||"

Finally, each new ID is replaced with a 5-character string which is appended as many times as there are digits in the input array, except the last two ones which are just inserted as-is:

 ID | String            | Repeated
----+-------------------+----------
  0 | `-----`           |   Yes          where:
  1 | `+---+`           |   Yes            X = horizontal digit
  2 | `| ${X} |`        |   Yes            Y = vertical digit
  3 | `|${X*Y/10|0} /|` |   Yes
  4 | `| / |`           |   Yes
  5 | `|/ ${X*Y%10}|`   |   Yes
  6 | Y                 |   No
  7 | `|   |`           |   No
\$\endgroup\$
2
\$\begingroup\$

Java 11, 352 344 340 309 bytes

a->{int l=a.length,i=0;String Z="+"+"-".repeat(l*5),A=Z+"-----+\n",Y="|   ",B=Y+Z+"+|\n",X="||\n",D=Y+="|",C=Y+"+---+".repeat(l)+X,r=A+B+C,t,u,v;for(int d:a)D+="| "+d+" |";for(r+=D+X;i++<9;r+=C+t+X+u+X+v+X){t=v=Y;u="| "+i+" |";for(int d:a){d*=i;t+="|"+d/10+" /|";u+="| / |";v+="|/ "+d%10+"|";}}return r+B+A;}

-4 bytes thanks to @ShieruAsakoto
-32 bytes thanks to @ceilingcat.

Try it online.

Explanation:

a->{                 // Method with digit-array as parameter and String return-type
  int l=a.length     //  Amount of digits in the input
      i=0;           //  Index-integer
  String
    Z="+"+"-".repeat(l*5),
                     //  String `Z` for the "+------..." of the four lines
    A=Z+"-----+\n",  //  String `A` for the "+---...---+" of the first and last lines
    Y="|   ",        //  String `Y` for "|   "
    B=Y+Z+"+|\n",    //  String `B` for the second and next to last lines
    X="||\n",        //  String `X` for "||" + newline
    D=Y+="|",        //  String `D` starting with "|   |"
                     //  (and change `Y` to this as well now)
    C=Y+"+---+".repeat(l)+X,
                     //  String `C` for the third and fifth lines
    r=A+B+C,         //  Result-String, starting at the first three lines
    t,u,v;           //  Three temp Strings, uninitialized for now
  for(int d:a)       //  Loop over the input-digits
    D+="| "+d+" |";  //   Append `D` with "| d |" where `d` is the digit
  for(r+=D+X;        //  Append `X` to `D`, and then `D` to the result-String
      i++<9;         //  Loop `i` in the range [1, 9]
      r+=            //    After every iteration, append the result-String with:
         C           //     line `C`
         +t+X        //     and line `t` with a trailing `X`
         +u+X        //     and line `u` with a trailing `X`
         +v+X){      //     and line `v` with a trailing `X`
    t=v=Y;           //   Reset `t` and `v` to `Y`
    u="| "+i+" |";   //   and `u` to "| i |" where `i` is the `i` from the loop
    for(int d:a){    //   Inner loop over the input-digits
      d*=i;          //    Multiply the current digit with `i`
      t+="|"         //    Append `t` with "|"
         +d/10       //     and the first of two digits for the multiplication result
         +" /|";     //     and " /|"
      u+="| / |";    //    Append `u` with "| / |"
      v+="|/ "       //    Append `v` with "|/ "
         +d%10       //    and the second of two digits for the multiplication result
         +"|";}}     //    and "|"
  return r           //  And finally return the result-String,
         +B+A;}      //   appended with lines `B` and `A`
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Seems that the parentheses around d/10 and d%10 are not necessary thanks to operation precedence? \$\endgroup\$ Sep 21, 2018 at 11:29
  • \$\begingroup\$ @ShieruAsakoto Ah, of course, thanks! If the integer-calculations are at the start of a String no parenthesis are necessary, so I added them because they are in the middle here (i.e. String s=i+1+" some text"; is possible, but String s="some text"+i+1; or String s="some"+i+1+"text"; should be (i+1) instead). But completely forgot that they are / and % here, instead of the usual + and -, so then operator precedence indeed kicks in, so thanks for -4 bytes. :) \$\endgroup\$ Sep 21, 2018 at 11:45

Your Answer

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

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