20 cards with no Set Background

Set is a card game. The deck consists of 81 unique cards that vary in four features: number of shapes (one, two, or three), shape (diamond, squiggle, oval), shading (solid, striped, or open), and color (red, green, or purple).

For convenience, let's write a card as a 4-tuple of numbers from 1 to 3, e.g.


1111 = one red solid diamond
1122 = one red striped squiggle
1223 = one green striped oval
2312 = two purple solid squiggle


Given several cards (usually 12), the objective of the game is to find a "set" of three cards such that


They all have the same number or have three different numbers.
They all have the same shape or have three different shapes.
They all have the same shading or have three different shadings.
They all have the same color or have three different colors.


i.e. the cards are either all the same or all different in each of the four features.

Here are some examples of sets:

1111, 1112, 1113
1111, 2222, 3333
2312, 3321, 1333


Here are some examples of non-sets:

1111, 1122, 1123
2131, 3221, 1213


A cap set is a collection of cards that doesn't contain any Set. It was proven in 1971 that the maximum number of cards without a Set is 20. Interestingly, finding the largest cap set for the generalized game of Set is still an open problem in mathematics.

The Wikipedia page shows an example of 20-cap set, and here is the 20 cards in the number notation:

1111, 1113, 1131, 1133,
1312, 1332, 1321, 1323,
3311, 3313, 3331, 3333,
3112, 3132, 3121, 3123,
1222, 2122, 2322, 3222


There are 682344 20-cap sets in total, but under affine transformations on 4-dimensional finite space, they all reduce to essentially one cap set.

Task

Output any of the 20-cap sets in the game of Set.

Input and output

Your program/function is not allowed to take input.

The output is a collection (list, set, ...) of 20 cards which is a cap set. Each card should be represented as a 4-tuple (or equivalent ordered collection) whose elements are one of three distinct values (not necessarily 1, 2, 3). Flexible output applies in the following ways:


Nested or flattened list
Ordering of cards doesn't matter
You may choose to output the same set or different set across runs
For string/text output, it's fine as long as we can clearly identify the structure (20 chunks of four items) of the output


Verification script example in Python using the example shown above.

Scoring and winning criterion

Standard code-golf rules apply. The shortest valid code in bytes wins.
Haskell, 62 bytes



tail[t|t@[a,b,c,d]&lt;-mapM(:[1,2])[0,0,0,0],mod(a*a+b*b+c*d)3&lt;1]


Try it online!

Defines a cap-set as all  \$(a,b,c,d)\$ from \$\{0,1,2\}^4\$ where $$a^2+b^2+cd=0\bmod3,$$ except not \$(0,0,0,0)\$.

I found this formula by looking at Wikipedia's example and coming up with progressively simpler formulas linking the allowed inner coordinates \$(a,b)\$ to the outer coordinates \$(c,d)\$.



Haskell, 46 bytes



[t|t&lt;-mapM(:"12")"0000",sum[1|'0'&lt;-t!!0:t]==2]


Try it online!

This uses a modified condition giving a different but equivalent cap set:

$$a^2+b^2+c^2 - d^2=0\bmod3,$$ still without \$(0,0,0,0)\$.

This is equivalent to \$a^2+b^2+c^2 + d^2 + d^2 =0\bmod3,\$, so we can duplicate an element and check that the give-element list of squares adds to zero modulo 3. Since squares modulo 3 are 0 or 1, this is further equivalent to this condition:


  There are exactly \$2\$ zeroes among \$[a,b,c,d,d]\$.


This automatically excludes the all-zero point. Of course, duplicating $d$ was arbitrary -- choosing another element gives a different but equivalent cap-set.