g | x | w | all
Bytes Lang Time Link
103Python 3.8 prerelease250904T145210ZV_R
076Perl 5 + p250408T201312ZDom Hast
025Jelly250408T191934ZJonathan
098Ruby250407T220325ZLevel Ri
03605AB1E250407T073439ZKevin Cr
028Charcoal250407T084203ZNeil
085JavaScript Node.js250407T022653Zl4m2

Python 3.8 (pre-release), 103 bytes

This may not be the best solution, but I thought it worth posting because it has a theme (reversal). Outputs lists of strings with "1" instead of "∩", which I will argue should be penaltyless, since the literal "1" is not found in the code, although 1 is.

lambda n:print([bin(x)[:1:-1].replace("0"," ")for x in[32,132,32,80,330,594,168,693,1453,427][2-n::3]])

Try it online!

Explanation

The core algorithm is to store each line of output as a binary number, printing 3-4 of these lines depending on the (zero-indexed) input number n.

OP says It's acceptable to have zero space between cups in adjacent pyramids., and I take advantage of this to shorten the number of bits in the binary numbers. The numbers are stored in base 10 in the code.

The output for n=2 has four lines, whereas the other outputs have three. Usually having outputs of different lengths means you can't use the slicing trick on lists with (in this case) [n::3] to get every third number starting at n. We can get around this by reversing the order of the items in the list and slicing with 2-n::3. Only when n=2 is 2-n=0, and the list is just long enough that if and only if 2-n=0 is there space for a fourth item.

For the binary numbers themselves, note that the lines of the outputs start with different characters: some lines with and some with . This makes it hard to encode the outputs as binary without running into issues with leading 0s. However, each line ends with the same character, . This means we can encode as 1 and as 0 if we encode each output line backwards. This means our code needs to convert our base-10 numbers back to binary (bin(x)), get rid of the 0b prefix (bin(x)[2:]) and reverse with (bin(x)[2:][::-1]). However, these string slices can be combined as bin(x)[:1:-1], saving a few bytes.

So we encode the data backwards as a list of binary numbers and index into the list backwards.

Perl 5 + -p, 76 bytes

$_=('6
1313
01','25
1131
0','5
41
311
0')[$_].1x5;s/./(($")x hex$&).'∩'/ge

Try it online!

Jelly, 25 bytes

ị“ʠTJ‘BŒBS3ƤẒŻƊƬṚa⁽œṡo⁶ỌY

A monadic Link that accepts the state as a positive integer from \$\{1,2,3\}\$ and yields a list of characters. Also, a full program that accepts the same and prints the result.

Note that:

Both appear to be allowed, and both aid the golf.

Try it online!

How?

The left-half of each state's base row is encoded in a byte, which is fetched and processed to build the rest of the state:

ị“ʠTJ‘BŒBS3ƤẒŻƊƬṚa⁽œṡo⁶ỌY - Link: integer, N
 “ʠTJ‘                    - Code-page indices = [165, 84, 74]
ị                         - {N} 1-index into {that}
      B                   - convert to binary -> HalfBaseRowBits
       ŒB                 - bounce -> BaseRowBits
               Ƭ          - collect up while distinct, applying:
              Ɗ           -   last four links as a monad - f(Current):
          3Ƥ              -     for each 3-slice of {Current}
         S                -       sum {the three bits} -> 0, 1, or 2
            Ẓ             -     is prime? (vectorises)
                                 - i.e. [v==2 for v in {3-slice sums}]
             Ż            -     prefix {that} with a zero -> NextRowBits
                Ṛ         - reverse {these rows}
                 a⁽œṡ     - logical AND 8745 - replace 1s with 8745s
                     o⁶   - logical OR space - replace 0s with spaces
                       Ọ  - cast to characters - replace 8745s with ∩s
                        Y - join with newline characters
                          - (implicit print when run as a full program)

Ruby, 102 98 bytes

->i{"
TyBfx\32*2x"[i*3,j=3+i/2].bytes{|k|puts (" "*j-=1)+("%07b"%k+=6).tr("01"," ∩").chars*" "}}

Try it online!

longer than I hoped but it works. Accepts a number 0..2

05AB1E, 37 36 bytes

•U₅Ā8AÞ‡|ÔδÚ5∍–ŒZ•3äRIè„ 
ŽYнçšÅвJ.º

Takes the 0-based index as input.

Try it online or verify all three outputs.

Explanation:

•U₅Ā8AÞ‡|ÔδÚ5∍–ŒZ•
          # Push compressed integer 38058123976930001615649986047041278960
 3ä       # Try to split it into 3 equal-sized parts, where the trailing part(s)
          # could be one character shorter:
          #  [3805812397693,"0001615649986","047041278960"]
   R      # Reverse this list
 Iè       # Pop and keep the 0-based input'th integer
„ \n      # Push string " \n"
    ŽYн   # Push compressed integer 8745
       ç  # Convert it to a character with this codepoint: "∩"
        š # Convert the earlier string to a list and prepend this: ["∩"," ","\n"]
Åв        # Convert the larger integer to this custom base,
          # aka, convert it to base-3, and index into this list of three characters
  J       # Join everything together to a string
   .º     # Mirror vertically with overlap
          # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why •U₅Ā8AÞ‡|ÔδÚ5∍–ŒZ• is 38058123976930001615649986047041278960 and ŽYн is 8745.

Charcoal, 28 bytes

F§⪪”)⊞″?;”³N«G↗↘Iι…∩ ¶ ⁵→→

Try it online! Link is to verbose version of code. Takes 1-indexed input. Explanation:

F§⪪”)⊞″?;”³N«

Split the compressed string 14123233 into groups of 3, cyclically index by the input step, then loop over the digits.

G↗↘Iι…∩ ¶ ⁵

Draw a pyramid of that size, but using a complex fill so that s only appear at alternating positions. Charcoal automatically counts 3 bytes for , which is why I use …...⁵ to repeat the as this saves a byte.

→→

Move to the next pyramid.

JavaScript (Node.js), 85 bytes

n=>([`8
3424
2`,`46
3242
`,`7
62
522
`][n]+222222).replace(/./g,k=>'∩'.padStart(k))

Try it online!