Rock Paper Scissors (Sorta) Quine

Python 3, 273, 489, 429 bytes

Rock:

r=['tie', 'lose', 'win'];s="i=input();t=[f'r={r[n:]+r[:n]};s={s!r};exec(s)'for n in[0,1,2]];print(i in t and r[i.find('t')//7]or t[0])";exec(s)

Try it online against itself!
Try it online against Paper!
Try it online against Scissors!
Try it online against rubbish!

Paper:

r=['win', 'tie', 'lose'];s="i=input();t=[f'r={r[n:]+r[:n]};s={s!r};exec(s)'for n in[0,1,2]];print(i in t and r[i.find('t')//7]or t[0])";exec(s)

Try it online against itself!
Try it online against Scissors!
Try it online against Rock!
Try it online against garbage!

Scissors:

r=['lose', 'win', 'tie'];s="i=input();t=[f'r={r[n:]+r[:n]};s={s!r};exec(s)'for n in[0,1,2]];print(i in t and r[i.find('t')//7]or t[0])";exec(s)

Try it online against itself!
Try it online against Rock!
Try it online against Paper!
Try it online against trash!

The same as the previous version, but check that the input exactly matches the source code of one of the programs.

Try it online (together)!

Old (invalid) version

Rock:

s="print(['tie','lose','win','s='+repr(s)+';exec(s)',''][input().find('ti')//7-1])";exec(s)

Paper:

s="print(['win','tie','lose','s='+repr(s)+';exec(s)',''][input().find('ti')//7-1])";exec(s)

Scissors:

s="print(['lose','win','tie','s='+repr(s)+';exec(s)',''][input().find('ti')//7-1])";exec(s)

Try it online!

Three almost identical programs (all with 91 bytes), the only difference is the order of the win/tie/lose, which each program uses the position of the 'tie' to determine the result from it's own ordering.

As pointed out, these programs are invalid, as they will only print out themselves if the input doesn't contain 'ti' (or the 'ti' is in a certain place).


Java 10, 1716 (three time 572) bytes

Rock program:

interface R{static void main(String[]a){var s="interface R{static void main(String[]a){var s=%c%s%1$c;System.out.print((s=s.format(s,34,s)).equals(a[0])?%1$ctie%1$c:t(s).equals(a[0])?%1$close%1$c:t(t(s)).equals(a[0])?%1$cwin%1$c:s);}static String t(String s){var r=%1$c%1$c;for(int b:s.getBytes())r+=(char)(b==82?80:b==80?90:b==90?82:b);return r;}}";System.out.print((s=s.format(s,34,s)).equals(a[0])?"tie":t(s).equals(a[0])?"lose":t(t(s)).equals(a[0])?"win":s);}static String t(String s){var r="";for(int b:s.getBytes())r+=(char)(b==82?80:b==80?90:b==90?82:b);return r;}}

The Paper program is similar, except with both R replaced with P.
The Scissor program is similar, except with both R replaced with Z (since S is already used in String).

Rock program:
- Try it online with itself as input.
- Try it online with the Paper program as input.
- Try it online with the Scissor program as input.
- Try it online with rubbish input.

Paper program:
- Try it online with itself as input.
- Try it online with the Scissor program as input.
- Try it online with the Rock program as input.
- Try it online with rubbish input.

Scizzor program:
- Try it online with itself as input.
- Try it online with the Rock program as input.
- Try it online with the Paper program as input.
- Try it online with rubbish input.

Explanation:

General quine explanation:

  • The var s contains the unformatted source code
  • %s is used to put this String into itself with s.format(...)
  • %c, %1$c, and 34 are used to format the double-quotes
  • s.format(s,34,s) puts it all together

Challenge part:

I've added a separated method t which will transliterate the characters RPZ once clockwise in all three programs:

static String t(String s){ // Method with String as both parameter and return-type:
  var r="";                //  Result-String, starting empty
  for(int b:s.getBytes())  //  Loop over the characters of the input-String:
    r+=                    //   Append to the result-String:
       (char)(             //    A character with codepoint:
              b==82?       //     If the character is 'R':
               80          //      Change it to 'P' (codepoint 80)
              :b==80?      //     Else-if the character is 'P':
               90          //      Change it to 'Z' (codepoint 90)
              :b==90?      //     Else-if the character is 'Z':
               82          //      Change it to 'R' (codepoint 82)
              :            //     Else:
               b);         //      Leave the character unchanged
  return r;}               //  Return the resulting String

When we're printing, it will do the following checks:

s.equals(a[0])?            // If the program equals the input:
 "tie"                     //  Print "tie"
:t(s).equals(a[0])?        // Else-if the program transliterated once equals the input:
 "lose"                    //  Print "lose"
:t(t(s)).equals(a[0])?     // Else-if the program transliterated twice equals the input:
 "win"                     //  Print "win"
:                          // Else:
 s                         //  Print the source code-String itself

Jelly, 67 59 bytes × 3 = score of 177

“3ṛṾ;Ṫ,ɠ;µḣ2O_/2ị%3+1×ḣ2a2¦Ɱ3Ṿ€¤ċɗ/$ịṚ“win“lose“tie“1ịv”1ịv

Try it online!

A full program that reads a line from STDIN and returns tie if given the same program, win if given a program against which it can win and lose if a program against which it loses. If provided with anything except one of the rock, paper or scissors programs it prints itself.

The digit in second position in the program indicates which it is:

  1. Rock
  2. Scissors
  3. Paper