Siapa yang akan memenangkan permainan Rock, Paper, Scissors, Lizard, Spock?

24

Ada beberapa pertanyaan tentang game ini , bahkan kontes sini . Tapi saya pikir semua tantangan dan kontes itu membutuhkan cara untuk secara otomatis menentukan pemenang pertandingan. Begitu:

Tantangan

Diberikan dua input dalam kisaran yang ["rock", "paper", "scissors", "lizard", "spock"]mewakili pilihan untuk pemain 1 dan pemain 2, tentukan pemenang pertandingan.

Aturan

[Winner] [action]    [loser]
-----------------------------
scissors cut         paper
paper    covers      rock
rock     crushes     lizard
lizard   poisons     spock
spock    smashes     scissors
scissors decapitates lizard
lizard   eats        paper
paper    disproves   spock
spock    vaporizes   rock
rock     crushes     scissors

Batasan

  • Input akan berupa sepasang string dalam rentang yang diberikan (tidak ada string lain yang dapat digunakan). Anda bisa menggunakan array chars jika Anda mau, asalkan mereka mewakili salah satu nilai yang disebutkan.
  • Anda dapat memilih untuk menggunakan huruf kecil, huruf besar ( "ROCK") atau unta ( "Rock") untuk string input, selama case yang dipilih sama untuk semua input.
  • Output akan menjadi trio nilai yang menentukan pemenang, yang bisa berupa apa saja yang Anda inginkan asalkan jawabannya konsisten. Contoh: 1jika input pertama menang, 2jika input kedua menang, 0jika ada seri. Atau mungkin Ajika input pertama menang, Bjika input kedua menang, <empty string>jika ada seri.

Tujuan

Ini adalah , jadi semoga program / metode / fungsi / lambda terpendek untuk setiap bahasa menang!

Tes

[Input 1] [Input 2] [Output: 1/2/0]
-----------------------------------
 rock      paper     2
 rock      scissors  1
 lizard    spock     1
 spock     rock      1
 spock     paper     2
 rock      rock      0
Charlie
sumber
Ini berasal dari kotak pasir .
Charlie
1
Sangat terkait .
Stewie Griffin
Saya telah menutupnya sebagai duplikat dari pertanyaan terkait karena pertanyaan yang sama dengan 2 nilai baru dan sedikit variasi pada IO.
Wheat Wizard
4
@WheatWizard terkadang sedikit perubahan pada input menghasilkan output yang sangat berbeda. Pertanyaannya mungkin sangat mirip tetapi dua nilai baru membuat lebih banyak kasus untuk dipertimbangkan, sehingga algoritma yang digunakan di sini cukup berbeda untuk membuat orang berpikir lagi (lihat jawaban dengan caketriknya).
Charlie
4
Saya setuju, dan memilih untuk membuka kembali.
GB

Jawaban:

25

Python 3 , 68 50 48 byte

EDIT: Terima kasih atas 3 trik dari Neil, dan 2 dari Mr. Xcoder

Setiap string input memiliki karakter keempat yang berbeda, jadi saya menggunakannya untuk membedakannya. Jika Anda mengatur elemen-elemen dalam siklus (gunting, kertas, batu, kadal, spock), maka setiap elemen mengalahkan elemen secara langsung setelah itu dan elemen 3 bintik di sebelah kanan, secara siklis. Jadi kami mengurangi posisi input dalam siklus. Jika angka itu adalah 0, itu adalah seri. Jika 1 atau 3, itu adalah kemenangan untuk pemain pertama. Dalam solusi asli saya, perbedaan siklus akan diindeks ke string "210100" untuk membedakan hasil permainan. Neil entah bagaimana menemukan ini dapat dicapai tanpa pengindeksan dengan menambahkan 7 dan mengambil modulus oleh 3. Edit: Awalnya saya menggunakan karakter kedua untuk mengidentifikasi string, tetapi jika Anda menggunakan keempat dan membalikkan siklus, Anda mendapatkan kue. Dan kita semua bisa menggunakan lebih banyak kue.

lambda x,y,z="cake".find:(7+z(y[3])-z(x[3]))%5%3

Cobalah online!

Versi yang lebih lama:

lambda x,y,z="caoip".index:(7+z(y[1])-z(x[1]))%5%3

Cobalah online!

Versi asli:

b="caoip"
def r(x,y):return"210100"[(b.index(y[1])-b.index(x[1]))%5]

Cobalah online!

Melakukan apa
sumber
1
50 byte: Cobalah secara online!
Neil
6
Selamat datang di PPCG!
Steadybox
1
49 byte: Cobalah secara online! (beralih .indexke .find)
Tn. Xcoder
1
48 byte: Cobalah secara online! (Anda tidak perlu p, "chaoi"cukup)
Tn. Xcoder
14

JavaScript (ES6), 56 byte

Mengambil input dalam sintaks currying (a)(b). Kembali 0jika A menang, 1jika B menang, atau falseuntuk seri.

a=>b=>a!=b&&a>b^614>>((g=s=>parseInt(s,31)%9)(a)^g(b))&1

Demo

Bagaimana?

Kami mendefinisikan fungsi hash H () sebagai:

H = s => parseInt(s, 31) % 9

Ini memberi:

s          | H(s)
-----------+-----
"rock"     |  2
"paper"    |  8
"scissors" |  1
"lizard"   |  3
"spock"    |  4

Diberikan dua input a dan b , kami mempertimbangkan pernyataan berikut:

  1. apakah kita memiliki > b ? (dalam urutan leksikografis)
  2. apakah b memenangkan permainan?
  3. berapa nilai N = H (a) XOR H (b) ?

Dari (1) dan (2), kami menyimpulkan apakah hasil dari a> b harus dibalik untuk mendapatkan pemenang yang benar dan kami menyimpan bendera ini di bit ke-N dari bitmask pencarian.

a        | H(a) | b        | H(b) | N  | a > b | b wins | invert
---------+------+----------+------+----+-------+--------+-------
rock     |   2  | paper    |   8  | 10 | Yes   | Yes    | No
rock     |   2  | scissors |   1  |  3 | No    | No     | No
rock     |   2  | lizard   |   3  |  1 | Yes   | No     | Yes
rock     |   2  | spock    |   4  |  6 | No    | Yes    | Yes
paper    |   8  | rock     |   2  | 10 | No    | No     | No
paper    |   8  | scissors |   1  |  9 | No    | Yes    | Yes
paper    |   8  | lizard   |   3  | 11 | Yes   | Yes    | No
paper    |   8  | spock    |   4  | 12 | No    | No     | No
scissors |   1  | rock     |   2  |  3 | Yes   | Yes    | No
scissors |   1  | paper    |   8  |  9 | Yes   | No     | Yes
scissors |   1  | lizard   |   3  |  2 | Yes   | No     | Yes
scissors |   1  | spock    |   4  |  5 | No    | Yes    | Yes
lizard   |   3  | rock     |   2  |  1 | No    | Yes    | Yes
lizard   |   3  | paper    |   8  | 11 | No    | No     | No
lizard   |   3  | scissors |   1  |  2 | No    | Yes    | Yes
lizard   |   3  | spock    |   4  |  7 | No    | No     | No
spock    |   4  | rock     |   2  |  6 | Yes   | No     | Yes
spock    |   4  | paper    |   8  | 12 | Yes   | Yes    | No
spock    |   4  | scissors |   1  |  5 | Yes   | No     | Yes
spock    |   4  | lizard   |   3  |  7 | Yes   | Yes    | No

Karenanya bit:

bit | value
----+-----------
 0  | 0 (unused)
 1  | 1
 2  | 1
 3  | 0
 4  | 0 (unused)
 5  | 1
 6  | 1
 7  | 0
 8  | 0 (unused)
 9  | 1
10  | 0
11  | 0
12  | 0

Membaca ini dari bawah ke atas dan mengabaikan angka nol di depan, angka ini menghasilkan 1001100110 , atau 614 dalam desimal.

Arnauld
sumber
6

05AB1E , 16 byte

ε'³²s3èk}Æ7+5%3%

Cobalah online! atau sebagai Test Suite

Penjelasan

Menggunakan cake-trick yang sangat bagus dari user507295

ε       }          # apply to each in the input pair
    s3è            # get the 4th letter
 '³²   k           # get its cake-index
         Æ         # reduce by subtraction
          7+       # add 7
            5%3%   # mod by 5 and then 3
Emigna
sumber
4

Ruby , 36 byte

->a,b{(2+a.sum%88%6-b.sum%88%6)%5%3}

Kembali 0jika pemain pertama menang, 1jika pemain kedua menang, dan 2untuk hasil seri.

Berdasarkan jawaban user507295 tetapi menggunakan rumus matematika untuk melakukan hash. a.sumadalah jumlah dari semua kode ASCII dari string a, mod 1<<16dan dimaksudkan sebagai checksum yang belum sempurna. Hash ditemukan menggunakan kode berikut:

1.upto(99){|j|p j,["scissors","paper","rock","lizard","spock"].map{|i|i.sum%j%6}}

Ini menghasilkan dua nilai jyang memberikan hash yang cocok untuk huruf kecil, yaitu 88 dan 80, yang keduanya memberikan urutan menurun [3,2,1,0,4](atau [4,3,2,1,0]jika spock berputar ke awal.)

Seperti dijelaskan dalam jawaban lain, hash yang memberikan perbedaan modulo 5 konstan untuk elemen berurutan dalam urutan di atas diperlukan untuk membuat (h[a]-h[b])%5rumus bekerja. Setiap elemen mengalahkan elemen 1 atau 3 tempat ke kanan dan kehilangan ke elemen 2 atau 4 tempat ke kanan.

Cobalah online!

Level River St
sumber
4

JavaScript (ES6), 63 54 53 49 byte

f=
(l,r,g=s=>"cake".search(s[3]))=>(7+g(r)-g(l))%5%3
<div onchange=o.textContent=`RLT`[f(a.selectedOptions[0].value,b.selectedOptions[0].value)]>L: <select id=a><option>Rock<option>Paper<option>Scissors<option>Lizard<option>Spock</select> R: <select id=b><option>Rock<option>Paper<option>Scissors<option>Lizard<option>Spock</select> Winner: <span id=o>T

Port of my golf untuk jawaban @ WhatToDo. Catatan: snippet menerjemahkan hasil numerik menjadi sesuatu yang sedikit kurang dapat dibaca. Sunting: Disimpan 1 byte berkat @Arnauld. Disimpan 4 byte berkat @ovs.

Neil
sumber
@ovs Ugh, saya tidak melakukan porting golf ke jawaban WhatToDo dengan cukup keras ...
Neil
3

C, 53bytes

a="FÈ..J..ÁE";
z=*++y==*++x?0:a[*y&47>>1]>>*++x&7&1+1;

Saya telah memperlakukan masalah ini sebagai mesin keadaan, di mana ada 25 negara sebagaimana didefinisikan oleh dua, lima masukan negara.

Dengan mendefinisikan hasil state dalam array bit. Saya mencari hasilnya di dalam dengan menggunakan spidol unik dalam input.

Seperti dicatat dalam solusi lain, karakter 2, 3 dan 4 adalah unik di antara input yang mungkin. Saya telah memusatkan penggunaan pada karakter 2 dan 3 yang saya gunakan untuk memilih bit yang sesuai dalam array jawaban saya.

Dalam Character 2, bit 1 hingga 4 dengan jelas mengidentifikasi input. Dengan menutupi bit-bit ini dan menggeser secara tepat [itulah "* y & 47 >> 1"], input dapat dicatat sebagai 0, 1, 4, 7 atau 8. Oleh karena itu string jawaban saya memiliki 9 karakter. (bit menarik yang dipisahkan)

character 2:
a 61   011 0000 1
c 63   011 0001 1
i 69   011 0100 1
p 70   011 1000 0
o 6f   011 0111 1

Dalam karakter 3, bit 0, 1 dan 2 mengidentifikasi input dengan jelas. Dengan Masking bit-bit ini (menggeser tidak diperlukan) [itulah "* x & 7"], input dapat dicatat sebagai 0, 1, 2, 3 atau 7. (bit menarik yang dipisahkan)

character 3
p 70   01110 000
i 69   01101 001
z 7a   01111 010
o 6f   01101 111
c 63   01100 011

String jawaban kemudian dapat dihitung dengan hanya mengisi bit untuk karakter yang sesuai.

0th char represents X=paper
1st char represents X=scissors
4th char represents X=Lizard
7th char represents X=Rock
8th char represents X=Spock

0th bit represents Y=Paper
1st bit represents Y=Scissors
2nd bit represents Y=Lizard
3rd bit represents Y=Rock
7th bit represents Y=Spock

Jadi, atur bit di char di mana Y menang

char  7654 3210   in hex    in ascii
0     0100 0110    46         F
1     1100 1000    c8         È
2     0100 0000    d/c        .
3     0100 0000    d/c        .
4     0100 1010    4a         J
5     0100 0000    d/c        .
6     0100 0000    d/c        .
7     1100 0001    c1         Á
8     0100 0101    45         E

Maka logikanya sederhana: jika karakter kedua sama maka gambarlah, jika tidak, dapatkan karakter ascii berdasarkan karakter kedua y dan geser bit dengan karakter ketiga x dan tambahkan satu. Ini membuat jawaban 0 untuk seri, 1 untuk x menang dan 2 untuk y menang.

meismich
sumber
Selamat datang di PPCG! Ini adalah jawaban yang bagus dan dipikirkan dengan matang.
FantaC
1

Clojure, 130 118 byte

-12 byte dengan menyingkirkan penggunaan aneh saya comp.

(fn[& m](let[[p q](map #(apply +(map int(take 2 %)))m)d(- p q)](cond(= d 0)0(#{5 -16 12 -14 13 1 4 -18 2 11}d)1 1 2)))

Saya pikir saya pintar, tetapi ini berakhir naif dibandingkan dengan beberapa jawaban lain, dan lebih lama.

Mengambil 2 huruf pertama dari setiap string bergerak, mendapatkan kode char, dan menjumlahkannya. Itu kemudian mengurangi jumlah untuk mendapatkan d. Jika d0, ini adalah dasi (0), jika dalam himpunan #{5 -16 12 -14 13 1 4 -18 2 11}, p1 menang (1), atau p2 menang (2).

(defn decide [& moves] ; Using varargs so I don't need to duplicate the steps.
  ; Pop the first 2 chars of each string, convert them to their ASCII code, and sum them.
  (let [[p1 p2] (map #(apply + (map int (take 2 %))) moves)
        d (- p1 p2)]

    (cond
      (= d 0) ; A tie
      0

      (#{5 -16 12 -14 13
         1 4 -18 2 11} d) ; P1 Wins
      1

      :else ; P2 Wins
      2)))

Untuk mendapatkan "angka ajaib" yang menentukan apakah P1 menang, saya berlari

(let [ms ["rock", "paper", "scissors", "lizard", "spock"]]
  (for [p1 ms
        p2 ms]

    ; Same as above
    (let [[p q] (map #(apply + (map int (take 2 %))) [p1 p2])
          d (- p q)]

      [p1 p2 d])))

Yang menghasilkan daftar dnilai untuk setiap skenario yang mungkin:

(["rock" "rock" 0]
 ["rock" "paper" 16]
 ["rock" "scissors" 11]
 ["rock" "lizard" 12]
 ["rock" "spock" -2]
 ["paper" "rock" -16]
 ["paper" "paper" 0]
 ["paper" "scissors" -5]
 ["paper" "lizard" -4]
 ["paper" "spock" -18]
 ["scissors" "rock" -11]
 ["scissors" "paper" 5]
 ["scissors" "scissors" 0]
 ["scissors" "lizard" 1]
 ["scissors" "spock" -13]
 ["lizard" "rock" -12]
 ["lizard" "paper" 4]
 ["lizard" "scissors" -1]
 ["lizard" "lizard" 0]
 ["lizard" "spock" -14]
 ["spock" "rock" 2]
 ["spock" "paper" 18]
 ["spock" "scissors" 13]
 ["spock" "lizard" 14]
 ["spock" "spock" 0])

Lalu saya membandingkan grafik kemenangan dengan output ini. Untungnya tidak ada "tabrakan" selain 0.

Carcigenicate
sumber