21
\$\begingroup\$

Implement the classic rock paper scissors.

Conditions:

  • user will input 'r', 'p' or 's'
  • program will output 'r', 'p' or 's' and the result
  • program choice ('r', 'p' or 's') has to be pseudo random (I'm looking at you Howard)
  • result can be represented with any printable character, there should always be three possible results for what the user has input (the user wins, lose or is a tie).
  • what happens if the user inputs nothing, or something different that 'r', 'p' or 's' should be not important.

You need to:

  • Provide the golfed code.
  • The ungolfed code
  • How do you invoke the program
  • A sample run

I will choose the answer with less characters, if a tie presents the most up voted answer will be chosen.

Good golfing and may luck be ever in your favor.

I will be posting an answer my self, in Java.

For the ones that live in a mountain under a rock:

r = rock

p = paper

s = scissors

rock: wins to scissors, loses with paper, a tie with rock.

paper: wins to rock, loses with scissors, a tie with paper.

scissors: wins to paper, loses with rock, a tie with scissors.

Current Positions:

  • UN: Username
  • PL: Programming Language
  • CC: Character Count
  • UV: Up votes
╔══════════════════╦════════════╦══════╦════╗
║        UN        ║     PL     ║  CC  ║ UV ║
╠══════════════════╬════════════╬══════╬════╣
║ Howard           ║ GolfScript ║    6 ║ 15 ║
║ primo            ║ Perl       ║   27 ║  7 ║
║ TwiNight         ║ APL        ║   31 ║  4 ║
║ primo            ║ Perl       ║   33 ║  7 ║
║ marinus          ║ APL        ║   36 ║  5 ║
║ primo            ║ Perl       ║   38 ║  7 ║
║ primo            ║ Perl       ║   48 ║  7 ║
║ manatwork        ║ Ruby       ║   54 ║ 13 ║
║ w0lf             ║ GolfScript ║   62 ║  4 ║
║ tmartin          ║ K          ║   67 ║  2 ║
║ Abhijit          ║ Python 3   ║   74 ║  5 ║
║ beary605         ║ Python 3   ║   76 ║  4 ║
║ rlemon           ║ javascript ║   85 ║  4 ║
║ ugoren           ║ C          ║   86 ║  3 ║
║ Egor Skriptunoff ║ LUA        ║   87 ║  4 ║
║ Shmiddty         ║ javascript ║   87 ║  3 ║
║ Fors             ║ Befunge    ║  107 ║  3 ║
║ Briguy37         ║ javascript ║  117 ║  2 ║
║ Vi.              ║ Clojure    ║  129 ║  1 ║
║ Henrik           ║ C#         ║  167 ║  4 ║
║ dystroy          ║ Go         ║  169 ║  1 ║
║ Praveen          ║ javascript ║  250 ║  0 ║
║ ryan             ║ javascript ║  256 ║  1 ║
║ primo            ║ ferNANDo   ║  259 ║  5 ║
║ anakata          ║ Java       ║  259 ║  1 ║
║ epoch            ║ Java       ║  387 ║  1 ║
║ jdstankosky      ║ LOLCODE    ║ 1397 ║ 15 ║
╚══════════════════╩════════════╩══════╩════╝

I can't select Howards answer, since it was a (successful) attempt to bend the rules, but I change them, to make them extra explicit.

primo 27 character answer can't be selected because it's not pseudo random per se

primo -p answer, I'm gonna go with "-p would be counted as 3 bytes: one for the -, one for the p, and one more the necessary whitespace."

Thanks to all who answered, I hope you have had a good time!

NOTE: I will be trying to edit this every other week, to adjust the table, and change my selected answer if someone beats the current one, so If you just got here, post your answer if you want!

\$\endgroup\$
  • 2
    \$\begingroup\$ You might consider adding a clause that all outcomes - Win, Lose, Draw - must be possible. \$\endgroup\$ – primo Apr 10 '13 at 5:14
  • \$\begingroup\$ Since this is popularity, I decided to go with the LOLZ \$\endgroup\$ – jdstankosky Apr 10 '13 at 15:24
  • \$\begingroup\$ I edited the rules before you submitted your answer. Popularity will only be the tie breaker. \$\endgroup\$ – jsedano Apr 10 '13 at 15:27
  • 1
    \$\begingroup\$ Pfft, it's not popularity anymore? Boring. \$\endgroup\$ – jdstankosky Apr 10 '13 at 15:38
  • 1
    \$\begingroup\$ @anakata By traditional Perlgolf rules (compiled by none other than Ton Hospel himself) -p would be counted as 3 bytes: one for the -, one for the p, and one more the necessary whitespace. However, many other competitions on CG.SE have counted each option as a single byte. It's usually up to the author of the question to decide which system to honor. \$\endgroup\$ – primo Apr 12 '13 at 9:15

32 Answers 32

9
\$\begingroup\$

APL, 31

'TWL'[1+3|-/x⍳⎕←⍞,(?3)⌷x←'rps']

x←'rps' Assign string 'rps' to x

(?3)⌷ Choose random integer 1~3, choose that index of x

⍞, Prepend user input to machine choice

⎕← Output resulting string

x⍳ Convert to numerical array by indexOf in x

-/ Difference of the two numbers

1+|3 Modulus 3 and plus 1

'TWL'[...] indexing from 'TWL'

Sample

r
rp
L

User choose rock, program choose paper: Lose

\$\endgroup\$
42
\$\begingroup\$

LOLCODE, 1397

Note: I submitted this before I noticed the winning requirement was changed from popularity with golf tie-break to golf with popularity tie-break.

There's not really any strict syntax, but I'm sure this is acceptable.

HAI
    I HAS A CRAZY, LUCKY, CHALLENGE, TREAT
    I HAS YUMMY ITZ "LOL U LOZED"
    I HAS MEH ITZ "NOWAI TIED"
    I HAS GROSS ITZ "OMG U WONNED"
    I HAS BURNT ITZ "LAME"
    GIMMEH CHALLENGE
    BTW I HOPE I R TEH WINZ
    LOL CRAZY IZ BETWEEN 1 AN 3
    I HAS A SUPA ITZ A BUKKIT
    LOL SUPA'Z 1 R "ROCK"
    LOL SUPA'Z 2 R "PAPER"
    LOL SUPA'Z 3 R "SCIZZORS"
    LOL LUCKY R SUPA'Z CRAZY
    GOT CHALLENGE, WTF?
        OMG "Rock"
            GOT LUCKY, WTF?
                OMG ROCK, LOL TREAT R MEH, GTFO
                OMG PAPER, LOL TREAT R YUMMY, GTFO
                OMG SCIZZORS, LOL TREAT R GROSS, GTFO
            OIC
        OMG "Paper"
            GOT LUCKY, WTF?
                OMG ROCK, LOL TREAT R GROSS, GTFO
                OMG PAPER, LOL TREAT R MEH, GTFO
                OMG SCIZZORS, LOL TREAT R YUMMY, GTFO
            OIC
        OMG "Scissors"
            GOT LUCKY, WTF?
                OMG ROCK, LOL TREAT R YUMMY, GTFO
                OMG PAPER, LOL TREAT R GROSS, GTFO
                OMG SCIZZORS, LOL TREAT R MEH, GTFO
            OIC
        OMGWTF
            VISIBLE "WHAT U SAYZ?", LOL TREAT R BURNT
            GTFO
    OIC
        BOTH SAEM TREAT AN BURNT, O RLY?
            YARLY
                VISIBLE "YOU BURNTED MAH TREAT!"
            NOWAI
                VISIBLE SMOOSH "I GUESSED " AN LUCKY
                VISIBLE TREAT
        KTHX
KTHXBAI

If this were to be successfully executed as RockPaperScissors.LOL, here's what some possible random outcomes could be:

  • Input: Rock - Output: I GUESSED SCIZZORS U WONNED
  • Input: Paper - Output: I GUESSED PAPER NOWAI TIED
  • Input: Scissors - Output: I GUESSED ROCK LOL U LOZED
  • Input: Tuna - Output: WHAT U SAYZ? YOU BURNTED MAH TREAT!
\$\endgroup\$
  • 6
    \$\begingroup\$ +1 just for being LOLCODE. Looks like something I should learn sometime, just for the LOLz. \$\endgroup\$ – Iszi Nov 29 '13 at 8:47
23
\$\begingroup\$

GolfScript

n"Draw"

Above code implements the required functionality. Additionally, it ensures that the player will never be left angry because of a (perceived) unfairness of computer's strategy.

Ungolfed version

n"Draw"

How to invoke the program

The input (a single character of 'r', 'p', 's') has to be provided on STDIN, possibly terminated with newline.

A sample run

> echo r | ruby golfscript.rb rockpaperscissors.gsc
r
Draw

Explanation of the code

For all those not familiar with GolfScript I'll add an detailed explanation of how this code works. The code essentially exists of three parts.

### Computer's strategy ###
# The strategy used to play r/p/s. 
# The computer is so fast, it can really guess in an instance 
# what the player has played. Since the computer should 
# not play unfair, the best strategy is to always go for a 
# draw and choose the same move.
        # on the stack is player's move
        # choose to play the same -> now the computer's move is on the stack

### Fiddle with input ###
# The input may of may not be delimited by newline.
# In order to make the output readable, we'll give
# a newline here.
n       # Push a newline onto the stack

### Give the result ###
# We can skip a complicated calculation of the result
# since we chose to play draw anyways.
"Draw"  # Push the result onto the stack

# Output is printed automatically when GolfScript code terminates.

Notes

Since this is not code-golf but popularity contest I didn't choose the shortest version. Maybe in case of a tie a shorter code will knock out my solution. Nevertheless, for those interested in golfing, the following possibilities are given:

  • Deal only with proper input and force user to provide a newline. This will save one character.
  • The rules have a small insufficiency which allows to save another character by bending the rules. The result can always be printed as "Win" - it was not specified that the correct result has to be printed. But note that players will soon get angry if you choose to implement a cheating program.
  • The output format is not well specified. We can choose 0 as output for draw. Thus, the shortest valid program is the single-character code 0.
\$\endgroup\$
  • 1
    \$\begingroup\$ OK, I have added more verbosity to the rules ! I admit I made two rookie mistakes. \$\endgroup\$ – jsedano Apr 10 '13 at 14:32
  • \$\begingroup\$ "The only winning move is not to play." :P \$\endgroup\$ – Viezevingertjes Nov 25 '13 at 12:38
  • 1
    \$\begingroup\$ +1 for the ungolfed version and the really good explanation \$\endgroup\$ – izlin Jul 21 '14 at 6:32
  • \$\begingroup\$ I suggest n"d", as the question said that the output must be any printable character, it doesn't say anything about using full words. \$\endgroup\$ – ender_scythe Dec 6 '16 at 2:02
20
\$\begingroup\$

Ruby: 61 54 characters

o="rps";p o[c=rand(3)],%w{Draw Win Lose}[c.-o.index$_]

Somehow explained:

The entire problem is reduced to calculating the following results:

  ╲ machine
h  ╲| 0 1 2
u ──┼──────
m 0 │ 0 1 2 
a 1 │ 2 0 1
n 2 │ 1 2 0

Where the numbers mean:

  • choice: 0 rock, 1 paper, 2 scissor
  • result: 0 draw, 1 win, 2 lose

For this I used the formula: machine_choice - human_choice. This occasionally results negative value, but as it is only used as index and negative index is counted backward, will pick the correct array element.

# ┌── choosable object type
# │           ┌── machine's choice numeric code
# │           │                  ┌── result type
# │           │                  │                   ┌── human's choice
# │           │          ┌───────┴───────┐           │
  o="rps";p o[c=rand(3)],%w{Draw Win Lose}[c.-o.index$_]
#           └─────┬────┘                   └─────┬────┘  
#                 └── machine's choice letter    │
#                                                └── result numeric code

Used methods (others then Fixnum's obvious ones):

Ungolfed:

object_type = "rps";
result_type = %w{Draw Win Lose}

machine_choice = rand(3)
human_choice = $_

p object_type[machine_choice]

result_code = machine_choice - object_type.index(human_choice)
p result_type[result_code]

Sample run:

bash-4.2$ ruby -nle 'o="rps";p o[c=rand(3)],%w{Draw Win Lose}[c.-o.index$_]'
r
"p"
"Win"
p
"p"
"Draw"
s
"p"
"Lose"
\$\endgroup\$
  • 1
    \$\begingroup\$ Very similar to mine. [(c-o.index($_)+3)%3] can be replaced by [c.-o.index$_] for 7 bytes. Also, you should add two to your score for -nl at the very least. \$\endgroup\$ – primo Apr 10 '13 at 11:34
  • 1
    \$\begingroup\$ Doh! That was my very first intention, to make use of negative indexes. Seems I forgot to retry this approach after fixing an operand order issue. Thank you, @primo. And one more thank you for the c. tip. \$\endgroup\$ – manatwork Apr 10 '13 at 11:46
  • \$\begingroup\$ I have to say that I love this answer!! \$\endgroup\$ – jsedano Apr 12 '13 at 3:18
  • 2
    \$\begingroup\$ @manatwork the trick is actually .-. Dotted operators have a much lower precedence than their non-dotted counterparts. For example, a/(b+c) can be replaced by a./b+c. \$\endgroup\$ – primo Apr 12 '13 at 4:40
9
\$\begingroup\$

C# (167 characters)

My very first try at golfing.

Golfed

using System;class P{static void Main(string[] i){var m="rspr";var a=m[Environment.TickCount%3];Console.WriteLine(a+" "+(i[0][0]==a?"T":m.Contains(i[0]+a)?"W":"L"));}}

Un-golfed

using System;

class P
{
    static void Main(string[] i)
    {
        var m = "rspr";
        var a = m[Environment.TickCount % 3];
        Console.WriteLine(a + " " + (i[0][0] == a ? "T" : m.Contains(i[0] + a) ? "W" : "L"));
    }
}

Sample Run The app requires single char inputs as argument 1 to the application, either r, s or p.

cmd > app.exe r

All possible outcomes

  • cmd > app.exe r gives output r T (rock, tie)
  • cmd > app.exe r gives output p L (paper, lost)
  • cmd > app.exe r gives output s W (scissors, win)
  • cmd > app.exe p gives output r W (rock, win)
  • cmd > app.exe p gives output p T (paper, tie)
  • cmd > app.exe p gives output s L (scissors, lost)
  • cmd > app.exe s gives output r L (rock, lost)
  • cmd > app.exe s gives output p W (paper, win)
  • cmd > app.exe s gives output s T (scissors, tie)
\$\endgroup\$
9
\$\begingroup\$

Perl 48 bytes

$%=rand 3;print"$%
"^B,(Draw,Lose,Win)[$%-=<>^B]

The script prints the result from the computer's perspective, for example if the player chooses r and the computer chooses s, the result is Lose. $% (format page number) is used to store the computer's move, as it may only contain an integer value, which saves an int cast.

Ungolfed:

# choose a random move index 0, 1, or 2
$cindex = int(rand 3);
# convert this index to a move
# 0 => r, 1 => s, 2 => p
$cmove = "$cindex" ^ B;

# read the player's move
$pmove = <>;
# convert this move to its index
$pindex = $pmove ^ B;

# print computer's move
print $cmove, $/;
# compare indices, and output result
@result = (Draw, Lose, Win);
print $result[$cindex - $pindex];

Sample usage:

$ echo p | perl rps.pl
s
Win

$ echo r | perl rps.pl
r
Draw

$ echo s | perl rps.pl
p
Lose

The script may also be run interactively, by typing your move followed by Enter:

$ perl rps.pl
r
s
Lose

Rule Stretching

Perl 35 +3 bytes

$_=($%=rand 3).(D,L,W)[$%-($_^B)]^B

Requires the -p command line switch (counted as 3 bytes). Each of the outcomes Win, Lose and Draw have been mapped to W, L, D. The newline between the computer's choice and the result has been excluded.

Sample usage:

$ echo r | perl -p rps.pl
sL

Perl 30 +3 bytes

$_=($%=rand 3).($%-($_^B))%3^B

Once again requires -p. Here Win, Lose and Draw have been mapped to 2, 1 and 0 respectively. This is still technically compliant, as they are printable characters.

Sample usage:

$ echo r | perl -p rps.pl
s1

Perl 24 +3 bytes

$_=$^T%3 .($^T-($_^B))%3^B

Requires -p, WLD mapped to 2, 1, 0 as before. Each ^T should be replaced with a literal ascii character 20. This one is admittedly a bit of a stretch; $^T returns the number of seconds since epoch from when the script was started. All outcomes are possible, but it doesn't quite qualify as pseudo-random.

Sample usage:

$ echo r | perl -p rps.pl
s1
\$\endgroup\$
7
\$\begingroup\$

APL (38 36)

c[i],(⌽↑⌽∘'TWL'¨⍳3)[⍞⍳⍨c←'rps';i←?3]

Outputs 'T', 'W' and 'L' for tie, win and lose.

Sample run:

      c[i],(⌽↑⌽∘'TWL'¨⍳3)[⍞⍳⍨c←'rps';i←?3]
p    
rW

(User types 'p' for paper. Computer chooses 'r' (rock), user wins)

Explanation:

  • ⌽↑⌽∘'TWL'¨⍳3: generates the following matrix:
TLW
WTL
LWT
  • ⍞⍳⍨c←'rps': set c to the string 'rps', read user input and get the index of the user input in the string (this will be a value from 1 to 3). This index is used as the Y coordinate into the matrix.
  • i←?3: get a random number from 1 to 3 and store it in i, this is the computer's choice. This is used as the X coordinate into the matrix.
  • c[i]: use i as an index into c, displaying the computer's choice as 'r', 'p', or 's'.
\$\endgroup\$
6
\$\begingroup\$

ferNANDo 1184 (259 golfed) bytes

An interpreter written in Python can be found at the bottom of the linked page.

ferNANDo is a esoteric language which supports only one variable type, boolean, and only one operation, NAND. As you might imagine, this can lead to some fairly long logic to accomplish seemingly simple tasks. It has support for reading from stdin (one byte at a time), writing to stdout (also one byte at a time), conditional loops, and also a random boolean generator.

There are no keywords whatsoever; everything is a variable. A statement's function is determined solely by the number of variables it contains. There are also no comments, so I've done my best to make the code self-commenting. The last four lines might be a bit confusing, but it will probably suffice to say that it prints Win!, Lose, or Draw depending on the outcome.

not sure, but right now i'm guessing you're_not_paper you're_scissors
you're_paper not you're_not_paper
you're_not_scissors not you're_scissors
you're_rock you're_not_paper you're_not_scissors
you're_rock you're_rock

o_shi-
i'm_not_paper right ?
i'm_scissors right ?
i'm_paper not i'm_not_paper
i'm_not_scissors not i'm_scissors
o_shi- i'm_paper i'm_scissors
o_shi- o_shi-
o_shi-
i'm_rock i'm_not_paper i'm_not_scissors
i'm_rock i'm_rock

print right now but only if i'm_not_paper i'm_scissors
print a newline here, not more, not less

i_win_if i'm_scissors you're_paper
or_if i'm_rock you're_scissors
or_even_if i'm_paper you're_rock

i_win i_win_if or_if
i_win i_win
i_win or_even_if

i_lose_if i'm_paper you're_scissors
or_if i'm_scissors you're_rock
or_even_if i'm_rock you're_paper

i_lose i_lose_if or_if
i_lose i_lose
i_lose or_even_if

i_don't_win not i_win
i_don't_lose not i_lose
we_tie i_don't_win i_don't_lose
we_tie we_tie
we_don't_tie not we_tie

print now if i_win i_lose not i_win i_win
print but not we_tie we_don't_tie i_lose i_don't_win we_don't_tie
print right now i_lose i_win i_win we_don't_tie i_don't_win
print i_don't_win but we_tie or i_don't_win we_tie now

The script can be run interactively, by typing your move followed by Enter.

Sample usage (assuming you've named the interpreter nand.py):

$ python nand.py rps.nand
p
s
Win!

$ python nand.py rps.nand
r
r
Draw

$ python nand.py rps.nand
s
p
Lose

Edit: Just to prove that ferNANDo can compete with Java, here's a 'golfed' version at 259 bytes. The logic is sightly different; it checks not win and not tie, which saves a few NAND gates (because then I only need the not versions of the player's moves, and because not lose wasn't required for the output). Not nearly as interesting to read, though.

1 _ _ _ _ _ _ A b
B 1 b
C A B
o
P 1 ?
s 1 ?
p 1 P
S 1 s
o p s
o o
o
r P S
r r
0 1 1 1 0 0 P s
0 0 0 0 1 0 1 0
t s A
u r B
v p C
W t u
W W
W v
t p A
u s B
v r C
D t u
D D
D v
w 1 W
d 1 D
l W D
l l
0 1 0 w l 1 w w
0 1 1 d D l W D
0 1 1 l w w D W
0 W 1 d 0 W d 1
\$\endgroup\$
  • 2
    \$\begingroup\$ HAHAHA o_shi- o_shi- o_shi- This was hilarious self-commenting. \$\endgroup\$ – jdstankosky Apr 11 '13 at 19:53
  • 1
    \$\begingroup\$ @jdstankosky perhaps a bit of an over-reaction to rolling a q, but he does do the sensible thing and reroll. \$\endgroup\$ – primo Apr 12 '13 at 2:30
5
\$\begingroup\$

Python 3.x: 74 Characters

import time
A,f="psr",time.gmtime()[5]%3
print(A[(A.find(input())+f)%3],f)

How it works

Before Machine Proceeds it determines the outcome of the game and based 
on the outcome, it determines the choice which would result in the outcome
viz Human's choice


\     Outcome
 \    0  1  2
  \_____________
H  | 
U 0|  0  1  2
M 1|  1  2  0
A 2|  2  0  1
N  |

Where Choices are represented as 
0 --> Paper
1 --> Scissor
2 --> Rock

Outcome (From Computer's Perspective)
0 --> Draw
1 --> Win
2 --> Fail

Given the sequence of choices as a string
"psr"
So its easy to see, if computer needs to win, it needs to choose the character
next to what human chooses. 
If computer needs to loose, it needs to choose the previous character to what
human chooses


MACHINE's|      CHOICES    |  Formulation
FATE     |-----------------|  For Machine's
         |  P     S      R |  Choice
---------|-----------------|-----------------------------
WIN(1)   |        H ---> M | (CHOICE+1) % 3 = (CHOICE+WIN)%3 
---------|-----------------|-----------------------------
LOSS(2)  |  M     H -----\ | (CHOICE+2)%3   = (CHOICE+LOSS)%3 
         |  ^            | |
         |  |____________| |
---------|-----------------|------------------------------       
DRAW(0)  |        H        | (CHOICE+0)%3   = (CHOICE+DRAW)%3
         |        M        |  
---------|-----------------|         

Combining all the above we have

MACHINE's CHOICE = (HUMAN CHOICE + MACHINE's FATE) % 3

Based on the fate, it determines what should it's choice be based on the formula

result = (User_choice + machines_fate) % no_of_choices

machine_choice = "psr"[result]

Un-golfed Version

import time
choices = "psr"
#time.gmtime() returns the time structure in gmt
#time.gmtime()[5] is the current second tick
fate = time.gmtime()[5]%3
user_choice = input()
result = (choices.find(user_choice)+fate)%len(choices)
machine_choice = choices[result]
print(machine_choice, fate)

Sample run

D:\temp\rivalry>rps.py
r
r 0

D:\temp\rivalry>rps.py
r
p 1

D:\temp\rivalry>rps.py
p
r 2

D:\temp\rivalry>rps.py
p
r 2

D:\temp\rivalry>rps.py
p
s 1

D:\temp\rivalry>rps.py
p
s 1

D:\temp\rivalry>rps.py
p
p 0
\$\endgroup\$
  • 2
    \$\begingroup\$ interesting, deciding beforehand the outcome, then throwing whatever sign to get that result... \$\endgroup\$ – acolyte Apr 10 '13 at 13:57
  • 1
    \$\begingroup\$ I'm not sure time in seconds qualifies under "program choice ('r', 'p' or 's') has to be pseudo random". Milliseconds probably would, though. \$\endgroup\$ – primo Apr 11 '13 at 7:37
4
\$\begingroup\$

Lua, 87

c,n=os.time()%3+1,'rps'print(n:sub(c,c),({'Draw','Win','Defeat'})[(n:find(...)-c)%3+1])

Usage:

$ lua rps.lua p
s   Defeat

Ungolfed:

names = 'rps'
comp_idx = os.time()%3 + 1                -- 1, 2 or 3 (depends on timer)
comp_move = names:sub(comp_idx, comp_idx) -- 'r', 'p' or 's'
user_move = ...                           -- input parameter: 'r', 'p' or 's'
user_idx = names:find(user_move)          -- 1, 2 or 3
delta_idx = (user_idx - comp_idx) % 3     -- 0, 1 or 2
all_results = {'Draw', 'Win', 'Defeat'}   -- [1]=='Draw', [2]=='Win', [3]=='Defeat'
game_result = all_results[delta_idx + 1]
print(comp_move, game_result)
\$\endgroup\$
  • \$\begingroup\$ You can save 3 characters by using 'Lose' instead of 'Defeat' and 'Tie' instead of 'Draw'. ;) \$\endgroup\$ – Roddy of the Frozen Peas Apr 10 '13 at 16:13
4
\$\begingroup\$

GolfScript 62

An alternative GolfScript solution, much more boring than Howard's :).

The program chooses a move randomly and displays the result from the perspective of the user.

The Code

'rssppr'.[6rand=]''+:§@+..&,({?)§\'Lose''Win'if}{;;§'Draw'}if`

Sample run

> echo s | ruby golfscript.rb rps.gs

r"Lose"

Online test

You can run the program and experiment with different inputs here: http://golfscript.apphb.com/?c=OydzJwoKJ3Jzc3BwcicuWzZyYW5kPV0nJys6wqdAKy4uJiwoez8pwqdcJ0xvc2UnJ1dpbidpZn17OzvCpydEcmF3J31pZmA%3D

Note, however, that the parameter (user move) that's usually passed in the command line is now added to the stack in the code itself (there's no way to provide "real" command line parameters in this online tool).

"Ungolfed" version

I don't have any idea what ungolfed means when it comes to GolfScript, so I tried to add comments. Hopefully that will clarify how the code works and make it a bit more readable:

# initially, the input (user's move) is on the stack

'rssppr'                # push the string 'rsspr' on the stack...
.                       # ...twice.

[
    6rand               # get a pseudo-random integer in the [0-5] range
    =                   # use the random index to get 
                        # a letter from the string above

]''+                    # workaroud to get the actual letter instead of the
                        # ASCII code

:§                      # assign the randomly chosen letter (computer's move)
                        # to a nice variable called "§"

@                       # rotates last 3 elements on the stack, bringing
                        # the user input in the uppermost position
                        # So, now we have: "rssppr" <computer_move> <user_move>
                        # on the stack

+                       # concatenate the two moves, so now we have a string
                        # that contains both (ex: "rs")

..                      # copy the move string twice
&                       # do a setwise AND to get the DISTINCT elements
,(                      # get the length of the resulting string and subtract 1
                        # (now we have 0 if the letters were equal and non-zero otherwise)

{                       # beginning of block to execute when the moves are different:

                        # now we have on the stack two strings:
                        #     - the string 'rssppr'
                        #     - the string containing the moves (ex: 'rs')

    ?                   # find the second string inside the first one,
                        # and get the index at which it occurs
                        # (or -1 if it does not)

    )                   # increment that number (we now get 0 if no occurrence, 1 otherwise)

    §                   # recall the § variable (so we display the computermove)
    \                   # rotate the uppermost two stack entries

    'Lose''Win'if       # if the move pair is found in the 'rssppr' string, 
                        # then print 'Lose', otherwise print 'Win'
}

{                       # beginning of block to execute when the moves are identical:

    ;;                  # discard the latest two stack items (not needed in this case)
    §                   # display computer's move
    'Draw'              # display the text 'Draw'
}
if                      # if computer's and user's moves were NOT equal, 
                        # execute the first block.
                        # if they were, execute the second block

`                       # put the last word in quotes to separate it from computer's move
\$\endgroup\$
4
\$\begingroup\$

C, 92 86 chars

main(y){
    srand(time(0));
    y="rps"[rand()%3];
    printf("%c%c\n",y,"LWWTLLW"[getchar()-y+3]);
}

Prints the computer's choice, and the result from the user's point of view - W=you win, L=you lose, T=tie.
The simple formula x-y, given the ASCII values of the choices, gives 0 on draw (obviously) and a unique value in each other case.

\$\endgroup\$
4
\$\begingroup\$

Python 2 (86 84 80 78), Python 3 - 76 chars

0 - tie, 1 - lose, 2 - win

from random import*
a=raw_input()
b=choice('psr')
print(a!=b)+(b+a in'rpsr'),b

from random import*
a=input()
b=choice('psr')
print((a!=b)+(b+a in'rpsr'),b)

Ungolfed

from random import*
moves = 'psr'
inp   = raw_input()
comp  = choice(moves)
match = comp+inp
is_not_tie = inp!=comp
wins = 'r' + moves         #rpsr; rock beats scissors, scissors beats paper, paper beats rock
print is_not_tie + (match in wins), comp

How to run: python file_name_here.py

Problems:
Computer AI: 35 characters

\$\endgroup\$
  • 1
    \$\begingroup\$ Nice! I don't think you need A though, and you can save another char with from random import*. \$\endgroup\$ – grc Apr 10 '13 at 5:12
  • \$\begingroup\$ @grc: thanks, I didn't try from random, because I thought it didn't change it... \$\endgroup\$ – beary605 Apr 10 '13 at 6:20
  • \$\begingroup\$ You can strip a further 2 characters by changing (a==b)*2 to (a!=b) and changing outcomes to "0-tie, 1-win, 2-lose" \$\endgroup\$ – Dhara Apr 10 '13 at 8:59
  • \$\begingroup\$ Sorry, meant ""0-tie, 1-lose, 2-win" \$\endgroup\$ – Dhara Apr 10 '13 at 9:11
  • \$\begingroup\$ @Dhara: Thanks, wouldn't have figured that out. manatwork: Oh! I'll fix that. \$\endgroup\$ – beary605 Apr 10 '13 at 13:12
4
\$\begingroup\$

First try without reviewing others.

golfed: 107 85 bytes

i=prompt(),c="rps"[new Date%3],w={r:"s",p:"r",s:"p"};alert(c+(i==w[c]?2:w[i]==c?1:3))

output is [npc-choice][1:win, 2:loss, 3:tie]

ungolfed:

var input = prompt(),
    choices = ["r","p","s"],
    computer_choice = choices[Math.floor(Math.random() * 3)],
    outcomes = {'r':'s','p':'r','s':'p'},
    winner;

    if( input == outcomes[computer_choice] ) {
        winner = 'NPC';
    } else if ( computer_choice == outcomes[input] ) {
        winner = 'You';
    } else {
        winner = 'No one, it was a Tie!';
    }

    alert('Computer chose: ' + computer_choice + '\n' +
          'The winner is: ' + winner);
\$\endgroup\$
4
\$\begingroup\$

PowerShell: 144 133 117 111 92 73

Changes from original:

  • Completely re-wrote script after seeing Danko Durbic's three-player even or odd solution.
  • Changed $s to a single string instead of a character array.
  • Used IndexOf as a direct method on $s, instead of spelling out the .NET class & method.
  • Removed redundant %3s.

All told, nearly cut the length in half from my original answer!

Golfed code:

$p=($s='rps').IndexOf((read-host));$s[($c=Random 3)];"TWLLTWWLT"[$p+$c*3]

Can be run straight from the console.

Ungolfed, with comments:

# Variable $p will store the player's selection as a ternary digit by finding its position in a string containing the possible choices.
$p=(
    # Possible choices will be stored in a variable, $s, for later reuse.
    $s='rps'
# Get the position of the player's choice from $s.
).IndexOf((read-host));

# Express the computer's choice by outputting the appropriate character from $s.
$s[(
    # Computer's choice will be stored as a ternary digit in $c.
    $c=Random 3
)];

# Outcome for the player will be chosen from a string of possible outcomes by looking up the decimal repesentation of a two-digit ternary number.
# The threes digit is represented by $c, ones digit by $p.
"TWLLTWWLT"[$p+$c*3]

# Variable cleanup - do not include in golfed code.
rv p,s,c

Some sample runs at the console:

enter image description here

\$\endgroup\$
3
\$\begingroup\$

JAVA 259 :(

class c {public static void main(String[]a){char y=a[0].charAt(0);char m="rps".charAt(new java.util.Random().nextInt(3));if(y==m)a[0]="T";else if((y=='r'&& m=='s')||(y=='s'&& m=='p')||(y=='p'&& m=='r'))a[0]="1";else a[0]="0";System.out.println(m+":"+a[0]);}}

Highly ungolfed code:

class c {
    public static void main(String[] a) {
        char y = a[0].charAt(0);
        char m = "rps".charAt(new java.util.Random().nextInt(3));
        if (y == m) {
            a[0] = "T";
        } else if ((y == 'r' && m == 's') || (y == 's' && m == 'p') || (y == 'p' && m == 'r')) {
            a[0] = "1";
        } else {
            a[0] = "0";
        }
        System.out.println(m + ":" + a[0]);
    }
}

Sample runs:

C:>java c r

s:1

C:>java c p

p:T

C:>java c s

s:T

\$\endgroup\$
3
\$\begingroup\$

Befunge: 107 characters

~v@,"w"<   <   <  <
v?v3.14159265@,"l"<
"""358979323846>3-|
rps26433832>:1+|
"""7950>:2+|
>>>:,-:|
28@,"t"<

Slightly clunky. It is shrinkable, the question is by how much.

\$\endgroup\$
3
\$\begingroup\$

JavaScript (87)

Golfed:

o='LDW'[2*((a=prompt())+(b='prs'[new Date%3])!='ps'&a<b|a+b=='sp')+ +(a==b)];alert(b+o)

Ungolfed:

var player = prompt(), 
    computer = 'prs'[new Date%3], // Date mod 3 "pseudo-random"
    outcome = 'LDW'[2*(player+computer != 'ps' 
                    & player < computer 
                    | player + computer == 'sp') // convert boolean W/L outcome to int (0,2)
              +
              +(player == computer)]; // convert D outcome to int (0,1)
alert(computer + outcome);

You can simply paste the code in your browser's javascript console to run it.

If I'm allowed to print the result before printing the computer's selection (83):

alert('LDW'[2*((a=prompt())+(b='prs'[new Date%3])!='ps'&a<b|a+b=='sp')+ +(a==b)]+b)
\$\endgroup\$
2
\$\begingroup\$

K, 67

{-1'f:x,*1?"rps";$[f in b:("pr";"rs";"sp");"W";f in|:'b;"L";"D"]}

Prints W,L,D for win/lose/draw.

Ungolfed:

rps:{[x]
    res:x,*1?"rps";        // join user input to random selection of r,p,s
    -1'f;                  // print the user input and the program selection to stdout
    wins:("pr";"rs";"sp"); // the universe of winning combinations
    losses:|:'wins;        // reverse each win to the get losses

    $[f in wins;    
        "win";
    f in losses;
        "lose";
    "draw"]
    }

Or in Q, which is more readable:

rps:{[x]
    res:x,rand["rps"];        // join user input to random selection of r,p,s
    -1 each f;                // print the user input and the program selection to stdout
    wins:("pr";"rs";"sp");    // the universe of winning combinations
    losses:reverse each wins; // reverse each win to the get losses

    $[f in wins;    
        "win";
    f in losses;
        "lose";
    "draw"]
    }

Sample Run:

k){-1'f:x,*1?"rps";$[f in b:("pr";"rs";"sp");"W";f in|:'b;"L";"D"]}"r"
r
s
"W"
k){-1'f:x,*1?"rps";$[f in b:("pr";"rs";"sp");"W";f in|:'b;"L";"D"]}"s"
s
s
"D"
k){-1'f:x,*1?"rps";$[f in b:("pr";"rs";"sp");"W";f in|:'b;"L";"D"]}"p"
p
s
"L"
\$\endgroup\$
2
\$\begingroup\$

Javascript, 117 characters

Here's a data-driven approach to the problem. This can probably be optimized by generating the win/lose/draw data instead of mapping it manually, but it's a start :)

Golfed:

alert((r=[{v:"r",r:d="D",p:w="W",s:l="L"},{v:"p",r:l,p:d,s:w},{v:"s",r:w,p:l,s:d}][Math.random()*3|0]).v+r[prompt()])

Ungolfed:

//Output the result to the user
alert(
    (
        //Store the random computer outcome data
        randomRPSData =
            //Create the data for if the computer chooses r, p, or s
            [
                {
                    value: "r",
                    r: (d = "Draw"),
                    p: (w = "Win"),
                    s: (l = "Lose")},
                {
                    value: "p",
                    r: l,
                    p: d,
                    s: w},
                {
                    value: "s",
                    r: w,
                    p: l,
                    s: d}
            ]
            //Have the computer pick a random variable
            [Math.random() * 3 | 0]

    //Output the value the computer chose
    ).value

    //Output whether the user won or not
    + r[prompt()]
);

Finally, here's a fiddle with both.

\$\endgroup\$
1
\$\begingroup\$

Javascript: 256

golfed:

i=prompt(),a=['p','r','s'];a=a[Math.floor(Math.random()*(3-1+1))+1];if(i==a){alert('d');}else if(i=='p'){if(a=='s'){alert('l');}else{alert('w');}}else if(i=='r'){if(a=='s'){alert('w');}else{alert('l');}}else if(i=='s'){if(a=='r'){alert('l');}else{alert('w')}}

ungolfed:

i=prompt(),a=['p','r','s'];
a=a[Math.floor(Math.random()*(3-1+1))+1];
if(i==a){
    alert('d');
}
else if(i=='p'){
    if(a=='s'){
        alert('l');
    }else{alert('w');}
}else if(i=='r'){
    if(a=='s'){
        alert('w');
    }else{alert('l');}
}else if(i=='s'){
    if(a=='r'){
        alert('l');
    }else{alert('w')}
} 
\$\endgroup\$
1
\$\begingroup\$

Clojure:

(def r 0) (def s 1) (def p 2)
(def object-name #(get {'p "Paper", 's "Scissors", 'r "Rock"} %))
(def result-name #(get {\d "Draw", \w "Win", \l "Lose"} %))
(defn computer-choice [] (nth ['r 's 'p] (int (rand 3))))
(defn game [a b] (get "dwlldwwld" (+ (* 3 a) b) ))
(defn print-game [user comp result] (print (format
  "User: %s\nComputer: %s\nResult: %s\n" 
  (object-name user) (object-name comp) (result-name result))))
(println "Enter 'p', 's' or 'r' and press return")
(let [comp (computer-choice),  user (read)]  (print-game user comp (game (eval user) (eval comp))))

Mini version (129 code characters):

java -jar clojure.jar -e \
"(def r 0)(def s 1)(def p 2)(let[u(read),c(nth['r 's 'p](int(rand 3)))](print c)(print (get \"dwlldwwld\"(+(* 3(eval u))(eval c)))))"
\$\endgroup\$
1
\$\begingroup\$

JAVA (387) first code golf!

import java.util.HashMap;public class _ {public static void main(String i[]){HashMap l = new HashMap(){{put('r',0);put('p',1);put('s',2);put(0,'T');put(1,'L');put(2,'W');}};char u =i[0].charAt(0);char c ="rps".charAt((int)(Math.random()*3)%3);int[][] m =new int[][]{{0,1,2},{2,0,1},{1,2,0}};System.out.println("U"+u+"C"+c+"R"+(Character)l.get(m[(Integer)l.get(u)][(Integer)l.get(c)]));}}

Ungolfed

import java.util.HashMap;
public class _ {
    public static void main(String[] input) {
       input = new String[] {"s"};
       HashMap lookup = new HashMap(){{
           put('r', 0);
           put('p', 1);
           put('s', 2);
           put(0, 'T');
           put(1, 'L');
           put(2, 'W');
       }};
       char user = input[0].charAt(0);
       char computer = new char[] {'r', 'p', 's'}[(int)(Math.random()*3)%3];
       int[][] matrix = new int[][] {{0,1,2}, {2,0,1}, {1,2,0}};

       Integer userChoice = (Integer) lookup.get(user);
       Integer computerChoice = (Integer) lookup.get(computer);
       Character result = (Character) lookup.get(matrix[userChoice][computerChoice]);

       System.out.println("u:" + user + ",c:" + computer + ",r:" + result);
    }
    /*
     t = 0, l = 1, w = 2
     *
        +---------------+
        | * | r | p | s |
        +---------------+
        | r | 0 | 1 | 2 |
        +---------------+
        | p | 2 | 0 | 1 |
        +---------------+
        | s | 1 | 2 | 0 |
        +---------------+
     */
}

Golfed (Spacing/Indentation)

import java.util.HashMap;
public class _ {
public static void main(String i[]) {
    HashMap l = new HashMap(){{
        put('r',0);put('p',1);put('s',2);put(0,'T');put(1,'L');put(2,'W');
    }};

    char u =i[0].charAt(0);char c = "rps".charAt((int)(Math.random()*3)%3);
    int[][] m =new int[][]{{0,1,2},{2,0,1},{1,2,0}};

    System.out.println("U"+u+"C"+c+"R:"+(Character)l.get(m[(Integer)l.get(u)][(Integer)l.get(c)]));
}}

Not the shortest code, but my first try

\$\endgroup\$
  • 1
    \$\begingroup\$ Some improvements you may apply: 1) import java.util.* 2) HashMap l -> Map l 3) cast to (int) instead of (Integer) 4) new Random().nextInt(3) 5) omit new int[][] 6) remove cast to (Character) 7) use ints instead of chars. \$\endgroup\$ – Howard Apr 11 '13 at 12:30
1
\$\begingroup\$

Go (169)

Golfed :

package main
import("fmt";"os")
func main(){v:=map[uint8]int{114:0,112:1,115:2}
u:=os.Args[1][0]
c:="rps"[os.Getpid()%3]
fmt.Printf("%c\n%c\n",c,"TWL"[(3+v[c]-v[u])%3])}

Ungolfed (as formatted by go fmt):

package main

import (
    "fmt"
    "os"
)

func main() {
    v := map[uint8]int{114: 0, 112: 1, 115: 2}
    u := os.Args[1][0]
    c := "rps"[os.Getpid()%3]
    fmt.Printf("%c\n%c\n", c, "TWL"[(3+v[c]-v[u])%3])
}

Run :

go run main.go p

s

W

\$\endgroup\$
1
\$\begingroup\$

Pyth, 23

J"rps"K+wOJK%-XJ'KXJtK3

Output is in the form:

Tie: 0 Win: 1 Loss: 2

Explanation:

J"rps"             J="rps"
K+wOJ              K=input()+random_choice(J)
K                  print K
  XJ'K             index of K[0] in J
      XJtK         index of K[1] in J
 -XJ'KXJtK         difference of above indexes
%-XJ'KXJtK3        above difference mod 3

Run as follows:

$ cat rps
J"rps"K+wOJK%-XJ'KXJtK3
s
$ cat rps | python3 pyth.py
< Extraneous debug output removed>
sp
1

For only 4 more characters, we can use T for tie, W for win and L for loss:

J"rps"K+wOJKr@"TWL"-XJ'KXJtK

Everything is the same up until the difference of indexes, at which point we use the difference as the index into the string"TWL".


Note: while I did develop this language after the challenge was posted, I had not seen the challenge until today. The challenge did not influence any aspect of the language.

\$\endgroup\$
0
\$\begingroup\$

Groovy, 89

v='rps'
r=new Random().nextInt(3)
print"${v[r]}${'TLW'[((r-v.indexOf(this.args[0]))%3)]}"

Takes user choice as argument. Example:

groovy rps.groovy p
sL
\$\endgroup\$
0
\$\begingroup\$

C# & LinqPad 133

golfed:

char i,c,r;i=Console.ReadLine()[0];var a="prsp";c="prs"[new Random().Next(3)];r=i==c?'T':a.Contains(""+i+c)?'W':'L';(c+">"+r).Dump();

ungolfed:

        char i, c, r; // i for input / c for choosen by computer / r for result
        i = Console.ReadLine()[0]; //getting input in LinqPad
        var a = "prsp"; 
        c = "prs"[new Random().Next(3)]; // Computer choose a random string
        r = i == c ? 'T' : a.Contains("" + i + c) ? 'W' : 'L'; (c + ">" + r).Dump(); //check for win - dump for output in LinqPad

sample output(input was s) : r>L //Computer chooses rock(r) -> so we lost

\$\endgroup\$
0
\$\begingroup\$

JavaScript (79)

Bumping an old one, but here we go ...

With the added bonus that you can use any rock you like pegnatite, pyroxenite, scoria, sovite, kimberlite, trondjemite, tuff or any other. Only limitation is that you can not use p or s ;-)


Input:

r = rock      (Or , ...)
p = paper
s = scissors

Output:

[computers choice][0=Loss, 1=Win, 2=Draw]

Example:

User  Computer  Result
r     r         r2
r     p         p0
r     s         s1

Golfed code:

u=~~{p:1,s:2}[prompt()],c=new Date%3;alert('rps'[c]+(u==c?2:!u&c>1|u&!c|u>1&c))

The main tricks used are:

1. u = ~~{}[prompt()]

       Using object {} and retrieving value by user input from prompt(). So far so good. Then instead of having r : 0 we can force it to be converted to 0 by using the ~~ NOT operator. It is frequently used to floor numbers, but also has the (advantage) of not returning NaN when other operators would, like for example: +{a:1, b:2}['c'].

2. c = new Date%3

       Date is frequently tricked with by e.g. using +new Date to convert it to timestamp directly, else one would get a string representation. Here by using mod one achieve the same effect.

3. 'rps'[c]

       Indexed access on string giving computers choice 0 = r, 1 = p or 2 = s.

4. (u==c ? 2 : !u&c>1 | u&!c | u>1&c )

   IF  u == c
       Draw                    (aka 2)
   ELSE IF !u&c>1|u&!c|u>1&c 
       Win                     (aka 1)
   ELSE
       Loss                    (aka 0)
   ENDIF


...

The ungolfed code can be something like this:

function rock_paper_scissors() {
    var choices = {
            r : 0,
            p : 1,
            s : 2,
        },
        tr_table = ['Rock','Paper','Scissors'],
        user, pc, result
    ;

    function get_input() {
        var input = prompt("Enter your choice `r', `p' or `s':")
                    .toLowerCase();

        if (!/^[rps]/.test(input)) {
            console.warn("Bad input. Please choose `r', `p' or `s'.");
            // return get_input();
            return null;
        }
        return input[0];
    }
    function report(c1, c2) {
        if (c1 === pc) {
            return 'Draw';
        } else if (
            (c1 === 0 && c2  >  1) ||
            (c2 === 0 && c1 === 1) ||
            (c1  >  1 && c2  >  0)
        ) {
            return 'Win';
        } else {
            return 'Loss';
        }
    }

    if ((user = get_input())) {
        user = choices[user];
        pc = Math.floor(Math.random() * 3);
        result  = 
            'Computers choice: ' + tr_table[pc] + ', ' +
            'Your choice: ' + tr_table[user] + ', ' +
            'Result=' +  report(user, pc);
        console.log(result);
    }
    return result;
}

rock_paper_scissors();
\$\endgroup\$
0
\$\begingroup\$

Golfscript - 29

This is an actual answer this time (looking at you, n"Draw" :P ).

'rps'.@\?3rand.@- 3%@@[=]''+\

Ungolfed:

'rps'3rand[=]''+.2$={\;'
T'}{.@'rspr'.@?@@(;\?='
L''
W'if=}if

You can run it with ruby golfscript.rb MyCode.txt, where MyCode.txt is the program code.

Sample runs (all with input "r", but it works with everything) (tie is 0, win is 2, loss is 1):

ruby golfscript.rb MyCode.txt
r0
ruby golfscript.rb MyCode.txt
p2
ruby golfscript.rb MyCode.txt
s1

If you want an explanation of either version and/or see a potential improvement, tell me.

\$\endgroup\$
0
\$\begingroup\$

Javascript, 65 71 70

Without computer choise output: 65

alert('-+0+0+0'['rppssrr'.indexOf('rps'[new Date%3]+prompt())+1])

Just to test that solution is correct:

for(x in {r:0,p:0,s:0})
  for(y in {r:0,p:0,s:0})
    console.log("%s %s %s", x, y, '-+0+0+0'['rppssrr'.indexOf(x+y)+1])

With computer choise output: 71

alert((c='rps'[new Date%3])+'-+0+0+0'['rppssrr'.indexOf(c+prompt())+1])

70

alert((g='rps'[new Date%3]+prompt())+-('srps'.match(g)?-1:g[0]!=g[1]))

and the test:

for(x in {r:0,p:0,s:0})
  for(y in {r:0,p:0,s:0})
    console.log((g=x+y)+-('srps'.match(g)?-1:g[0]!=g[1]))
\$\endgroup\$

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.