| Bytes | Lang | Time | Link |
|---|---|---|---|
| 016 | Jelly | 250219T182804Z | Unrelate |
| 016 | 05AB1E | 250220T182618Z | Kevin Cr |
| 069 | JavaScript Node.js | 250219T170501Z | l4m2 |
| 044 | Retina 0.8.2 | 250220T083108Z | Neil |
| 033 | Charcoal | 250220T013211Z | Neil |
Jelly, 18 16 bytes
-*×ỊÄṂÐƤ=$ƤḋẒŻxḂ
Not sure if this has massive room for improvement or if Jelly is just that bad at balanced string stuff. Maps
∘ <-> 1
⋅ <-> 2
⊙ <-> 3
⊃ <-> 0
This mapping was chosen so that
idandfork, which both change the expression's structure/have arities other than 1, have absolute values less than or equal to 1 (Ị) and different parities from each other (-*),gapanddip, which both apply their subexpression deeper, are prime (Ẓ),- and
idanddip, which both select a stack element, are odd (Ḃ).
The idea is that, for every stack element selected by an id or dip, its depth is the number of gaps and dips which apply to it(s selector), either directly or to a fork containing it--which is the number of gaps and dips to its left minus those which apply to a different branch of a fork, lying between the fork operator and an id.
Ä Cumulative sums of
-* -1 to the power of each input element
×Ị or 0 if the element isn't an id or dip.
$Ƥ For each prefix,
= does each element
ṂÐƤ have no strictly smaller element to its right?
ḋ Sum the comparisons in each prefix which correspond to
Ẓ dip or gap.
Ż Prepend a 0,
x then keep only elements at the same positions as
Ḃ an id or dip in the original input.
Jelly, 21 bytes
0W
Ṫ‘
ÇŻ
Ṫ;Ṫ
Uṭ@ṛĿ¥ƒḟ
-0 but function compatibility thanks to Jonathan Allan
Horrendously ungolfed... except I'm struggling to actually golf it at all. Maps
∘ <-> 1
⋅ <-> 2
⊙ <-> 3
⊃ <-> 4
although any improvement is likely to hinge on changing this mapping for easy-to-check and possibly combinable conditions, since it's (almost) completely arbitrary.
0W Link 1: [0]
Ṫ‘ Link 2: Pop the last element and increment it.
ÇŻ Link 3: Call link 2 then prepend 0 to its result.
Ṫ;Ṫ Link 4: Pop the last two elements and concatenate them reversed.
Uṭ@ṛĿ¥ƒḟ Main link:
U Reverse the input,
¥ƒ then reduce starting from the input by:
ṭ@ append to the accumulator
Ŀ the result of calling on the accumulator
ṛ the link at the index provided by the current element being reduced.
ḟ Filter out the scalars from the original input.
05AB1E, 16 bytes
ÎvyiDëydi=}>y_i\
Uses 012⋅ for identify, fork, dip, gap (or ∘⊃⊙⋅) respectively.
Try it online or verify all test cases.
Explanation:
Î # Push 0 and the input
v # Pop the input, and loop over its characters `y`:
yi # If `y` is a 1 (aka, it's a Fork):
D # Duplicate the current top value, and continue with the next iteration
ë # Else:
ydi # If `y` is a number >=0 (aka, it's an Identity or Dip):
= # Print the top of the stack with trailing newline (without popping)
} # Close the inner if-statement
> # Increase the top value by 1
y_i # If `y` is 0 (aka, it's an Identity):
\ # Discard the top value from the stack
JavaScript (Node.js), 69 bytes
x=>x.flatMap(t=>t>2?x.push(i)&&[]:(s=i++,t>1?i=x.pop():0,t?s:[]),i=0)
⋅⊙∘⊃ map to 0123
Retina 0.8.2, 44 bytes
(?<=(∘()|⊃(?<-2>)?|.(\2|()))*)[⊙∘]
$#4
⋅|⊃
Try it online! Link includes test cases and uses original characters for convenience, but obviously I could just substitute them with ASCII characters. Explanation:
(?<=(∘()|⊃(?<-2>)?|.(\2|()))*)[⊙∘]
$#4
Match a dip or id, replacing it with the count of how many dips or gaps there are to its left, except while scanning to the left, use .NET balancing groups to keep track of whether there are ids whose forks have not yet been matched in which case don't count any intervening dips or gaps. (Technically since this is a lookbehind the parts of the alternation should be reversed as they match right-to-left but it doesn't matter as the second part is always zero width.)
⋅|⊃
Delete the gaps and forks.
Charcoal, 33 bytes
⊞υ⁰FS≡ιF⊞υ↨υ⁰«≔⊟υθF⁻Iι⊞υ⊕θF⁻Gι⟦Iθ
Try it online! Link is to verbose version of code. Takes input using DFGI for dip, fork, gap and id, or Try it online! using the original characters. Outputs the order on separate lines. Explanation:
⊞υ⁰
Start with no items consumed from the stack.
FS≡ι
Switch over each character of the input.
F⊞υ↨υ⁰«
If it's an F then duplicate the number of items consumed, otherwise:
≔⊟υθ
Get the number of items consumed into a variable.
F⁻Iι⊞υ⊕θ
If the character is not an I then save one more item consumed. (In the case of I the previously duplicated F value gets used for subsequent commands.)
F⁻Gι⟦Iθ
If the character is not a G then output the current number of items consumed.