Rock-Paper-Scissor的可扩展解决方案

时间:2012-03-04 07:06:56

标签: java algorithm

刚刚浏览了游戏的变体:Rock-Paper-Scissor-Lizard-Spock

我已经为传统的R-P-S问题编写了一个Java代码,但是当我尝试将代码扩展到更新版本的游戏(R-P-S-L-S)时......我觉得我的代码非常不好。这是一个片段:

 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 / cases。我需要一些帮助重新设计我的代码以实现2个目标:

  1. 根据R-P-C-L-S问题进行进一步修改。

  2. 支持超过2名玩家。

  3. 我不需要代码,只需要一些指导方针即可。

    谢谢!

    编辑:似乎我错误地认为这个游戏可以由超过2名玩家玩。我很抱歉这个错误,请忽略第二个要求。

7 个答案:

答案 0 :(得分:29)

在Rock-Paper-Scissor游戏中,很容易决定是否在一个周期内使用他们的索引来移动胜利。因此,您不必在代码中手动确定每个组合的结果,如此处的其他答案所示。


对于Rock-Paper-Scissor-Spock-Lizard版本:

让我们为每个动作分配一个数字(0,1,2,3,4)。

请注意,每一步都有两个动作:

  1. 在周期中前面的移动(或前面四个案例)
  2. 在周期中向前移动两个案例
  3. 所以让d = (5 + a - b) % 5。然后:

    1. d = 1或d = 3 =>赢了
    2. d = 2或d = 4 => b胜利
    3. d = 0 =>领带

    4. 对于Rock-Paper-Scissor版本:

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

      1. d = 1 =>赢了
      2. d = 2 => b胜利
      3. d = 0 =>领带

      4. 泛化对于n> = 3和n odd:

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

        1. 如果d = 0 =>领带
        2. 如果d%2 = 1 =>赢了
        3. 如果d%2 = 0 => b胜利
        4. enter image description here

答案 1 :(得分: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;
        }
    }

}

添加更多案例(Lizard和Spock)因此相对简单。增加更多玩家会更复杂;除此之外,你必须确定三人Rock-Paper-Scissors的规则是什么,因为我不知道。

答案 2 :(得分:1)

我认为:1比2或5输给其他人。 2节拍3或1输给其他人。 3次节拍4或2失去休息。 4节拍5或3输给其他人。 5只野兽1或3输给其余的。对于3名玩家,比较2名玩家的值,然后将胜者与玩家3进行比较。

答案 3 :(得分:1)

设计一个枚举Choice(ROCK,PAPER,SCISSORS),其中每个枚举都有一个Set<Choice>赢得它。

让每个玩家选择其中一个选择。

通过你的玩家进行迭代,并且对于每个玩家,在玩家列表中迭代跟在他后面的所有其他玩家(对于玩家0,通过玩家1,2,3等迭代;对于玩家1,迭代通过球员2,3等等; ......)。

对于每场比赛,您有三种可能性:

  1. 节拍B(B的选择在A节拍的选择中):增加A的分数
  2. A和B有相同的选择:什么都不做
  3. A没有击败B:增加B的分数

答案 4 :(得分:1)

我提出了更好的设计in an answer to another post。只需一个开关,并切换每个可能的移动组合的单个编码,对于编码,使用位数为2的基数的位置编号系统,这样每个数字将直接映射到多个位,并且所以按位操作是直观的。

三个位对于五个选择就足够了,虽然八进制是理想的,但语法很糟糕,所以使用十六进制。然后,每个十六进制数字代表您的五个移动中的一个,有空余空间。一个字节足够大,两个编码两个玩家的同时移动,一个是8的int,一个是16的长。这很简单。请点击链接获取代码示例。

答案 5 :(得分: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”之外,此解决方案不依赖于任何数量的玩家。所以它应该扩展到&gt; 5名球员等

答案 6 :(得分: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