10
\$\begingroup\$

In these previous challenges[1][2] I've been dealing with "mushroom forests". To help with these I draw little diagrams of the forests to help. In this challenge we are going to reverse engineer the data from these diagrams.

To recap ha! mushroom forests are a list of pairs of non-negative integers. Each pair represents a mushroom whose center is at that horizontal coordinate. The only part of the mushroom we care about is the cap (the flat bit at the top).

The first integer in each pair represents which row the cap is placed in. i.e. the height of the mushroom.

The second integer represents the radius of the cap. If it's zero then there just isn't a mushroom in that position. Other for size \$n\$ a total of \$2n-1\$ spaces are occupied centered at the index of the pair. For example 1 means that its cap only occupies a space above it, a 2 means it occupies a space above it and the spaces one unit to the left and right.

To draw the data I represent rows using lines of text separated by newlines. There are twice as many lines as there are rows with the even rows being used for spacing. I draw the caps using the = and I only draw caps on odd numbered lines. If a mushroom cap is present at coordinate \$(x,y)\$ I draw an = at \$(2x,2y+1)\$. Here's an example:

                  =
                
= = = = = = = = = = = = = = = = =

          = = = = =

          = = =       =

          [ 2,3,9,1,0,1 ] <- Widths
          [ 0,1,2,3,2,1 ] <- Heights

Then between =s of the same height I add an extra = if they belong to the same mushroom.

                  =
                
=================================

          =========

          =====       =

          [ 2,3,9,1,0,1 ] <- Widths
          [ 0,1,2,3,2,1 ] <- Heights

Then I draw stalks extending from the bottom row up to the cap the correspond to. If there's already a = in a space I leave it alone. I don't draw any stalks for mushrooms with width 0.

                  =
                  |
=================================
                | |
          =========
              | | |
          ===== | |   =
            | | | |   |
          [ 2,3,9,1,0,1 ] <- Widths
          [ 0,1,2,3,2,1 ] <- Heights

Task

Your task is to take as input a string of an ascii diagram as described above and output the list of widths used to draw that diagram. We don't care about the heights at all.

You may output trailing and leading zeros in your result, as they don't change the diagram. You may also assume that the input is padded to a perfect rectangle enclosing the bounding box of the art. You may assume that there is always a valid solution to the input and you do not have to handle malformed input.

This is so the goal is to minimize the size of your source code as measured in bytes.

Test cases

Test cases are provided with all leading and trailing zeros trimmed in the output, however the output is aligned to the input for clarity.

                  =              
                  |              
=================================
                | |              
          =========              
              | | |              
          ===== | |   =          
            | | | |   |          
           [2,3,9,1,0,1]

  = =
  | |
 [1,1]

=====     =====
  |         |  
 [2,0,0,0,0,2]

===== ============= =
  |         |       |
  | =====   |   =====
  |   |     |     | |
  =====     =========
  | | |     |   | | |
 [2,2,2,0,0,4,0,3,2,1]

  ===== =      
    |   |      
===== =========
  | |   | |    
 [2,2,0,1,3]

    =============
          |      
  =============  
        | |      
    ===== |      
      | | |      
    = | | |      
    | | | |      
===== | | |      
  | | | | |      
 [2,1,2,4,4]
\$\endgroup\$
0

7 Answers 7

6
\$\begingroup\$

Python, 125 bytes

import re
def f(s):
 o=[0]*len(s[0])
 for l in s:
  for m in re.finditer("=+",l):o[sum(m.span())//4]=len(m[0])//4+1
 return o

Attempt This Online!

Bad, terrible, no good.

Need variable-length lookbehind.

\$\endgroup\$
3
  • 4
    \$\begingroup\$ +1 for Bad, terrible, no good. :-p \$\endgroup\$
    – Arnauld
    Jun 30 at 11:24
  • 1
    \$\begingroup\$ The ascii art looks much nicer on ATO. \$\endgroup\$
    – Wheat Wizard
    Jun 30 at 11:26
  • 1
    \$\begingroup\$ @WheatWizard That's what font ligatures get you :) \$\endgroup\$
    – pxeger
    Jun 30 at 11:37
4
\$\begingroup\$

Jelly, 23 20 16 bytes

OḂŒgÄ=U×ƊF€Sm2HĊ

Try it online!

-3 thanks to Jonathan Allan, also opening up another -1 (×=¥UFƊ€ -> =U×ƊF€)

    Ä   Ɗ           Consider the cumulative sums of
  Œg                the runs in each row of
OḂ                  whether or not each character is an equals sign
 Ḃ                  (ones bit of
O                   the codepoints).
     =              For each element of each cumsummed run, is it equal to
      U             the corresponding element of the run backwards?
       ×            Multiply it by the result.
         F€         Flatten each row,
           S        Sum each column,
            m2      remove alternating elements,
              H     halve,
               Ċ    and ceiling.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Nice ninja CYA edit with the "probably -> might" lol. Do not underestimate me! \$\endgroup\$
    – pxeger
    Jun 30 at 11:25
  • 1
    \$\begingroup\$ Save a byte with ordinal mod 2 and another two with some different chaining like so TIO \$\endgroup\$ Jun 30 at 23:54
3
\$\begingroup\$

Retina, 39 bytes

^
¶
(=*)=\1
$1!$1
{*.\Cm`^!|\G==
m`^..

Try it online!

Explanation

^, : Add a line feed at the start of the string.

(=*)=\1, $1!$1: Match each mushroom, and change the centre character to a !.

{: Repeat until no change:

  • *.\Cm`^!|\G==:
    • C: Count matches of ^!|\G==: ! at the start of a line (m makes ^ match the start of each line), or == immediately after the previous match (\G). This gives the size of a half-mushroom with its centre at the start of a line, if there is one, or 0 if there is none.
      (The added empty line at the start of the string makes sure \G== does not match at the start of the string.)
    • \: Output the result of the above.
    • *: Do not change the working string. (According to the documentation, this should not be necessary as "output stages are purely used for their side effect and will never affect the working string themselves", but that doesn't seem to be what actually happens?)
    • .: Disable implicit output.
  • m`^.. (with an empty second source): Remove the first two characters of each line. (This is implicitly a Replace stage.)
\$\endgroup\$
3
  • \$\begingroup\$ Save 2 bytes by moving the m on line 5 to before the { so that you can remove it on line 6. Save 1 byte by switching to Retina 0.8.2 because * automatically prints (need to replace {. with ;{ too). \$\endgroup\$
    – Neil
    Jul 1 at 11:08
  • \$\begingroup\$ An output stage just prints the working string on its way to or from its child stage without changing it, but the child stage can still change it, and the output stage doesn't affect that. \$\endgroup\$
    – Neil
    Jul 1 at 11:12
  • \$\begingroup\$ (Retina 0.8.2 would also need M instead of C of course.) \$\endgroup\$
    – Neil
    Jul 1 at 11:32
2
\$\begingroup\$

05AB1E, 21 bytes

'=QεγεƶÐÅsQ*}˜}øOιн;î

Port of @UnrelatedString's Jelly answer, since it's shorter than any monstrosity I was attempting..

Input as a (right-padded) matrix of characters. Output as a list of doubles with leading/trailing 0s.

Try it online or verify all test cases. (Footer 0Úï is to pretty-print the output; feel free to remove it to see the actual output.)

Explanation:

'=Q         '# Check for each character in the (implicit) input-matrix if it's a "="
   ε         # Map over each row of 0s/1s:
    γ        #  Split it into groups of adjacent equal elements
     ε       #  Inner map over each group:
      ƶ      #   Multiply each value by its 1-based index
       Ð     #   Triplicate this list
        Ås   #   Pop one, and push the middle item
          Q  #   Pop another, and check which values are equal to this middle
           * #   Multiply each at the same positions to the remaining list
     }˜      #  After the inner map: flatten the list of groups
   }ø        # After the outer map: zip/transpose; swapping rows/columns
     O       # Sum each inner list (the columns)
      ι      # Uninterleave it into two parts
       н     # Pop and only leave the first part
        ;    # Halve each value
         î   # Ceil each value
             # (after which the result is output implicitly)

ÐÅmQ* could alternatively be Z>;Qƶ for the same byte-count:

       Z     #   Push the maximum (without popping the list)
        >    #   Increase it by 1
         ;   #   Halve it
          Q  #   Check which values are equal to this middle
           ƶ #   Multiply each value by its 1-based index
\$\endgroup\$
2
\$\begingroup\$

Haskell, 161 160 bytes

-1 bytes thanks to @Unrelated String

p[]=[]
p(x:y:z)=map(`div`4)[y-x+3,x+y]:p z
m=map(=='=')
f a=[sum[w|[w,x]<-concat[p[j|(j,x,y)<-zip3[0..](m$' ':b)$m$b++" ",x/=y]|b<-a],x==y]|y<-[1..length$a!!0]]

Attempt This Online!

\$\endgroup\$
1
1
\$\begingroup\$

Vyxal, 18 bytes

C∷ƛĠv¦ƛṘ=*;f;∑y_½⌈

Try it Online!

Port of Jelly.

\$\endgroup\$
0
\$\begingroup\$

Charcoal, 36 bytes

WS⊞υιIΦEEθ⌕⭆υ§λκ=|∧⊕ι⊕⊘L⊟⪪…§υικ ¬﹪κ²

Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated strings. Explanation:

WS⊞υι

Input the forest.

Eθ⌕⭆υ§λκ=|

Find the first positions of all of the substrings =| in the columns, if any.

E...∧⊕ι⊕⊘L⊟⪪…§υικ 

For each column, if the substring was not found then return 0 otherwise truncate the row containing the mushroom at the column, split on spaces, and take the incremented halved length of the last substring, which will be the row of =s to the left of the middle of the mushroom.

IΦ...¬﹪κ²

Output alternate columns, since we're not interested in the other columns.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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