Do the figures fit?

7

4

Challenge

Make the shortest program to determine if the figures in the input will fit into the space in the input.

Requirements

The input will be in the format of this example: Input:

+----+      -- +--+
|    +----+    |  |
|         |    +--+
|         |
+---------+

Output:

+----+
|+--++----+
||  |--   |
|+--+     |
+---------+

First, starting in the upper left corner, is the space that the program will try to fit the figures into. Then there is a space. Then there is a figure, in this case two dashes. Then there is a space, then a second figure. The output is the figures fitted inside of the space.

Rules about figures and input:

  • The upper left corner of a shape will always be on the first row.
  • After a figure, there is one space, as shown in the example.
  • There is no limit on the size of the figures.
  • The first figure will always be the space that the program will determine if the figures fit into.
  • There is no limit on the number of figures, but there will only be one space to fit them into.
  • All figures will be made of | and - for the sides and + for the corners. These are the only characters used besides spaces and newlines.
  • Figures cannot be rotated.
  • Borders cannot overlap.
  • You may fit one figure inside of another.
  • The figures do not have to be closed.
  • The space will always be closed.
  • The space does not have to be completely filled.
  • You may not split up shapes.

Rules about output:

  • If the figures fit into the space, the program should output the figures inside of the space, as shown above. It does not matter how they are arranged, as long as no borders overlap, all figures are correct, and no shapes are split up.
  • If the figures do not fit, output "no".

Examples

Input:

+--+ |
+--+

Output:

no

Input:

+---+  -+
|   |   |
|   |
+---+

Output:

+---+
|-+ |
| | |
+---+

This is also valid:

+---+
| -+|
|  ||
+---+

Input:

+----------+ +-----+ -+
|          | |     |  |
|          | |     |  
|          | +-----+
|          |
+----------+

Output:

+----------+
|+-----+   |
||-+   |   |
|| |   |   |
|+-----+   |
+----------+

This is a code golf, so the shortest answer wins.

Dave Jones

Posted 2017-02-22T14:49:15.590

Reputation: 465

2You say make the shortest program at the top, but answer with most votes wins at the bottom. Note that this will get closed as a popularity contest. – Dennis – 2017-02-22T14:53:06.833

1This isn't a programming puzzle either. That has a fairly specific meaning; check the tag wiki for more information. – None – 2017-02-22T14:54:23.303

I fixed this. It is now a code golf challenge – Dave Jones – 2017-02-22T14:56:55.717

1Consider editing out the specific "no" output, and either (1) only having to handle valid input (any behaviour); or (2) allowing standard falsey outputs and errors. – Jonathan Allan – 2017-02-22T15:07:38.710

It looks like the two -- are misplaced in one of the first two images [Requirements]. – Jonathan Allan – 2017-02-22T15:09:43.873

Which is the upper-left corner in ambiguous cases? – Jonathan Allan – 2017-02-22T15:10:48.897

"The first figure will always be the space that the program will determine if the figures fit into." - can we not take the two figures separately? Parsing out the set of figures seems to detract from the main task. – Jonathan Allan – 2017-02-22T15:12:34.853

If the case is ambiguous, the first character in the input will be the upper corner of the space. The program does not have to output anything if the input is invalid. It outputs "no" is the figures do not fit into the space. – Dave Jones – 2017-02-22T15:18:26.490

Answers

5

Python 2, 529 692 683 681 bytes

L=len
R=range
def g(s):S=s.split('\n');S=[l.ljust(L(S[0]))for l in S];Z=zip(*S);I=[-1]+[i for i in R(L(Z))if{' '}==set(Z[i])]+[None];return[[list(x)for x in zip(*Z[I[i]+1:I[i+1]])if set(x)!={' '}]for i in R(L(I)-1)]
def f(s):
 S=g(s);G(S[0],1,1)
 for l in F(*S)or['no']:print''.join(l).replace('~',' ')
def G(a,i,j):
 if len(a)>i>-1<j<len(a[0])and'!'>a[i][j]:
	for x,y in(0,1),(0,-1),(1,0),(-1,0):G(a,i+x,j+y);a[i][j]='~'
def F(a,*s):
 if not s:return a
 c=s[0];h,w=L(c),L(c[0])
 for i in R(1,L(a)-h):
	for j in R(1,L(a[0])-w):
	 T=1;A=[l[:]for l in a]
	 for y in R(h):
		for x in R(w):
		 C=c[y][x]
		 if' '<C:T&=A[y+i][x+j]>'}';A[y+i][x+j]=C
	 r=T and F(A,*s[1:])
	 if r:return r

Try it online!

Gained a lot of bytes by adding a flood fill to the first shape.

This is to fix fix cases where a figure can be outside the shape, but inside its bounding box.

eg. The shape fits inside the bounding box, but outside the shape:

Input:        Wrong:      Correct:
+-+    --     +-+         +-+
| |           | |--       | |
| +--+        | +--+      | +--+
|    |        |    |      |--  |
+----+        +----+      +----+

Explanation

f takes input as a single string with newlines.

+----+      -- +--+
|    +----+    |  |
|         |    +--+
|         |
+---------+

The shapes are split up with g(s) and mapped to lists of lists

[[['+', '-', '-', '-', '-', '+', ' ', ' ', ' ', ' ', ' '], ['|', ' ', ' ', ' ', ' ', '+', '-', '-', '-', '-', '+'], ['|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|'], ['|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|'], ['+', '-', '-', '-', '-', '-', '-', '-', '-', '-', '+']],
[['-', '-']],
[['+', '-', '-', '+'], ['|', ' ', ' ', '|'], ['+', '-', '-', '+']]]

The first shape is flood filled with ~ (G(S[0])), so we know the allowed area:

+----+     
|~~~~+----+
|~~~~~~~~~|
|~~~~~~~~~|
+---------+

For each other shape we recursively fit them into the first F(a,*s), returning when all of them fit, or at the end, if no configuration does.

+----+        +----+        +----+        +----+        +----+     
|--~~+----+   |~--~+----+   |~~--+----+   |~~~~+----+   |~~~~+----+
|~~~~~~~~~|   |~~~~~~~~~|   |~~~~~~~~~|   |--~~~~~~~|   |~--~~~~~~|
|~~~~~~~~~|   |~~~~~~~~~|   |~~~~~~~~~|   |~~~~~~~~~|   |~~~~~~~~~|
+---------+   +---------+   +---------+   +---------+   +---------+
     |             |             |             |             |
     V             V             V             V             V
  No room        No room      No room       No room     +----+     
  for next       for next     for next      for next    |+--++----+
  shape          shape        shape         shape       ||--|~~~~~|
                                                        |+--+~~~~~|
                                                        +---------+

                                                           Done!

Lastly we print the combined shapes, without ~.

+----+     
|+--++----+
||--|     |
|+--+     |
+---------+

TFeld

Posted 2017-02-22T14:49:15.590

Reputation: 19 246

+1 for being fast enough to be runnable. I think (disclaimer: I don't know Python) C>' ' can be replaced with C>32. – user202729 – 2017-11-01T10:01:52.937

Great answer. Will accept it if there are no new answers for a while. – Dave Jones – 2017-11-01T11:31:21.270

@user202729 Python's object comparison does allow for comparing strings with integers, though int("...")<"..." will always be true; Python's 'chars' are really strings of length one, which always come after an integer. One thing one could do to save a byte, though, would be to replace if C>' ' with if' '<C. – Jonathan Frech – 2017-11-02T06:31:26.880

2

Wolfram Language (Mathematica), 811 bytes

(M=MorphologicalComponents;L=Length;A=Thread;T=Last;B=Table;P=Position;W=Prepend;g=AnyTrue[#,#!=" "&]&;h[n_]:=If[DuplicateFreeQ[Join@@B[(#-{1,1}+W[n,{1,1}][[i]]&)/@P[t[[i]],1],{i,L[y]}]],n,Nothing];R[z_]:=PadRight[#,Max[L/@z]," "]&/@z;s=Characters/@StringSplit[#,"\n"];s=R@s;r=Map[#/.{Longest[" "...],n___," "...}->{n}&,DeleteCases[A/@Split[A@s,g],_?(!g@#&),2],2];r[[1]]=R@#&@@r;t=r/.{"|"|"+"|"-"->1," "->0};y=M[#,Method->"ConvexHull"]&/@t;o=y-M/@t;u=T[h/@T@T@Reap[Outer@@Append[W[B[{NoneTrue[Flatten@B[#[[q+1,w+1]]==1&&o[[1]][[i+q,j+w]]==0,{w,0,L@#&@@#-1},{q,0,L@#-1}],TrueQ],i,j},{i,1,1+L@#&@@y-L@#},{j,1,1+L@y[[1,1]]-L@#&@@#}]&/@y[[2;;]],If[And@@(First/@{##}),Sow[#[[2;;]]&/@{##}]]&],2]]];If[u=={},"no",Grid@ReplacePart[r[[1]],Join@@B[(#-{1,1}+u[[i-1]])->Part[r[[i]],Sequence@@#]&/@P[t[[i]],1],{i,2,L@y}]]])&

enter image description here

It needs a frontend to display grid (which is not supported on tio.run).

The code does the following things:

  1. Get inside points of 1st shape
  2. Iterate over all starting point combinations
  3. Pick a combination where all other (2, 3, ...) shapes' points lie in waht we get in Step 1, and without any overlapped points
  4. Output (by ReplacePart)

If the input format can be more flexible, the code can be shortened to ~680 bytes. Besides that, there is still a lot of golfing space, though.

Try it online!

Expanded:

(M = MorphologicalComponents; L = Length; A = Thread; T = Last; 
  B = Table; P = Position; W = Prepend; g = AnyTrue[#, # != " " &] &; 
  h[n_] := If[
    DuplicateFreeQ[
     Join @@ B[(# - {1, 1} + W[n, {1, 1}][[i]] &) /@ P[t[[i]], 1], {i,
         L[y]}]], n, Nothing]; 
  R[z_] := PadRight[#, Max[L /@ z], " "] & /@ z; 
  s = Characters /@ StringSplit[#, "\n"]; s = R@s; 
  r = Map[# /. {Longest[" " ...], n___, " " ...} -> {n} &, 
    DeleteCases[A /@ Split[A@s, g], _?(! g@# &), 2], 2]; 
  r[[1]] = R@# & @@ r; t = r /. {"|" | "+" | "-" -> 1, " " -> 0}; 
  y = M[#, Method -> "ConvexHull"] & /@ t; o = y - M /@ t; 
  u = T[h /@ 
     T@T@Reap[
        Outer @@ 
         Append[W[
           B[{NoneTrue[
                Flatten@
                 B[#[[q + 1, w + 1]] == 1 && 
                   o[[1]][[i + q, j + w]] == 0, {w, 0, 
                   L@# & @@ # - 1}, {q, 0, L@# - 1}], TrueQ], i, 
               j}, {i, 1, 1 + L@# & @@ y - L@#}, {j, 1, 
               1 + L@y[[1, 1]] - L@# & @@ #}] & /@ y[[2 ;;]], 
           If[And @@ (First /@ {##}), Sow[#[[2 ;;]] & /@ {##}]] &], 
          2]]]; If[u == {}, "no", 
   Grid@ReplacePart[r[[1]], 
     Join @@ B[(# - {1, 1} + u[[i - 1]]) -> 
          Part[r[[i]], Sequence @@ #] & /@ P[t[[i]], 1], {i, 2, 
        L@y}]]]) &

Keyu Gan

Posted 2017-02-22T14:49:15.590

Reputation: 2 028