Frame this nice ASCII-Art

30

2

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!

Denker

Posted 2016-02-16T18:21:00.643

Reputation: 6 639

29A non-ASCII frame for ASCII art? Heresy! – Dennis – 2016-02-16T18:27:04.390

@Dennis I like the irony too :) – Denker – 2016-02-16T18:31:07.077

5Very closely related. Same challenge, but only using a single (ASCII) character for the frame. – Martin Ender – 2016-02-16T18:31:52.147

13(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.) – Martin Ender – 2016-02-16T18:38:02.290

@MartinBüttner This is indeed a very similar challenge, did not find it before (guess I should have searched for something more than just frame). But I also think its different enough to leave this one open. – Denker – 2016-02-16T18:43:32.980

1This is also a multiline challenge, while the previous challenge was only a single line of text. – Neil – 2016-02-16T19:12:47.067

@MartinBüttner According to your rules, this question is a duplicated. Quoting from http://meta.codegolf.stackexchange.com/a/3605/14732 : "[...] the differences seem very minor, if someone did adapt an old answer, the heavy lifting would have been done by the user who answered the previous question.".

– Ismael Miguel – 2016-02-17T01:55:54.637

6@IsmaelMiguel I have won the previous contest and don't see how I could adapt my old answer at all. – Martin Ender – 2016-02-17T06:31:56.880

@MartinBüttner I can. Just replace the "middle section" with multi-line support. Which is exactly what I did. Check the answers below. – Ismael Miguel – 2016-02-17T12:13:27.410

2I suspect that DenkerAffe is assuming CP437 or something where the frame chars are also one byte. – Joshua – 2016-02-17T18:48:02.640

Answers

6

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

Sp3000

Posted 2016-02-16T18:21:00.643

Reputation: 58 729

16

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.

nimi

Posted 2016-02-16T18:21:00.643

Reputation: 34 639

9

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}╝`

Neil

Posted 2016-02-16T18:21:00.643

Reputation: 95 035

1Can you actually encode Javascript using CP437 and still run it? If not, then this isn't actually 138 bytes. – Mama Fun Roll – 2016-02-17T04:28:48.150

@ӍѲꝆΛҐӍΛПҒЦꝆ 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. – Neil – 2016-02-17T09:01:25.700

Okay, cool. Have an upvote! – Mama Fun Roll – 2016-02-17T14:20:28.520

6

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 ║
╚═══════════════════════╝

Runium

Posted 2016-02-16T18:21:00.643

Reputation: 1 878

1Your 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). – Denker – 2016-02-17T08:19:48.783

1Nice!, 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. – F. Hauri – 2016-02-17T13:59:40.887

@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. – Denker – 2016-02-18T07:02:50.760

5

AWK, 159 bytes

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

Apparently awk can print Unicode if you can figure out how to get it in the code.

Robert Benson

Posted 2016-02-16T18:21:00.643

Reputation: 1 339

I'm having so many ideas for awesome pipes now ... – Sebb – 2016-02-17T23:22:41.833

@Sebb That does seem like fun. :) – Robert Benson – 2016-02-18T13:52:28.583

5

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  \  ║
╚═══════════╝

Toby Speight

Posted 2016-02-16T18:21:00.643

Reputation: 5 058

4

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.

Blue

Posted 2016-02-16T18:21:00.643

Reputation: 26 661

4

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).

Ismael Miguel

Posted 2016-02-16T18:21:00.643

Reputation: 6 797

Impressive to say the least :) – MonkeyZeus – 2016-02-17T21:39:18.243

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. – Runium – 2016-02-17T23:39:29.620

@Sukminder Don't forget that (at least) Windows converts \n into \r\n, when opening the file in ASCII/text mode. – Ismael Miguel – 2016-02-17T23:43:30.823

2

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 ║
║   !   ║
╚═══════╝

SumnerHayes

Posted 2016-02-16T18:21:00.643

Reputation: 77

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+"╝". – Denker – 2016-02-19T10:49:42.350

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. – SumnerHayes – 2016-02-19T18:58:39.983

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+"╝" – SumnerHayes – 2016-02-19T21:45:22.620

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. – Denker – 2016-02-19T22:33:37.170

This doesn't work if the input is non-rectangular, while the question says that no line will have trailing whitespace. – Dennis – 2016-02-23T20:36:44.393

2

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.

Jenny Miller

Posted 2016-02-16T18:21:00.643

Reputation: 21

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. – Dennis – 2016-02-23T20:33:53.067

I count 107 bytes. I don't think you need to include the "UTF-8 BOM mark signature". – CalculatorFeline – 2016-03-16T15:36:42.960

@CatsAreFluffy Are you using Python2? In Python3 all strings are unicode, but it's trickier with Python2. – Jenny Miller – 2016-03-18T16:51:15.387

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. – CalculatorFeline – 2016-03-18T16:57:46.973

The UTF-8 BOM is 3 bytes (https://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

– Jenny Miller – 2016-03-22T19:49:27.797

-3bytes: Switch to Python 3. It works perfectly there. (Tested too!) – CalculatorFeline – 2016-03-22T19:57:48.983

1

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!

tucuxi

Posted 2016-02-16T18:21:00.643

Reputation: 583

252 bytes – ceilingcat – 2020-01-12T22:28:31.970