Imagine a list of elements and their outcomes when some non-commutative function is applied to them. For example, we will use the elements Rock, Paper, and Scissors, the outcomes Win, Lose, and Tie, and an operator * such that X*Y = what would happen if you played X against Y

As a list, you might write it this way:

[Rock*Rock=Tie,     Rock*Paper=Loss,    Rock*Scissors=Win,
Paper*Rock=Win,     Paper*Paper=Tie,    Paper*Scissors=Loss,
Scissors*Rock=Loss, Scissors*Paper=Win, Scissors*Scissors=Tie]

In table form, it might look like this:

top*left Rock Paper Scissors
Rock Tie Win Loss
Paper Loss Tie Win
Scissors Win Loss Tie

One might observe that for any pair of elements, there is a pair of outcomes. For the unordered pair (Rock,Paper), Rock*Paper gives Loss and Paper*Rock gives Win.

You might think of a function which takes a pair of elements and outputs a pair of outcomes given by the table. In our initial example, that'd be (Rock,Paper) => (Loss,Win)

A few more examples:

     (Rock,Rock) => (Tie,Tie)
(Paper,Scissors) => (Win,Loss)
   (Paper,Paper) => (Tie,Tie)

Note that order of input and output doesn't really matter here, since we're just asking which outcomes exist at all between the two elements.

Finally, consider the inverse to this function, which takes a pair of outcomes as input and outputs tall pairs of elements which can have both outcomes.

Here are all possible distinct inputs and their outputs for the example case:

  (Win, Win) => 
 (Win, Loss) => (Rock,Paper), (Paper,Scissors), (Scissors,Rock)
  (Win, Tie) =>
(Loss, Loss) =>
 (Loss, Tie) =>
  (Tie, Tie) => (Rock,Rock), (Paper,Paper), (Scissors,Scissors)

Note again that order doesn't matter here, so

(Win,Loss) => (Rock,Paper), (Paper,Scissors), (Scissors,Rock)
(Loss,Win) => (Rock,Paper), (Paper,Scissors), (Scissors,Rock)
(Win,Loss) => (Paper,Rock), (Scissors,Paper), (Scissors,Rock)
(Win,Loss) => (Scissors,Rock), (Rock,Paper), (Paper,Scissors)

are all valid.

Implementing this inverse is your challenge.


Write a program or function which does the following:

  • Takes a list of ordered element pairs and their outcomes when some non-commutative function is applied, referred to as the "Interaction Table" from here onward. This can be done in any consistent reasonable format, specified by the solver.
  • Takes a single unordered pair of outcomes x,y as a second input, referred to as the "Given Pair" from here onward. This can be done in any consistent reasonable format, specified by the solver.
  • Outputs a list of all unique unordered pairs of elements a,b such that, according to the Interaction Table, a*b is one of x,y and b*a is the other. This can be done in any consistent reasonable format, specified by the solver.

This is , So shortest code in bytes wins.

More specification

  • The Interaction Table does not actually have to be a literal table. It can be taken in any reasonable format, standard I/O etc. Just remember to specify exactly how you take input, especially if it's somewhat unusual.
  • Instead of taking the Given Pair as a second input, your program/function may take only the Interaction Table as input and output a program/function which takes the Given Pair as its only input and provides the expected output for the challenge.
  • You may restrict elements and outcomes to a reasonable degree, e.g. "only integers" / "only alphabetical strings" is fine, but "only digits 0-9" is not.
  • Since outputs will always be pairs of elements, you don't need to use a second delimiter to separate pairs, only individual elements. e.g. both (A B) => (1 2) (3 4) and A B => 1 2 3 4 are both valid formats.
  • You may assume that there are no missing interactions, i.e. every element within the Interaction Table will be paired with every other element and itself in each possible permutation.
  • You may assume that the Interaction Table is given in some standard order, if that helps you in some way.
  • You may not assume that every Given Pair will have an output. In these cases, any falsy output or no output is fine, so long as you don't output an element pair.
  • You may not output duplicate pairs. (A,B) => (1,2),(1,2) is not valid, and since pairs are unordered, (A,B) => (1,2),(2,1) is also not valid.

More examples

Here is another example of a possible Interaction Table input


Which can correspond to this literal table

x A B C
A 1 2 1
B 1 3 2
C 2 2 1

Some example Given Pairs and their outputs

(1,1) => (A,A),(C,C)
(2,2) => (B,C)
(2,3) => 
(1,2) => (A,B),(A,C)

Another possible Interaction Table input


Which can correspond to this literal table

x What Who
What Yeah Nah
Who Yeah Yeah

Some example Given Pairs and their outputs

 "Nah" "Yeah" => "Who" "What"
 "Yeah" "Nah" => "Who" "What"
  "Nah" "Nah" => 
"Yeah" "Yeah" => "What" "What" "Who" "Who"

One more possible Interaction Table input

"0 0 a 0 1 b 1 0 c 1 1 d"

Which can correspond to this literal table

x 0 1
0 a c
1 b d
  • 1
    \$\begingroup\$ I find it funny that the order of each pair doesn't matter, because this (I think) implies that uninvert(invert(f())) is not necessarily the same as f(). Not that this is essential for this challenge, of course... \$\endgroup\$ May 30, 2022 at 7:49

4 Answers 4


Curry (PAKCS), 56 bytes

-2 bytes thanks to @Wheat Wizard.

(!)#p|[x!y,y!x]==(p?reverse p)&&x<=y=(x,y)where x,y free

Try it online!

Takes the Interaction Table as a function and the pair as a list with two elements.

For example, the Interaction Table of Rock-Paper-Scissors is given by the following function:

f "Rock" "Rock" = "Tie"
f "Rock" "Paper" = "Loss"
f "Rock" "Scissors" = "Win"
f "Paper" "Rock" = "Win"
f "Paper" "Paper" = "Tie"
f "Paper" "Scissors" = "Loss"
f "Scissors" "Rock" = "Loss"
f "Scissors" "Paper" = "Win"
f "Scissors" "Scissors" = "Tie"

And f # ["Loss", "Win"] would give the result:

  • \$\begingroup\$ maybe im a noob but this is so cool, you literally take a function as input. awesome! \$\endgroup\$ May 30, 2022 at 4:17
  • 3
    \$\begingroup\$ @thejonymyster Welcome to functional programming! \$\endgroup\$ May 30, 2022 at 14:15

Vyxal, 24 bytes


Try it Online!

A mess.


vh                       # Get the first item of each of the (implicit) first input
  '                      # Filter-keep for:
   Ḃ"                    #   Pair with reverse
     ƛ                   #   For both:
      £                  #     Store in register
       ¹'                #     Filter-keep for first input:
         h¥⁼             #       Is the first item equal to the contents of the register? (non-vectorizing)
            ;            #     Close filter
             ht          #     Get the first item of the results of the filter, and get the last item of that
               ;         #   Close map
                s        #   Sort the results
                 ⁰s⁼     #   Is it equal to the first input sorted? (non-vectorizing)
                    ;    # Close filter
                     vs  # Sort each
                       U # Uniquify

C (GCC), 118 bytes

f(n,e,t,x,y,i,j)int**t,*e;{for(i=0;i<n;++i)for(j=0;j<n;++j)t[i][j]-x|t[j][i]-y|x==y&i>=j||printf("%d %d ",e[i],e[j]);}

Attempt This Online!

Arguments description:

  • n is the number of elements;
  • e is a vector of n items, each representing an element;
  • t is the table, represented as an array of arrays;
  • x and y are the two result which form the pair to invert;
  • i and j are dummy arguments.
  • 2
    \$\begingroup\$ Technically I don't think you're allowed dummy arguments but you can just declare them global instead i.e. i;k;f(n,e,t,x,y). \$\endgroup\$
    – Neil
    May 29, 2022 at 23:36
  • 2
    \$\begingroup\$ @Neil they can be omitted, so it's fine (they'll take on junk values) \$\endgroup\$
    – att
    May 30, 2022 at 3:31
  • \$\begingroup\$ @att Well not in general, because it depends on the calling convention, but obviously for PPCG purposes it's OK if there's at least one case where it works. \$\endgroup\$
    – Neil
    May 30, 2022 at 7:17
  • \$\begingroup\$ @Neil I mean that you can omit them when you call the function, i.e. calling the function as f(n,e,t,x,y) is valid. \$\endgroup\$
    – att
    May 30, 2022 at 20:53
  • 1
    \$\begingroup\$ I could be wrong but it looks like you could iterate in reverse order, i.e: for(i=n;i--;)for(j=n;j--;).... This should only change the order of the output for -6 bytes \$\endgroup\$
    – c--
    Jun 20, 2022 at 19:48

R, 116 bytes

function(t,x,r=function(x)sub('(.*) (.*)','\\2 \\1',x),d=names(t),f=paste(t[d],t[r(d)]),c=d[f==x|f==r(x)])c[c<=r(c)]

Try it online!

R version 4 saves 14 bytes because you can say \(x) rather than function but isn't supported by TIO.

This is a pretty straightforward approach, taking input as ('a,b') in string format (so no commas is the constraint for inputs/outputs). The table is a named vector to use R's indexing abilities to compute preimages and apply functions, and we build the function f (an unnamed vector on domain d) that takes (a,b) to (t(a,b),t(b,a)). Then we deduplicate at the end.

1 byte freed by replacing gsub with sub.

Improved to 112 bytes by https://codegolf.stackexchange.com/users/55372/pajonk, and R version 4 improves this to 98 bytes.

  • \$\begingroup\$ Switching from comma-separated to space-separated shaves 5 characters off the paste0. \$\endgroup\$
    – Cong Chen
    May 30, 2022 at 13:50
  • 1
    \$\begingroup\$ The TIO link doesn't actually seem to work... \$\endgroup\$ May 30, 2022 at 15:33
  • \$\begingroup\$ Thanks for catching that - the test cases had the wrong signature. Fixed now, and 5 bytes saved per earlier comment. \$\endgroup\$
    – Cong Chen
    May 30, 2022 at 17:32
  • 1
    \$\begingroup\$ -4 bytes by renaming function r to !. \$\endgroup\$
    – pajonk
    May 31, 2022 at 6:08
  • 1
    \$\begingroup\$ Also switching to R>=4.1 saves 2*7=14 bytes if I'm not wrong. \$\endgroup\$
    – pajonk
    May 31, 2022 at 6:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.