Code Golf: recognize ascii art boxes

Viewed 2271

Came up with this a while ago while doing some data structure work, though it'd make a good code golf: Given a two dimensional array of characters containing ascii art rectangles, produce a list of coordinates and sizes for the rectangles.

  • Any trivially convertable input or output format is fine (eg: char**, list of strings, lines on standard input; list of four ints, struct, fixed amount +/- for the size; etc).
  • Similarly, output need not be in any particular order.
  • You dont have to anything useful for invalid input or malformed rectangles, but you shouldnt to produce valid-looking coordinates for a rectangle that isnt in the input.
  • No two valid rectangles share a + (though + may appear not only as part of rectangle)
  • You can assume that all rectangles are at least 3x3: each side has a - or | in it.

Examples:

"        "
"  +-+ | "
"  | | \-"
"  +-+   "
(2,1;3,3)

"+--+  +--+"
"|  |  |  |"
"+--+  +--+"
(0,0;4,3), (6,0;4,3)

"  +---+  "
"->|...|  "
"  +---+  "
(2,0;5,3)

"+-+ +--+  +--+"
"| | |  |  |  |"
"+-+ |  |  + -+"
"    |  |      "
"    +--+  +-+ "
"  +--+    |   "
"  +--+    +-+ "
(0,0;3,3), (4,0;4,5) # (2,5;4,2) is fine, but not needed
10 Answers

Python 2.6 (251 characters)

I come in a bit late, anyway, some fun. Python, using regular expressions. To save a print statement and stay shorter than Fredb219's this won't print anything if you run it as a script, but typing one line at a time in the interpreter it's gonna show the result. Not really solid, it won't handle nested boxes nor most cases more complex than the ones given by DavidX. Haven't done testing, but I think it's likely to show results in a wrong order if something "strange" occurs.

import re
l,a,o=s.index("\n")+1,re.finditer,sorted
o(o(set((m.start(),m.end())for m in a(r'\+-* *-*\+',s)for n in a(r'\|.+\|',s)if(m.start()%l,m.end()%l)==(n.start()%l,n.end()%l)if m.start()+l==n.start()or m.start()-l==n.start())),key=lambda x:x[0]%l)

Input is a single string, lines (all same length) separated by a newline character. Results are the string slices of the top and the bottom for every "good" box, starting top left. It also allows "broken" boxes (i.e. with some space in the middle of one side, not without one entire side). This was just a way to fix an unwanted behavior creating many brand new side effects! :-)

input:

>>>s = """+-+ +--+  +--+
| | |  |  |  |
+-+ |  |  + -+
    |  |      
    +--+  +-+ 
  +--+    |   
  +--+    +-+ """

or:

>>>s = "+-+ +--+  +--+\n| | |  |  |  |\n+-+ |  |  + -+\n    |  |      \n    +--+  +-+ \n  +--+    | \n  +--+    +-+ "

then:

>>>import re
>>>l,a,o=s.index("\n")+1,re.finditer,sorted
>>>o(o(set((m.start(),m.end())for m in a(r'\+-* *-*\+',s)for n in a(r'\|.+?\|',s)if(m.start()%l,m.end()%l)==(n.start()%l,n.end()%l)if m.start()+l==n.start()or m.start()-l==n.start())),key=lambda x:x[0]%l)

output:

[(0, 3), (30, 33), (4, 8), (64, 68), (10, 14), (40, 44)]

so (0,3) top of 1st box (30,33) bottom of same box, (4,8) top of 2nd box and so on.

Related