# Collect data on mushroom forests

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


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]


# 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!

Need variable-length lookbehind.

• +1 for Bad, terrible, no good. :-p Jun 30 at 11:24
• The ascii art looks much nicer on ATO. Jun 30 at 11:26
• @WheatWizard That's what font ligatures get you :) Jun 30 at 11:37

# Jelly, 2320 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.

• Nice ninja CYA edit with the "probably -> might" lol. Do not underestimate me! Jun 30 at 11:25
• Save a byte with ordinal mod 2 and another two with some different chaining like so TIO Jun 30 at 23:54

# 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.)
• 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).
– Neil
Jul 1 at 11:08
• 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.
– Neil
Jul 1 at 11:12
• (Retina 0.8.2 would also need M instead of C of course.)
– Neil
Jul 1 at 11:32

# 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


-1 bytes thanks to @Unrelated String

p[]=[]
p(x:y:z)=map(div4)[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!

• 160 Jul 1 at 12:04

# Vyxal, 18 bytes

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


Try it Online!

Port of Jelly.

# Charcoal, 36 bytes

ＷＳ⊞υιＩΦＥＥθ⌕⭆υ§λκ=|∧⊕ι⊕⊘Ｌ⊟⪪…§υικ ¬﹪κ²


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

ＷＳ⊞υι


Input the forest.

Ｅθ⌕⭆υ§λκ=|


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

Ｅ...∧⊕ι⊕⊘Ｌ⊟⪪…§υικ


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.

ＩΦ...¬﹪κ²


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