Cistercian numerals

From Rosetta Code
Revision as of 00:39, 9 December 2020 by Chunes (talk | contribs) (Update image link in task description; the only one was dead.)
Task
Cistercian numerals
You are encouraged to solve this task according to the task description, using any language you may know.

Cistercian numerals were used across Europe by Cistercian monks during the Late Medieval Period as an alternative to Roman numerals. They were used to represent base 10 integers from 0 to 9999.

How they work

All Cistercian numerals begin with a vertical line segment, which by itself represents the number 0. Then, glyphs representing the digits 1 through 9 are optionally added to the four quadrants surrounding the vertical line segment. These glyphs are drawn with vertical and horizontal symmetry about the initial line segment. Each quadrant corresponds to a digit place in the number:

  • The upper-right quadrant represents the ones place.
  • The upper-left quadrant represents the tens place.
  • The lower-right quadrant represents the hundreds place.
  • The lower-left quadrant represents the thousands place.

Please consult the following image for examples of Cistercian numerals showing each glyph: [1]

Task
  • Write a function/procedure/routine to display any given Cistercian numeral. This could be done by drawing to the display, creating an image, or even as text (as long as it is a reasonable facsimile).
  • Use the routine to show the following Cistercian numerals:
  • 0
  • 1
  • 20
  • 300
  • 4000
  • 5555
  • 6789
  • And a number of your choice!
Notes

Due to the inability to upload images to Rosetta Code as of this task's creation, showing output here on this page is not required. However, it is welcomed — especially for text output.

See also


C++

Translation of: Go

<lang cpp>#include <array>

  1. include <iostream>

template<typename T, size_t S> using FixedSquareGrid = std::array<std::array<T, S>, S>;

struct Cistercian { public:

   Cistercian() {
       initN();
   }
   Cistercian(int v) {
       initN();
       draw(v);
   }
   Cistercian &operator=(int v) {
       initN();
       draw(v);
   }
   friend std::ostream &operator<<(std::ostream &, const Cistercian &);

private:

   FixedSquareGrid<char, 15> canvas;
   void initN() {
       for (auto &row : canvas) {
           row.fill(' ');
           row[5] = 'x';
       }
   }
   void horizontal(size_t c1, size_t c2, size_t r) {
       for (size_t c = c1; c <= c2; c++) {
           canvas[r][c] = 'x';
       }
   }
   void vertical(size_t r1, size_t r2, size_t c) {
       for (size_t r = r1; r <= r2; r++) {
           canvas[r][c] = 'x';
       }
   }
   void diagd(size_t c1, size_t c2, size_t r) {
       for (size_t c = c1; c <= c2; c++) {
           canvas[r + c - c1][c] = 'x';
       }
   }
   void diagu(size_t c1, size_t c2, size_t r) {
       for (size_t c = c1; c <= c2; c++) {
           canvas[r - c + c1][c] = 'x';
       }
   }
   void drawOnes(int v) {
       switch (v) {
       case 1:
           horizontal(6, 10, 0);
           break;
       case 2:
           horizontal(6, 10, 4);
           break;
       case 3:
           diagd(6, 10, 0);
           break;
       case 4:
           diagu(6, 10, 4);
           break;
       case 5:
           drawOnes(1);
           drawOnes(4);
           break;
       case 6:
           vertical(0, 4, 10);
           break;
       case 7:
           drawOnes(1);
           drawOnes(6);
           break;
       case 8:
           drawOnes(2);
           drawOnes(6);
           break;
       case 9:
           drawOnes(1);
           drawOnes(8);
           break;
       default:
           break;
       }
   }
   void drawTens(int v) {
       switch (v) {
       case 1:
           horizontal(0, 4, 0);
           break;
       case 2:
           horizontal(0, 4, 4);
           break;
       case 3:
           diagu(0, 4, 4);
           break;
       case 4:
           diagd(0, 4, 0);
           break;
       case 5:
           drawTens(1);
           drawTens(4);
           break;
       case 6:
           vertical(0, 4, 0);
           break;
       case 7:
           drawTens(1);
           drawTens(6);
           break;
       case 8:
           drawTens(2);
           drawTens(6);
           break;
       case 9:
           drawTens(1);
           drawTens(8);
           break;
       default:
           break;
       }
   }
   void drawHundreds(int hundreds) {
       switch (hundreds) {
       case 1:
           horizontal(6, 10, 14);
           break;
       case 2:
           horizontal(6, 10, 10);
           break;
       case 3:
           diagu(6, 10, 14);
           break;
       case 4:
           diagd(6, 10, 10);
           break;
       case 5:
           drawHundreds(1);
           drawHundreds(4);
           break;
       case 6:
           vertical(10, 14, 10);
           break;
       case 7:
           drawHundreds(1);
           drawHundreds(6);
           break;
       case 8:
           drawHundreds(2);
           drawHundreds(6);
           break;
       case 9:
           drawHundreds(1);
           drawHundreds(8);
           break;
       default:
           break;
       }
   }
   void drawThousands(int thousands) {
       switch (thousands) {
       case 1:
           horizontal(0, 4, 14);
           break;
       case 2:
           horizontal(0, 4, 10);
           break;
       case 3:
           diagd(0, 4, 10);
           break;
       case 4:
           diagu(0, 4, 14);
           break;
       case 5:
           drawThousands(1);
           drawThousands(4);
           break;
       case 6:
           vertical(10, 14, 0);
           break;
       case 7:
           drawThousands(1);
           drawThousands(6);
           break;
       case 8:
           drawThousands(2);
           drawThousands(6);
           break;
       case 9:
           drawThousands(1);
           drawThousands(8);
           break;
       default:
           break;
       }
   }
   void draw(int v) {
       int thousands = v / 1000;
       v %= 1000;
       int hundreds = v / 100;
       v %= 100;
       int tens = v / 10;
       int ones = v % 10;
       if (thousands > 0) {
           drawThousands(thousands);
       }
       if (hundreds > 0) {
           drawHundreds(hundreds);
       }
       if (tens > 0) {
           drawTens(tens);
       }
       if (ones > 0) {
           drawOnes(ones);
       }
   }

};

std::ostream &operator<<(std::ostream &os, const Cistercian &c) {

   for (auto &row : c.canvas) {
       for (auto cell : row) {
           os << cell;
       }
       os << '\n';
   }
   return os;

}

int main() {

   for (auto number : { 0, 1, 20, 300, 4000, 5555, 6789, 9999 }) {
       std::cout << number << ":\n";
       Cistercian c(number);
       std::cout << c << '\n';
   }
   return 0;

}</lang>

Output:
0:
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x

1:
     xxxxxx
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x

20:
     x
     x
     x
     x
xxxxxx
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x

300:
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x    x
     x   x
     x  x
     x x
     xx

4000:
     x
     x
     x
     x
     x
     x
     x
     x
     x
     x
    xx
   x x
  x  x
 x   x
x    x

5555:
xxxxxxxxxxx
 x   x   x
  x  x  x
   x x x
    xxx
     x
     x
     x
     x
     x
    xxx
   x x x
  x  x  x
 x   x   x
xxxxxxxxxxx

6789:
x    xxxxxx
x    x    x
x    x    x
x    x    x
xxxxxxxxxxx
     x
     x
     x
     x
     x
x    x    x
x    x    x
x    x    x
x    x    x
x    xxxxxx

9999:
xxxxxxxxxxx
x    x    x
x    x    x
x    x    x
xxxxxxxxxxx
     x
     x
     x
     x
     x
xxxxxxxxxxx
x    x    x
x    x    x
x    x    x
xxxxxxxxxxx

Factor

Works with: Factor version 0.99 2020-08-14

<lang factor>USING: combinators continuations formatting grouping io kernel literals math.order math.text.utils multiline sequences splitting ;

CONSTANT: numerals $[ HEREDOC: END

 +    +-+  +    +    + +  +-+  + +  +-+  + +  +-+
 |    |    |    |\   |/   |/   | |  | |  | |  | |
 |    |    +-+  | +  +    +    | +  | +  +-+  +-+
 |    |    |    |    |    |    |    |    |    |  
 |    |    |    |    |    |    |    |    |    |  
 |    |    |    |    |    |    |    |    |    |  
 +    +    +    +    +    +    +    +    +    +  

END "\n" split harvest [ 5 group ] map flip ]

precedence ( char char -- char )
   2dup [ CHAR: + = ] either? [ 2drop CHAR: + ] [ max ] if ;
overwrite ( glyph glyph -- newglyph )
   [ [ precedence ] 2map ] 2map ;
flip-slashes ( str -- new-str )
   [
       {
           { CHAR: / [ CHAR: \ ] }
           { CHAR: \ [ CHAR: / ] }
           [ ]
       } case
   ] map ;
hflip ( seq -- newseq ) [ reverse flip-slashes ] map ;
vflip ( seq -- newseq ) reverse [ flip-slashes ] map ;
get-digits ( n -- seq ) 1 digit-groups 4 0 pad-tail ;
check-cistercian ( n -- )
   0 9999 between? [ "Must be from 0 to 9999." throw ] unless ;
.cistercian ( n -- )
   [ check-cistercian ] [ "%d:\n" printf ] [ get-digits ] tri
   [ numerals nth ] map
   [ { [ ] [ hflip ] [ vflip ] [ hflip vflip ] } spread ]
   with-datastack [ ] [ overwrite ] map-reduce [ print ] each ;

{ 0 1 20 300 4000 5555 6789 8015 } [ .cistercian nl ] each</lang>

Output:
0:
  +  
  |  
  |  
  |  
  |  
  |  
  +  

1:
  +-+
  |  
  |  
  |  
  |  
  |  
  +  

20:
  +  
  |  
+-+  
  |  
  |  
  |  
  +  

300:
  +  
  |  
  |  
  |  
  | +
  |/ 
  +  

4000:
  +  
  |  
  |  
  |  
  +  
 /|  
+ +  

5555:
+-+-+
 \|/ 
  +  
  |  
  +  
 /|\ 
+-+-+

6789:
+ +-+
| | |
+-+-+
  |  
+ | +
| | |
+ +-+

8015:
+-+-+
  |/ 
  +  
  |  
+-+  
| |  
+ +  

Go

Translation of: Wren

<lang go>package main

import "fmt"

var n = make([][]string, 15)

func initN() {

   for i := 0; i < 15; i++ {
       n[i] = make([]string, 11)
       for j := 0; j < 11; j++ {
           n[i][j] = " "
       }
       n[i][5] = "x"
   }

}

func horiz(c1, c2, r int) {

   for c := c1; c <= c2; c++ {
       n[r][c] = "x"
   }

}

func verti(r1, r2, c int) {

   for r := r1; r <= r2; r++ {
       n[r][c] = "x"
   }

}

func diagd(c1, c2, r int) {

   for c := c1; c <= c2; c++ {
       n[r+c-c1][c] = "x"
   }

}

func diagu(c1, c2, r int) {

   for c := c1; c <= c2; c++ {
       n[r-c+c1][c] = "x"
   }

}

var draw map[int]func() // map contains recursive closures

func initDraw() {

   draw = map[int]func(){
       1: func() { horiz(6, 10, 0) },
       2: func() { horiz(6, 10, 4) },
       3: func() { diagd(6, 10, 0) },
       4: func() { diagu(6, 10, 4) },
       5: func() { draw[1](); draw[4]() },
       6: func() { verti(0, 4, 10) },
       7: func() { draw[1](); draw[6]() },
       8: func() { draw[2](); draw[6]() },
       9: func() { draw[1](); draw[8]() },
       10: func() { horiz(0, 4, 0) },
       20: func() { horiz(0, 4, 4) },
       30: func() { diagu(0, 4, 4) },
       40: func() { diagd(0, 4, 0) },
       50: func() { draw[10](); draw[40]() },
       60: func() { verti(0, 4, 0) },
       70: func() { draw[10](); draw[60]() },
       80: func() { draw[20](); draw[60]() },
       90: func() { draw[10](); draw[80]() },
       100: func() { horiz(6, 10, 14) },
       200: func() { horiz(6, 10, 10) },
       300: func() { diagu(6, 10, 14) },
       400: func() { diagd(6, 10, 10) },
       500: func() { draw[100](); draw[400]() },
       600: func() { verti(10, 14, 10) },
       700: func() { draw[100](); draw[600]() },
       800: func() { draw[200](); draw[600]() },
       900: func() { draw[100](); draw[800]() },
       1000: func() { horiz(0, 4, 14) },
       2000: func() { horiz(0, 4, 10) },
       3000: func() { diagd(0, 4, 10) },
       4000: func() { diagu(0, 4, 14) },
       5000: func() { draw[1000](); draw[4000]() },
       6000: func() { verti(10, 14, 0) },
       7000: func() { draw[1000](); draw[6000]() },
       8000: func() { draw[2000](); draw[6000]() },
       9000: func() { draw[1000](); draw[8000]() },
   }

}

func printNumeral() {

   for i := 0; i < 15; i++ {
       for j := 0; j < 11; j++ {
           fmt.Printf("%s ", n[i][j])
       }
       fmt.Println()
   }
   fmt.Println()

}

func main() {

   initDraw()
   numbers := []int{0, 1, 20, 300, 4000, 5555, 6789, 9999}
   for _, number := range numbers {
       initN()
       fmt.Printf("%d:\n", number)
       thousands := number / 1000
       number %= 1000
       hundreds := number / 100
       number %= 100
       tens := number / 10
       ones := number % 10
       if thousands > 0 {
           draw[thousands*1000]()
       }
       if hundreds > 0 {
           draw[hundreds*100]()
       }
       if tens > 0 {
           draw[tens*10]()
       }
       if ones > 0 {
           draw[ones]()
       }
       printNumeral()
   }

}</lang>

Output:
Same as Wren example.

Julia

Gtk graphic version. <lang julia>using Gtk, Cairo

const can = GtkCanvas(800, 100) const win = GtkWindow(can, "Canvas") const numbers = [0, 1, 20, 300, 4000, 5555, 6789, 8123]

function drawcnum(ctx, xypairs)

   move_to(ctx, xypairs[1][1], xypairs[1][2])
   for p in xypairs[2:end]
       line_to(ctx, p[1], p[2])
   end
   stroke(ctx)

end

@guarded draw(can) do widget

   ctx = getgc(can)
   hlen, wlen, len = height(can), width(can), length(numbers)
   halfwspan, thirdcolspan, voffset = wlen ÷ (len * 2), wlen ÷ (len * 3), hlen ÷ 8
   set_source_rgb(ctx, 0, 0, 2550)
   for (i, n) in enumerate(numbers)
       # paint vertical as width 2 rectangle
       x = halfwspan * (2 * i - 1)
       rectangle(ctx, x, voffset, 2, hlen - 2 * voffset)
       stroke(ctx)
       # determine quadrant and draw numeral lines there
       dig = [(10^(i - 1), m) for (i, m) in enumerate(digits(n))]
       for (d, m) in dig
           y, dx, dy = (d == 1) ? (voffset, thirdcolspan, thirdcolspan) :
               (d == 10) ? (voffset, -thirdcolspan, thirdcolspan) :
               (d == 100) ? (hlen - voffset, thirdcolspan, -thirdcolspan) :
               (hlen - voffset, -thirdcolspan, -thirdcolspan)
           m == 1 && drawcnum(ctx, [[x, y], [x + dx, y]])
           m == 2 && drawcnum(ctx, [[x, y + dy], [x + dx, y + dy]])
           m == 3 && drawcnum(ctx, [[x, y], [x + dx, y + dy]])
           m == 4 && drawcnum(ctx, [[x, y + dy], [x + dx, y]])
           m == 5 && drawcnum(ctx, [[x, y + dy], [x + dx, y], [x, y]])
           m == 6 && drawcnum(ctx, [[x + dx, y], [x + dx, y + dy]])
           m == 7 && drawcnum(ctx, [[x, y], [x + dx, y], [x + dx, y + dy]])
           m == 8 && drawcnum(ctx, [[x, y + dy], [x + dx, y + dy], [x + dx, y]])
           m == 9 && drawcnum(ctx, [[x, y], [x + dx, y], [x + dx, y + dy], [x, y + dy]])
       end
       move_to(ctx, x - halfwspan ÷ 6, hlen - 4)
       Cairo.show_text(ctx, string(n))
       stroke(ctx)
   end

end

function mooncipher()

   draw(can)
   cond = Condition()
   endit(w) = notify(cond)
   signal_connect(endit, win, :destroy)
   show(can)
   wait(cond)

end

mooncipher() </lang>

Lua

Translation of: Go

<lang lua>function initN()

   local n = {}
   for i=1,15 do
       n[i] = {}
       for j=1,11 do
           n[i][j] = " "
       end
       n[i][6] = "x"
   end
   return n

end

function horiz(n, c1, c2, r)

   for c=c1,c2 do
       n[r+1][c+1] = "x"
   end

end

function verti(n, r1, r2, c)

   for r=r1,r2 do
       n[r+1][c+1] = "x"
   end

end

function diagd(n, c1, c2, r)

   for c=c1,c2 do
       n[r+c-c1+1][c+1] = "x"
   end

end

function diagu(n, c1, c2, r)

   for c=c1,c2 do
       n[r-c+c1+1][c+1] = "x"
   end

end

function initDraw()

   local draw = {}
   draw[1] = function(n) horiz(n, 6, 10, 0) end
   draw[2] = function(n) horiz(n, 6, 10, 4) end
   draw[3] = function(n) diagd(n, 6, 10, 0) end
   draw[4] = function(n) diagu(n, 6, 10, 4) end
   draw[5] = function(n) draw[1](n) draw[4](n) end
   draw[6] = function(n) verti(n, 0, 4, 10) end
   draw[7] = function(n) draw[1](n) draw[6](n) end
   draw[8] = function(n) draw[2](n) draw[6](n) end
   draw[9] = function(n) draw[1](n) draw[8](n) end
   draw[10] = function(n) horiz(n, 0, 4, 0) end
   draw[20] = function(n) horiz(n, 0, 4, 4) end
   draw[30] = function(n) diagu(n, 0, 4, 4) end
   draw[40] = function(n) diagd(n, 0, 4, 0) end
   draw[50] = function(n) draw[10](n) draw[40](n) end
   draw[60] = function(n) verti(n, 0, 4, 0) end
   draw[70] = function(n) draw[10](n) draw[60](n) end
   draw[80] = function(n) draw[20](n) draw[60](n) end
   draw[90] = function(n) draw[10](n) draw[80](n) end
   draw[100] = function(n) horiz(n, 6, 10, 14) end
   draw[200] = function(n) horiz(n, 6, 10, 10) end
   draw[300] = function(n) diagu(n, 6, 10, 14) end
   draw[400] = function(n) diagd(n, 6, 10, 10) end
   draw[500] = function(n) draw[100](n) draw[400](n) end
   draw[600] = function(n) verti(n, 10, 14, 10) end
   draw[700] = function(n) draw[100](n) draw[600](n) end
   draw[800] = function(n) draw[200](n) draw[600](n) end
   draw[900] = function(n) draw[100](n) draw[800](n) end
   draw[1000] = function(n) horiz(n, 0, 4, 14) end
   draw[2000] = function(n) horiz(n, 0, 4, 10) end
   draw[3000] = function(n) diagd(n, 0, 4, 10) end
   draw[4000] = function(n) diagu(n, 0, 4, 14) end
   draw[5000] = function(n) draw[1000](n) draw[4000](n) end
   draw[6000] = function(n) verti(n, 10, 14, 0) end
   draw[7000] = function(n) draw[1000](n) draw[6000](n) end
   draw[8000] = function(n) draw[2000](n) draw[6000](n) end
   draw[9000] = function(n) draw[1000](n) draw[8000](n) end
   return draw

end

function printNumeral(n)

   for i,v in pairs(n) do
       for j,w in pairs(v) do
           io.write(w .. " ")
       end
       print()
   end
   print()

end

function main()

   local draw = initDraw()
   for i,number in pairs({0, 1, 20, 300, 4000, 5555, 6789, 9999}) do
       local n = initN()
       print(number..":")
       local thousands = math.floor(number / 1000)
       number = number % 1000
       local hundreds = math.floor(number / 100)
       number = number % 100
       local tens = math.floor(number / 10)
       local ones = number % 10
       if thousands > 0 then
           draw[thousands * 1000](n)
       end
       if hundreds > 0 then
           draw[hundreds * 100](n)
       end
       if tens > 0 then
           draw[tens * 10](n)
       end
       if ones > 0 then
           draw[ones](n)
       end
       printNumeral(n)
   end

end

main()</lang>

Output:
0:
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x

1:
          x x x x x x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x

20:
          x
          x
          x
          x
x x x x x x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x

300:
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x         x
          x       x
          x     x
          x   x
          x x

4000:
          x
          x
          x
          x
          x
          x
          x
          x
          x
          x
        x x
      x   x
    x     x
  x       x
x         x

5555:
x x x x x x x x x x x
  x       x       x
    x     x     x
      x   x   x
        x x x
          x
          x
          x
          x
          x
        x x x
      x   x   x
    x     x     x
  x       x       x
x x x x x x x x x x x

6789:
x         x x x x x x
x         x         x
x         x         x
x         x         x
x x x x x x x x x x x
          x
          x
          x
          x
          x
x         x         x
x         x         x
x         x         x
x         x         x
x         x x x x x x

9999:
x x x x x x x x x x x
x         x         x
x         x         x
x         x         x
x x x x x x x x x x x
          x
          x
          x
          x
          x
x x x x x x x x x x x
x         x         x
x         x         x
x         x         x
x x x x x x x x x x x

Phix

<lang Phix>-- -- Define each digit as {up-down multiplier, left-right multiplier, char}, -- that is starting each drawing from line 1 or 7, column 3, -- and with `/` and `\` being flipped below when necessary. -- constant ds = {{{0,0,'+'},{0,1,'-'},{0,2,'-'}}, -- 1

              {{2,0,'+'},{2,1,'-'},{2,2,'-'}},     -- 2
              {{0,0,'+'},{1,1,'\\'},{2,2,'\\'}},   -- 3
              {{2,0,'+'},{1,1,'/'},{0,2,'/'}},     -- 4
              {{2,0,'+'},{1,1,'/'},{0,2,'+'},
                         {0,0,'+'},{0,1,'-'}},     -- 5
              Template:0,2,',     -- 6
              {{0,0,'+'},{0,1,'-'},{0,2,'+'},
                         {1,2,'|'},{2,2,'|'}},     -- 7
              {{2,0,'+'},{2,1,'-'},{2,2,'+'},
                         {1,2,'|'},{0,2,'|'}},     -- 8
              {{2,0,'+'},{2,1,'-'},{2,2,'+'},
                         {1,2,'|'},{0,2,'+'},
                         {0,1,'-'},{0,0,'+'}}}     -- 9

function cdigit(sequence s, integer d, pos) -- -- s is our canvas, 7 lines of 5 characters -- d is the digit, 0..9 -- pos is 4..1 for bl,br,tl,tr (easier to say/see 'backwards') --

   if d then
       integer ud = {+1,+1,-1,-1}[pos],
               lr = {+1,-1,+1,-1}[pos],
               l = {1,1,7,7}[pos]
       sequence dset = ds[d]
       for i=1 to length(dset) do
           integer {udm, lrm, ch} = dset[i],
                   tf = find(ch,`/\`)
           if tf and ud!=lr then ch=`\/`[tf] end if
           s[l+ud*udm][3+lr*lrm] = ch
       end for
   end if
   return s

end function

procedure cisterian(sequence n)

   sequence res = {}
   for i=1 to length(n) do
       integer cn = n[i]
       res = append(res,sprintf("%4d:",cn))
       sequence s = repeat("  |  ",7)
       integer pos = 1
       while cn do
           s = cdigit(s, remainder(cn,10), pos)
           pos += 1
           cn = floor(cn/10)
       end while
       res &= s
   end for
   puts(1,join_by(res,8,10))

end procedure

cisterian({0,1,2,3,4,5,6,7,8,9,20, 300, 4000, 5555, 6789, 9394, 7922, 9999})</lang>

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

  20:    300:   4000:   5555:   6789:   9394:   7922:   9999:
  |       |       |     +-+-+   | +-+   +-+ /     |     +-+-+
  |       |       |      \|/    | | |   | |/      |     | | |
--+       |       |       +     +-+-+   +-+     --+--   +-+-+
  |       |       |       |       |       |       |       |
  |       | /     +       +     | | |   +-+ /   | +-+   +-+-+
  |       |/     /|      /|\    | | |   | |/    | | |   | | |
  |       +     / |     +-+-+   | +-+   +-+     +-+-+   +-+-+

Plain English

<lang plainenglish>To run: Start up. Show some example Cistercian numbers. Wait for the escape key. Shut down.

To show some example Cistercian numbers: Put the screen's left plus 1 inch into the context's spot's x. Clear the screen to the lightest gray color. Use the black color. Use the fat pen. Draw 0. Draw 1. Draw 20. Draw 300. Draw 4000. Draw 5555. Draw 6789. Draw 9394. Refresh the screen.

The mirror flag is a flag.

To draw a Cistercian number: Split the Cistercian number into some thousands and some hundreds and some tens and some ones. Stroke zero. Set the mirror flag. Stroke the ones. Clear the mirror flag. Stroke the tens. Turn around. Stroke the hundreds. Set the mirror flag. Stroke the thousands. Turn around. Label the Cistercian number. Move the context's spot right 1 inch.

To label a Cistercian number: Save the context. Move down the half stem plus the small stem. Imagine a box with the context's spot and the context's spot. Draw "" then the Cistercian number in the center of the box with the dark gray color. Restore the context.

Some tens are a number.

Some ones are a number.

To split a number into some thousands and some hundreds and some tens and some ones: Divide the number by 10 giving a quotient and a remainder. Put the remainder into the ones. Divide the quotient by 10 giving another quotient and another remainder. Put the other remainder into the tens. Divide the other quotient by 10 giving a third quotient and a third remainder. Put the third remainder into the hundreds. Divide the third quotient by 10 giving a fourth quotient and a fourth remainder. Put the fourth remainder into the thousands.

The small stem is a length equal to 1/6 inch.

The half stem is a length equal to 1/2 inch.

The tail is a length equal to 1/3 inch.

The slanted tail is a length equal to 6/13 inch.

To stroke a number: Save the context. If the number is 1, stroke one. If the number is 2, stroke two. If the number is 3, stroke three. If the number is 4, stroke four. If the number is 5, stroke five. If the number is 6, stroke six. If the number is 7, stroke seven. If the number is 8, stroke eight. If the number is 9, stroke nine. Restore the context.

To turn home: If the mirror flag is set, turn right; exit. Turn left.

To turn home some fraction of the way: If the mirror flag is set, turn right the fraction; exit. Turn left the fraction.

To stroke zero: Save the context. Stroke the half stem. Turn around. Move the half stem. Stroke the half stem. Restore the context.

To stroke one: Move the half stem. Turn home. Stroke the tail.

To stroke two: Move the small stem. Turn home. Stroke the tail.

To stroke three: Move the half stem. Turn home 3/8 of the way. Stroke the slanted tail.

To stroke four: Move the small stem. Turn home 1/8 of the way. Stroke the slanted tail.

To stroke five: Stroke 1. Stroke 4.

To stroke six: Move the half stem. Turn home. Move the tail. Turn home. Stroke the tail.

To stroke seven: Stroke 1. Stroke 6.

To stroke eight: Stroke 2. Stroke 6.

To stroke nine: Stroke 1. Stroke 8.</lang>

Output:

https://commons.wikimedia.org/wiki/File:Cistercian_numerals.png

Python

I tried to create a three-line font from UTF8 characters taking three lines per Cistercian number. <lang python># -*- coding: utf-8 -*- """ Some UTF-8 chars used:

‾ 8254 203E ‾ OVERLINE ┃ 9475 2503 BOX DRAWINGS HEAVY VERTICAL ╱ 9585 2571 BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT ╲ 9586 2572 BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT ◸ 9720 25F8 UPPER LEFT TRIANGLE ◹ 9721 25F9 UPPER RIGHT TRIANGLE ◺ 9722 25FA LOWER LEFT TRIANGLE ◻ 9723 25FB WHITE MEDIUM SQUARE ◿ 9727 25FF LOWER RIGHT TRIANGLE

"""

  1. %% digit sections

def _init():

   "digit sections for forming numbers"
   digi_bits = """
  1. 0 1 2 3 4 5 6 7 8 9
.  ‾   _  ╲  ╱  ◸  .|  ‾|  _|  ◻
.  ‾   _  ╱  ╲  ◹  |.  |‾  |_  ◻
.  _  ‾   ╱  ╲  ◺  .|  _|  ‾|  ◻
.  _  ‾   ╲  ╱  ◿  |.  |_  |‾  ◻

""".strip()

   lines = [[d.replace('.', ' ') for d in ln.strip().split()]
            for ln in digi_bits.strip().split('\n')
            if '#' not in ln]
   formats = '<2 >2 <2 >2'.split()
   digits = [[f"{dig:{f}}" for dig in line]
             for f, line in zip(formats, lines)]
   return digits

_digits = _init()


  1. %% int to 3-line strings

def _to_digits(n):

   assert 0 <= n < 10_000 and int(n) == n
   
   return [int(digit) for digit in f"{int(n):04}"][::-1]

def num_to_lines(n):

   global _digits
   d = _to_digits(n)
   lines = [
       .join((_digits[1][d[1]], '┃',  _digits[0][d[0]])),
       .join((_digits[0][   0], '┃',  _digits[0][   0])),
       .join((_digits[3][d[3]], '┃',  _digits[2][d[2]])),
       ]
   
   return lines

def cjoin(c1, c2, spaces=' '):

   return [spaces.join(by_row) for by_row in zip(c1, c2)]
  1. %% main

if __name__ == '__main__':

   #n = 6666
   #print(f"Arabic {n} to Cistercian:\n")
   #print('\n'.join(num_to_lines(n)))
   
   for pow10 in range(4):    
       step = 10 ** pow10
       print(f'\nArabic {step}-to-{9*step} by {step} in Cistercian:\n')
       lines = num_to_lines(step)
       for n in range(step*2, step*10, step):
           lines = cjoin(lines, num_to_lines(n))
       print('\n'.join(lines))
   
   numbers = [0, 5555, 6789, 6666]
   print(f'\nArabic {str(numbers)[1:-1]} in Cistercian:\n')
   lines = num_to_lines(numbers[0])
   for n in numbers[1:]:
       lines = cjoin(lines, num_to_lines(n))
   print('\n'.join(lines))</lang>
Output:
Arabic 1-to-9 by 1 in Cistercian:

  ┃‾      ┃_      ┃╲      ┃╱      ┃◸      ┃ |     ┃‾|     ┃_|     ┃◻ 
  ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃  
  ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃  

Arabic 10-to-90 by 10 in Cistercian:

 ‾┃      _┃      ╱┃      ╲┃      ◹┃     | ┃     |‾┃     |_┃      ◻┃  
  ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃  
  ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃  

Arabic 100-to-900 by 100 in Cistercian:

  ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃  
  ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃  
  ┃_      ┃‾      ┃╱      ┃╲      ┃◺      ┃ |     ┃_|     ┃‾|     ┃◻ 

Arabic 1000-to-9000 by 1000 in Cistercian:

  ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃  
  ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃       ┃  
 _┃      ‾┃      ╲┃      ╱┃      ◿┃     | ┃     |_┃     |‾┃      ◻┃  

Arabic 0, 5555, 6789, 6666 in Cistercian:

  ┃      ◹┃◸    |_┃◻    | ┃ |
  ┃       ┃       ┃       ┃  
  ┃      ◿┃◺    | ┃_|   | ┃ |

Note: There may be some horizontal placement issues evident in the HTML rendering between pre tags that may not be shown in the monospace rendering of a terminal (or the edit pane in firefox).
The pre tag may have to shift from one monospace font to a second that contains a character missing from the first. Those two individually monospaced fonts may have differing character widths between fonts (although consistent within individual monospaced fonts).
Paste the output into a monospace code editor and the stems of each number might well align!

Raku

Handles 0 through 9999 only. No error trapping. If you feed it an unsupported number it will truncate to maximum 4 digits.

<lang perl6>my @line-segments = (0, 0, 0, 100),

   (0,  0, 35,  0), (0, 35, 35, 35), (0,  0, 35, 35), (0, 35, 35,  0), ( 35,  0, 35, 35),
   (0,  0,-35,  0), (0, 35,-35, 35), (0,  0,-35, 35), (0, 35,-35,  0), (-35,  0,-35, 35),
   (0,100, 35,100), (0, 65, 35, 65), (0,100, 35, 65), (0, 65, 35,100), ( 35, 65, 35,100),
   (0,100,-35,100), (0, 65,-35, 65), (0,100,-35, 65), (0, 65,-35,100), (-35, 65,-35,100);

my @components = map {@line-segments[$_]}, |((0, 5, 10, 15).map: -> $m {

   |((0,), (1,), (2,), (3,), (4,), (1,4), (5,), (1,5), (2,5), (1,2,5)).map: {$_ »+» $m}

});

my $out = 'Cistercian-raku.svg'.IO.open(:w);

$out.say: # insert header q|<svg width="875" height="470" style="stroke:black;" version="1.1" xmlns="http://www.w3.org/2000/svg">

<rect width="100%" height="100%" style="fill:white;"/>|;

my $hs = 50; # horizontal spacing my $vs = 25; # vertical spacing

for flat ^10, 20, 300, 4000, 5555, 6789, 9394, (^10000).pick(14) -> $cistercian {

   $out.say: |@components[0].map: { # draw zero / base vertical bar
       qq|<line x1="{.[0] + $hs}" y1="{.[1] + $vs}" x2="{.[2] + $hs}" y2="{.[3] + $vs}"/>|
   };
   my @orders-of-magnitude = $cistercian.polymod(10 xx *);
   for @orders-of-magnitude.kv -> $order, $value {
       next unless $value; # skip zeros, already drew zero bar
       last if $order > 3; # truncate too large integers
       # draw the component line segments
       $out.say: join "\n", @components[$order * 10 + $value].map: {
           qq|<line x1="{.[0] + $hs}" y1="{.[1] + $vs}" x2="{.[2] + $hs}" y2="{.[3] + $vs}"/>|
       }
   }
   # insert the decimal number below
   $out.say: qq|<text x="{$hs - 5}" y="{$vs + 120}">{$cistercian}</text>|;
   if ++$ %% 10 { # next row
       $hs = -35;
       $vs += 150;
   }
   $hs += 85; # increment horizontal spacing


} $out.say: q|</svg>|; # insert footer</lang> See sample SVG image: (offsite link)

REXX

A fair amount of code dealt with displaying multiple Cistercian numerals on the terminal,   and also trying to present
ASCII characters that tried mimicking what a scribe might draw.

Comprehensive error checking was also included. <lang rexx>/*REXX program displays a (non-negative 4-digit) number in Cistercian (monk) numerals. */ parse arg nums if nums= | nums="," then nums= 0 1 20 300 4000 5555 6789 9393 $.=; nnn= words(nums)

            do j=1  for nnn;                z= word(nums, j);    L= length(z)
            if L>4                then call serr  'number has too many numerals: '   z
            if \datatype(z, 'W')  then call serr  'number is not numeric: '          z
            if \datatype(z, 'N')  then call serr  'number is not an integer: '       z
            if z<0                then call serr  'number is negative: '             z
            if z>9999             then call serr  'number is too large (>9,999): '   z
            call monk z / 1                     /*create   the Cistercian quad numeral.*/
            end   /*j*/

call show /*display " " " " */ exit 0 /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ @: parse arg @x,@y; return @.@x.@y /*return a value from the point (@x,@y)*/ quad: parse arg #; if #\==0 then interpret 'call' #; return /*build numeral.*/ serr: say '***error*** ' arg(1); exit 13 p: do k=1 by 3 until k>arg(); x= arg(k); y= arg(k+1); @.x.y= arg(k+2); end; return sect: do q=1 for 4; call quad s.q; end; return /*build a Cistercian numeral character.*/ eye: do a=0 for 10; @.0.a= '│'; end; return /*build an "I" glyph (vertical axis).*/ /*──────────────────────────────────────────────────────────────────────────────────────*/ monk: parse arg n; n= right(n, 4, 0); @.= ' ' /*zero─fill N; blank-out numeral grid.*/

     s= '     ';   $.11= $.11  ||  '    '  ||  n  ||  "    "  ||  s;   call eye
     parse var n s.4 2 s.3 3 s.2 4 s.1;    call sect;    call nice;    call app;   return

/*──────────────────────────────────────────────────────────────────────────────────────*/ nice: if @(-1,9)=='─' then call p 0, 9, '┐'; if @(1,9)=='─' then call p 0, 9, '┌'

     if @(-1,9)=='─'  &  @(1,9)=='─'                                then call p 0, 9, '┬'
     if @(-1,0)=='─'     then call p 0, 0, '┘';     if @(1,0)=='─'  then call p 0, 0, '└'
     if @(-1,0)=='─'  &  @(1,0)=='─'                                then call p 0, 0, '┴'
        do i=4  to 5
        if @(-1,i)=='─'  then call p 0, i, '┤';     if @(1,i)=='─'  then call p 0, i, '├'
        if @(-1,i)=='─'  &  @(1,i)=='─'                             then call p 0, i, '┼'
        end   /*i*/;                                                               return

/*──────────────────────────────────────────────────────────────────────────────────────*/ app: do r= 9 for 10 by -1; /*process 1 row at a time (top first). */

          do c=-5  for 11;  $.r= $.r || @.c.r   /*   "    " col  " "   "  (left─►right)*/
          end   /*c*/;      $.r= $.r s
       end      /*r*/;            return

/*──────────────────────────────────────────────────────────────────────────────────────*/ show: do jj= 11 for 10+2 by -1; say strip($.jj, 'T') /*display 1 row at a time.*/

       if jj==5  then do 3;  say strip( copies('     │     ' s, nnn), 'T');     end
       end   /*r*/;               return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 1: ?= '─'; if q==1 then call p 1, 9, ?, 2, 9, ?, 3, 9, ?, 4, 9, ?, 5, 9, ?

           if q==2  then call p -1, 9, ?, -2, 9, ?, -3, 9, ?, -4, 9, ?, -5, 9, ?
           if q==3  then call p  1, 0, ?,  2, 0, ?,  3, 0, ?,  4, 0, ?,  5, 0, ?
           if q==4  then call p -1, 0, ?, -2, 0, ?, -3, 0, ?, -4, 0, ?, -5, 0, ?;  return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 2: ?= '─'; if q==1 then call p 1, 5, ?, 2, 5, ?, 3, 5, ?, 4, 5, ?, 5, 5, ?

           if q==2  then call p -1, 5, ?, -2, 5, ?, -3, 5, ?, -4, 5, ?, -5, 5, ?
           if q==3  then call p  1, 4, ?,  2, 4, ?,  3, 4, ?,  4, 4, ?,  5, 4, ?
           if q==4  then call p -1, 4, ?, -2, 4, ?, -3, 4, ?, -4, 4, ?, -5, 4, ?;  return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 3: ?= '\'; if q==1 then call p 1, 9, ?, 2, 8, ?, 3, 7, ?, 4, 6, ?, 5, 5, ?

  ?= '/';  if q==2  then call p -1, 9, ?, -2, 8, ?, -3, 7, ?, -4, 6, ?, -5, 5, ?
  ?= '/';  if q==3  then call p  1, 0, ?,  2, 1, ?,  3, 2, ?,  4, 3, ?,  5, 4, ?
  ?= '\';  if q==4  then call p -5, 4, ?, -4, 3, ?, -3, 2, ?, -2, 1, ?, -1, 0, ?;  return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 4: ?= '/'; if q==1 then call p 1, 5, ?, 2, 6, ?, 3, 7, ?, 4, 8, ?, 5, 9, ?

  ?= '\';  if q==2  then call p -5, 9, ?, -4, 8, ?, -3, 7, ?, -2, 6, ?, -1, 5, ?
  ?= '\';  if q==3  then call p  1, 4, ?,  2, 3, ?,  3, 2, ?,  4, 1, ?,  5, 0, ?
  ?= '/';  if q==4  then call p -5, 0, ?, -4, 1, ?, -3, 2, ?, -2, 3, ?, -1, 4, ?;  return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 5: ?= '/'; if q==1 then call p 1, 5, ?, 2, 6, ?, 3, 7, ?, 4, 8, ?

  ?= '\';  if q==2  then call p -4, 8, ?, -3, 7, ?, -2, 6, ?, -1, 5, ?
  ?= '\';  if q==3  then call p  1, 4, ?,  2, 3, ?,  3, 2, ?,  4, 1, ?
  ?= '/';  if q==4  then call p -4, 1, ?, -3, 2, ?, -2, 3, ?, -1, 4, ?;  call 1;   return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 6: ?= '│'; if q==1 then call p 5, 9, ?, 5, 8, ?, 5, 7, ?, 5, 6, ?, 5, 5, ?

           if q==2  then call p -5, 9, ?, -5, 8, ?, -5, 7, ?, -5, 6, ?, -5, 5, ?
           if q==3  then call p  5, 0, ?,  5, 1, ?,  5, 2, ?,  5, 3, ?,  5, 4, ?
           if q==4  then call p -5, 0, ?, -5, 1, ?, -5, 2, ?, -5, 3, ?, -5, 4, ?;  return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 7: call 1; call 6; if q==1 then call p 5, 9, '┐'

                             if q==2  then call p -5, 9, '┌'
                             if q==3  then call p  5, 0, '┘'
                             if q==4  then call p -5, 0, '└';                      return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 8: call 2; call 6; if q==1 then call p 5, 5, '┘'

                             if q==2  then call p -5, 5, '└'
                             if q==3  then call p  5, 4, '┐'
                             if q==4  then call p -5, 4, '┌';                      return

/*──────────────────────────────────────────────────────────────────────────────────────*/ 9: call 1; call 2; call 6; if q==1 then call p 5, 5, '┘', 5, 9, '┐'

                                    if q==2  then call p -5, 5, '└', -5, 9, '┌'
                                    if q==3  then call p  5, 0, '┘',  5, 4, '┐'
                                    if q==4  then call p -5, 0, '└', -5, 4, '┌';   return</lang>
output   when using the default inputs:
    0000             0001             0020             0300             4000             5555             6789             9393

     │                ┌─────           │                │                │           ─────┬─────      │    ┌────┐      ┌────┐\
     │                │                │                │                │            \   │   /       │    │    │      │    │ \
     │                │                │                │                │             \  │  /        │    │    │      │    │  \
     │                │                │                │                │              \ │ /         │    │    │      │    │   \
     │                │           ─────┤                │                │               \│/          └────┼────┘      └────┤    \
     │                │                │                │                │                │                │                │
     │                │                │                │                │                │                │                │
     │                │                │                │                │                │                │                │
     │                │                │                │    /          /│               /│\          │    │    │      ┌────┤    /
     │                │                │                │   /          / │              / │ \         │    │    │      │    │   /
     │                │                │                │  /          /  │             /  │  \        │    │    │      │    │  /
     │                │                │                │ /          /   │            /   │   \       │    │    │      │    │ /
     │                │                │                │/          /    │           ─────┴─────      │    └────┘      └────┘/

Wren

Library: Wren-fmt

This draws each Cistercian numeral on the terminal within a grid of 15 rows by 11 columns. The vertical line segment is drawn at column 5 (zero indexed) so there are 5 columns at either side. <lang ecmascript>import "/fmt" for Fmt

var n

var init = Fn.new {

   n = List.filled(15, null)
   for (i in 0..14) {
       n[i] = List.filled(11, " ")
       n[i][5] = "x"
   }

}

var horiz = Fn.new { |c1, c2, r| (c1..c2).each { |c| n[r][c] = "x" } } var verti = Fn.new { |r1, r2, c| (r1..r2).each { |r| n[r][c] = "x" } } var diagd = Fn.new { |c1, c2, r| (c1..c2).each { |c| n[r+c-c1][c] = "x" } } var diagu = Fn.new { |c1, c2, r| (c1..c2).each { |c| n[r-c+c1][c] = "x" } }

var draw // map contains recursive closures draw = {

   1: Fn.new { horiz.call(6, 10, 0) },
   2: Fn.new { horiz.call(6, 10, 4) },
   3: Fn.new { diagd.call(6, 10, 0) },
   4: Fn.new { diagu.call(6, 10, 4) },
   5: Fn.new {
          draw[1].call()
          draw[4].call()
      },
   6: Fn.new { verti.call(0, 4, 10) },
   7: Fn.new {
          draw[1].call()
          draw[6].call()
      },
   8: Fn.new {
          draw[2].call()
          draw[6].call()
      },
   9: Fn.new {
          draw[1].call()
          draw[8].call()
      },
   10: Fn.new { horiz.call(0, 4, 0) },
   20: Fn.new { horiz.call(0, 4, 4) },
   30: Fn.new { diagu.call(0, 4, 4) },
   40: Fn.new { diagd.call(0, 4, 0) },
   50: Fn.new {
          draw[10].call()
          draw[40].call()
       },
   60: Fn.new { verti.call(0, 4, 0) },
   70: Fn.new {
          draw[10].call()
          draw[60].call()
       },
   80: Fn.new {
          draw[20].call()
          draw[60].call()
       },
   90: Fn.new {
          draw[10].call()
          draw[80].call()
       },
   100: Fn.new { horiz.call(6, 10, 14) },
   200: Fn.new { horiz.call(6, 10, 10) },
   300: Fn.new { diagu.call(6, 10, 14) },
   400: Fn.new { diagd.call(6, 10, 10) },
   500: Fn.new {
           draw[100].call()
           draw[400].call()
        },
   600: Fn.new { verti.call(10, 14, 10) },
   700: Fn.new {
           draw[100].call()
           draw[600].call()
        },
   800: Fn.new {
           draw[200].call()
           draw[600].call()
        },
   900: Fn.new {
           draw[100].call()
           draw[800].call()
        },
   1000: Fn.new { horiz.call(0, 4, 14) },
   2000: Fn.new { horiz.call(0, 4, 10) },
   3000: Fn.new { diagd.call(0, 4, 10) },
   4000: Fn.new { diagu.call(0, 4, 14) },
   5000: Fn.new {
            draw[1000].call()
            draw[4000].call()
         },
   6000: Fn.new { verti.call(10, 14, 0) },
   7000: Fn.new {
            draw[1000].call()
            draw[6000].call()
         },
   8000: Fn.new {
            draw[2000].call()
            draw[6000].call()
         },
   9000: Fn.new {
            draw[1000].call()
            draw[8000].call()
         }

}

var numbers = [0, 1, 20, 300, 4000, 5555, 6789, 9999] for (number in numbers) {

   init.call()
   System.print("%(number):")
   var thousands = (number/1000).floor
   number = number % 1000
   var hundreds  = (number/100).floor
   number = number % 100
   var tens = (number/10).floor
   var ones = number % 10
   if (thousands > 0) draw[thousands*1000].call()
   if (hundreds > 0) draw[hundreds*100].call()
   if (tens > 0) draw[tens*10].call()
   if (ones > 0) draw[ones].call()
   Fmt.mprint(n, 1, 0, "")
   System.print()

}</lang>

Output:
0:
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          

1:
          x x x x x x
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          

20:
          x          
          x          
          x          
          x          
x x x x x x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          

300:
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x         x
          x       x  
          x     x    
          x   x      
          x x        

4000:
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
          x          
        x x          
      x   x          
    x     x          
  x       x          
x         x          

5555:
x x x x x x x x x x x
  x       x       x  
    x     x     x    
      x   x   x      
        x x x        
          x          
          x          
          x          
          x          
          x          
        x x x        
      x   x   x      
    x     x     x    
  x       x       x  
x x x x x x x x x x x

6789:
x         x x x x x x
x         x         x
x         x         x
x         x         x
x x x x x x x x x x x
          x          
          x          
          x          
          x          
          x          
x         x         x
x         x         x
x         x         x
x         x         x
x         x x x x x x

9999:
x x x x x x x x x x x
x         x         x
x         x         x
x         x         x
x x x x x x x x x x x
          x          
          x          
          x          
          x          
          x          
x x x x x x x x x x x
x         x         x
x         x         x
x         x         x
x x x x x x x x x x x