2012-03-04 51 views
9

可擴展的解決方案只需通過遊戲的變體去:Rock-Paper-Scissor-Lizard-Spock爲石頭紙剪刀

我已經寫了傳統RPS問題Java代碼,但是當我試圖延長我的代碼爲遊戲的新版本(RPSLS)..我覺得我的代碼是可怕不好。這裏是一個片段:

if (player1.equals("ROCK") && 
     player2.equals("SCISSORS")) { 
     winner = 1; 
    } 
    // Paper covers rock... 
    else if (player1.equals("PAPER") && 
     player2.equals("ROCK")) { 
     winner = 1; 
    } 
    // Scissors cut paper... 
    else if (player1.equals("SCISSORS") && 
     player2.equals("PAPER")) { 
     winner = 1; 
    } 
    else { 
     winner = 2; 
    } 

我實現的代碼不能方便地針對新版本進行擴展 - 以及超過2名球員。這主要是因爲多個if/else或switch/case。我需要一些幫助重新設計我的代碼實現了2個目標:

  1. 進一步修改按R-P-C-L-S的問題。

  2. 支持超過2名玩家。

我不需要代碼,只是一些指導方針應該有所幫助。

謝謝!

編輯:似乎我錯了,認爲這個遊戲可以由2個以上的玩家玩。對於這個錯誤我很抱歉,請忽略第二個要求。

+0

我非常感興趣的是去除if-else塊和硬編碼數據... – SlowAndSteady 2012-03-04 07:17:43

+0

謝謝大家 - 太多好的答案! – SlowAndSteady 2012-03-04 10:58:04

+0

繪製決策表。然後執行決策表。 – 2012-07-07 21:06:15

回答

23

在Rock-Paper-Scissor遊戲中,很容易決定是否在一個循環中使用它們的索引移動勝利b。因此,您不必在您的代碼中手動決定每個組合的結果,因爲這裏提供了其他答案。


對於石頭紙剪刀-斯波克-蜥蜴版本:

讓我們號碼指定給每個移動(0,1,2,3,4)。

注意一舉一動擊敗兩個動作:

  1. 在週期此舉先於它(或提前4案件)
  2. 的前進兩種情況下的週期

所以讓d = (5 + a - b) % 5。然後:

  1. d = 1或D = 3 =>一個奪
  2. d = 2或d = 4 => B贏得
  3. d = 0 =>扎

對於Rock-Paper-Scissor版本:

let d = (3 + a - b) % 3。然後:

  1. d = 1 =>一個奪
  2. d = 2 => B贏得
  3. d = 0 =>扎

泛化對於n> = 3和n奇數:

d = (n + a - b) % n。然後:

  1. 如果d = 0 =>扎
  2. 如果d%2 = 1 =>一個奪
  3. 如果d%2 = 0 => B贏得

enter image description here

+3

這是迄今爲止最優雅的解決方案:) – treaz 2013-03-31 10:24:30

1

我認爲:1打2或5輸給其餘。其餘的2次3或1次輸。 3次4或2次失去休息。剩下的4次5或3次輸了。 5只野獸1或3失敗。對於3名球員,比較2名球員的數值,然後將勝者與球員3進行比較。

+1

這是不正確的。有3名球員,每名球員可以贏得其他球員的勝利。雙贏關係不是聯想:A(搖滾)擊敗B(剪刀)和B(剪刀)擊敗C(紙),但這並不意味着A(搖滾)擊敗C(紙)。 – 2012-03-04 07:19:07

+0

這是正確的。如果A擊敗B,但A不擊敗C,那就是一條領帶。瞭解循環賽比賽。 3次中有1次沒有贏家,但總是有1個贏家1對1 – 2012-03-04 07:21:30

+0

如果2名玩家扔相同,他們只有1名玩家​​。如果3名球員扔同樣的領帶 – 2012-03-04 07:27:12

10

Rock-Paper-Scissors的性質使得您必須明確處理每種可能的狀態組合的情況。因此,您必須覆蓋的案例數量隨着玩家數量呈指數增長,並以多項式(以多項式的階數爲玩家人數)和選項數量呈指數增長。

話雖如此,Java的枚舉對這種事情很好。

這裏是我的刺吧:

import java.util.Arrays; 
import java.util.List; 

enum Result { 
    WIN, LOSE, DRAW; 
} 

enum Option { 

    ROCK(SCISSORS), 
    PAPER(ROCK), 
    SCISSORS(PAPER); 

    private List<Option> beats; 

    private Option(Option... beats) { 
     this.beats = Arrays.asList(beats); 
    } 

    Result play(Option other) { 
     if beats.contains(other) { 
      return Result.WIN; 
     } else if other.beats.contains(this) { 
      return Result.LOSE; 
     } else { 
      return Result.DRAW; 
     } 
    } 

} 

添加更多的情況下(蜥蜴和斯波克),因此是比較簡單的。增加更多球員會更加複雜;除其他外,你必須確定三人洛克紙剪刀的規則是什麼,因爲我不知道。

+1

令人印象深刻,而且非常可讀。 – 2012-03-04 07:35:17

+1

@sch真;我沒有想到這一點。 – Taymon 2012-03-04 18:00:08

+0

雖然這是最優雅的解決方案 - 它不會工作。你在初始化之前不能引用一個選項:(你需要一箇中間的'set'方法 – 2012-03-31 04:31:52

1

設計一個枚舉Choice(ROCK,PAPER,SCISSORS),其中每個枚舉有一個它贏得對手的Set<Choice>

讓每個玩家選擇其中一個選項。

迭代你的玩家,併爲每個玩家迭代玩家列表中的所有其他玩家(對於玩家0,遍歷玩家1,2,3等;對於玩家1,迭代通過球員2,3等; ...)。

對於每場比賽,你有三種可能性:

  1. 一個節拍B(B的選擇是在集合的選擇,一拍):增量的得分
  2. A和B具有相同的選擇:什麼都不做
  3. A不打B:增量B的分數
1

我提出了一個更好的設計in an answer to another post。有一個開關,並切換每種可能組合的單一編碼,編碼時使用位數系統,其基數爲2,因此每個數字將直接映射到若干位,並且所以按位操作很直觀。

三位足以滿足五個選擇,雖然八進制是理想的,但語法很糟糕,所以使用十六進制。然後每個十六進制數字代表你的五次移動中的一次,剩餘空間。一個字節足夠大,兩個編碼兩個球員的同時移動,一個爲8,長爲16。這很簡單。按照代碼示例的鏈接。

1

這是一個基本的邏輯問題。它足夠小,你可以做一個手動真值表(或者跳到k-map),最小化並得到一個解決方案。

所以基本上,你需要先評估一下,如果是平局。然後,你需要評估相對於其他玩家的勝利。這樣做而不需要與每個用戶進行比較可能是一個令人困惑的任務。由於這隻有5個變量,因此您可以找到帶有K-map的最小化解決方案。

您將需要評估每個用戶,根據他們選擇哪個項目並使用特定算法來確定他們是否獲勝。請注意,如果有兩名以上的球員,如果兩個人選擇了相同的球員,但都擊敗了第三名球員,則可以有多個贏家。或者你可以考慮一個領帶,不管。我會假設前者。你也應該檢查所有玩家都沒有選擇相同的物品。

因此,當您正在評估的用戶選擇「搖滾」時,我已經完成了算法的第一部分。

在代碼中,這將是這樣的:

rock=0, paper=0, scissors=0, lizard=0, spock=0, win=0, tie=0 
if (someone chose rock) rock=1 
if (someone chose paper) paper=1 
if (someone chose scissors) scissors=1 
if (someone chose lizard) lizard=1 
if (someone chose spock) spock=1 

// Check if tie/draw, double check these, but I think I got them all 
tie=rock && !paper && spock && lizard || rock && paper && scissors || 
    rock && paper && lizard || spock && paper && scissors || 
    spock && !rock && paper && lizard || !spock && scissors && lizard && paper 

if (tie) die() 

CheckIfUserWins() { 
    if (user chose rock) { 
    win=rock && !paper && !spock 
    if (user chose paper) { 
    // .... calculate using k-map and fill in 

} 

return win 

注意win=rock && !paper && !spock正是將基於什麼在跳動的鏈接,你提供什麼樣的圖形可以預期的。所以你可以去看那個圖形,很快地填入其餘的方程。

該解決方案不依賴於任何數量的玩家,而不是說「某人選擇了X」。因此,它應該擴展到> 5個玩家等。

0

的捷徑:

var n = 5; // Rock, Paper, Scissors, Lizard-Spock 

function calculate(x, y, n) { 
    return 1 - ((n + x - y) % n) % 2; 
} 

function getWinner(p1Gestrure, p2Guesture) { 
    if(p1Gestrure === p2Guesture) { 
    return - 1; // tie 
    } 

    return this.calculate(p1Gestrure, p2Guesture); // 0: win for p1. 1: win for p2. 
} 

我創建了一個cli遊戲,請隨時在那裏看看。 https://github.com/julianusti/rpc-es6