6
\$\begingroup\$

(randomly inspired by this question)

Let's make a drawing from some pipes | and hyphens -. Choosing a subset, if chosen carefully, you can form a rectangular box or block shape (meaning that the corners are formed by |- or -|). For this challenge, we're concerned only with identifying the corners -- the vertical and horizontal pieces of the block shape can be made of either | or -, and the block may be hollow.

Here's the original drawing, and the subset showing a block shape.

|--|---|     |--|---|
|-|||-|| --> |      |
|------|     |------|

However, note that the following subsets from this same example do not make a block, because the corners are not all -| or |-

|--|
|-||

||-||
----|

|-|
---

Each combination of -| or |- can only form one corner. This means that the smallest possible block shape is these eight characters

|--|
|--|

and that these six characters do not form a block shape, since the corners are being "doubled up."

|-|
|-|

The challenge here is to turn these blocks fluffy. How? Replace every hard-edged straight character that forms the block edges (both corners and sides) with a much rounder, fluffier character, in this case, an o. But, don't fill in the block - we only want to get rid of the hard edges and sharp corners.

|--|---|     oooooooo
|-|||-|| --> o-|||-|o
|------|     oooooooo

Input

A 2D string representation of the pipe/hyphen diagram. Input can be as a multiline string, an array of strings, etc., however is convenient for your language. The input is guaranteed to be rectangular (i.e., every row will be the same length), and will only contain | and -.

Output

The same diagram, with the "block" characters replaced with o as described above and the remaining characters unchanged. The result can be printed to the screen or STDOUT, returned from a function, etc.

Rules

  • Note that blocks can overlap (see example #8) and blocks can share corners (see example #5).
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

#1
-|--|
|--|-
|--||

-|--|
oooo-
oooo|

#2
|--|---|
|-|||-||
|------|

oooooooo
o-|||-|o
oooooooo

#3
|||||

|||||

#4
|-----|
||---|-
||---|-
|-----|

ooooooo
ooooooo
ooooooo
ooooooo

#5
-|--|--|
|||-|--|
-|-----|

-ooooooo
|o|-oooo
-ooooooo

#6
|-||-|
|----|

oooooo
oooooo

#7
--|--|-
|-----|

--|--|-
|-----|

#8
|-----|---
||--||-|--
||||--|--|
|-|-||||-|
|--|--|-||
---||---||
---|-----|

ooooooo---
o|--||o|--
o||ooooooo
o-|o||o|-o
ooooooo-|o
---o|---|o
---ooooooo
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

Perl, 448 bytes

$_=<>;$o=$_;~y/-|/Aa/;$N=$_;while($n ne $N){$n=$N;$c=$N;$M=$c;while($c=~s/^(.*?;)??([aA]*?)aA([aA]*)Aa(.*;(?i)\2)aA((?i)\3)Aa(.*)$/\L\1\2\UAA\3AA\L\4\UAA\5AA\L\6/){if($N eq $n){substr($N,(length $1)+(length $2),1)="X"}substr($M,-(length $6)-1,1)="X";$c=~s/^([xa;]*;)?(a*)A(A*)A(a*;)\2a((?i)\3)a/\1\2A\3A\4\2A\5A/;1 while $c=~s/(^|;)(a*)A(a*)A(a*;)\2a((?i)\3)a/\1\2A\3A\4\2A\5A/;while($c=~/A/g){substr($o,(pos $c)-1,1)="o"}$c=$M}}$o=~y/;/\n/;print$o

I haven't used perl before so there's going to be massive room for improvement here (especially since I was mostly glad to get it working, so haven't tried to optimise it yet). I was a bit disappointed that the regular expression language didn't have some of the features I wanted, but I think it does pretty well.

Usage

Takes input on stdin, with lines semicolon-separated (optionally add a semicolon to the end to make the final printed output end with a newline). Outputs to stdout. Example command:

printf -- "-|--|--|;|||-|--|;-|-----|;" | perl boxes.perl

Breakdown

$_=<>; # Load input
$o=$_; # Create output variable
~y/-|/Aa/; # Replace - and | with A and a so that we can use case insensitive tricks later
$N=$_;
# For each distinct top-left corner...
while($n ne $N){
    $n=$N;
    $c=$N;
    $M=$c;
    # For each distinct box...
    while($c=~s/^(.*?;)??([aA]*?)aA([aA]*)Aa(.*;(?i)\2)aA((?i)\3)Aa(.*)$/\L\1\2\UAA\3AA\L\4\UAA\5AA\L\6/){
        if($N eq $n){
            # mark top-left corner used (x)
            substr($N,(length $1)+(length $2),1)="X"
        }
        # mark bottom-right corner used (x)
        substr($M,-(length $6)-1,1)="X";

        # Fill in sides of identified box
        $c=~s/^([xa;]*;)?(a*)A(A*)A(a*;)\2a((?i)\3)a/\1\2A\3A\4\2A\5A/;
        1 while $c=~s/(^|;)(a*)A(a*)A(a*;)\2a((?i)\3)a/\1\2A\3A\4\2A\5A/;

        # Replace output chars with "o" where box was found
        while($c=~/A/g){
            substr($o,(pos $c)-1,1)="o"
        }

        # Continue to next box
        $c=$M
    }
}

# Convert to nice output & print
$o=~y/;/\n/;
print$o
\$\endgroup\$
1
  • \$\begingroup\$ If anybody knows how to make perl loop through all possible matching groups (as opposed to just the non-overlapping matches), it would save the need for both while loops and all the "x" logic. \$\endgroup\$
    – Dave
    Nov 15, 2016 at 22:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.