text:
Generating generating expressions for sequences
(yes, "generating generating" in the title is correct :) )
Context
In middle (?) school we are taught about sequences and, in particular, we are taught about linear sequences where the nth term is generated with an expression of the form an + b, where a and b are some coefficients. In this challenge, we will deal with sequences generated by polynomials of arbitrary degree.
Task
Given the first m terms of a sequence, find the coefficients of the polynomial of lowest degree that could have generated such a sequence.
A polynomial, and thus the generating expression you are looking for, is to be seen as a function \$p(n)\$ that takes n as an argument and returns
$$a_0 + a_1 n + a_2 n^2 + a_3 n^3 + \cdots + a_k n^k$$
where \$k \geq 0\$ and \$a_i, 0 \leq i \leq k\$ have to be found by you.
You will assume that the m terms you were given correspond to taking n = 0, n = 1, ..., n = m-1 in the generating polynomial above.
Examples
If I am given the sequence [2, 2, 2] then I realize this is a constant sequence and can be generated by a polynomial of degree 0: p(n) = 2.
If I am given the sequence [1, 2, 3] then I realize this cannot come from a constant polynomial but it could come from a linear polynomial p(n) = n + 1, so that is what my output should be. Notice how
p(0) = 1
p(1) = 2
p(2) = 3    # and NOT p(1) = 1, p(2) = 2, p(3) = 3

Input
Your input will be the first terms of a sequence, which you can take in any reasonable format/data type. A standard list is the most obvious choice.
You may assume the input sequence is composed of integers (positive, 0 and negative).
Output
The coefficients of the polynomial of lowest degree that could have generated the input sequence. The output format can be in any sensible way, as long as the coefficients can be retrieved unambiguously from the output. For this, both the value of each coefficient and the degree of each coefficient are important. (e.g. if using a list, [1, 0, 2] is different from [0, 1, 2]).
You can assume the polynomial you are looking for has integer coefficients.
Test cases
For these test cases, the input is a list with the first terms; the output is a list of coefficients where (0-based) indices represent the coefficients, so [1, 2, 3] represents 1 + 2x + 3x^2.
[-2] -> [-2]
[0, 0] -> [0]
[2, 2, 2] -> [2]
[4, 4] -> [4]
[-3, 0] -> [-3, 3]
[0, 2, 4, 6] -> [0, 2]
[2, 6] -> [2, 4]
[3, 7] -> [3, 4]
[4, 8, 12, 16] -> [4, 4]
[-3, -1, 5, 15, 29] -> [-3, 0, 2]
[0, 1, 4, 9] -> [0, 0, 1]
[3, 2, 3, 6, 11] -> [3, -2, 1]
[3, 4, 13, 30, 55] -> [3, -3, 4]
[4, 12, 28, 52, 84] -> [4, 4, 4]
[2, 4, 12, 32, 70] -> [2, 1, 0, 1]
[3, 6, 21, 54] -> [3, -1, 3, 1]
[4, 2, 12, 52, 140] -> [4, -2, -3, 3]
[10, 20, 90, 280] -> [10, 0, 0, 10]
[-2, 8, 82, 352, 1022, 2368, 4738] -> [-2, 4, -1, 4, 3]
[4, 5, 32, 133, 380] -> [4, -2, 0, 2, 1]
[1, 0, 71, 646, 2877, 8996, 22675] -> [1, -1, 0, -3, 0, 3]
[4, 2, 60, 556, 2540, 8094, 20692] -> [4, -2, -1, 0, -2, 3]
[1, 2, -17, 100, 1517, 7966, 28027, 78128, 186265] -> [1, 3, -2, 4, -3, -2, 1]
[4, 5, 62, 733, 4160, 15869, 47290, 118997] -> [4, 3, -1, -3, 1, 0, 1]

Test cases generated with this code

This is code-golf so shortest submission in bytes, wins! If you liked this challenge, consider upvoting it! If you dislike this challenge, please give me your feedback. Happy golfing!

related

May we take m as part of the input?

@RobinRyder only if it is standard in your language to take the length of a vector as an argument alongside the vector (like it is in C, for example)

@RobinRyder Just as note, there was a relevant meta discussion about this some time ago. The conclusions were more or less what was decided here, too.

Can we output in polynomial form (1 + 2x + 3x^2)?

@Uriel "The output format can be in any sensible way, as long as the coefficients can be retrieved unambiguously" so yeah, you can!

Some answers round the resulting coefficients to integers, although I don’t read this as a hard requirement. Could you please  explicitly (not) require this?

Since the outputs can be assumed to be integers, is it OK to return near-zero (like 10⁻¹⁰ or smaller) numbers instead of proper zeros due to floating point errors?

@agtoever doing so, how do I draw the line between what is an acceptable error and what is not?

@Adám not sure; let me settle this with agtoever and your answer will probably come out of that.

Based on answers, I guess it's OK for the coefficient lists to include trailing zeroes? I wouldn't have thought that this would be allowed due to "Output: The coefficients of the polynomial of lowest degree..." But I think it indeed might make for a cleaner challenge not to require the extra step of removing trailing zeroes, which is how I expect most answers without built-ins would handle it.

@xnor when I saw the first answer with leading/trailing (depending on the order of the output) zeroes I also felt reluctant to accept them... But a 0 coefficient doesn't make the degree of the polynomial go up, as you know, and the zeroes don't mess with the unambiguous interpretation of the answers, so I allowed those.

@RGS That's fair. I was misunderstanding the "lowest degree" rule to refer to how the polynomials are shown in the output (without extraneous higher-power zero terms) rather than as a mathematical property of the polynomials themselves, which is of course not affected by how they are shown.

Arguably, the test case [0, 0] -> [0] would be more naturally, [0, 0] -> [], since the empty polynomial is already zero everywhere. But with the flexibility on trailing zeroes, it doesn't really matter.

@xnor I don't think I ever heard of an "empty polynomial" , mathematically speaking. Is it a common thing? To me, an "empty function" sounds like something that would not be defined for any input, no? For the sake of argument, I would say the test case 0, 0 -> 0 does make sense :)

Let us continue this discussion in chat.

Nothing related to the challenge, but "middle school" would actually be high school in English. :) For me in The Netherlands we have "basisschool" (roughly ages 5-11), "middelbare school" (roughly ages 12-17), and "hoge school / universiteit" (roughly ages 18-24) (which literally translates to "basic school", "middle school", "high school / university"; but which would actually translate to "elementary school", "high school" and "college / university" respectively in English).

@KevinCruijssen  I mean this middle school from ages ~10 to ~15, which precedes "high school" but comes after "elementary school" here in Pt. It really is weird if in English there is nothing between elementary school and high school... Maybe this standard is more explicit? I meant level 2 of the ISCED 2011 levels :)

"You can assume the polynomial you are looking for has integer coefficients." - so does this mean we can output some coefficients with floating-point rounding errors? ...and does that include any higher-order zeros?

@JonathanAllan definitely not for higher order zero coefficients. As for the terms of lower degree, how can I enforce "reasonable" errors?

If they are errors due to floating-point inaccuracies you don't need to, it just comes under real-world machine inaccuracies. At present, for example, my Jelly answer rounds to 0 decimal places but accepts a list of integers each of which is unbounded, hence there exist inputs for which it will give incorrect answers as it is, so the three bytes of rounding I included actually adds no value as far as I can tell, but without them some of the test cases yield sligtly inaccurate results.

@JonathanAllan I understand that floating-point inaccuracies arise naturally; what I mean is from the little experience I've had with this community, stating that "X is allowed as long as it occurs naturally" doesn't look very acceptable.

JavaScript (ES7),  193 ... 154  145 bytes
Saved 9 bytes thanks to @Bubbler
Returns \$(a_0,a_1,...,a_k)\$ with some possible trailing zeros.
v=>v.map((_,i)=>(g=(i,m=v.map((n,y)=>v.map((_,x)=>x==i?n:y**x)))=>+m||m.reduce((s,[v],i)=>v*g(0,m.map(([,...r])=>r).filter(_=>i--))-s,0))(i)/g())

Try it online!
(removed the penultimate test case, which requires more precision than IEEE-754 provides)
How?
We use Cramer's rule to solve a system of linear equations based on a square Vandermonde matrix:

Given an input vector of length \$n\$, we build a Vandermonde matrix \$V_n\$ of size \$n\times n\$ with coefficients \$\alpha_i=i,0\le i <n\$:
$$Vn=\begin{pmatrix}
1&0&0&...&0\\
1&1&1&...&1\\
1&2&4&...&2^{n-1}\\
\vdots&\vdots&\vdots&\ddots&\vdots\\
1&n-1&(n-1)^2&...&(n-1)^{n-1}
\end{pmatrix}$$

Using Cramer's rule, the coefficient \$a_i\$ of the polynomial is computed by taking the determinant of the matrix obtained by replacing the \$i\$-th column of \$V_n\$ with the input vector, and dividing by the determinant of \$V_n\$.

Example for \$(4,2,12,52,140)\$
The constant coefficient \$a_0\$ is given by:
$$a_0=\begin{vmatrix}
\color{blue}4&0&0&0&0\\
\color{blue}2&1&1&1&1\\
\color{blue}{12}&2&4&8&16\\
\color{blue}{52}&3&9&27&81\\
\color{blue}{140}&4&16&64&256
\end{vmatrix}/|V_5|=\frac{1152}{288}=4$$
The coefficient \$a_1\$ is given by:
$$a_1=\begin{vmatrix}
1&\color{blue}4&0&0&0\\
1&\color{blue}2&1&1&1\\
1&\color{blue}{12}&4&8&16\\
1&\color{blue}{52}&9&27&81\\
1&\color{blue}{140}&16&64&256
\end{vmatrix}/|V_5|=\frac{-576}{288}=-2$$
And so on.

-4 bytes by replacing m.reduce(...) with m.reduceRight((s,[v],i)=>v*g(0,m.map(([,...r])=>r).filter(_=>i--))-s,0).

@Bubbler Very nice!

Looks like reduce instead of reduceRight also works -- it would invert the sign of even-sized(?) matrices' determinants, but the same inversion happens on both numerator and denominator, cancelling each other. (It gives spurious -0s, but -0==0 anyway.)

@Bubbler Yes, that's fine.

R, 55 52 bytes
-3 bytes thanks to Giuseppe.
round(solve(outer(n<-seq(a=u<-scan())-1,n,"^"))%*%u)

Try it online!
Outputs \$(a_0, a_1,\ldots,)\$ with possible trailing zeros.
Let \$u\$ be the output sequence, and \$X\$ be the \$m\times m\$ matrix such that \$X_{i,j}=i^j\$ (0-indexed), i.e.
\$
X=\begin{pmatrix}
1&0&0&\ldots&0\\
1&1&1&\ldots&1\\
1&2&4&\ldots&2^{m-1}\\
1&3&9&\ldots&3^{m-1}\\
\vdots&\vdots&\vdots&\ddots&\vdots\\
1&m-1&(m-1)^2&\ldots&(m-1)^{m-1}
\end{pmatrix}.
\$
Then in matrix notation, \$u=Xa\$, hence \$a=X^{-1}u\$.
The code implements this: n is the vector (0, 1, ..., m-1) where m is the length of u; this is used to construct X = outer(n, n, "^"). The function solve performs matrix inversion, and the round is there to avoid numerical errors.

52 bytes

alternative 55 bytes

Note you need the a= in the seq statement for the first test case -2.

@Giuseppe Thanks! I really need to remember about seq_along; this isn't the first time you've improved one of my answers with that!

I have this niggling feeling that R has an inbuilt function to do this, but I cannot for the life of me think what it is (and it would probably be disqualified anyway)

APL+WIN, 16 bytes
Index origin = 0
Prompts for input as a vector and outputs coefficients from a0 to an-1 where n is the length of the vector. The order of the polynomial can be obtained by summing the number of coefficients up to the last none zero coefficient:
0⍕n⌹m∘.*m←⍳⍴n←,⎕

Try it online! Courtesy of Dyalog Classic

Nice solution; wouldn't have thought of it! Pretty sure you can golf it down even further to 13 bytes with either of {⍵⌹m∘.*m←⍳⍴⍵} or, closer to your style, n⌹b∘.*b←⍳⍴n←⎕ :)

@AviF.S. Thanks for your suggestion but the first option is not available in APL+WIN and the second the comma before quad is to force a vector if a scalar is entered and the 0⍕ is required to filter out the extremely small errors that can occur and display as nonexistent coefficients

You're totally right about the , being necessary to vectorize! I looked at the other test cases, but didn't notice the domain error with the scalar; you're totally right! About the 0⍕, I'm curious which test cases yielded errors. I haven't been able to reproduce any, but then again TIO is running Dyalog classic and not APL+WIN, could that be the difference?

@AviF.S. Take [10, 20, 90, 280] -> [10, 0, 0, 10] for example without 0⍕ the result would be 10 ¯9.371726267E¯15 1.308691287E¯14 10 as opposed to 10 0 0 10

@AviF.S. if you can golf my approach down using a modern rather than my ancient APL with your own entry by all means do so as I like to see APL being able to compete with golfing languages.

No way am I taking any credit for your clever answer! However, I do want to point out that in Dyalog 10 20 90 280 does indeed yield 10 0 0 10 with only n⌹b∘.*b←⍳⍴n←,⎕ . I'm sure someone else will come along and let us know what the history there is :) For now, since your TIO link is to Dyalog anyway, seems like you can just change the language name to be Dyalog as well and shave off 2 bytes! Try It Online

Why the , if you specify that input has to be a vector?

@Adám Force of  habit. I have written lots of code that requires vector input and had users input a scalar. Rightly or wrongly I always assume TIO will nor recognise vector input if a user simply enters one number as in the first example

OK, but for code golf purposes, you can definitely be strict towards the "user" and require a proper vector as input.

@AviF.S. ⊢⌹∘.*⍨∘⍳∘≢ is the shortest I can make it.

@Adám In the context of APL do all golfers know the difference when trying out our code on TIO

@Graham I'd say yes. If they are even slightly interested in APL/J/K (otherwise, why are they looking at the TIO?) they'll understand that. If you want it completely clear to everyone, you can use ⎕JSON'[1,2,3]' and ⎕JSON '[42]'.

And to think that some people claim that APL isn't legible...

Wolfram Language (Mathematica), 50 49 37 bytes
Returns a polynomial.
Mathematica is so awesome x+1 can be used as a variable in this context. Apart is a weird built-in that, quoting from the docs, seems to attempt to rewrite an expression as a sum of terms with minimal denominators, and also happens to expand polynomials (that are returned in a weird collapsed form by default) into something more sane.
Apart@InterpolatingPolynomial[#,x+1]&

Try it online!
Sledgehammer, 8 bytes
(it will try to deceive you into thinking it's actually 7.5, but it's actually not)
⣕⢤⣏⠛⡪⣊⠵⢼

Explanation: It's Apart@InterpolatingPolynomial[Input[], x+1], but compressed via an awesome Mathematica compressor (it is so awesome that, as far as I understand, it translates Mathematica to an intermediate stack-based language).
Unfortunately, running this is fairly painful.

49 bytes

According to the comments under the question you can also return the polynomial itself rather than its coefficients, which gets you to 38 bytes

@LukasLang Nice. Reading the docs for Expand, I noticed Apart that achieves the same thing for one byte less in this case.

J, 10 bytes
%.^/~@i.@#

Try it online!
Obligatory J answer on a matrix-related challenge. Takes input as a vector of extended integers (otherwise the answer may have small floating-point errors), and gives the polynomial's coefficients in lowest-first order, possibly with some extra zeroes at the end.
How it works
%.^/~@i.@#  NB. Input: a vector V of extended integers.
         #  NB. Length of V
      i.@   NB. Generate 0..(len(V)-1)
  ^/~@      NB. Self outer product by ^(exponentiation)
%.          NB. Matrix-divide V by the matrix above,
            NB.   i.e. solve a linear system of equations

Pari/GP, 38 bytes
a->Vecrev(polinterpolate([0..#a-1],a))

Try it online!

Python 3 + Numpy, 69 bytes
lambda x:polyfit(range(len(x)),x,len(x)-1).round()
from numpy import*

Try it online!
May have leading zeros.

The output doesn't have to be reversed, you can give the coefficient list from highest degree to lowest, so 69 bytes.

Thanks, I edited the answer

I think you can skip the -1: this gives an extra leading 0, but this is allowed. Saves you 2 bytes.

If you use Python 3.8 with PEP572 (assignment expressions), you can save another 2 bytes with l:=len(x) for the first len and replace the second len(x) with just l.

I can't find numpy for pyhon 3.8

@agtoever it doesn't work, it errors

Charcoal, 68 62 bytes
≔⟦¹⟧ηＦＬθ«⊞υ⁰≔÷⁻§θιΣＥυ×κＸιλ∨ΠＥι⊕κ¹ζＵＭυ⁺κ×ζ§ηλ⊞η⁰≔Ｅη⁻§η⊖λ×κιη»Ｉυ

Try it online! Link is to verbose version of previous version of code that excludes trailing zeros, but apparently it isn't necessary to do that, thus saving 6 bytes. Outputs the terms in power order i.e. the constant term is printed first. Explanation:
≔⟦¹⟧η

Start by creating a helper polynomial \$ h(x) = 1 \$.
ＦＬθ«

Loop over the \$ m \$ terms.
⊞υ⁰

Add a \$ 0x^i \$ term to the result polynomial \$ u(x) \$.
≔÷⁻§θιΣＥυ×κＸιλ∨ΠＥι⊕κ¹ζ

Subtract the value of \$ u(i) \$ from the input term and divide that by \$ i! \$.
ＵＭυ⁺κ×ζ§ηλ

Multiply \$ h \$ by that value and add the result to \$ u \$. This doesn't change the values of \$ u(0) ... u(i-1) \$ but the value of \$ u(i) \$ is now the input term.
⊞η⁰≔Ｅη⁻§η⊖λ×κιη

Multiply \$ h \$ by \$ x - i \$.
»Ｉυ

Print the coefficients of \$ u \$, which may include trailing zeros.

Haskell, 77 bytes
h%(a:t)=h-a:a%t
h%_=[h]
f(h:t)=h:foldr(%)[](f$zipWith((/).(-h+))t[1..])
f e=e

Try it online!

APL (Dyalog Unicode), 10 bytesSBCS
⊢⌹∘.*⍨∘⍳∘≢

Try it online!
A port of Graham's APL+WIN solution into a modern APL, which happens to work exactly the same (and have the same byte count) as my own J solution.
How it works
⊢⌹∘.*⍨∘⍳∘≢  ⍝ Input: V, result of a polynomial evaluated at 0..m-1
       ⍳∘≢  ⍝ Generate 0..m-1
  ∘.*⍨∘     ⍝ Self outer product by * (exponentiation)
⊢⌹          ⍝ Matrix divide V by above (solve linear system of equations)

APL smashes the competition. Nice.

05AB1E, 48 47 bytes
g≠iā<DδmUεXøINǝ}Xšεā<sUœε©2.ÆíÆ.±Xε®Nèè}«P}O}ć÷

Sometimes 05AB1E's lack of almost all matrix builtins is pretty annoying.. ;)
Inspired by @Arnauld's JavaScript answer.
Try it online or verify almost all test cases (removed the last two largest ones, since they time out on TIO).
Explanation:
First handle the edge case of a single-element input-list (would cause issues with the « later on in the code):
g                # Get the length of the (implicit) input-list
 ≠i              # And if it is NOT 1, continue with:
                 #  ... (see below)
                 # (implicit else:)
                 #  (output the implicit input-list as implicit output)

Next we'll get the exponentiation matrix of the list [0, input-length):
ā                #  Push a list in the range [1, (implicit) input-length] (without popping)
 <               #  Decrease each value by 1 to make the range [0, input-length)
  Dδ             #  Apply double-vectorized on itself by first duplicating:
    m            #   Take the power of the two values
     U           #  Pop and store this exponentiation matrix in variable `X`

Next we'll create a list of this matrix, with every column one by one replaced with the input-list:
ε     }          #  Map over the input-list that was still on the stack
 X               #   Push the exponentiation matrix from variable `X`
  ø              #   Zip/transpose it; swapping rows/columns
     ǝ           #   Replace the transposed row of the exponentiation matrix
    N            #   at the current map-index
   I             #   with the input-list

We'll prepend the original exponentiation matrix to this list:
Xš               #  Prepend the matrix `X` in front of this list

And we'll calculate the determinant of each inner matrix in this list:
ε              } #  Map over the list of matrices:
 ā               #   Push a list in the range [1, matrix-length] (without popping)
  <              #   Decrease it by 1 to make the range [0, matrix-length)
   sU            #   Swap to get the matrix again, and pop and store it in variable `X`
     œ           #   Get all permutations of the [0, matrix-length) list
      ε          #   Inner map over each permutation:
       ©         #    Store the current permutation in variable `®` (without popping)
        2.Æ      #    Get all 2-element combinations of this permutation
           í     #    Reverse each inner pair
            Æ    #    Reduce it by subtracting
             .±  #    And get it's signum (-1 if a<0; 0 if a==0; 1 if a>0)
       X         #    Push the matrix from variable `X`
        ε        #    Map over each of its rows:
         ®       #     Push the current permutation of variable `®`
          Nè     #     Get the value in the permutation at the current map-index
            è    #     And use that to index into the current matrix-row
        }«       #    After the map of rows: merge it together with the signum list
          P      #    And take the product of this entire list
      }O         #   After the map of permutations: sum all values

Now that we have all determinants of the matrices, we get the default one again to divide all others by it:
ć                #  Extract head: pop and push remainder-list and first item separated
 ÷               #  Integer-divide each value in the remainder-list by this head
                 #  (after which the result is output implicitly)

24 without using matrices. Feels like just brute-forcing polynomials could be even shorter.

23

@Grimmy Ah, it's in reverse order of course. Still, the [4,5,62,733,4160,15869,47290,118997] test case lacks its 0 between the 1s. Same applies to some of the other test cases, like [-3,-1,5,15,29].

SageMath, 63 48 bytes
lambda v:QQ[x].lagrange_polynomial(enumerate(v))

Try it online!
Outputs the polynomial as
$$a_k n^k + \cdots + a_3 n^3 + a_2 n^2 + a_1 n + a_0 $$

I don't understand how to use the "try it online" link you provide

Shalom Uriel. Baruch mechayei hameitim!

@RGS wrong link, fixed :)

@Adám Thanks! Long time away

Aren't there any test cases for which those floats come with errors? Because we are only dealing with integers so you are expected to return the exact coefficients.

@RGS forget what I said - updated to use the Rationals ring that gives integer answers

MATL, 12 bytes
n:qGyz3$ZQYo

The result is given with higher-order coefficients first, and may contain leading zeros.
Try it online! Or verify all test cases
Explanation
Consider input [-3, -1, 5, 15, 29] as an example.
n:q    % Implicit input. Number of elements. Range. Subtract 1, element-wise
       % STACK: [0, 1, 2, 3, 4]
G      % Push input again
       % STACK: [0, 1, 2, 3, 4], [-3, -1, 5, 15, 29]
yz     % Duplicate from below. Number of non-zero elements
       % STACK: [0, 1, 2, 3, 4], [-3, -1, 5, 15, 29], 4
3$ZQ   % Fit polynomial with inputs x, y, degree
       % STACK: [3.7536e-16, -3.1637e-15, 2.0000, -8.8363e-15, -3]
Yo     % Round, element-wise. Implicit display
       % STACK: [0, 0, 2, 0, -3]

Jelly, 14 bytes
J’*þ`æ*-⁸æ×ær0

A monadic Link accepting a list of integers which yields a list of the exponents (floats and/or integers) with the lowest degree on the left of the same length as the input (with trailing zeros if need be).
Try it online!
How?
J’*þ`æ*-⁸æ×ær0 - Link: list of integers, V
J              - range of length (V)
 ’             - decrement (vectorises)
    `          - use as both arguments of:
   þ           -   outer-product using:
  *            -     exponentiation
       -       - minus one
     æ*        - matrix-exponentiation (i.e. inverse)
        ⁸      - chain's left argument, V
         æ×    - matrix-multiplication
           ær0 - round to zero decimal places (vectorises)

authors: Bob Jarvis - Слава Україні


text:
Let's decompress a bit
Given a compressed string \$s\$ made of printable ASCII characters (32 to 126), your task is to print or return the original text by applying this simple decompression algorithm:

Start with \$k=0\$
Look for the first occurrence of the digit \$k\$ in \$s\$ and the sub-string \$s'\$ consisting of the \$2\$ characters preceding it. If the pattern is not found, stop here.
Remove the first occurrence of the digit \$k\$. Replace all other occurrences with \$s'\$.
Increment \$k\$. If it's less than or equal to \$9\$, resume at step \$2\$.

Example 1
Input: bl3a2h1 00001!

The first occurrence of "0" is preceded by "1 ". We remove the first occurrence of "0" and replace all other ones with "1 ", leading to "bl3a2h1 1 1 1 1!".
We do the same thing for "1", with the sub-string "2h". This gives "bl3a2h 2h 2h 2h 2h!".
We do the same thing for "2", with the sub-string "3a". This gives "bl3ah 3ah 3ah 3ah 3ah!".
We do the same thing for "3", with the sub-string "bl". This gives "blah blah blah blah blah!", which is the final output because there are no more digits in \$s\$.

Example 2
Input: Peter Pipe1r pick0ed a 10 of pi0led 1p1rs.
The first step uses the sub-string "ck" and gives:
Peter Pipe1r picked a 1ck of pickled 1p1rs.

The second and final step uses the sub-string "pe" and gives:
Peter Piper picked a peck of pickled peppers.

Rules

The input string is guaranteed to be valid. In particular, there will always be at least 2 characters before the first occurrence of a digit.
However, the input string may not be compressed at all, in which case it must be returned as-is.
The uncompressed text is guaranteed not to contain any digit.
This is code-golf.

Test cases
Input
Short test cases (one per line):
Hello, World!
antidis0establ0hmentarian0m
bl3a2h1 00001!
A AB4 43C22D11E00F0FG
Peter Pipe1r pick0ed a 10 of pi0led 1p1rs.
The 7first 9rul7of Fi6g5h98C3l2ub1 is: You4 do no9talk ab495210. Th7second rul7of 50 is: Y4 do no9talk ab4950.

Longer test case (first paragraph of the Adventures of Sherlock Holmes / A Scandal in Bohemia, from Project Gutenberg):
To Sher6lock Holmes 3she 9i3a8lway3_the_ woman. I h4av9seldom4eard4im mention246 und68ny oth6 name. In4i3eye3sh9eclipses8nd predomin5ate3t7h19whol9of46 sex. It 0wa3not1at49felt8ny emoti28k57o lov9for Iren9Adl6. All emoti2s,8nd1a029particularly, w69abhorrent7o4i3cold, precise, but8dmirably balanced m5d. H9was, I7ak9it,19mos0p6fec0reas25g8nd obs6v5g mach59that19world4a3seen; but,8s8 lov6,49would4av9placed4imself 58 fals9positi2. H9nev6 spok9of19soft6 passi2s, sav9with8 gib9and8 sne6. They w69admirabl9th5g3for19obs6v6--excellen0for draw5g19veil from men'3motives8nd8cti2s. Bu0for19tra5ed reas267o8dmi0such 5trusi235to4i3own delicat9and f5ely8djusted7emp6amen0was7o 5troduc9a distract5g factor which might1row8 doub0up28ll4i3mental results. Gri058 sensitiv95strument, or8 crack 5 29of4i3own4igh-pow6 lenses, would no0b9mor9disturb5g1an8 str2g emoti2 58 natur9such8s4is. And yet169wa3bu029woman7o4im,8nd1a0woman was19lat9Iren9Adl6, of dubious8nd questi2abl9memory.

Output
Hello, World!
antidisestablishmentarianism
blah blah blah blah blah!
A AB ABC ABCD ABCDE ABCDEF ABCDEFG
Peter Piper picked a peck of pickled peppers.
The first rule of Fight Club is: You do not talk about Fight Club. The second rule of Fight Club is: You do not talk about Fight Club.

Longer one:
To Sherlock Holmes she is always _the_ woman. I have seldom heard him mention her under any other name. In his eyes she eclipses and predominates the whole of her sex. It was not that he felt any emotion akin to love for Irene Adler. All emotions, and that one particularly, were abhorrent to his cold, precise, but admirably balanced mind. He was, I take it, the most perfect reasoning and observing machine that the world has seen; but, as a lover, he would have placed himself in a false position. He never spoke of the softer passions, save with a gibe and a sneer. They were admirable things for the observer--excellent for drawing the veil from men's motives and actions. But for the trained reasoner to admit such intrusions into his own delicate and finely adjusted temperament was to introduce a distracting factor which might throw a doubt upon all his mental results. Grit in a sensitive instrument, or a crack in one of his own high-power lenses, would not be more disturbing than a strong emotion in a nature such as his. And yet there was but one woman to him, and that woman was the late Irene Adler, of dubious and questionable memory.

What happens if there are not two characters before a digit? Something like "a0bd000"?

@Xcali This would be an invalid input. So you don't have to support that.

Shouldn't the k = 0  initial condition be k = '0' (the ASCII character for the digit 0), not the integer zero?  I had to look at the examples to figure out what the rules were saying because the type mismatch between integers and strings was confusing.

@PeterCordes k='0' should indeed be clearer for users that are familiar with C-like languages but may be just as confusing for those who are not. I've rephrased a bit to emphasize that we're looking for a digit. Thank you for pointing that out.

There appears to be a non-ASCII character in the compressed Sherlock Holmes sample (unless my browser is acting funky and changing characters on me).  In the middle, find the part that reads "obs6v6—excellen0for". The character after "v6" is appears to be some non-ASCII multibyte dash character.  (I replaced it with a hyphen in my test suite, and it worked OK that way.  But maybe it's supposed to be two hyphens in a row, for an ASCII rendition of a dash?)

@MitchellSpector Good catch! Now fixed.

Can you add the expected output for Peter Pipe1r picked a 1 of piled 1p1rs.?  The majority of the answers are currently substituting the 1, but based on "If the pattern is not found, stop here" it seems to me like the input should be returned unaltered in this case.  If my understanding is correct, you may want to notify the existing answers.

@Jonah In theory, it should be returned unaltered. But because the uncompressed text is guaranteed not to contain any digit, this is actually an invalid input and you don't have to support it.

Python 3, 74 bytes
s=input()
for k in'0123456789':a,*b=s.split(k);s=a+a[-2:].join(b)
print(s)

Try it online!

Retina, 36 bytes
~(`.+
9*
L$`
(?<=(..)$.`.$*)?$.`¶$$1

Try it online! Link includes test cases. Unfortunately Retina does not have a convenient way to access a loop index in its loop construct, so it turns out to be easier to create and evaluate the 179-byte program Retina 0.8.2 would need to solve this. Explanation:
~(`

When the inner program has finished, evaluate the result as a Retina program on the original input.
.+
9*

Replace the input with 9 characters that we can loop over.
L$`

Loop $.` from 0 to 9.
(?<=(..)$.`.$*)?$.`¶$$1

Generate a replacement stage that for each $.` in the input, replaces it with the two characters preceding the first $.`. If the first $.` could not be found then this is the first $.` and it is simply deleted. Expanded for $.` = 0 the code looks like this:
(?<=(..)0.*)?0
$1

J, 49 48 bytes
(i.~{2<\.]rplc[;i.~{2]\[,,)&> ::]/@|.@;;/@Num_j_

Try it online!
({~rplc~^:_~>@]{3({:;}:)\_2|.[)i.&Num_j_<^:3@-.#

Try it online!

"for the time being".. :)

Btw, current count should be 49, you didn't subtract the count for f=.

So I tried to improve on this, and was not able to.  Despite the problem not being a great fit for J, I think this is elegant and as J-like as it could be.  Nice work.  As an arguably slightly more readable version of the leftmost fork, but for no byte saving, I offer up (;/|.Num_j_)

05AB1E, 22 13 12 bytes
9ƒN¡ćDŠ2.£ý«

-1 byte thanks to @CommandMaster.
Try it online or verify all test cases.
Explanation:
9ƒ            # Loop `N` in the range [0,9]:
  N¡          #  Split the string at `N`
              #  (which uses the implicit input in the first iteration)
    ć         #  Extract head; pop and push remainder-list and first item separated
     D        #  Duplicate this head
      Š       #  Triple swap a,b,c to c,a,b on the stack (head, remainder-list, head)
       2.£    #  Pop the head, and only leave its last two characters
          ý   #  Join the remainder-list by this 2-char string as delimiter
           «  #  Append it to the duplicated head
              # (after the loop, the resulting string is output implicitly)

-1 by using DŠ instead of ©s®

@CommandMaster Ah, of course. Thanks! :)

Bash + GNU utilities, 113 112 bytes
s=`rev`
for n in {0..9};{ s=`sed "s/\(.*\)$n/\1/;s/$n/$(sed "s/.*$n\(..\).*/\1/"<<<"$s")/g"<<<"$s"`;}
rev<<<"$s"

Try the test suite online!
Input on stdin, output on stdout.
Here's how the program works:

(1) The input is reversed right-to-left, to accommodate sed's greedy regex matching.
(2) Then the reversed string is decompressed using multiple calls to sed (using the mirror image of OP's decompression
  rules because the string has been reversed).
(3) Finally, the resulting string is reversed again.

Step (2), the mirror-image decompression, is implemented as follows.

For each n from 0 to 9:
(2a) Due to the way bash does its expansions, the inner sed
$(sed "s/.*$n\(..\).*/\1/"<<<"$s")
is evaluated first.  Its value is the
  string consisting of the two characters immediately following the last
  n.  That two-character string replaces the entire string
$(sed "s/.*$n\(..\).*/\1/"<<<"$s")
in its enclosing larger expression, and only then is the larger expression
  evaluated.
(2b) Now, going back to the first sed, the last n in the string is
  deleted.
(2c)  All the earlier occurrences of n in the string are replaced with
  the two-character string evaluated in step 2a.

Python 2, 111 \$\cdots\$ 98 97 bytes
Saved 2 10 bytes thanks to Uriel!!!
Save a byte thanks to Surculose Sputum!!!
def f(s):
 for k in'0123456789':i=s.find(k);s=[s,s[:i]+s[i+1:].replace(k,s[i-2:i])][i>0]
 print s

Try it online!
Borrowed test rig from Uriel.

101 bytes by reversing condition and using OP promise for valid input

@Uriel Interesting, missed that rule that the uncompressed output won't have a digit - thanks! :-)

print s instead of return s saves a byte

@SurculoseSputum Nice one - thanks! :-)

Perl 5 -p, 53 bytes
for$c(0..9){s/(..)\K$c(.*)/"'$2'=~s|$c|\Q$1\E|gr"/ee}

Try it online!

Red, 94 91 bytes
func[s][foreach k"0123456789"[t: copy/part p: any[find s k""]-2 take p replace/all s k t]s]

Try it online!

Charcoal, 35 bytes
Ｆχ«≔⌕θＩιη≔⁺…θη⪫⪪✂θ⊕ηＬθ¹Ｉι✂θ⁻η²η¹θ»θ

Try it online! Link is to verbose version of code. Explanation:
Ｆχ«

Loop over each digit.
≔⌕θＩιη

Find the first digit in the input.
≔⁺…θη⪫⪪✂θ⊕ηＬθ¹Ｉι✂θ⁻η²η¹θ

Replace each digit in its suffix with the last two characters of the prefix, and prepend its prefix.
»θ

After all the digits have been expanded, print the result.

Python 3.8, 93 89 87 bytes
f=lambda s,k=0:(g:=s.find(m:=str(k)))+1and f(s[:g]+s[g+1:].replace(m,s[g-2:g]),k+1)or s

Try it online!

Java (JDK), 121 bytes
s->{int j;for(char i=47;++i<58;s=j>0?s.replaceFirst(""+i,"").replace(""+i,s.substring(j-2,j)):s)j=s.indexOf(i);return s;}

Try it online!
Naive Java implementation.
Credits

-1 byte thanks to Kevin Cruijssen

You can save a byte similar as yesterday: 121 bytes

Haskell, 154 148 bytes
n%c=show n==[c]
n#(a:s@(b:c:_))|n%c=[a,b]|1>0=n#s
_#_=""
f n s|n>9||n#s==[]=s|1>0=f(n+1)$l++r>>= \c->last$[c]:[n#s|n%c]where(l,(_:r))=break(n%)s
f 0

Try it online!
Ungolfed:
digitIsChar :: Int -> Char -> Bool
digitIsChar n c = show n == [c]

getSubStr :: Int -> String -> String
getSubStr n (a:b:c:s)
    | digitIsChar n c = [a,b]
    | otherwise = getSubStr n (b:c:s)
getSubStr _ _ = ""

replaceKey :: Int -> String -> Char -> String
replaceKey n key c
    | digitIsChar n c = key
    | otherwise = [c]

decompress :: Int -> String -> String
decompress n s
    | n >= 10 || null key = s
    | otherwise = decompress (n+1) (lhs ++ replaced)
    where
        key = getSubStr n s
        (lhs, (_:rhs)) = break (digitIsChar n) s
        replaced = rhs >>= replaceKey n key

Edits

-6 bytes (@FrownyFrog)

Raku (raku -p), 66 61 58 56 Bytes
my $a=-1;$_=S/(..)$a/{$0}/.subst(/$a/,$0,:g)until ++$a>9

First attempt. I am sure it can be improved

Wolfram Language (Mathematica), 124 bytes
(r=StringReplace;s=ToString;i=-1;FixedPoint[(i++;r[r[#,s@i->"",1],s@i->StringCases[#,_~~_~~s@i][[1]]~StringTake~2])&,#,10])&

Try it online!

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Is this a legal date? - April Fools' edition
Task
A date can be compactly represented in a 6-character string in the format ddmmyy where the first two characters (dd) represent a day, the 3rd and 4th characters (mm) represent a month and the last two characters (yy) represent a 20XX year. Given a string with 6 characters in [0-9] determine if it represents a valid date. But because today (the day this was posted) is April Fools' day, we will have a twist in the way dates work:
April Fools' dates
We will pretend every 30-day month has 31 days and every 31-day month has 30 days. Furthermore, in years when February is supposed to have 29 days we will pretend February only has 28 days and in all the other years we will pretend February has 29 days; i.e.:

months 01, 03, 05, 07, 08, 10 and 12 have 30 days;
months 04, 06, 09 and 11 have 31 days;
February has 28 days if the year yy is a multiple of 4, otherwise February has 29 days (let us assume we are in the year 20yy);

Input
An integer in [0 - 311299] or a 0-padded string representation of such an integer.
Output
A Truthy value if the input corresponds to a date as per the April Fools' dates, Falsy otherwise.
Test cases
Python naïve implementation for your convenience.
"000511" -> False
"000611" -> False
"290200" -> False
"290204" -> False
"290208" -> False
"310004" -> False
"310005" -> False
"310104" -> False
"310105" -> False
"310204" -> False
"310205" -> False
"310304" -> False
"310305" -> False
"310504" -> False
"310505" -> False
"310704" -> False
"310705" -> False
"310804" -> False
"310805" -> False
"311004" -> False
"311005" -> False
"311204" -> False
"311205" -> False
"311304" -> False
"311305" -> False
"311404" -> False
"311405" -> False
"010694" -> True
"031288" -> True
"050199" -> True
"050298" -> True
"050397" -> True
"060496" -> True
"070595" -> True
"100793" -> True
"150892" -> True
"181189" -> True
"200991" -> True
"251090" -> True
"280200" -> True
"280201" -> True
"280202" -> True
"280203" -> True
"280204" -> True
"280205" -> True
"280206" -> True
"280207" -> True
"280208" -> True
"290201" -> True
"290202" -> True
"290203" -> True
"290205" -> True
"290206" -> True
"290207" -> True
"310404" -> True
"310405" -> True
"310604" -> True
"310605" -> True
"310904" -> True
"310905" -> True
"311104" -> True
"311105" -> True

This challenge was inspired by this one.

This is code-golf so shortest submission in bytes, wins! If you liked this challenge, consider upvoting it! If you dislike this challenge, please give me your feedback. Happy golfing!

This will probably also discourage using built-ins

@RedwolfPrograms do you mean that as a plain statement, a pro of this challenge or a con?

A definite pro. Should encourage a lot of interesting answers.

Should include a test case where the day is 0.

Are we allowed to take the input as day/month/year?

Is a list of six integers [digits] as input acceptable?

@S.S.Anne do you mean as a string formatted like dd/mm/yy? If that is what you mean, sorry but no. The idea is that the input should be an integer and formatting it like you said would be a very weird way of accepting an integer as input.

@JonathanAllan yes, that is reasonable as input.

I mean like three integers, d, m, and y corresponding to day, month, and year.

@S.S.Anne it really bothers me to say no again, but same argument applies; my argument holds to preserve the association between my post and the one that inspired it

Why limit input to 311299?

@ThomasAyoub From that integer onward, there is no other valid date. Also, I wanted to keep my challenge similar to the challenge that inspired mine.

Shame you’re limiting the dates to the 21st century – would have been slightly more challenging if the input were DDMMYYYY instead.

@JanusBahsJacquet I understand but I didn't want to make input strings too large :) but will I be seeing a submission of yours either way?

@RGS Absolutely not. I enjoy viewing the clever puzzles and solutions on here, but I so do not have what it takes to actually write them. :-)

JavaScript (ES6),  62 60  59 bytes
Takes input as a 0-padded string. Returns \$0\$ for false or a positive integer for true.
s=>(m=s[2]+s[3])<13&31-(m^2?~m%9%2:s%4?1:2)>(s/=1e4)&&~~s*m

Try it online!
or Check all possible outputs against an ungolfed implementation
Commented
s =>                // s = input string
  (m = s[2] + s[3]) // m = month, as a string
  < 13 &            // make sure that m is less than 13
  31 - (            // compute the upper bound for this month:
    m ^ 2 ?         //   if the month is not February:
      ~m % 9 % 2    //     use either 31 or 32
    :               //   else:
      s % 4 ?       //     if this is not a leap year:
        1           //       use 30
      :             //     else:
        2           //       use 29
  )                 // end of upper bound computation
  > (s /= 1e4)      // make sure that it's greater than the day
  && ~~s * m        // and finally make sure that day * month is not zero

Simply brilliant. I especially love the ~m%9%2. For my own solution I tried regular expressions but soon realised I wouldn't get it anywhere near 100 chars, let alone your sixty-something...

@Christallkeks Thank you. :-) Note that a direct port of Neil's 100% regex answer would be 94 bytes.

longer than hardcode

Python 3.8, 77 67 65 62 61 bytes
-2 bytes thanks to @Bubbler
-3 bytes thanks to @xnor
-1 byte thanks to @PoonLevi's mod by float trick
lambda s:13>(m:=s//100%100)>0<s//1e4<30-[s%4<1,m%-1.76][m!=2]

Try it online!
Input: Date as an integer.
Output: True or False if the date is valid or invalid respectively.
How:
Overall approach: return 13 > m > 0 < d < max_date_of_month where d, m are date and month respectively.
The max date of month m is calculated as:

If m==2: 30-(s%4<1) evaluates to 29 if the year is divisible by 4, and 30 otherwise. Since the year is the last 2 digits of the input, input mod 4 is the same as the year mod 4.
If m!=2: 30-m%-1.76 evaluates to 31.xxx or 30.xxx

Old solution
Python 3.8, 86 83 71 bytes
lambda s:13>(m:=s//100%100)>0<s//1e4<29+[s%4>0,([3,2]*7)[m+m//8]][m!=2]

Try it online!
Input: Date as an integer.
Output: True or False if the date is valid or invalid respectively.
How: ([3,2]*7)[m+m//8] first creates a list storing the max_date + 1 for each month (except February) by repeating [3, 2] a few times. If the month is August or after, the pattern switches, so we add 1 to the index.

-2 bytes.

29+[s%4>0,2+m%-7%2][m!=2] saves 3 bytes

@xnor Very nice way to get rid of those brackets!

-1: 30-[s%4<1,m%-1.76][m!=2]. The divisor must be somewhere between -7/4 and -9/5 (exclusive) for it to switch between 7 and 8.

@PoonLevi Thanks! So close to shaving off a character, with -1.8!

Retina 0.8.2, 96 93 91 81 bytes
^(?!(..)?00|..[2-9]|..1[3-9]|31(?!0[469]|11)|3002|2902([02468][048]|[13579][26]))

Try it online! Link includes test cases. Edit: Saved 3 bytes thanks to @mathjunkie. Saved 2 bytes thanks to @ThomasAyoub. Saved a further 10 bytes thanks to @ThomasAyoub for noting that the day cannot be greater than 31. Explanation:
^

Match only at the beginning of the string.
(?!...)

Invert the condition so we're now looking for invalid dates. The invalidity conditions (separated by | in the original code) are as follows:
(..)?00

Either the day or month are zero.
..[2-9]

The month is 20 or higher.
..1[3-9]

The month is between 13 and 19.
31(?!0[469]|11)

The day is 31 and the month is not 4, 6, 9 or 11.
3002

February 30th.
2902([02468][048]|[13579][26])

February 29th on a leap year.

93 bytes: Try it online!

(?!04|06|09|11) could be (?!0[469]|11) to save 2 bytes

Since input is limited to 311299, you can save bytes again removing [4-9]|

same goes for (3|..)[2-9]

@ThomasAyoub Ah, I hadn't realised that. I guess it's only the day to which that restriction applies, right?

Yes, since the month input could be [00, 99].

Jelly, 28 bytes
Ɠ⁽¿ÇB31_+2¦4ḍ~ƊR;€"J$ḅ³Fċ:³$

A full program accepting a single integer from STDIN which prints a 1 or 0 to STDOUT.
Try it online! Or see the test-suite.
How?
Ɠ⁽¿ÇB31_+2¦4ḍ~ƊR;€"J$ḅ³Fċ:³$ - Main Link
Ɠ                            - set the chain's left argument, N, to evaluated STDIN
 ⁽¿Ç                         - base 250 integer = 3765
    B                        - to binary     = [1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1]
     31_                     - 31 minus      = [30,30,30,31,30,31,30,30,31,30,31,30]
              Ɗ              - last three links as a monad - f(N):
           4ḍ                -   four divides (N)?
             ~               -   bitwise NOT (0 becomes -1 and 1 becomes -2)
          ¦                  - sparse application...
         2                   - ...to indices: [2]
        +                    - ...action: add
                               i.e. x=9 or 8: [30,2x,30,31,30,31,30,30,31,30,31,30]
               R             - range (vectorises) = [[1,2,...30],...]
                    $        - last two links as a monad - f(that):
                   J         -   range of length = [1,2,...,12]
                  "          -   zip with:
                ;€           -     concatenate each -> [[[1,1],[2,1],...,[30,1]],...]
                     ḅ       - convert from base (vectroises):
                      ³      -   100               -> [[101,201,...,3001],...]
                       F     - flatten
                        ċ    - count occurrences of:
                           $ -   last two links as a monad - f(N):
                         :   -     (N) integer divide:
                          ³  -       100

05AB1E, 34 bytes
2ô¨Ðθ©13‹sĀPr`2QiI4Ö≠ë®7(%ÉÌ}29+‹P

Just an initial answer. Can definitely be golfed by a few bytes.
Inspired by both @Arnauld's JavaScript answer and @SurculoseSputum's Python answer, so make sure to upvote them!!
Try it online or verify all test cases.
Explanation:
2ô             # Split the (implicit) input in parts of size 2: ddmmyy → [dd,mm,yy]
  ¨            # Remove the last item (the year): [dd,mm]
   Ð           # Triplicate this
               #  STACK: [[dd,mm],[dd,mm],[dd,mm]]
    θ          # Pop and push the last item
               #  STACK: [[dd,mm],[dd,mm],mm]
     ©         # Store the month in variable `®` (without popping)
      13‹      # Check that it's smaller than 13
               #  STACK: [[dd,mm],[dd,mm],mm<13]
   s           # Swap to get the triplicate value again
               #  STACK: [[dd,mm],mm<13,[dd,mm]]
    ĀP         # Check for both that they're not 0
               #  STACK: [[dd,mm],mm<13,(dd!=0)*(mm!=0)]
   r           # Reverse the stack
               #  STACK: [(dd>0)*(mm>0),mm<13,[dd,mm]]
    `          # Push both values separately to the stack
               #  STACK: [(dd>0)*(mm>0),mm<13,dd,mm]
     2Qi       # If the month is 2:
        I4Ö≠   #  Check that the input is NOT divisible by 4
               #   STACK: [(dd>0)*(mm>0),mm<13,dd,input%4>0]
       ë       # Else:
        ®7(%É  #  Check that the month (from variable `®`) modulo -7 is odd
               #   STACK: [(dd>0)*(mm>0),mm<13,dd,mm%-7%2>0]
             Ì #  And increase this by 2
               #   STACK: [(dd>0)*(mm>0),mm<13,dd,(mm%-7%2>0)+2]
       }29+    # After the if-else: add 29 to this value
               #  STACK: [(dd>0)*(mm>0),mm<13,dd,(input%4>0)+29] if mm == 2
               #  STACK: [(dd>0)*(mm>0),mm<13,dd,(mm%-7%2>0)+31] if mm != 2
           ‹   # Check that the dd is smaller than this value
               #  STACK: [(dd>0)*(mm>0),mm<13,dd<(input%4>0)+29] if mm == 2
               #  STACK: [(dd>0)*(mm>0),mm<13,dd<(mm%-7%2>0)+31] if mm != 2
            P  # And take the product of the stack to check if all are truthy
               #  STACK: [(dd>0)*(mm>0)*(mm<13)*(dd<(input%4>0)+29)] if mm == 2
               #  STACK: [(dd>0)*(mm>0)*(mm<13)*(dd<(mm%-7%2>0)+31)] if mm != 2
               # (after which this is output implicitly as result)

Python 3.8, 136 \$\cdots\$93 78 bytes
Takes the date as an integer and returns Truthy or Falsy.
lambda s,h=100:13>(m:=s//h%h)>0<s//h//h<(30-(s%4<1),31+(m in(4,6,9,11)))[m!=2]

Try it online!

Perl 5 Mbigint -p, 76 75 bytes
/(..)(..)/;$_=$1>0&&$1<substr 113130-($_%4?0:1).31323132313132313231,2*$2,2

Try it online!

C (gcc), 95 \$\cdots\$ 71 65 bytes
Saved 3 4 bytes thanks to ceilingcat!!!
Saved a whopping 15 bytes thanks to Olivier Grégoire!!!
Saved 6 bytes thanks to Arnauld!!!
Takes the date as an integer and returns \$0\$ or \$1\$.
m;f(s){m=s/100%100;s=m<13&(m-2?~m%9%2-1:s%4<1)+(s/=1e4)<30&&s*m;}

Try it online!

Replace (m-4&&m-6&&m-9&&m-11)-2 with ~m%9%2-1.

@OlivierGrégoire Fantastic - thanks! :-)

65 bytes, I think -- but this should be double-checked.

@Arnauld Looks good. Very nice - thanks! :-)

Java (JDK), 74 bytes
n->{int m=n/100%100;return(m==2?n%4<1?2:1:~m%9%2)<31-(n/=1e4)&13>m&n*m>0;}

Try it online!
Credits

-1 byte thanks to ceilingcat
-3 bytes thanks to Kevin Cruijssen

74 bytes

Bash + GNU utilities, 86 85 83 82 bytes
a=0424343443434;fold -2|xargs|(read d m y;date -d${a:${m#0}:1}/$d/0$[!(${y#0}%4)])

Try it online!
Input is on stdin.
Output is the exit code: 0 for truthy, 1 for falsey.

I thought I'd do a solution based on a date built-in, since I don't think anyone else has done that yet.
This program takes the input string \$x\$ and computes another string \$y\$ with the property that \$x\$ is a valid "April Fools date" iff \$y\$ is a valid normal date.  So GNU date applied to \$y\$ will give the desired answer.

Swift 279 277 272 264 262 257 256 254 252 bytes
func v(s:String)->Int{let m=Int(s.suffix(4).prefix(2))!;switch m{case 0,13...:return 0;case _:switch Int(s.prefix(2))!{case 1...28:return 1;case 29,30:return Int(s.suffix(4))!%4==0&&m==2 ?0:1;case 31:return[4,6,9,11].contains(m) ?1:0;case _:return 0}}}

My first and most probably failed attempt at code golf. Please be nice!
Here is a more readable version:
func validDate(s :String) -> Int {
    let mm = Int(s.suffix(4).prefix(2))!
    switch mm {
    case 0,13...:
        return 0
    case _:
    switch Int(s.prefix(2))! {
    case 1...28:
        return 1
    case 29, 30:
        return Int(s.suffix(4))! % 4 == 0 && mm == 2 ? 0: 1
    case 31:
        return[4,6,9,11].contains(mm) ? 1:0
    case _:
        return 0
    }
  }
}

Any constructive feedback is welcome, negative feedback not so welcome.
Link to project with swift tests on
Github
Updated solution
to make it work for console input
288 251 249 bytes
let s=readLine()!;let m=Int(s.suffix(4).prefix(2))!;let d=Int(s.prefix(2))!;if m<0||m>13{print(0)};if(1...28).contains(d){print(1)}else if d==29||d==30{print(!(Int(s.suffix(4))!%4==0&&m==2))}else if d==31{print([4,6,9,11].contains(m))}else{print(0)}

Try it online

Hey there, welcome! Can you provide any sort of try it online link ao we can run your answer? :)

Hi, I'm not sure how they work. Here is a link to my repo for this challenge which contains all the pythons tests provided converted to swift. Downloading it, installing swift and running swift test in the directory should run the tests on Mac or Linux. https://github.com/johannwerner/AprilFoolsGolfChallenge

The way they work is simple. You go to this TIO Swift link, paste your code and tests, and then use the hyperlink button on top of the page to generate a link that points to the code you just pasted. For example, here is a link to a python program that prints "hey there, user1898829".

JavaScript (Node.js), 53 bytes
s=>`2${s&3&&1}2323223232`[s[2]+s[3]-1]>s/1e4-29&s>1e4

Try it online!

Raku (raku -n file-with-one-line) 118 Bytes
/(..)(.)(.)(..)/;$!=10*$1+$2;die if 12 <$!||1>$!;$!=7.5-abs(7.5-$!);$!=($!+|4)+^1 if $!!= 2;Date.new($3%4??0!!1,$!,$0)

Result as exit code (0: ok, 1: error)

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
How happy is this emoticon?
In this challenge, submissions will be programs or function which, when given an emoticon such as :-), :(, or :D, will rate their happiness from 0 to 3.
An emoticon will be one of the following:

:(: 0
:|: 1
:): 2
:D: 3

Emoticons may also have noses (a - after the :).
Test cases:
:(  -> 0
:-| -> 1
:D  -> 3
:-) -> 2
:|  -> 1

This is a code golf challenge, shortest answer per language wins.

What about (:?

@anatolyg I figured having to handle reversed strings as well would make the challenge too difficult

@anatolyg Don't forget ☺and ☻ either

@anatolyg What about D:?

or :-{D (someone with a mustache) or :-{D> (someone with a mustache and goatee) or :-{D} (someone with a mustache and beard).  For a full list see http://marshall.freeshell.org/smileys.html

It would be cool to see a solution that looked like a smiley ...

Only 8 possible inputs?

@Iamkindofalanguagedev Yes

Python 3, 26 bytes
lambda s:ord(s[-1])*2%19%4

Try it online!
$$ f(x) = (2x \bmod 19) \bmod 4 $$

You can save 1 character by using the formula in the Ruby solution below : https://codegolf.stackexchange.com/a/202907/61997

@mr.mams, then it will be absolutely identical to another python answer

Ruby, 20 bytes
s[-1].ord will give us the codepoint of the last character in the string, which we can then plug into this formula:
$$(160 \bmod c) \bmod 7 $$
->s{160%s[-1].ord%7}

Try it online!

Nice find on the formula! I tried brute-forcing for expressions in Python no longer than 160%n%7 (7 bytes) and got only that with nothing shorter. Here are the 8-byte ones: TIO

APL (Dyalog), 11 8 bytes
3 bytes saved thanks to @Bubbler!
⊃'(|)'⍳⌽

Try it online!
       ⌽  reverse the string
⊃         take the last (now first) byte
 '(|)'⍳    index inside '(|)' (if not found ('D') returns the length (3))

8 bytes

@Bubbler Unfortunately, it says the link can’t be decode; mind repasting?

@AviF.S. Here it is. Weird though, because I can open it fine on my PC.

Very odd! Still doesn’t work for me but I’m on the mobile app (iPhone). Though I couldn’t find anything on Meta re: bugs with TIO and mobile... Suppose I’ll just hold my excitement ‘til I can check on my computer :)

Python 3, 28 27 bytes
lambda e:"(|)D".find(e[-1])

Try it online!
Because we don't care about the eyes/nose, we can just look at the mouth (the last character) and find its index in a string with all the mouths, ordered from saddest to happiest :) Thanks @Surculose Sputum!

find works the same as index and saves 1 byte

Python 3, 25 bytes
lambda s:160%ord(s[-1])%7

Try it online!
Math taken from @dingledooper

C (gcc),  37  33 bytes
Saved 4 bytes on both versions thanks to @ceilingcat and @dingledooper
I overlooked the rule about the optional nose, so this is not as effective as expected.
f(char*s){s=390%~-s[*++s%9<1]&3;}

Try it online!
How?
Among the characters that we have to deal with, the hyphen is the only one whose ASCII code is congruent to \$0\$ modulo \$9\$. We use this property to decide whether we need to work on the second or the third character.
Given the ASCII code \$n\$ of the relevant smiley character, we apply the following formula to get the happiness:
$$h(n)=(390\bmod (n-1))\bmod 4$$

C (gcc),  36  32 bytes
Using Uriel's formula is 1 byte shorter.
f(char*s){s=s[*++s%9<1]*2%19&3;}

Try it online!

-1 byte for both, by recursively searching for the end of the string.

Excel, 25 bytes
=FIND(RIGHT(A1),"(|)D")-1

Jelly,  8  7 bytes
⁽$9,4ḥ’

A monadic Link accepting a list of characters which yields an integer in \$[0,3]\$.
Try it online!
How?
⁽$9,4ḥ’ - Link: list of characters, A
⁽$9     - base 250 literal = 10058
   ,4   - pair with four
     ḥ  - Jelly hash A using 10058 as a salt and [1,2,3,4] as the domain
      ’ - decrement

Previous 8 byter:
“|)D”iⱮS

Try it online!
How?
“|)D”iⱮS - Link: list of characters, A             e.g. ":-)"     OR  ":-("
      Ɱ  - map across c in A with:
     i   -   first index of c in (or 0 if not found):
“|)D”    -     list of characters = "|)D"               [0,0,2]       [0,0,0]
       S - sum                                          2             0

Bash + GNU utilities, 17 bytes
tr '(|)D:-' 0-3\

Try it online!
Note: There's a space character after the backslash.
Input on stdin, output on stdout.
The challenge doesn't specify the format of the output.  Depending on the input, this program may print the output in either %2d or %3d format (that is, with one or two spaces before the 0, 1, 2, or 3).
If that's not acceptable, then
tr -s '(|)D:-' 0-3\
(20 bytes) always prints the digit in %2d format.  (There's a space after the backslash here too.)
Or
tr '(|)D:-' 0-4|tr -d 4
(23 bytes) prints just the digit (with no spaces).

Raku, 19 bytes
{TR:d/(|)D:-/0123/}

Try it online!

If raku -p is acceptable, you could reduce to tr:d/(|)D:-/0123/

Mornington Crescent, 1820 bytes
Try it online!
A port of @dingledooper's fantastic Ruby answer, which just so happens to work seamlessly in Mornington Crescent because of a convenient 7 in it. Props to them!
Take Northern Line to Leicester Square
Take Northern Line to Leicester Square
Take Piccadilly Line to Turnpike Lane
Take Piccadilly Line to Turnpike Lane
Take Piccadilly Line to Leicester Square
Take Northern Line to Leicester Square
Take Northern Line to Charing Cross
Take Northern Line to Charing Cross
Take Bakerloo Line to Baker Street
Take Bakerloo Line to Paddington
Take Bakerloo Line to Charing Cross
Take Bakerloo Line to Charing Cross
Take Northern Line to Moorgate
Take Circle Line to Moorgate
Take Metropolitan Line to Chalfont & Latimer
Take Metropolitan Line to King's Cross St. Pancras
Take Victoria Line to Seven Sisters
Take Victoria Line to Victoria
Take Circle Line to Victoria
Take Circle Line to Bank
Take Circle Line to Hammersmith
Take Circle Line to Cannon Street
Take Circle Line to Hammersmith
Take Circle Line to Cannon Street
Take Circle Line to Bank
Take Circle Line to Hammersmith
Take District Line to Upminster
Take District Line to Hammersmith
Take District Line to Upminster
Take District Line to Victoria
Take Circle Line to Victoria
Take Circle Line to Aldgate
Take Circle Line to Aldgate
Take Metropolitan Line to Chalfont & Latimer
Take Metropolitan Line to Preston Road
Take Metropolitan Line to Baker Street
Take Metropolitan Line to Preston Road
Take Metropolitan Line to Pinner
Take Metropolitan Line to Preston Road
Take Metropolitan Line to King's Cross St. Pancras
Take Victoria Line to Seven Sisters
Take Victoria Line to King's Cross St. Pancras
Take Circle Line to King's Cross St. Pancras
Take Metropolitan Line to Pinner
Take Metropolitan Line to Preston Road
Take Metropolitan Line to Pinner
Take Metropolitan Line to Preston Road
Take Metropolitan Line to King's Cross St. Pancras
Take Circle Line to King's Cross St. Pancras
Take Northern Line to Mornington Crescent

The only major thing I feel I need to point out is how I got 160 in the program. To do this, I took the first letter of Paddington, which gives an ASCII value of 80 when run through Charing Cross, then multiplied it by 2 in Chalfont & Latimer to get 160. Subsequently, the program computes 160 % (ASCII of last character) % 7 via Preston Road, the formula found by @dingledooper.

Wait, Turnpike Lane exists?

Retina 0.8.2, 16 12 bytes
T`-:(|)D`__d

Try it online!
T`

Enter transliteration mode
(|)D`d

Replace the mouth character with the corresponding digit (0 to 3)
-:`__

Remove each of - and : from the string.
Implicitly output the result, which will be a single digit.

MATL, 9 bytes
'|)D'jmfs

Try it online!
Explanation
'|)D' % Push this string
j     % Read input as unevaluated string
m     % ismember: true for chars of the first string that are present in the second
f     % find: (1-based) indices of true entries. The result will have length 0 or 1
s     % sum. This is needed to transform an empty array into 0
      % Implicitly display

Keg, -hr, 18 bytes
?^⑵¦P0|\1|R2|\¦3™

Try it online!
The same switch statement format, but with a different character checking criteria.

05AB1E, 8 bytes
θÇx19%4%

Try it online!
Explanation
I used Uriel's formula.
θ        # Get mouth (last char)
 Ç       # ASCII value
  x      # Multiply by 2
   19%   # Modulo 19
      4% # Modulo 4

If you don't want to have the answer wrapped into a list, you could swap the θÇ to Çθ. (PS: x actually pushes 2n without popping, but there is also · which pops and pushes 2n. Doesn't matter here, but figured I'd let you know in case you're using it in future answers.) Here also another 8-bytes alternative based on dingledooper's Ruby answer: ƵxIÇθ%7%. Try it online.

@Kevin Cruijssen I knew that x did that, just that I looked for * 2 and not 2 * in info.txt. I also made a solution based on dingledooper's formula, but it was 9 bytes.

Perl 5 -p, 24 bytes
s/.*(.)/ord($1)*2%19%4/e

Try it online!
Steals the math from @Uriel's Python answer

Using the method in this answer is slightly shorter (abusing -F to get the last char): Try it online!

Even shorter using @JoKing's TR approach: Try it online!

Charcoal, 10 bytes
Ｉ⌕(|)D§Ｓ±¹

Try it online! Link is to verbose version of code. Explanation:
       Ｓ    Input string
      §     Cyclically indexed by
         ¹  Literal 1
        ±   Negated
 ⌕          Find index in
  (|)D      Literal string of mouths
Ｉ           Cast to string
            Implicitly print

Io, 31 bytes
Io's strings are made of integers, so character-converting is unneccecary. Although Io doesn't allow us to index the last item of a sequence using last()...
method(x,160%x reverse at(0)%7)

Try it online!

naz, 120 bytes
8a5m2x1v1a2x2v4a2x3v9a9a5a2x4v1x1f2r3x3v1e2f0x1x2f3x1v3e3x2v5e3x4v6e4f0x1x3f0m1o0x1x4f0m1a1o0x1x5f0m2a1o0x1x6f0m3a1o0x1f

Explanation (with 0x commands removed)
8a5m2x1v                 # Set variable 1 equal to 40 ("(")
1a2x2v                   # Set variable 2 equal to 41 (")")
4a2x3v                   # Set variable 3 equal to 45 ("-")
9a9a5a2x4v               # Set variable 4 equal to 68 ("D")
1x1f                     # Function 1
    2r                   # Read the second byte in the input string, removing it
      3x3v1e             # Jump back to the start of the function if it equals variable 3
            2f           # Otherwise, jump to function 2
1x2f                     # Function 2
    3x1v3e               # Jump to function 3 if the register equals variable 1
          3x2v5e         # Jump to function 5 if the register equals variable 2
                3x4v6e   # Jump to function 6 if the register equals variable 4
                      4f # Otherwise, jump to function 4
1x3f                     # Function 3
    0m1o                 # Output 0
1x4f                     # Function 4
    0m1a1o               # Output 1
1x5f                     # Function 5
    0m2a1o               # Output 2
1x6f                     # Function 6
    0m3a1o               # Output 3
1f                       # Call function 1

Pyth, 8 bytes
x"(|)D"e

Try it online!
Exalanation
x"(|)D"e
          : Implicit evaluated input
       e  : Last element of input
 "(|)D"   : The string "(|)D"
x         : First occurrence of the last element of input in "(|)D"

Red, 32 bytes
func[s][select"(0|1)2D3"last s]

Try it online!

C# (Visual C# Interactive Compiler), 17 14 bytes
Turns out Ranges finally started to actually exist and work! Thanks to an anonymous user for pointing this out (by proposing an edit, but anonymous users cannot comment...)

s=>160%s[^1]%7

Try it online!

batch, 109 bytes 99 bytes
@For %%G in ("(=0",")=2","D=3","|=1")Do @Set %%G
@Set "T=%~1"
@<Nul Call Call Set/P"=%%%T:~-1%%%"

106 Bytes when lines are terminated by LF instead of CR LF, using Shift+CTRL+J

the space in front of do is optional

JavaScript, 35 32 29 bytes
I based the logic off of the Java solution submitted April 2 and edited April 8, by branboyer. I suppose it would be referred to as a port of their answer, but I don’t know exactly how that’s supposed to be marked.
a=>"(|)D".indexOf(a[2]||a[1])

An anonymous function, taking a string and returning an integer. Please help me shorten it further, I’m new to golfing code. Just the code, without the way of inputting (no idea how to get input in try it online) is at this Try it online link

Welcome to the site! As this is an anonymous function, you can remove the b= from the byte count. You can just link to a third party test area, such as Try It Online! if you don't want to include the HTML/full script, which is definitely not required in your answer. As for tips on how to shorten it, I'd recommend you check out the Tips for golfing in Javascript and look at other JS answers around the site.

You can also drop the ;

You don't need to add any HTML for javascript answers. If you want to shorten it, you can replace a[a.length-1] with a[2]||a[1]

Here is a TryItOnline link of your answer, which verifies all test cases.

Thanks for the Try it online link, @dingledooper! I will edit that in instead of my link.

International Phonetic Esoteric Language, 11 bytes
iʁ2f{J}ⱱ4ⱱo

Based on Uriel's formula.
iʁ2f{J}ⱱ4ⱱo
iʁ          (split the face into it's ord values)
  2f        (mouth * 2)
    {J}ⱱ    (mod 19) (base 26)
        4ⱱ  (mod 4)
          o (print)

sed, 20 bytes
y/(|)D/0123/;s/:-*//

Pretty self explanatory. Replaces the the "mouth" characters with numbers using the y/// transform command and then strips off the eyes and the nose if they exist.
Try it online!
This is one byte longer, but perhaps it gets bonus points for having an emoticon in the code itself? :-\
y/(|)D/0123/;s/:-\?//

The shorter solution (16 bytes)
y/(|)D:-/0123  /

also works, but adds extra whitespace to each line of output. It also has two emoticons D: and :-/. :)
Try it online!

Japt, 9 bytes
"(|)D"bUÌ

Try it

Erlang (escript), 32 bytes
The verbosity offseted the bytecount.
h(I)->160rem lists:last(I)rem 7.

Try it online!

W, 7 bytes
☻M:ù·±♥

Uncompressed:
(|)D"azx

Explanation
         % Implicit quote
(|)D"    % The string "(|)D"
     az  % The last item of the input
       x % Where is ^ in the above string?

J, 10 9 bytes
-1 byte thanks to FrownyFrog ang Bubbler
'(|)'i.{:

Try it online!

You can drop D as bubbler pointed out.

@FrownyFrog Yes, indeed. Thanks!

GolfScript, 11 bytes
)3?11%2/(p;

I'm convinced my method is the smallest possible, but this isn't the best possible one - just one of the earliest low-value ones.
)3?11%2/(p;
)           #Pop the last element of the string (as ascii value)
 3?         #Cube the number
   11%      #Modulo 11
      2/    #Divide by 2 (round down)
        (   #Decrement by one (gotta be 0 1 2 3, not 1 2 3 4)
         p; #Print the value we want, and shunt the rest of the stack

I used the following TIO to search for answers, and 11 popped up quite early. I also tried squares and higher powers, but they weren't as clean and short.
Try it online!
Every case!

Raku -p  23 Bytes -> 19 Bytes
$_=(4-.ords[*-1]*2%5)%4

$_=160%.ords[*-1]%7      #(with @dingledooper's formula)

17-byte port of the Perl 5 -p solution: tr:d/(|)D:-/0..3/

PowerShell, 16 bytes
2*$args[-1]%19%4

Try it online!
PowerShell port of the modulo formula going around. Takes input via splatting

Wolfram Language (Mathematica), 38 bytes
Mod[2Last@ToCharacterCode@#,19]~Mod~4&

Try it online!
This borrows Uriel's formula, which happens to be the same length as dingledooper's, but I can't help but wonder if another formula would be shorter. I will investigate.
For comparison, here's the string indexing solution (51 bytes):
("(|)D"~StringPosition~Last@Characters@#)[[1, 1]]-1&

Try it online!

MAWP, 27 bytes
|2W!!92W1MP92W1MWA!!4P4WA:.

Try it!

JavaScript, 2335
(・・? Did somebody say emoticons?

a =
// The function:
(w)=>{(笑)=(w);ﾟωﾟﾉ= /｀ｍ´）ﾉ ~┻━┻   //*´∇｀*/ ['_']; o=(ﾟｰﾟ)  =_=3; c=(ﾟΘﾟ) =(ﾟｰﾟ)-(ﾟｰﾟ); (ﾟДﾟ) =(ﾟΘﾟ)= (o^_^o)/ (o^_^o);(ﾟДﾟ)={ﾟΘﾟ: '_' ,ﾟωﾟﾉ : ((ﾟωﾟﾉ==3) +'_') [ﾟΘﾟ] ,ﾟｰﾟﾉ :(ﾟωﾟﾉ+ '_')[o^_^o -(ﾟΘﾟ)] ,ﾟДﾟﾉ:((ﾟｰﾟ==3) +'_')[ﾟｰﾟ] }; (ﾟДﾟ) [ﾟΘﾟ] =((ﾟωﾟﾉ==3) +'_') [c^_^o];(ﾟДﾟ) ['c'] = ((ﾟДﾟ)+'_') [ (ﾟｰﾟ)+(ﾟｰﾟ)-(ﾟΘﾟ) ];(ﾟДﾟ) ['o'] = ((ﾟДﾟ)+'_') [ﾟΘﾟ];(ﾟoﾟ)=(ﾟДﾟ) ['c']+(ﾟДﾟ) ['o']+(ﾟωﾟﾉ +'_')[ﾟΘﾟ]+ ((ﾟωﾟﾉ==3) +'_') [ﾟｰﾟ] + ((ﾟДﾟ) +'_') [(ﾟｰﾟ)+(ﾟｰﾟ)]+ ((ﾟｰﾟ==3) +'_') [ﾟΘﾟ]+((ﾟｰﾟ==3) +'_') [(ﾟｰﾟ) - (ﾟΘﾟ)]+(ﾟДﾟ) ['c']+((ﾟДﾟ)+'_') [(ﾟｰﾟ)+(ﾟｰﾟ)]+ (ﾟДﾟ) ['o']+((ﾟｰﾟ==3) +'_') [ﾟΘﾟ];(ﾟДﾟ) ['_'] =(o^_^o) [ﾟoﾟ] [ﾟoﾟ];(ﾟεﾟ)=((ﾟｰﾟ==3) +'_') [ﾟΘﾟ]+ (ﾟДﾟ) .ﾟДﾟﾉ+((ﾟДﾟ)+'_') [(ﾟｰﾟ) + (ﾟｰﾟ)]+((ﾟｰﾟ==3) +'_') [o^_^o -ﾟΘﾟ]+((ﾟｰﾟ==3) +'_') [ﾟΘﾟ]+ (ﾟωﾟﾉ +'_') [ﾟΘﾟ]; (ﾟｰﾟ)+=(ﾟΘﾟ); (ﾟДﾟ)[ﾟεﾟ]='\\'; (ﾟДﾟ).ﾟΘﾟﾉ=(ﾟДﾟ+ ﾟｰﾟ)[o^_^o -(ﾟΘﾟ)];(oﾟｰﾟo)=(ﾟωﾟﾉ +'_')[c^_^o];(ﾟДﾟ) [ﾟoﾟ]='\"';(ﾟДﾟ) ['_'] ( (ﾟДﾟ) ['_'] (ﾟεﾟ+(ﾟДﾟ)[ﾟoﾟ]+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (ﾟｰﾟ)+ (ﾟΘﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (ﾟｰﾟ)+ ((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (ﾟΘﾟ))+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((o^_^o) +(o^_^o))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+((ﾟｰﾟ) + (ﾟΘﾟ))+ (c^_^o)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟｰﾟ)+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟДﾟ)[ﾟεﾟ]+((ﾟｰﾟ) + (ﾟΘﾟ))+ (c^_^o)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟΘﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (c^_^o)+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟｰﾟ)+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟДﾟ)[ﾟεﾟ]+((ﾟｰﾟ) + (ﾟΘﾟ))+ ((o^_^o) +(o^_^o))+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟΘﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((ﾟｰﾟ) + (ﾟΘﾟ))+ ((o^_^o) +(o^_^o))+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (ﾟｰﾟ)+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (ﾟｰﾟ)+ ((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((ﾟｰﾟ) + (o^_^o))+ (c^_^o)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (ﾟΘﾟ)+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (ﾟｰﾟ)+ ((o^_^o) +(o^_^o))+ (ﾟДﾟ)[ﾟεﾟ]+((ﾟｰﾟ) + (ﾟΘﾟ))+ (c^_^o)+ (ﾟДﾟ)[ﾟεﾟ]+(oﾟｰﾟo)+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟДﾟ) .ﾟΘﾟﾉ+ (ﾟΘﾟ)+ (ﾟΘﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (o^_^o)+ (o^_^o)+ (ﾟДﾟ)[ﾟεﾟ]+((o^_^o) +(o^_^o))+ ((o^_^o) - (ﾟΘﾟ))+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (o^_^o)+ ((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟｰﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(oﾟｰﾟo)+ ((ﾟｰﾟ) + (o^_^o))+ (ﾟДﾟ) .ﾟΘﾟﾉ+ (ﾟΘﾟ)+ (ﾟΘﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (o^_^o)+ (o^_^o)+ (ﾟДﾟ)[ﾟεﾟ]+((o^_^o) +(o^_^o))+ (ﾟΘﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+(ﾟΘﾟ)+ (o^_^o)+ ((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟДﾟ)[ﾟεﾟ]+((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟΘﾟ)+ (ﾟДﾟ)[ﾟεﾟ]+((ﾟｰﾟ) + (ﾟΘﾟ))+ (ﾟΘﾟ)+ (ﾟДﾟ)[ﾟoﾟ]) (ﾟΘﾟ)) ('_');}
// Execute function:
a(':D');

I took it from this answer, encoded it with aaencode, and wrapped it an the arrow function.

Perl 5 -p, 14 bytes
y/(|)D:-/0-3/d

Try it online!
Basically a port of my sed answer, but the y/// command in perl has the additional utilities of deleting extra characters and specifying ranges of characters, so this manages to be shorter and still contain :-/ and D: as essential parts of the code.

Factor, 20 bytes
[ last "(|)D"index ]

Try it online!
Explanation:
If ":)" is on the data stack when this quotation is called...

last Take the last element of the input.
Stack: 41 (code point for ))

"(|)D" Push a string to the stack.
Stack: 41 "(|)D"

index Find the index of 41 in "(|)D".
Stack: 2

Vyxal K, 7 bytes
td19%4%

Try it Online!
-1 thanks to exedraj.

7 bytes

brainfuck, 94 bytes
,[[>++<-]>>,]>++++[<++++>-]<[+++<[>->+<[>]>[<+>-]<<[<]>-]>[-]<<<[>>>>>+<<]>>]>-[>+<-----]>---.

Try it online!
Uses Uriel's formula. Here's how it works:
,[[>++<-]>>,]

A nifty input loop that handles the optional nose and doubling the characters. It gets a character, doubles it into the next cell, then moves two cells over and tries to get another character. At the end, the tape looks something like
0 2*c1 0 2*c2 0 2*c3 0 ...
                     ^

This requires an implementation with EOF=0 or no change (which accounts for most of them including TIO).
>++++[<++++>-]<

Put 16 after the last doubled input. Now on to the main loop:
[+++<[>->+<[>]>[<+>-]<<[<]>-]>[-]<<<[>>>>>+<<]>>]

This loop will

add 3 to the dividend (current cell). I do this because it's 2 bytes shorter to get 16 rather than 19, and these can be reused to construct 4 for the second dividend.
compute the modulus of the previous%current cell.
clear out a temporary variable
check if the value of the cell 3 indices back is non-zero (which is only true on the first iteration since the loop ends 2 indices to the right of where it started). If it is, increment the cell where the next dividend will be (this sets up the second modulo 4).

For clarity, here's what the tape looks like during the first iteration, before the tempvar is cleaned:
0 2*c1 0 2*c2 0 0 tmp 2*c3%19 0 ...
                  ^

And the same for the second:
0 2*c1 0 2*c2 0 0 0 0 tmp 2*c3%19%4 0 ...
                      ^

So checking the cell 3 indices back is an easy way to see which iteration we're on without using a counter.
>-[>+<-----]>---.

And finally, a bit of wrapping abuse to add 48 to the result so it can be outputted.
There's probably room for improvement, particularly in the input loop or the memory layout, but this is the best I could come up with.

Thunno 2 tB, 5 bytes
ṇ;Œ7%

Try it online!
Uses dingledooper's formula.
Explanation
ṇ;Œ7%  # Implicit input
       # Convert to codepoints
ṇ;     # Push compressed integer 160
  Œ    # Take 160 mod each codepoint
   7%  # Mod each by 7
       # Implicit output of last item

Kotlin,  27  24 bytes
-3 Refactor to remove it.
{"(|)D".indexOf(last())}

Try it online!

T-SQL, 34 bytes
SELECT CHARINDEX(RIGHT(@,1),'|)D')-1

Requires the variable @ to be declared and assigned the input.
This code takes the right most character, and searches an indexed list of the possible mouthes. CHARINDEX returns a 1-based index. But, failing to find anything returns 0. So we leave the frown out of the search string (making the sad face even sadder).
Try it online! (SQL Fiddle)

Hy, 33 bytes
(fn[s](%(%(*(ord(last s))2)19)4))

Try it online!
It's a basic port of Uriel's answer. I might be able to shorten it by getting rid of a % but I need to play around with the syntax.

MAWP 0.1, 27 bytes
|2W!!99M1MP99M1MWA!!4P4WA:.

Uses the modulo formula from @Uriel 's answer

Golfscript, 10 bytes
-1='(|)D'?

Try It Online!
Explanation:
-1=        # Gets the ASCII value of the final character.
   '(|)D'? # Finds the index of that ASCII value, in the string '(|)D'.

And then, the index value is implicitly printed.


text:
Mirror and reverse text
Inspired by I reverse the source code, ...
Your task, if you wish to accept it, is to reverse text and mirror select characters. Yes, yes, I know. Very surprising.
Input
A string, stdin, an array of characters, or any other source of text. All characters of the input are guaranteed to be in the printable ASCII range (32-126).
Output
The reversed text with some characters mirrored. To do this:

You replace any occurrences of the characters (, ), /, \, <, >, [, ], {, or } in the text with the corresponding "mirrored" character: ), (, \, /, >, <, ],  [, }, or {.
and then reverse the text.

You may assume a maximum line length of 255.
Rules

Standard loopholes apply.
This is code-golf, which means that the shortest answer in each programming languages wins. Consequently, I will not be accepting an answer.

Testcases
(s)t/r\i<n>g[i]e{s} -> {s}e[i]g<n>i/r\t(s)
stringies -> seignirts
()/\<>[]{} -> {}[]<>/\()
{s}e[i]g<n>i/r\t(s) -> (s)t/r\i<n>g[i]e{s}
seignirts -> stringies
{}[]<>/\() -> ()/\<>[]{}
qwertyuiop database -> esabatad poiuytrewq

As seen above, the output should go back to the input if run through the program again.
Sandbox link

Related

Related: “Convenient palindrome” checker

Also related: I'm symmetric, not palindromic!

am I missing something, or the examples don't show the first rule in action? ie. shouldn't (s)t/r convert to r\t)s( ?

@Gnudiff The point is that you replace (){}/\[] with )(}{\/][ and then reverse it, so the text looks "mirrored". The title was planned to be "mirror text" but that was too short, so I had to add some filler.

Python 3, 61 60 59 bytes
lambda s,t="(/<[{}]>\)":[(c+t)[~t.find(c)]for c in s][::-1]

Try it online!
 -1 byte thanks to @xnor.
Changed the lookup string, so that the c in t test is eliminated.

Python 2, 63 bytes
lambda s,b='(/<[{}]>\)':map(dict(zip(b,b[::-1])).get,s,s)[::-1]

Try it online!
-1 byte thanks to @xnor.
Python 3, 65 64 bytes
lambda s,b=b'(/<[{}]>\)':s.translate(dict(zip(b,b[::-1])))[::-1]

Try it online!
Just for fun using idiomatic Python. (More idiomatic would be using str.maketrans, but it's way too long.)
-1 byte for both because the \ in '\)' doesn't need to be escaped.

In TIO,all the cases pass without using the 'r' prefix, so 60 bytes?

@dingledooper I was already editing my answer exactly for that :)

I really like your test rig, especially those unicode characters.

@xnor It's from Noodle9's answer.

I found a byte-save with (c+t)[~t.find(c)] TIO. FWIW, Python 2 can do the second one for 63 as lambda s,b='(/<[{}]>\)':map(dict(zip(b,b[::-1])).get,s,s)[::-1]

The 3.8 walrus might also be useful: TIO. Maybe there's something better there.

Stax, 2 bytes
:R

Try it online!
Well, um, yeah, Stax has a two-byte built-in that exactly does the job.

A Stax answer that you don't even have to pack to make it shorter, haha. xD

Why are you so hesitant to say that? I'm pretty sure that Canvas has a 1-byte built-in.

Bash + GNU utilities, 33 bytes
tr '(<[{/)>]}\' ')>]}\\(<[{/'|rev

Try it online!
A straightforward solution seems best here. Really the only golfing is making sure that the backslash appears last in one of the arguments to tr, because then that backslash doesn't have to be escaped, saving 1 byte.

JavaScript (ES6),  65  59 bytes
Saved 6 bytes thanks to @Bubbler
I/O format: array of characters
a=>a.map(c=>(S='()/\\<>[]{}')[S.indexOf(c)^1]||c).reverse()

Try it online!

05AB1E, 4 (or 3?) bytes
ºsK

Doesn't work for single-character inputs that are not in the mirror character-set (i.e. "a").
Thanks to @Grimmy for this version.
Try it online or verify all test cases.
º2äθ

Also works for single-character inputs that aren't in the mirror character-set.
Try it online or verify all test cases.
Explanation:
º     # Mirror the (implicit) input-string
      #  i.e. "(s)t/r\i<n>g[i]e{s}" → "(s)t/r\i<n>g[i]e{s}{s}e[i]g<n>i/r\t(s)"
 sK   # And remove the input-string from it
      #  → "{s}e[i]g<n>i/r\t(s)"
      # (after which it is output implicitly)

º     # Mirror the (implicit) input-string
      #  i.e. "(s)t/r\i<n>g[i]e{s}" → "(s)t/r\i<n>g[i]e{s}{s}e[i]g<n>i/r\t(s)"
 2ä   # Split it into two equal-sized parts
      #  → ["(s)t/r\i<n>g[i]e{s}","{s}e[i]g<n>i/r\t(s)"]
   θ  # Pop and only leave the mirrored second part
      #  → "{s}e[i]g<n>i/r\t(s)"
      # (after which it is output implicitly)

3-byter ºsK passes all test cases. It fails if the input is a single letter, though.

@Grimmy Thanks, added :)

Python 3, 69 bytes
lambda s,t=r"()/\[]{}<>":[[c,t[t.find(c)^1]][c in t]for c in s][::-1]

Try it online!
Input: A sequence of character.
Output: The reversed string, as list of characters.
How:
For each character c:

c in t checks if c is a bracket.
t.find(c) finds the index of c in the bracket string. t.find(c)^1 finds the index of the mirrored bracket, which is 1 more or 1 less than the index of c.
[c,t[t.find(c)^1]][c in t] evaluates to the same character if c is not a bracket, otherwise evaluates to the mirrored bracket.
[::-1] reverses the result.

Retina 0.8.2, 22 bytes
T`(/<[{}]>\\)`Ro
O^$`.

Try it online! Link includes test cases. Explanation:
T`(/<[{}]>\\)`Ro

Transliterate the string (/<[{}]>\) to its reverse.
O^$`.

Reverse the whole string.

Charcoal, 13 bytes
Ｐθ‖ＴＦθ¿№βι←ι←

Try it online! Link is to verbose version of code. Explanation:
Ｐθ

Print the input string without moving the cursor.
‖Ｔ

Reflect the canvas. This mirrors the characters ()/\<>[]{}bdpq.
Ｆθ

Loop over the original string.
¿№βι

Is the current character a b, d, p, q (or any other lowercase letter that wouldn't have been transformed)?
←ι

If so then replace it with the original lowercase letter and move left.
←

Otherwise leave the current character, which might be a transformed ()/\<>[]{}.

C (gcc), 112 \$\cdots\$ 84 83 bytes
Saved a whopping 27 bytes thanks to Bubbler!!!
Saved a byte thanks to dingledooper!!!
Saved a byte thanks to ceilingcat!!!
char*t,*b="()/\\<>[]{}";f(char*s){*s&&putchar((t=index(b,*s))?b[t-b^1]:*s,f(s+1));}

Try it online!

85 bytes

@Bubbler Amazing recusive refactoring - thanks! :-)

You can save 1 byte by replacing strchr with index instead.

@dingledooper Nice one - thanks! :-)

@ceilingcat Clever - thanks! :-)

batch, 442 408 bytes
@Echo off&Setlocal EnableDelayedExpansion
for %%A in (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z)do Set %%A=%%A
for %%B in ("(=)",")=(","<=>",">=<","[=]","]=[","{=}","}={","/=\","\=/")do Set "%%~B"
Set "_=%~1"
Call :M
Echo(!$!
Endlocal
Exit /B
:M
For /L %%C in (0,1,256)do (
If "!_:~%%C,1!"=="" Exit /B
Set ".=!_:~%%C,1!"
For %%D in ("!.!")do IF "!%%~D!"=="" (Set "$= !$!")Else (Set "$=!%%~D!!$!")
)

Output:

Python 3, 111 \$\cdots\$ 75 69 bytes
lambda s,b=r'()/\<>[]{}':[[c,b[b.find(c)^1]][c in b]for c in s][::-1]

Try it online!

I really like your test rig, especially those Unicode characters.

@xnor Thanks, have them memorised they're so useful. :D

Java (JDK), 111 bytes
s->{var a="(\\<[{}]>/)";for(int i=s.length,j;i-->0;System.out.print(j<0?s[i]:a.charAt(9-j)))j=a.indexOf(s[i]);}

Try it online!
Credits

-1 byte thanks to Kevin Cruijssen

Woops.. 127 bytes in that case. My bad.

J, 32 28 26 bytes
-4 bytes thanks to Bubbler!
-2 bytes thanks to FrownyFrog
|.rplc(;"0|.)@'([{/<>\}])'

Try it online!

28 bytes. You don't need to append anything to the replacement array.

@Bubbler Of course I don't! I feel stupid, like so many times before...
Thanks!

26 bytes minor adjustment

@FrownyFrog Thank you!

Canvas, 1 byte
Exactly. A 1 byte built-in.
↔

Try it here!

PowerShell, 69 58 bytes
+ to @Bubbler
-11 bytes thanks to @mazzy
$t='(/<[{}]>\)'
$args|%{$a="$_$t"[-1-($t|% i*f $_)]+$a}
$a

Expects input via splatting.
Try it online!

? [--$i] instead [-++$i]

? Try it online!

Red, 69 bytes
func[s][reverse s forall s[s/1: any[select"()([][{}{<></\/"s/1 s/1]]]

Try it online!

Icon, 76 68 bytes
procedure f(s)
r:=reverse
return map(r(s),t:="([{/<>\\}])",r(t))
end

Try it online!

Perl 5 -pl, 37 bytes
$_=reverse;y|(){}[]<>/\\|)(}{][><\\/|

Try it online!

PHP, 52 bytes
<?=strrev(strtr($argn,$a='(/<[{}]>\\)',strrev($a)));

Try it online!
Glad that this time PHP has an elegant way of doing it ^^


text:
Multiplayer Rock-Paper-Scissors
Objective
Given a nonempty multiset of Rock, Paper, and Scissors, output the winning figure according to the special rule.
Background
For a multiplayer RPS, if all three figures come out, usually it's considered a draw. But by that rule, the probability to draw would dramatically increase when there are many and many players.
Let's resolve that by a special rule.
Input
Though defined as a multiset, the input type and format doesn't matter. Valid formats of the input include:

A multiset
A sequential container with or without guarantee of order
An size-3 array of integers representing the count of each of RPS

Also, Rock, Paper, and Scissors may be encoded by an arbitrary type.
The Special Rule and Output
Let's say \$r\$ Rocks, \$p\$ Papers, and \$s\$ Scissors-es(?) are given.

If one of them is zero, output the winning figure of the other two.
If none of them is zero, allot them a score by multiplicating the number of themselves and the number of the figure they win to. That is, Rock gets score \$r×s\$, Paper gets score \$p×r\$, and Scissors get score \$s×p\$.

If the scores don't tie, output the figure with the maximum score.
If the scores tie by two figures, output the winning figure amongst the two figures.
Otherwise, output a fourth value indicating draw.

Otherwise, output either the only figure or the fourth value.

The output type and format doesn't matter.
Rule about code golf
Invalid inputs (Empty container, contains a fourth value, etc) fall into don't care situation.
Example
Given the following input:
[Rock, Rock, Rock, Paper, Paper, Scissors, Scissors]

Rock gets score 3×2=6, Paper gets score 2×3=6, and Scissors get score 2×2=4. Since Paper wins to Rock, the output is Paper.

I'm not sure what you mean by "The output format must match the input's format." Say, can the output be one of the numbers 0,1,2,3 for rock, paper, scissors, tie?

Is the "If one of them is zero, ..." rule necessary? That side would always get a score of 0 anyway.

I'd really suggest allowing input to just be the counts of the three symbols. Getting those counts from a list of items seems like an extraneous step that all solutions will do. (Edit: On second thought, I'm less sure about this. Maybe some solutions would get the product of counts directly by counting pairs via two loops.)

@Monicareinstate, I'm just making the rule intuitively understandable. Nice inspection for a code golf tho.

What's a multiset?

@S.S.Anne An associative container with entries repeatable.

Not really golfed, but the homepage of https://haxe.org/ contains a cool Rock-Paper-Scissors example.

05AB1E, 14 13 bytes
Ćü*ZÊ2βD3*7%M

Input as a list of integers in the order \$[r,s,p]\$.
Output as one of the following four:
Rock wins:      3
Scissors wins:  5
Paper wins:     6
Tie:            0

-1 byte thanks to @xnor.
Try it online or verify some more test cases.
Explanation:
Ć              # Enclose the (implicit) input-list, appending its own head
               #  i.e. input=[3,2,2] → STACK: [[3,2,2,3]
 ü             # For each overlapping pair: [a,b,c,d] → [[a,b],[b,c],[c,d]]
  *            #  Multiply them together
               #   STACK: [[6,4,6]]
   Z           # Get the maximum (without popping)
               #   STACK: [[6,4,6],6]
    Ê          # Check which of the values in the list are NOT equals to this maximum
               #  STACK: [[0,1,0]]
     2β        # Convert this list of 0s and 1s from a binary list to integer
               #  STACK: [2]
       D       # Duplicate it
               #  STACK: [2,2]
        3*     # Multiply it by 3
               #  STACK: [2,6]
          7%   # Take modulo-7:
               #  STACK: [2,6]
            M  # Push the largest value on the stack
               #  STACK: [2,6,6]
               # (after which the top of the stack is output implicitly as result)

After the Ćü*ZÊ we can have the following values:
                One of:
Rock wins:      [[0,1,1], [0,0,1]]
Scissors wins:  [[1,0,1], [1,0,0]]
Paper wins:     [[1,1,0], [0,1,0]]
Ties:           [[0,0,0]]

Converting those from binary-lists to integers:
                One of:
Rock wins:      [3, 1]
Scissors wins:  [5, 4]
Paper wins:     [6, 2]
Ties:           [0]

The 3*7% (thanks to @xnor!) will map the lower values to the higher values in the pair, and will also unsure the lower values won't increase.

This works because the pairs [1,3], [2,6], [4,5] are constructed from bits where the second number has two bits set: that of the first number, and the bit position to its right, wrapping around in 3 bits. This comes from the binary-list of the RPS game. We can do the set-next-bit with *3 and enforce 3-bit wrapping with %7.

                One of:
Rock wins:      [3→2, 1→3]
Scissors wins:  [5→1, 4→5]
Paper wins:     [6→4, 2→6]
Ties:           [0]

After which we can use M to only keep the largest value on the stack for our result:
                One of:
Rock wins:      [3, 3]
Scissors wins:  [5, 5]
Paper wins:     [6, 6]
Ties:           [0]

It might be useful that in each of the pairs in the mapping, the second number is the first one times 5 modulo 7.

@xnor Hmm, but how to effectively combine it so it won't map the other value. I could use D5*7%‚ß (Duplicate; use your *5%7; pair these two integers together; and pop and push the smallest integer), but unfortunately it's also 14 bytes: verify all test cases. PS: If we could somehow map the [1,4,2] to [3,5,6] and ensure that same fomula won't make [3,5,6] themselves larger, I could do it with D...M instead of D...‚ß to save a byte.

It looks like the reverse map of *3%7 would meet your criterion.

@xnor Awesome, thanks! :) Btw, I've asked Arnauld a similar question once before, but do you have some kind of test script to get certain magic formulas for the integers, or do you create that from scratch every time depending on the challenge and required mapping? Could you give me some tips on how to make it myself? PS: I could have easily written a test script in the form of *a%b, but I thought it would have required more operations.. How do you know how many operations (and which) are sufficient in terms of multiply, modulo, bitwise operations, etc.?

I've used a script for some brute-forcing before, and I'm rewriting it into a form that's less hacked-together that I intend to share. In this case though, I didn't use anything like that here, or even coded anything, but thought up the formula logically. The pairs(1,3), (2,6), (4,5) are constructed from bits where the second number has two bits set: that of the first number, and the bit position to its right, wrapping around in 3 bits. This comes from the RPS game. We can do the set-next-bit with *3 and enforce 3-bit wrapping with %7.

About your point about the formula being surprisingly short, it might be, probably because it comes "by design" rather than working by coincidental overfitting. I only have a vague sense of how long to expect a formula to need, and luck plays a big role, but at times I've estimated the number of possible formulas and the chance that a random mapping works.

Thinking through some bit logic, ~(n*2%7)&n converts [3,5,6] to [1,4,2] while leaving the latter unchaged.

Actually, n*5%7&n can fix the *5%7 version to not affect the powers of 2.

@xnor Ah, now the *3%7 makes a lot more sense when looking at the binary-lists (basically the bits of the integers) that I had before the base conversion. Thanks for the explanation!

And I look forward seeing your test script one day when you're posting it. I might try to make some test scripts myself for various operations, especially for 1-byte operations in 05AB1E, which also includes things like 2**n, 10**n, floor, ceil, round, gcd, first/last digit, abs(a-b), etc. etc. Although I'll start with the basics. ;) I probably also won't do it in 05AB1E, since it's performance isn't the best tbh. So I'll probably try some things in Java when I have the time.

Python, 41 bytes
lambda r,s,p:[s>p<=r>0,p>r<=s>0,r>s<=p>0]

Try it online!
Takes counts as (r,s,p). Outputs a three-element list with True at the position of the winner, or all False's if there's a tie or only a single figure appearing.
Rock:     [True, False, False]
Scissors: [False, True, False]
Paper:    [False, False, True]
Tie:      [False, False, False]

We use an alternate characterization without multiplication (except when only one figure is present). Below is the condition for Rock winning, with Scissors and Paper having similar conditions.

Rock wins if: Paper has the fewest, strictly fewer than Scissors but possibly the same as Rock.

We can write this in Python as s>p<=r using inequality chaining.
Unfortunately, this doesn't correctly handle the special case when r=p=0, saying that Rock wins even though only Scissors is present. To fix this, we strengthen the condition for Rock to win to include r>0 via s>p<=r>0, which makes the only-Scissors case give all False for every condition, matching a tie.

44 bytes
lambda r,s,p:r*s==s*p==p*r or[s>p<=r,p>r<=s]

Try it online!
Takes counts as (r,s,p). Outputs as:
Rock:     [True, False]
Scissors: [False, True]
Paper:    [False, False]
Tie:      True

The "Tie" case also includes where there's only a single figure present.

By my reading of the question, for an input of [Scissors, Scissors] you are allowed to output either Scissors wins or Tie, which would save 6 bytes.

@Neil Do you mean by getting rid of the >0's? The issue with that is for inputs [0, 2, 0] for two Scissors, the code would actually gives that Rock wins. The difficulty is that in a similarly ordered input like [1, 2, 1], we should in fact say that Rock wins due to it winning tiebreak between Rock and Scissors. So the two-zeros case is special.

Oh sorry I misunderstood the problem.

@Noodle9 Yup, good catch, thanks.

C (gcc), 61 \$\cdots\$ 53 52 bytes
Saved 3 bytes thanks to Kevin Cruijssen!!!
Saved 3 bytes thanks to Arnauld!!!
Saved a byte thanks to ceilingcat!!!
Uses xnor's formula converted to \$3\$ for Rock, \$2\$ for Scissors, \$1\$ for Paper, and \$0\$ for a tie or only a single figure appearing.
f(r,s,p){r=s>p&p<=r&&r?3:p>r&r<=s&&s?2:r>s&s<=p&&p;}

Try it online!

The first && in each part can be & for -3 (i.e. (s>p&&p<=r&&r) to (s>p&p<=r&&r)).

@KevinCruijssen Interesting - thanks! :-)

&&p?1:0 ~> &!!p?

@Arnauld Very sweet - thanks! :-)

@ceilingcat Very good, now realise the ?1:0 was totally redundant - thanks! :-)