Output visual diagram of picture

Write a program that inputs the dimensions of a painting, the matting width, and the frame width for a framed portrait. The program should output a diagram using the symbol X for the painting, + for the matting, and # for the framing. The symbols must be space-separated. Trailing whitespace is alright, as long as the output visually matches the criteria. The inputs can be 0.

INPUT: 3 2 1 2 (Width, Height, Matte Width, Frame Width)

OUTPUT:

In text form:

# # # # # # # # #
# # # # # # # # #
# # + + + + + # #
# # + X X X + # #
# # + X X X + # #
# # + + + + + # #
# # # # # # # # #
# # # # # # # # #


The winning code completes the conditions in the least possible bytes.

• Nice challenge! For future challenges you may want to use The Sandbox Commented Mar 19, 2019 at 0:19
• do you mind if the input is in a different order? Commented Mar 19, 2019 at 0:52
• Can we return a list of strings? Commented Mar 19, 2019 at 0:56
• Can any of the inputs be zero? Commented Mar 19, 2019 at 8:52
• Can we have an space at the end of each line? Commented Mar 19, 2019 at 14:57

Python 2, 98 bytes

w,h,a,b=input()
a*='+'
b*='#'
for c in b+a+h*'X'+a+b:print' '.join(min(c,d)for d in b+a+w*'X'+a+b)


Try it online!

Prints a space-separated grid, strictly following the spec. I'm amused that *= is used to convert a and b from numbers to strings.

Python 3 can save some bytes by avoiding ' '.join, maybe more by using f-strings and assignment expressions. Thanks to Jo King for -2 bytes.

Python 3, 93 bytes

def f(w,h,a,b):a*='+';b*='#';[print(*[min(c,d)for d in b+a+w*'X'+a+b])for c in b+a+h*'X'+a+b]


Try it online!

• I've been outgolfed! NIce job, seems pretty golfed Commented Mar 19, 2019 at 23:03
• Nice golf! Very clever. Commented Mar 19, 2019 at 23:29

JavaScript (ES6),  118 113  107 bytes

(w,h,M,F)=>(g=(c,n)=>'01210'.replace(/./g,i=>c(i).repeat([F,M,n][i])))(y=>g(x=>'#+X'[x<y?x:y]+' ',w)+
,h)


Try it online!

Commented

(w, h, M, F) => (       // given the 4 input variables
g = (                 // g = helper function taking:
c,                  //   c = callback function returning a string to repeat
n                   //   n = number of times the painting part must be repeated
) =>                  //
'01210'             // string describing the picture structure, with:
.replace(           //   0 = frame, 1 = matte, 2 = painting
/./g,             // for each character in the above string:
i =>              //   i = identifier of the current area
c(i)            //   invoke the callback function
.repeat         //   and repeat the result ...
([F, M, n][i])  //   ... either F, M or n times
)                   // end of replace()
)(                      // outer call to g:
y =>                  //   callback function taking y:
g(                  //     inner call to g:
x =>              //       callback function taking x:
'#+X'           //         figure out which character to use
[x < y ? x : y] //         according to the current position
+ ' ',          //         append a space
w                 //       repeat the painting part w times
)                   //     end of inner call
+ '\n',             //     append a line feed
h                     //   repeat the painting part h times
)                       // end of outer call


MATL, 24 bytes

&l,ithYaQ]'#+X'w)TFX*cYv


Input is: Height, Width, Matte Width, Frame Width.

Try it online!

Explanation

&l      % Take height and width implicitly. Push matrix of that size with all
% entries equal to 1
,       % Do twice
i     %   Take input
th    %   Duplicate, concatenate: gives a 1×2 vector with the number repeated
Ya    %   Pad matrix with those many zeros vertically and horizontally
Q     %   Add 1 to each entry
]       % End
'#+X'   % Push this string
w)      % Index into the string with the padded matrix
TF      % Push row vector [1 0]
X*      % Kronecker product. This inserts columns of zeros
c       % Convert to char again. Char 0 is will be displayed as space
Yv      % Remove trailing spaces in each line. Implicitly display


Wolfram Language (Mathematica), 142 bytes

(t=(p=Table)["# ",2(c=#4+#3)+#2,2c+#];p[t[[i,j]]="+ ",{j,z=#4+1,c+#3+#},{i,z,c+#3+#2}];p[t[[i,j]]="X ",{j,#3+z,c+#},{i,#3+z,c+#2}];""<>#&/@t)&


Try it online!

Charcoal, 4847 44 bytes

≔×ＮXθ≔×ＮXηＦＥ+#×Ｎι«≔⁺ι⁺θιθ≔⁺ι⁺ηιη»Ｅη⪫⭆θ⌊⟦ιλ⟧


Try it online! Link is to verbose version of code. Note: Trailing space. Edit: Now uses @xnor's algorithm. Explanation:

≔×ＮXθ≔×ＮXη


Input the width and height and convert them into strings of Xs.

ＦＥ+#×Ｎι


Loop over the characters + and #, converting them into strings of length given by the remaining two inputs. Then loop over those two strings.

«≔⁺ι⁺θιθ≔⁺ι⁺ηιη»


Prefix and suffix the painting with the strings for the matting and framing.

Ｅη⪫⭆θ⌊⟦ιλ⟧


Loop over the strings, taking the minimum of the horizontal and vertical characters, and then double-spacing the rows, implicitly printing each row on its own line.

05AB1E (legacy) / 05AB1E--no-lazy, 32 31 bytes

и'X×„+#vyI©×UεX.ø}®FDнgy×.ø]€S»


Takes the input in the order height, width, matte, frame. If the input order specified in the challenge is strict (still waiting on OP for verification), a leading s (swap) can be added for +1 byte.

Required the --no-lazy Elixir compiler flag in the new version of 05AB1E, since Elixir has some odd behavior due to lazy evaluation for nested maps/loops (here the result without this flag).

Explanation:

и              # Repeat the second (implicit) input the first (implicit) input amount of
# times as list
'X×          '# Repeat "X" that many times
„+#v           # Loop y over the characters ["+","#"]:
y          #  Push character y
I         #  Push the next input (matte in the first iteration; frame in the second)
©        #  And store it in the register (without popping)
×       #  Repeat character y that input amount of times
U      #  Pop and store that string in variable X
εX.ø}      #  Surround each string in the list with string X
®F         #  Inner loop the value from the register amount of times:
Dнg      #   Get the new width by taking the length of the first string
y×    #   Repeat character y that many times
.ø  #   And surround the list with this leading and trailing string
]           # Close both the inner and outer loops
€S         # Convert each inner string to a list of characters
»        # Join every list of characters by spaces, and then every string by newlines
# (and output the result implicitly)


Jelly, 17 bytes

;ŒB“#+X+#”xʋⱮ«Ɱ/G


Try it online!

Argument 1: [Frame width, Matte width]
Argument 2: [Width, Height]

Canvas, 24 bytes

Ｘ；«［ｌｘ＊ｅ⤢｝
X×＊+⁸#⁸ ＊Ｊ ×Ｏ


Try it here!

Should be 5 bytes shorter, but isn't because Canvas is buggy..

R, 119 bytes

function(w,h,m,f)write(Reduce(function(x,y)rbind(y,cbind(y,x,y),y),rep(c("+","#"),c(m,f)),matrix("X",w,h)),1,w+2*f+2*m)


Try it online!

Python 3.8 (pre-release), 116115 113 bytes

lambda a,b,c,d:"\n".join((g:=['#'*(a+2*c+2*d)]*d+[(h:='#'*d)+'+'*(a+c*2)+h]*c)+[h+'+'*c+'X'*a+'+'*c+h]*b+g[::-1])


Try it online!

First attempt at golfing, will be improved soon. a is width, b is height, c is matte width, and d is frame width.

-1 bytes using the := operator to define h as e * d

-2 bytes thanks to Jo King suggesting me to remove the e and f parameters

EXPLANATION:

lambda a,b,c,d:          Define a lambda which takes in arguments a, b, c, and d (The width of the painting, the height of the painting, the padding of the matte, and the padding of the frame width, respectively).
"\n".join(                       Turn the list into a string, where each element is separated by newlines
(g:=                         Define g as (while still evaling the lists)...
['#'*(a+2*c+2*d)]*d+       Form the top rows (the ones filled with hashtags)
[(h:='#'*d)+'+'*(a+c*2)+h]*c Form the middle-top rows (uses := to golf this section)
)+
[h+'+'*c+'X'*a+'+'*c+h]*b+       Form the middle row
g[::-1]                      Uses g to golf the code (forms the entire middle-bottom-to-bottom)
)

• Removing the e assignment saves you two bytes, the f assignment isn't saving you anything
– Jo King
Commented Mar 19, 2019 at 3:30
• @JoKing Oh wow, I forgot to remove the e and f assignments after discovering the g shortcut Commented Mar 19, 2019 at 22:57

Jelly, 353128 24 bytes

Dịx@“#+X+#”
⁽-Fç«þ⁽-ȥç$G  Try it online! Takes the input in the order frame, matte, width, height; comma separated. Outputs the ASCII-art picture with frame and matte. If the input order is strict I’d need to add more bytes (as per my original post). Couple of golfs based on @EriktheOutgolfer’s answer; I’d realised the characters were in ASCII order but hadn’t thought how best to take advantage of that, and had forgotten about G. His is still a better answer though! • I never program in Jelly, but surely 43134,43234 can be compressed? EDIT: I need to learn to read, you mention they can indeed be encoded in 4 bytes each. But what has the input-order to do with whether these numbers can be encoded or not? :S Commented Mar 19, 2019 at 10:35 • @KevinCruijssen the maximum integer that can be encoded using the two byte syntax is 32250; since both exceed that I can’t save the bytes. For now I’ll assume I can swap things around and revert if it’s not allowed! Commented Mar 19, 2019 at 10:38 • Ah ok, I see. 43134 will need 3 encoding characters, which including a leading/trailing character to indicate it's encoded will be 5 bytes as well. And does Jelly perhaps have a duplicate of some sort, since the second number is 100 larger than the first? Not sure if the actions push 43134, duplicate, push 100, plus, pair is possible and shorter in Jelly? Commented Mar 19, 2019 at 10:46 • @KevinCruijssen I originally tried that using +0,100 which doesn’t save any. I think I could use a nilad chain to use the fact that in a nilad ³ is 100, but if I’m allowed to reorder inputs the base 250 integers are better Commented Mar 19, 2019 at 10:51 Husk, 29 25 bytes mm;₁'#⁰₁'+²RR'X ‼‼(m↔Tm+R  Try it online! Ah, this was convoluted. The input order is Matte,Frame,Width,Height. -4 bytes after simplifying function 2 & 3. Explanation Function ₁: framing function ‼‼(m↔Tm+R parameters a(char),n(int),m(matrix) m+R add a side T Transpose m↔ reverse each row ‼‼( repeat that 3 more times Function ₀: main mm;₁'#⁰₁'+²RR'X RR'X make width × height matrix of 'X'es ₁'+² add the matte of '+'es ₁'#⁰ add the frame of '#'es mm; nest each character(adds spaces)  Javascript, 158 bytes (w,h,m,f)=>(q="repeat",(z=("#"[q](w+2*(m+f)))+ )[q](f))+(x=((e="#"[q](f))+(r="+"[q](m))+(t="+"[q](w))+r+e+ )[q](m))+(e+r+"X"[q](w)+r+e+ )[q](h)+x+z)  Can probably be trimmed down a little bit f= (w,h,m,f)=>(q="repeat",(z=("# "[q](w+2*(m+f))+ )[q](f))+(x=((e="# "[q](f))+(r="+ "[q](m))+(t="+ "[q](w))+r+e+ )[q](m))+(e+r+"X "[q](w)+r+e+ )[q](h)+x+z) console.log(f(3,2,1,2)) Perl 6, 98 bytes {map(&min,[X] map (($_='#'x$^d~'+'x$^c)~'X'x*~.flip).comb,$^a,$^b).rotor($b+2*($c+$d)).join("\n")}  Try it online! This is a port of xnor's Python answer. Perl 6, 115 bytes ->\a,\b,\c,\d{$_=['#'xx$!*2+a]xx($!=c+d)*2+b;.[d..^*-d;d..^a+$!+c]='+'xx*;.[$!..^*-$!;$!..^a+$!]='X'xx*;.join(" ")}  Try it online! Roughly golfed anonymous codeblock utilising Perl 6's multi-dimensional list assignment. For example, @a[1;2] = 'X'; will assign 'X' to the element with index 2 from the list with index 1, and @a[1,2,3;3,4,5]='X'xx 9; will replace all the elements with indexes 3,4,5 of the lists with indexes 1,2,3 with 'X'. Explanation: First, we initialise the list as a a+2*(c+d) by b+2*(c+d) rectangle of #s. $_=['#'xx$!*2+a]xx($!=c+d)*2+a;
State:
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #
# # # # # # # # #


Then we assign the inner rectangle of +s

.[d..^*-d;d..^a+$!+c]='+'xx*; State: # # # # # # # # # # # # # # # # # # # # + + + + + # # # # + + + + + # # # # + + + + + # # # # + + + + + # # # # # # # # # # # # # # # # # # # #  Finally, the innermost rectangle of Xs. .[$!..^*-$!;$!..^a+$!]='X'xx*; # # # # # # # # # # # # # # # # # # # # + + + + + # # # # + X X X + # # # # + X X X + # # # # + + + + + # # # # # # # # # # # # # # # # # # # #  Perl 5, 115 bytes $_=(X x$F[0].$/)x$F[1];sub F{s,^|\z,/.*/;$_[0]x"@+".$/,ge,s/^|(?= )/$_[0]/gm while$_[1]--}F('+',$F[2]);F('#',$F[3])  TIO PowerShell, 132 bytes param($w,$h,$m,$f)filter l{"$(,'#'*$f+,$_[0]*$m+,$_[1]*$w+,$_[0]*$m+,'#'*$f)"}($a=@('##'|l)*$f)
($b=@('++'|l)*$m)
@('+X'|l)*$h$b
\$a


Try it online!