31
\$\begingroup\$

Introduction

I think everyone agrees that nice pictures have to have a nice frame. But most challenges on this site about ASCII-Art just want the raw picture and don't care about it's preservation.
Wouldn't it be nice if we had a program that takes some ASCII-Art and surrounds it with a nice frame?

The Challenge

Write a program that takes some ASCII-Art as input and outputs it surrounded by a nice frame.

Example:

*****
 ***
  *
 ***
*****

becomes

╔═══════╗
║ ***** ║
║  ***  ║
║   *   ║
║  ***  ║
║ ***** ║
╚═══════╝
  • You have to use the exact same characters for the frame as in the example: ═ ║ ╔ ╗ ╚ ╝
  • The top and the bottom of the frame get inserted before the first and after the last line of the input.
  • The left and rights parts of the frame have to have exact one space padding to the widest line of the input.
  • There may be no leading or trailing whitespaces in the output. Only a trailing newline is allowed.
  • You may assume that the input has no unnecessary leading whitespaces.
  • You may assume that the input has no trailing whitespaces on any line.
  • You don't have to handle empty input.
  • The input will only contain printable ASCII-characters and newlines.

Rules

Happy Coding!

Using some great ASCII-Art, that was produced in any challenge on this site, as input to your program and showing it with a nice frame is highly encouraged!

\$\endgroup\$
10
  • 33
    \$\begingroup\$ A non-ASCII frame for ASCII art? Heresy! \$\endgroup\$
    – Dennis
    Commented Feb 16, 2016 at 18:27
  • 5
    \$\begingroup\$ Very closely related. Same challenge, but only using a single (ASCII) character for the frame. \$\endgroup\$ Commented Feb 16, 2016 at 18:31
  • 13
    \$\begingroup\$ (I should clarify I don't think it's a dupe. Having to use 6 different characters makes this a lot trickier. The other challenge can be solved by rotating the grid and appending # four times. Adapting such an approach here will be tricky at best, and not viable at worst.) \$\endgroup\$ Commented Feb 16, 2016 at 18:38
  • 6
    \$\begingroup\$ @IsmaelMiguel I have won the previous contest and don't see how I could adapt my old answer at all. \$\endgroup\$ Commented Feb 17, 2016 at 6:31
  • 2
    \$\begingroup\$ I suspect that DenkerAffe is assuming CP437 or something where the frame chars are also one byte. \$\endgroup\$
    – Joshua
    Commented Feb 17, 2016 at 18:48

11 Answers 11

16
\$\begingroup\$

Haskell, 139 bytes

q=length
g x|l<-lines x,m<-maximum$q<$>l,s<-[-1..m]>>"═"='╔':s++"╗\n"++(l>>= \z->"║ "++z++([q z..m]>>" ")++"║\n")++'╚':s++"╝"

As an example I'm framing snowman "12333321".

*Main> putStrLn $ g " _===_\n (O.O)\n/(] [)\\\n ( : )"
╔═════════╗
║  _===_  ║
║  (O.O)  ║
║ /(] [)\ ║
║  ( : )  ║
╚═════════╝

How it works:

bind
  l: input split into lines
  m: maximum line length
  s: m+2 times ═

build top line
prepend left frame to each line, pad with spaces, append right frame
build bottom line.
\$\endgroup\$
0
9
\$\begingroup\$

JavaScript (ES6), 138 bytes

This is 138 bytes in the IBM866 encoding, which at time of writing is still supported in Firefox, but 152 in UTF-8.

s=>`╔${t='═'.repeat(w=2+Math.max(...(a=s.split`
`).map(s=>s.length)))}╗
${a.map(s=>('║ '+s+' '.repeat(w)).slice(0,w+1)).join`║
`}║
╚${t}╝`
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Can you actually encode Javascript using CP437 and still run it? If not, then this isn't actually 138 bytes. \$\endgroup\$ Commented Feb 17, 2016 at 4:28
  • \$\begingroup\$ @ӍѲꝆΛҐӍΛПҒЦꝆ Although I couldn't find anything supporting CP437, Firefox currently supports IBM866 which also has these box drawing characters, so I've updated my answer. \$\endgroup\$
    – Neil
    Commented Feb 17, 2016 at 9:01
  • \$\begingroup\$ Okay, cool. Have an upvote! \$\endgroup\$ Commented Feb 17, 2016 at 14:20
6
\$\begingroup\$

CJam, 45 chars / 52 bytes

qN/_z,)[_)'═*N]2*C,3%'╔f+.\4/@@f{Se]'║S@2$N}*

Trying to avoid those expensive 3-byte chars was... interesting.

Try it online

Explanation

qN/                   Split input by newline
_z,                   Zip and get length L, i.e. length of longest line
)                     Increment -> L+1
[_)'═*N]              Make two-element array of "═"*(L+2) and newline
2*                    Double the array, giving ["═"*(L+2) "\n" "═"*(L+2) "\n"]

C,                    range(12), i.e. [0 1 2 ... 11]
3%                    Every third element, i.e. [0 3 6 9]
'╔f+                  Add "╔" to each, giving "╔╗╚╝"
.\                    Vectorised swap with the previous array, giving
                      ["╔" "═"*(L+2) "╗" "\n" "╚" "═"*(L+2) "╝" "\n"]
4/                    Split into chunks of length 4

@@                    Move split input and L+1 to top
f{...}                Map with L+1 as extra parameter...
  Se]                   Pad line to length L+1, with spaces
  '║S                   Put "║" and space before it
  2$N                   Put "║" and newline after it

*                     Join, putting the formatted lines between the top and bottom rows
\$\endgroup\$
6
\$\begingroup\$

Bash, 173 171 150 148 147 bytes, 157 136 134 133 characters

q(){((n=${#2}>n?${#2}:n));};mapfile -tc1 -C q v;for((p=++n+1;p;--p));do z+=═;done;echo ╔$z╗;printf "║ %-${n}s║\n" "${v[@]}";echo ╚$z╝

Multiline:

q() {
    (( n = ${#2} > n ? ${#2} : n))
}
mapfile -tc1 -C q v

for((p=++n+1;p;--p))
do 
    z+=═
done

echo ╔$z╗
printf "║ %-${n}s║\n" "${v[@]}"
echo ╚$z╝

Example execution:

bash -c 'q(){((n=${#2}>n?${#2}:n));};mapfile -tc1 -C q v;for((p=++n+1;p;--p));do z+=═;done;echo ╔$z╗;printf "║ %-${n}s║\n" "${v[@]}";echo ╚$z╝'< bear.txt

Sample run from script:

$ cat bear2.txt 
     (()__(()
     /       \
    ( /    \  \
     \ o o    /
     (_()_)__/ \
    / _,==.____ \
   (   |--|      )
   /\_.|__|'-.__/\_
  / (        /     \
  \  \      (      /
   )  '._____)    /
(((____.--(((____/mrf
$ ./frame< bear2.txt 
╔═══════════════════════╗
║      (()__(()         ║
║      /       \        ║
║     ( /    \  \       ║
║      \ o o    /       ║
║      (_()_)__/ \      ║
║     / _,==.____ \     ║
║    (   |--|      )    ║
║    /\_.|__|'-.__/\_   ║
║   / (        /     \  ║
║   \  \      (      /  ║
║    )  '._____)    /   ║
║ (((____.--(((____/mrf ║
╚═══════════════════════╝
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Your example has an emtpy line between the bottom frame and the input which is invalid. The top and bottom frames have to be inserted directly before and after the input (your previous version was fine btw). \$\endgroup\$
    – Denker
    Commented Feb 17, 2016 at 8:19
  • 1
    \$\begingroup\$ Nice!, But you could save approx 5 char if ...?${#2}+2:n)) instead of +1, drop 2 spaces and printf -v z %${n}s; instead of printf -v z " %*.s" $n. \$\endgroup\$ Commented Feb 17, 2016 at 13:59
  • \$\begingroup\$ @Sukminder Ok, was already assumnig that, but wanted to make that sure since the input you show does not contain an empty line. I did not demand that you clear the input of leading or traliing empty lines, so you program is perfectly fine. \$\endgroup\$
    – Denker
    Commented Feb 18, 2016 at 7:02
5
\$\begingroup\$

Perl, 111 characters

(score includes +5 for the interpreter flags)

#!/usr/bin/perl -n0 -aF\n
$n=(sort{$b<=>$a}map length,@F)[0];$l="═"x$n;
print"╔═$l═╗\n",(map{sprintf"║ %-${n}s ║\n",$_}@F),"╚═$l═╝";

First, we find the longest line length $n, by numerically sorting the lengths of all lines.

We set $l to be the header/footer bar to be $n repetitions of the horizontal frame character.

Then we print each line formatted to left-align in a field of width $n, sandwiched in between the frame characters.

Result:

╔═══════════╗
║   |\_/|   ║
║  / @ @ \  ║
║ ( > * < ) ║
║  `>>x<<'  ║
║  /  O  \  ║
╚═══════════╝
\$\endgroup\$
5
\$\begingroup\$

AWK, 159 141 bytes

{a[NR,1]=x=length(a[NR]=$0)
m=m<x?x:m}END{for(;i++<m+2;)t=t"═"
for(print"╔"t"╗";j++<NR;)printf"║ %-"m"s ║\n",a[j]
print"╚"t"╝"}

Try it online!

Apparently awk can print Unicode if you can figure out how to get it in the code. Thanks, @ceilingcat, for pointing out that my code could be rearranged to save 18 bytes.

\$\endgroup\$
3
  • \$\begingroup\$ I'm having so many ideas for awesome pipes now ... \$\endgroup\$
    – Sebb
    Commented Feb 17, 2016 at 23:22
  • \$\begingroup\$ @Sebb That does seem like fun. :) \$\endgroup\$ Commented Feb 18, 2016 at 13:52
  • \$\begingroup\$ @ceilingcat This was from before I even knew about TIO :0 Nice catches :) \$\endgroup\$ Commented Nov 1, 2023 at 15:22
4
\$\begingroup\$

Pyth, 44 chars (58 bytes)

++\╔K*JhheSlR.z\═\╗jbm+\║+.[+;d;J\║.z++\╚K\╝

Explanation

++\╔K*JhheSlR.z\═\╗                          - print out the first line
           lR.z                              -        map(len, all_input())
          S                                  -       sorted(^)
         e                                   -      ^[-1]
       hh                                    -     ^+2
      J                                      -    autoassign J = ^
     *         \═                            -   ^*"═"
    K                                        -  autoassign K = ^
++\╔             \╗                          - imp_print("╔"+^+"╗")

                   jbm+\║+.[+;d;J\║.z        - print out the middle
                   jb                        - "\n".join(V)
                     m             .z        -  [V for d in all_input()]
                      +\║+       \║          -   "║"+V+"║"
                          .[   ;J            -    pad(V, " ", J)
                            +;d              -     " "+d

                                     ++\╚K\╝ - print out the end
                                     ++\╚K\╝ - imp_print("╚"+K+"╝")

Try it here.

\$\endgroup\$
4
\$\begingroup\$

PHP 5.3, 209 bytes

This only works using the encoding OEM 860. It is an Extended ASCII superset, used in Portuguese DOS versions. Since I'm Portuguese (and I used to love doing these "frames" in Pascal) and this is a standard encoding, I went ahead with this:

<?foreach($W=explode('
',$argv[1])as$v)$M=max($M,strlen($v)+2);printf("É%'Í{$M}s»
º%1\${$M}sº
%2\$s
º%1\${$M}sº
È%1\$'Í{$M}s¼",'',join('
',array_map(function($v)use($M){return str_pad(" $v ",$M);},$W)));

Here's the base64:

PD9mb3JlYWNoKCRXPWV4cGxvZGUoJwonLCRhcmd2WzFdKWFzJHYpJE09bWF4KCRNLHN0cmxlbigkdikrMik7cHJpbnRmKCLilZQlJ+KVkHskTX1z4pWXCuKVkSUxXCR7JE19c+KVkQolMlwkcwrilZElMVwkeyRNfXPilZEK4pWaJTFcJCfilZB7JE19c+KVnSIsJycsam9pbignCicsYXJyYXlfbWFwKGZ1bmN0aW9uKCR2KXVzZSgkTSl7cmV0dXJuIHN0cl9wYWQoIiAkdiAiLCRNKTt9LCRXKSkpOw==

This answer was based on my answer on: https://codegolf.stackexchange.com/a/57883/14732 (the heavy lifting was all made there, just had to twitch a bit).

\$\endgroup\$
3
  • \$\begingroup\$ Impressive to say the least :) \$\endgroup\$
    – MonkeyZeus
    Commented Feb 17, 2016 at 21:39
  • \$\begingroup\$ The codes is 209 bytes/characters. 22+58+11+5+11+24+66+12=209 The last 12 is newlines and as it is DOS that means CRLF, or two bytes per newline. The charactercountonline site does not count newlines. Each of the non-ASCII glyphs are 1 byte in OEM 860. \$\endgroup\$
    – Runium
    Commented Feb 17, 2016 at 23:39
  • \$\begingroup\$ @Sukminder Don't forget that (at least) Windows converts \n into \r\n, when opening the file in ASCII/text mode. \$\endgroup\$ Commented Feb 17, 2016 at 23:43
2
\$\begingroup\$

Python 3, 119 Bytes

def f(x): 
 n='\n';s="║ ";e=" ║";h=(x.find(n)+2)*"═";return"╔"+h+"╗"+n+s+x.replace(n,e+n+s)+e+n+"╚"+h+"╝"

126 bytes

import sys
o=["║ %s ║\n"%j[:-1] for j in sys.stdin]
h="═"*(len(o[0])-3)
print("╔"+h+"╗\n"+"".join(o)+"╚"+h+"╝")

Input:

hello
there
  !  

Output:

╔═══════╗
║ hello ║
║ there ║
║   !   ║
╚═══════╝
\$\endgroup\$
5
  • \$\begingroup\$ Welcome to Progamming Puzzles & Code Golf! Nice first answer! You can always write functions instead of full programs (unless explicitly forbidden in the challenge) which might allow you to save some bytes by taking the input as argument. Also you might want to use Python 2, so you can save 2 bytes by going with print"╔"+h+"╗\n"+"".join(o)+"╚"+h+"╝". \$\endgroup\$
    – Denker
    Commented Feb 19, 2016 at 10:49
  • \$\begingroup\$ Thanks. I couldn't figure out how to get the high-bytes working in Python2 (probably setting the codec environment variable would work but I'm not sure how that plays into golf byte counts). The function approach eliminates python2/3 differences but adds a byte in my best approach. \$\endgroup\$ Commented Feb 19, 2016 at 18:58
  • \$\begingroup\$ Okay, I got it down to 119 characters as a function; takes input as a string. My mini-markdown is obviously not up to snuff; Line 1 is the def, the rest (after the colon) is line 2, with a leading space. def f(x): n='\n';s="║ ";e=" ║";h=(x.find(n)+2)*"═";return"╔"+h+"╗"+n+s+x.replace(n,e+n+s)+e+n+"╚"+h+"╝" \$\endgroup\$ Commented Feb 19, 2016 at 21:45
  • \$\begingroup\$ Just update your post with the new version and the new score (struck the old score out with <s>...</s>). Also you can add <!-- language-all: lang-python --> before your code-block to add syntax highlighting to your code. \$\endgroup\$
    – Denker
    Commented Feb 19, 2016 at 22:33
  • \$\begingroup\$ This doesn't work if the input is non-rectangular, while the question says that no line will have trailing whitespace. \$\endgroup\$
    – Dennis
    Commented Feb 23, 2016 at 20:36
2
\$\begingroup\$

Python 2, 115 Bytes

def f(i):w='═'*(i.find('\n')+2);return'╔%s╗\n║ %s ║\n╚%s╝'%(w,' ║\n║ '.join(i.split('\n')),w)

Looks shorter than 115 here, but working file includes 3-byte UTF-8 BOM mark signature, bumping it up to 115 bytes. If you were to run it in Python 3 you wouldn't need the BOM and it'd get down to 112 bytes.

\$\endgroup\$
6
  • \$\begingroup\$ Welcome to Programming Puzzles & Code Golf! Unfortunately, your code appears to assume that the input is rectangular, while the question says that no line will have trailing whitespace. \$\endgroup\$
    – Dennis
    Commented Feb 23, 2016 at 20:33
  • \$\begingroup\$ I count 107 bytes. I don't think you need to include the "UTF-8 BOM mark signature". \$\endgroup\$ Commented Mar 16, 2016 at 15:36
  • \$\begingroup\$ @CatsAreFluffy Are you using Python2? In Python3 all strings are unicode, but it's trickier with Python2. \$\endgroup\$ Commented Mar 18, 2016 at 16:51
  • \$\begingroup\$ Oops, I counted pipes as 2 bytes, but even after using an actual bytecounter, still only 111 bytes. Tell me where those 5 bytes came from. \$\endgroup\$ Commented Mar 18, 2016 at 16:57
  • \$\begingroup\$ The UTF-8 BOM is 3 bytes (en.wikipedia.org/wiki/Byte_order_mark). My count was one high because my text editor was adding a trailing newline, so my solution is really only 115 bytes. You could leave off the leading BOM bytes and get it down to 112 if you were using Python3 (which counts all strings as unicode). But I don't know how you're seeing only 111 bytes. btw, here's how I added the BOM: sed -i '1s/^\(\xef\xbb\xbf\)\?/\xef\xbb\xbf/' codeGolf.py \$\endgroup\$ Commented Mar 22, 2016 at 19:49
1
\$\begingroup\$

C, 290 bytes

Golfed function B, with dependencies; takes input as null-terminated char*

#define l(s) strlen(s)
p(char*s,int n){while(n--)printf(s);}
B(char*s){char*t=strtok(s,"\n");int x=l(t),z=1;while(t=strtok(0,"\n"))z++,x=l(t)>x?l(t):x;p("╔",1);p("=",x+2);p("╗\n",1);while(z--)printf("║ %s", s),p(" ",x-l(s)),p(" ║\n",1),s+=l(s)+1;p("╚",1);p("=",x+2);p("╝\n",1);}

Somewhat-ungolfed function in full program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1024

// GOLF-BEGIN =>
#define l(s) strlen(s)
// since multibyte chars don't fit in char: use char* instead
void p (char*s,int n){ while(n--)printf(s); } 
void B (char *s){
    char *t = strtok(s,"\n");
    int x=l(t), z=1;
    while(t=strtok(0,"\n"))z++,x=l(t)>x?l(t):x;  
    // x is l(longest line), z is #lines
    p("╔",1);p("=",x+2);p("╗\n",1);
    while(z--)printf("║ %s", s),p(" ",x-l(s)),p(" ║\n",1),s+=l(s)+1;
    p("╚",1);p("=",x+2);p("╝\n",1);       
}
// <= GOLF-END

int main(int argc, char **argv) {
    char buffer[MAX];
    memset(buffer, 0, MAX);
    FILE *f = fopen(argv[1], "rb");
    fread(buffer, 1, MAX, f); 
    B(buffer);
    return 0;
}

input

     _.,----,._
   .:'        `:.
 .'              `.
.'                `.
:                  :
`    .'`':'`'`/    '
 `.   \  |   /   ,'
   \   \ |  /   /
    `\_..,,.._/'
     {`'-,_`'-}
     {`'-,_`'-}
     {`'-,_`'-}
      `YXXXXY'
        ~^^~

output

╔======================╗
║      _.,----,._      ║
║    .:'        `:.    ║
║  .'              `.  ║
║ .'                `. ║
║ :                  : ║
║ `    .'`':'`'`/    ' ║
║  `.   \  |   /   ,'  ║
║    \   \ |  /   /    ║
║     `\_..,,.._/'     ║
║      {`'-,_`'-}      ║
║      {`'-,_`'-}      ║
║      {`'-,_`'-}      ║
║       `YXXXXY'       ║
║         ~^^~         ║
╚======================╝

C golfing tips appreciated!

\$\endgroup\$
1

Your Answer

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

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