24
\$\begingroup\$

Write a function that accepts a rectangular grid of ids in any reasonable format, for example a multi-line string:

IIILOO
ILLLOO

and a string or list of box drawing charcters such as:

' ═║╔╗╚╝╠╣╦╩╬'

or

[0x20, 0x2550, 0x2551, 0x2554, 0x2557, 0x255a, 0x255d, 0x2560, 0x2563, 0x2566, 0x2569, 0x256c']

(see below for more details) and returns a pretty printed version, as such:

╔═══════════╦═══╦═══════╗
║           ║   ║       ║
║   ╔═══════╝   ║       ║
║   ║           ║       ║
╚═══╩═══════════╩═══════╝

i.e. a rectangle made out of the box drawing characters, where each border indicates the border of each polyomino.

╔═══════════╦═══╦═══════╗
║ I   I   I ║ L ║ O   O ║
║   ╔═══════╝   ║       ║
║ I ║ L   L   L ║ O   O ║
╚═══╩═══════════╩═══════╝

Rules

Shortest submission in bytes per language wins. Standard rules apply.

Note that to leave room for annotations and as the characters used are half width each unit square is 2x4 (3x5 but boundary fields are shared with neighbouring squares) characters in the output.

You may assume that input is clean rectangular and ids are unique to orthogonally connected regions.

To avoid any unicode related issues I have decided to provide the box drawing characters as an input. This may be any flat container holding the characters in any order as long as it contains

  1. each character exactly once and
  2. only these characters (no fillers)
  3. access is sequential or per index only (no sophisticated lookup tables)

More examples:

In:

XXXSS
RXSSL
ROOOL
RROLL

' ═║╔╗╚╝╠╣╦╩╬'

Out:

╔═══════════╦═══════╗
║           ║       ║
╠═══╗   ╔═══╝   ╔═══╣
║   ║   ║       ║   ║
║   ╠═══╩═══════╣   ║
║   ║           ║   ║
║   ╚═══╗   ╔═══╝   ║
║       ║   ║       ║
╚═══════╩═══╩═══════╝

In:

1220003
2240503
2444666

' ═║╔╗╚╝╠╣╦╩╬'

Out:

╔═══╦═══════╦═══════════╦═══╗
║   ║       ║           ║   ║
╠═══╝   ╔═══╣   ╔═══╗   ║   ║
║       ║   ║   ║   ║   ║   ║
║   ╔═══╝   ╚═══╬═══╩═══╩═══╣
║   ║           ║           ║
╚═══╩═══════════╩═══════════╝
\$\endgroup\$
10
\$\begingroup\$

Charcoal, 147 129 80 78 76 75 71 65 bytes

≔⁺SψθWSF²⊞υ⁺⭆ι×⁴λψ⊞υ⭆⌊υψEυ⭆EιE⁴§§υ⁻κ÷ν²⁻μ∨⁼ν¹⁼ν²§θ﹪×⁷↨²Eλ⁼ν§λ⊕ξ⁹⁵

Try it online! Link is to verbose version of code. Expects the box-drawing characters first in the order ╬╦╠╔╩═╚╣╗║ ╝ followed by the newline-terminated grid of strings. Edit: Saved 6 bytes by stealing @Arnauld's cool mapping. Explanation:

≔⁺Sψθ

Append a null byte to the box drawing character string as this gives us a free modulo 13 due to Charcoal's cyclic indexing.

WSF²⊞υ⁺⭆ι×⁴λψ⊞υ⭆⌊υψ

Read in the grid, duplicating it vertically and quadruplicating it horizontally, plus suffix a row and column of null bytes of padding.

Eυ⭆EιE⁴§§υ⁻κ÷ν²⁻μ∨⁼ν¹⁼ν²§θ﹪×⁷↨²Eλ⁼ν§λ⊕ξ⁹⁵

Map over the expanded grid, collecting a 2×2 square for each character, then comparing the characters in that square pairwise, treating the comparison results as base 2, and hashing into the box-drawing characters.

Previous 129 byte canvas-based version:

≔⁺SψθWS⊞υιυUE¹¦¹F⊕⊗LυF⊕⊗Lη«J⊖κ⊖ι≔KMζ¿﹪ⅉ²¿﹪ⅈ²§θ﹪×⁷↨²E⁴⁼§ζ⊗λ§ζ⊗⊕λ⁹⁵F¬⁼§ζ¹§ζ⁵§θ⁵¿﹪ⅈ²F¬⁼§ζ³§ζ⁷§θ⁹»UMKA⎇№θιιψUE¹F⊕LυF⊗Lη«J⊖⊗κ⊖⊗ι§KV⊕⊗κ

Try it online! Link is to verbose version of code. Expects the box-drawing characters first in the order ╬╩╣╝╦═╗╠╚║ ╔ followed by the newline-terminated grid of strings. Explanation:

≔⁺Sψθ

Append a null byte to the box drawing character string as this gives us a free modulo 13 due to Charcoal's cyclic indexing.

WS⊞υιυ

Read and print the grid.

UE¹¦¹

Double-space the grid horizontally and vertically.

F⊕⊗LυF⊕⊗Lη«J⊖κ⊖ι

Loop through each cell of the extended grid, including the border.

≔KMζ

Get the contents of the adjacent cells.

¿﹪ⅉ²¿﹪ⅈ²§θ﹪×⁷↨²E⁴⁼§ζ⊗λ§ζ⊗⊕λ⁹⁵

If this is a cell e.g. between 4 ids then calculate which box-drawing character to draw.

F¬⁼§ζ¹§ζ⁵§θ⁵

If this is a row divider and the two ids differ then print a .

¿﹪ⅈ²F¬⁼§ζ³§ζ⁷§θ⁹

If this is a column divider and the ids differ then print a .

»UMKA⎇№θιιψ

Delete all non-box-drawing characters.

UE¹

Double-space the grid horizontally.

F⊕LυF⊗Lη«J⊖⊗κ⊖⊗ι§KV⊕⊗κ

Duplicate the row dividers.

\$\endgroup\$
3
  • \$\begingroup\$ Should the length on this be indicated in characters rather than bytes? It seems like the language uses more than 256 characters (though I could be wrong), so given that it would not be possible even define a one-byte-per-char encoding. \$\endgroup\$ Nov 2 at 23:45
  • 1
    \$\begingroup\$ @PaulFisher according to the Code page it seems to use fewer that 256; certainly I couldn't spot any missing characters. \$\endgroup\$
    – Neil
    Nov 3 at 0:31
  • \$\begingroup\$ You’re correct! Thank you; I had not seen that page. \$\endgroup\$ Nov 4 at 1:40
8
\$\begingroup\$

PowerShell, 282 243 219 bytes

Thanks @Arnauld for the idea that the values can be directly mapped to the output characters! I've made a code that finds such an expression by brute force. The *7%95%13 is single shortest expression.

-24 bytes thanks @Arnauld for "width 4w+1 and height 2h+1" before sliding over the input string.

param($t,$s)$n=($s=$s-replace'.',('$0'*4)|%{$_;$_})|% Le*|Sort -b 1
$s=$s+,''|% *ht($n+1)
$s|%{-join(0..$n|%{$x=$_,--$_
$b,$a,$d,$c=$s[--$y,++$y]|%{$_[$x]}
$t[(!($a-$b)+2*!($a-$c)+4*!($b-$d)+8*!($c-$d))*7%95%13]});$y++}

Try it online!

Less golfed:

param($t,$s)
$s=$s-replace'.',('$0'*4)|%{$_;$_}  # magnify to 4*width and 2*heght
$n=$s|% Length|sort -b 1            # find max length
$s=$s+,''|% PadRight($n+1)          # add +1 to width and height
$s|%{                               # (in addition, we got a rectangle)
    -join(0..$n|%{
        $x=$_,--$_
        $b,$a,$d,$c=$s[--$y,++$y]|%{$_[$x]}           # I need to golf
        $i=!($a-$b)+2*!($a-$c)+4*!($b-$d)+8*!($c-$d)  # this 2 lines  cxxx|;:;:;:;:;:;:>

        $t[7*$i%95%13]
    })
    $y++
}

Main idea

Let a square of 4 characters slide over the input string "magnified 4 times in width and twice in height".

..
..IILOO
 ILLLOO

 ..
 ..ILOO
 ILLLOO

  ..
 I..LOO
 ILLLOO

.~.~.~.~.~.

..IILOO
..LLLOO

 ..IILOO
 ..LLLOO

 I..ILOO
 I..LLOO

 II..LOO
 IL..LOO

.~.~.~.~.~.

 IIILOO
..LLLOO
..

.~.~.~.~.~.

 IIILOO
 ILLLO..
      ..

Let's name the points in the square as a,b,c,d.

The expression (a=b)+2*(a=c)+4*(b=d)+8*(c=d) returns numbers in range 0..15, which correspond to the border chars:

 0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15
----------------------------------------------------------------
 ab  aa  ab  aa  ab  aa  ab  aa  ab  aa  ab  aa  ab  aa  aa  aa
 cd  cd  ad  ad  cb  ca  ab  aa  cc  cc  aa  aa  bb  aa  aa  aa

 0   1   2   3   4   5   6   15  8   9   10  15  12  15  15  15  - the expression results

 ╬   ╦   ╠   ╔   ╣   ╗   ║       ╩   ═   ╚       ╝               - related border chars. the space char for 15
 0   7   1   8   2   9   3       4   11  5       6           10  - *7%95%13 - index in the "flat container"

 012345678901
 ╬╠╣║╩╚╝╦╔╗ ═    - the flat container

The script draws the border char for each position of the sliding square. Plus draws middle row between input lines.

The script expectes the flat container with border chars in order ╬╠╣║╩╚╝╦╔╗ ═.

\$\endgroup\$
8
\$\begingroup\$

JavaScript (ES6),  164 154  143 bytes

Expects (a)('╬╩╠╚╣╝║╦═╔ ╗'), where a is a list of strings.

a=>c=>[...a,...a,a[0]].map((r,y)=>[...r+r+r+r+0].map((v,x)=>c[g=d=>v==(v=(a[y-d%2>>1]||0)[x-~x-d>>3]),(g``,8*g(1)|g(3)|4*g(2)|2*g``)*7%95%13]))

Try it online!

How?

Given a matrix \$M\$ of size \$w\times h\$, we build an expanded matrix \$M'\$ of width \$4w+1\$ and height \$2h+1\$ filled with the original values of \$M\$ magnified 4 times in width and twice in height. The extra column and extra row are filled with undefined values.

For instance:

AB  ==> AAAABBBB?
CD      AAAABBBB?
        CCCCDDDD?
        CCCCDDDD?
        ?????????

For each cell \$(x,y)\$ in \$M'\$, we extract \${M'}_{x,y}\$ and 3 adjacent cells:

$$\begin{pmatrix}v_3={M'}_{x-1,y-1}&v_1={M'}_{x,y-1}\\ v_2={M'}_{x-1,y}&v_0={M'}_{x,y}\end{pmatrix}$$

Using these results, we build a 4-bit value as follows:

8 4 2 1
| | | |
| | | +--> set if v3 = v1
| | +----> set if v2 = v0
| +------> set if v3 = v2
+--------> set if v1 = v0

We may get all values from \$0\$ to \$15\$ except the ones with exactly 3 bits set: \$7\$, \$11\$, \$13\$ and \$14\$ (because if 3 equalities are satisfied, the 4th one must be satisfied as well).

The 12 remaining values can be directly mapped to the output characters. We use the expression \$((n\times7)\bmod 95)\bmod 13\$ to force all them into \$[0\dots 11]\$ (Try it online!).

\$\endgroup\$
5
  • \$\begingroup\$ Hmm, should I save six bytes by stealing that cool mapping?... \$\endgroup\$
    – Neil
    Nov 4 at 9:19
  • \$\begingroup\$ @Neil Sure, no problem :) \$\endgroup\$
    – Arnauld
    Nov 4 at 9:21
  • \$\begingroup\$ yes, The *7%95%13 is single shortest expression to force the range [0..15]-[7,11,13,14] into [0…11]. thanks. \$\endgroup\$
    – mazzy
    Nov 4 at 12:20
  • 1
    \$\begingroup\$ @mazzy Although interestingly all of our solutions still have the box drawing characters in a subtly different order. \$\endgroup\$
    – Neil
    Nov 5 at 0:37
  • \$\begingroup\$ Thanks. There is no the cyclic indexing in PowerShell. \$\endgroup\$
    – mazzy
    Nov 5 at 6:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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