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

刚刚经历了游戏的变种: 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 / cases。 我需要一些帮助来重新设计我的代码以实现这两个目标:

  1. 根据RPCLS问题进一步修改。

  2. 支持超过2名球员。

我不需要代码,只是一些指导方针应该有所帮助。

谢谢 !!

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

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


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

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

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

  1. 在周期中之前的行动(或前面的四个案例)
  2. 在周期中提前两个案例

所以让d = (5 + a - b) % 5 。 然后:

  1. d = 1或d = 3 => a获胜
  2. d = 2或d = 4 => b获胜
  3. d = 0 =>平局

对于Rock-Paper-Scissor版本:

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

  1. d = 1 =>胜利
  2. d = 2 => b胜
  3. d = 0 =>平局

广义对于n> = 3和n odd:

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

  1. 如果d = 0 =>平局
  2. 如果d%2 = 1 => a获胜
  3. 如果d%2 = 0 => b获胜

在此处输入图像描述

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 

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

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

设计一个枚举选项(ROCK,PAPER,SCISSORS),其中每个枚举都有一个Set ,它胜出。

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

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

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

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

我在回答另一篇文章时提出了更好的设计。 只需一个开关,并切换每个可能的移动组合的单个编码,对于编码,使用位数为2的幂的位置编号系统,这样每个数字将直接映射到多个位,并且因此按位操作是直观的。

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

这是一个基本的逻辑问题。 它足够小,你可以做一个手动真值表(或跳到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个玩家等。

最短的方式:

 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