| Bytes | Lang | Time | Link |
|---|---|---|---|
| 334 | Haskell | 171129T032221Z | Hjulle |
| 536 | Node | 170413T202436Z | Neil |
| 129 | CJam | 170413T023500Z | aditsu q |
| 632 | Python 3 | 170412T212331Z | hyperneu |
| 820 | PHP>=7.1 | 170412T011014Z | Jör |
Haskell, 388 340 338 334
-52 (!) bytes thanks to Ørjan Johansen
import Data.Bits
import Data.Array
(&)=(,)
z=maximum
r x=[minimum x..z x-1]
l=map(+1).r
e(a:b:c:d:q)=[x&y&n|((f,g),n)<-[id&l&1,id&r&2,l&id&4,r&id&8],x<-f[a,b],y<-g[c,d]]++e q;e[]=[]
f a|l<-[1..z a]=unlines[[" UD│L┘┐┤R└┌├─┴┬┼"!!(accumArray(.|.)0(1&1,z a&z a)(e a)!(x,y))|x<-l]|y<-l]
main=interact$f.map read.words
Ungolfed
import Data.Bits
import Data.Array
import Data.List.Split
(&) = (,) -- Alias for tuples
-- Given [a,b], returns a list of all x: a <= x < b
halfOpenLeft x = [minimum x..maximum x-1::Int]
r = halfOpenLeft
-- Same as above, but for all x: a < x <= b
halfOpenRight = map(+1).halfOpenLeft
l = halfOpenRight
up = ((id, halfOpenRight), 0) -- Coordinates that should have a line upwards
down = ((id, halfOpenLeft), 1) -- Coordinates that should have a line downwards
left = ((halfOpenRight, id), 2) -- Coordinates that should have a line leftwards
right = ((halfOpenLeft, id), 3) -- Coordinates that should have a line rightwards
-- [up, down, left, right] = [id&l&1,id&r&2,l&id&4,r&id&8]
-- Create a map between coordinates and line-segments. Each coordinate can have multiple line-segments.
lineSegments :: [[Int]] -> [((Int,Int),Int)]
lineSegments rects = [ ((x,y),n) | [x1,x2,y1,y2] <- rects, ((f,g),n) <- [up,down,left,right], x <- f [x1,x2], y <- g [y1,y2]]
-- Convert an array of bit-fields into a list of lines.
printBitfieldArray :: Int -> Array (Int,Int) Int -> [String]
printBitfieldArray size a = [[" UD│L┘┐┤R└┌├─┴┬┼"!!(a!(x,y))|x<-[1..size]]|y<-[1..size]]
-- Merge all the line-segments for each coordinate into a bitfield
createBitFieldArray :: Int -> [((Int,Int),Int)] -> Array (Int,Int) Int
createBitFieldArray m = accumArray setBit 0 ((1,1),(m,m))
-- First split the input for each rectangle,
-- then create a list of pairs of coordinates and directions,
-- then merge all directions for each coordinate into a bitfield
-- and finally use the bitfield as an index to find out which shape to draw.
drawRectangles :: Int -> [Int] -> [String]
drawRectangles m=printBitFieldArray m.createBitFieldArray m.lineSegments.chunksOf 4
-- Parse the input, solve the problem and format the output. Use the largest number as both width and height.
main=interact$unlines.(drawRectangles=<<maximum).map read.words
Explanation
- First,
lineSegments(ordin the golfed version) will loop over all rectangles, all directions and all coordinates that should have a line-segment in that direction from that rectangle and create a list of coordinates paired with directions. - Then
createBitFieldArrymerges all entries with identical coordinates into an array of bitfields. Here, the 0th bit means up, 1st means down, 2nd means left and the 3rd means right. In other words, 5 is rendered as "┘", 0 is " " and 15 is "┼". - Lastly,
printBitFieldArray(orp) converts the bitfields into box-drawing characters by using them as indices.
Node, 536 bytes
s=''
with(process.stdin){setEncoding('utf8')
on('readable',_=>s+=read()||'')
on('end',_=>{a=s.match(/(\d+\s+){3}\d+/g).map(s=>s.match(/\d+/g).map(m=>+m)).map(([m,n,o,p])=>[m>n?n:m,m>n?m:n,o>p?p:o,o>p?o:p])
m=i=>[...Array(Math.max(...a.map(a=>a[i])))]
console.log(m(3).map((_,y)=>m(1).map((_,x)=>' ??┘?│┐┤?└─┴┌├┬┼'[x++,a.some(([m,n,o,p])=>x==m|x==n&&y>o&y<=p)+2*a.some(([m,n,o,p])=>y==o|y==p&&x>m&x<=n)+4*a.some(([m,n,o,p])=>x==m|x==n&&y>=o&y<p)+8*a.some(([m,n,o,p])=>y==o|y==p&&x>=m&x<n)],y++).join``).join`\n`)})}
Directly calculates the correct character at each coordinate. Input is annoying to perform in Node...
CJam, 129
0a80*a25*[q~]4/{:(2/:$_::-+e_534915808 6b3/\ff=C2b.+{):A;)z{_A)+\[A!A].+_A)4*+\}*;}%{~:A;_3$=@_2$=A|tt}/}/" ┌ ─┐┬ └│├┘┴┤┼"ff=N*
Notes:
- If the boxes don't look quite right, it's possible that your browser is using a fallback font for box drawing characters.
- CJam doesn't specify an encoding for source files. In UTF-8, this code has 151 bytes, but you can save it using CP437 or CP850 instead (and run it with the same encoding), then it will use 1 byte/character.
Overview:
0a80*a25* creates a matrix of 80×25 zeros
[q~]4/ reads the input, converts to numbers and splits into quadruplets
:(2/:$_::-+e_ converts an [x1 x2 y1 y2] quadruplet to [xmin xmax ymin ymax -width -height] (negative values will be corrected later)
534915808 6b3/ generates [[1 2 5] [0 2 5] [0 3 4] [0 2 4]], to be used as indices in the previous array for extracting data about the 4 sides of the current box
\ff= extracts the data for each side, e.g. [1 2 5] -> [xmax ymin -height] for the right side
C2b.+ appends 1, 1, 0, 0 respectively to the arrays for the 4 sides (right, left, bottom, top); this number indicates the direction (0=horizontal, 1=vertical)
):A;)z{_A)+\[A!A].+_A)4*+\}*; generates line pieces for a side, as [x y bitmask] triplets; each piece is a line going from the center of the cell to one of 4 directions: 1=right, 2=bottom, 4=left, 8=top; e.g. [4 2 -3 0] (a horizontal line of length 3 starting at x=4, y=2) results in [4 2 1] [5 2 4] [5 2 1] [6 2 4] [6 2 1] [7 2 4]
{~:A;_3$=@_2$=A|tt}/ bitwise-OR's all these line pieces into the matrix, resulting in bitmasks from 0..15
" ┌ ─┐┬ └│├┘┴┤┼"ff= converts these bitmasks to the corresponding box-drawing characters
N* joins with newlines for display
Python 3, 632 bytes
i=input()
j=''
while i:j+=i+' ';i=input()
c=[int(k)-1for k in j.split()]
c=[c[k:k+4]for k in range(0,len(c),4)]
for q in c:
for v,w in[(0,1),(2,3)]:
if q[w]<q[v]:t=q[w];q[w]=q[v];q[v]=t
d=list(zip(*c))
w=max(d[1])+1
h=max(d[3])+1
g=[0]*w*h
def i(a,b,f):
for k in b:
for l in a:g[k*w+l]|=f[0];f=f[1:]
def p(k,l,m,n,o,j=0):
for i in range(m,n,o):l[i]|=k
if j:p(k,l,m+j,n+j,o)
for q in c:i(q[:2],q[2:],[6,12,3,9]);p(10,g,q[0]+1+q[2]*w,q[1]+q[2]*w,1,(q[3]-q[2])*w);p(5,g,q[0]+q[2]*w+w,q[0]+q[3]*w,w,q[1]-q[0])
print('\n'.join(map(lambda k: ''.join(map(lambda x: ' └ │┌├ ┘─┴┐┤┬┼'[x], k)),[g[x:x+w]for x in range(0,len(g),w)])))
PHP>=7.1, 820 Bytes
<?preg_match_all("#(\d+(\s+\d+){3})#s",$_GET[0],$t);$r=($w="array_fill")(1,25,$w(1,80," "));function u($n,$y,$x){global$r;$u=[$z=[" ","│",$c="┤","┐","└",$d="┴",$e="┬",$b="├","─","┘","┌",$a="┼"],["│",$c,$b,$a],[$c,$a],["┐",$c,$e,$a],["└",$d,$b,$a],[$d,$a],[$e,$a],[$b,$a],["─",$d,$e,$a],["┘",$c,$d,$a],["┌",$e,$b,$a],[$a]];$o=$r[$y][$x];$s=array_intersect($u[($k="array_search")($n,$z)],$u[$k($o,$z)]);$r[$y][$x]=reset($s);}foreach($t[1]as$e){[$a,$b,$c,$d]=explode(" ",preg_replace("#\s+#"," ",$e));u("┌",$h=min($c,$d),$f=min($a,$b));u("┐",$h,$g=max($a,$b));u("└",$i=max($c,$d),$f);u("┘",$i,$g);foreach(($l="array_slice")(range($f,$g),1,-1)as$x){u("─",$h,$x);u("─",$i,$x);}foreach($l(range($h,$i),1,-1)as$y){u("│",$y,$f);u("│",$y,$g);}}foreach($r as$v)echo join($v)."\n";
-6 Bytes for use "array_fill","array_search", "array_slice" without "
+19 Bytes echo ltrim(rtrim(join($v))."\n","\n"); instead of echo join($v)."\n"; to print only the necessary Chars
Expanded
preg_match_all("#(\d+(\s+\d+){3})#s",$_GET[0],$t); # find all rects
$r=($w="array_fill")(1,25,$w(1,80," ")); # fill a empty 2 D array with spaces
function u($n,$y,$x){ # Char , Y Coordinate, X Coordinate as parameter
global$r; # result array must be global to make changes
# The following array based on Set Theory
$u=[
$z=[" ","│",$c="┤","┐","└",$d="┴",$e="┬",$b="├","─","┘","┌",$a="┼"],
["│",$c,$b,$a],
[$c,$a],
["┐",$c,$e,$a],
["└",$d,$b,$a],
[$d,$a],
[$e,$a],
[$b,$a],
["─",$d,$e,$a],
["┘",$c,$d,$a],
["┌",$e,$b,$a]
,[$a]];
$o=$r[$y][$x]; # old value for YX
$s=array_intersect($u[($k="array_search")($n,$z)],$u[$k($o,$z)]); # make the Cut quantity
$r[$y][$x]=reset($s); # Take the first value Cut quantity and set it as new value
}
foreach($t[1]as$e){ # for each rect
[$a,$b,$c,$d]=explode(" ",preg_replace("#\s+#"," ",$e)); #split the four coordinates
# next 4 rows make edges and set minimum and maximum for X an Y values
u("┌",$h=min($c,$d),$f=min($a,$b));
u("┐",$h,$g=max($a,$b));
u("└",$i=max($c,$d),$f);
u("┘",$i,$g);
foreach(($l="array_slice")(range($f,$g),1,-1)as$x){u("─",$h,$x);u("─",$i,$x);} # make the X lines
foreach($l(range($h,$i),1,-1)as$y){u("│",$y,$f);u("│",$y,$g);} # make the Y lines
}
foreach($r as$v)echo join($v)."\n"; # Output
Order of the array Set Theory
foreach($u as $k0=>$v0)
foreach($u as $k1=>$v1)
echo "\n\n'".$z[$k0]."' + '".$z[$k1]."' = '". join("','",array_intersect($v0,$v1))."'";
Examples Set Theory all possible values
The array without the use of variables to short it
$u=[
$z=[" ","│","┤","┐","└","┴","┬","├","─","┘","┌","┼"],
["│","┤","├","┼"],
["┤","┼",],
["┐","┤","┬","┼"],
["└","┴","├","┼"],
["┴","┼"],
["┬","┼"],
["├","┼"],
["─","┴","┬","┼"],
["┘","┤","┴","┼"],
["┌","┬","├","┼"]
,["┼"]];');