下面的代码确实按照我需要的方式工作,但它很丑,过多或其他一些事情。我已经看了公式,并试图写一些解决方案,但我最终得到了类似数量的语句。

在这种情况下,是否有一种数学公式对我有益,或者是否可以接受16个if语句?

为了解释代码,这是一款基于同时回合制的游戏。两名玩家各有四个操作按钮,结果来自一个数组(0-3),但变量“1”和“2”可以赋值任何东西,如果这有帮助的话。结果是,0 =双方都不赢,1 = p1赢,2 = p2赢,3 =双方都赢。

public int fightMath(int one, int two) {

    if(one == 0 && two == 0) { result = 0; }
    else if(one == 0 && two == 1) { result = 0; }
    else if(one == 0 && two == 2) { result = 1; }
    else if(one == 0 && two == 3) { result = 2; }
    else if(one == 1 && two == 0) { result = 0; }
    else if(one == 1 && two == 1) { result = 0; }
    else if(one == 1 && two == 2) { result = 2; }
    else if(one == 1 && two == 3) { result = 1; }
    else if(one == 2 && two == 0) { result = 2; }
    else if(one == 2 && two == 1) { result = 1; }
    else if(one == 2 && two == 2) { result = 3; }
    else if(one == 2 && two == 3) { result = 3; }
    else if(one == 3 && two == 0) { result = 1; }
    else if(one == 3 && two == 1) { result = 2; }
    else if(one == 3 && two == 2) { result = 3; }
    else if(one == 3 && two == 3) { result = 3; }

    return result;
}

当前回答

当我在1 / 2和结果之间画一个表时,我看到了一个模式,

if(one<2 && two <2) result=0; return;

以上将减少至少3个if语句。我没有看到一个集合模式,也无法从给出的代码中收集到很多信息——但如果可以推导出这样的逻辑,它将减少大量的if语句。

希望这能有所帮助。

其他回答

除了JAB之外,我不喜欢任何提出的解决方案。其他方法都不容易阅读代码和理解正在计算的内容。

以下是我如何编写这段代码——我只会c#,不懂Java,但你可以想象:

const bool t = true;
const bool f = false;
static readonly bool[,] attackResult = {
    { f, f, t, f }, 
    { f, f, f, t },
    { f, t, t, t },
    { t, f, t, t }
};
[Flags] enum HitResult 
{ 
    Neither = 0,
    PlayerOne = 1,
    PlayerTwo = 2,
    Both = PlayerOne | PlayerTwo
}
static HitResult ResolveAttack(int one, int two)
{
    return 
        (attackResult[one, two] ? HitResult.PlayerOne : HitResult.Neither) | 
        (attackResult[two, one] ? HitResult.PlayerTwo : HitResult.Neither);
}    

现在,这里计算的内容更加清楚了:这强调了我们正在计算谁受到了什么攻击,并返回两个结果。

然而,这可能会更好;布尔数组有点不透明。我喜欢表格查找方法,但我更倾向于以一种能够明确游戏语义的方式来编写它。也就是说,与其“攻击为零,防御为一,结果是没有命中”,不如找到一种方法,让代码更清楚地暗示“低踢攻击和低阻挡防御,结果是没有命中”。让代码反映游戏的业务逻辑。

一个好的观点是将规则定义为文本,这样你就可以更容易地推导出正确的公式。这是从laalto漂亮的数组表示中提取出来的:

{ 0, 0, 1, 2 },
{ 0, 0, 2, 1 },
{ 2, 1, 3, 3 },
{ 1, 2, 3, 3 }

这里我们有一些一般性的评论,但你应该用规则来描述它们:

if(one<2) // left half
{
    if(two<2) // upper left half
    {
        result = 0; //neither hits
    }
    else // lower left half
    {
        result = 1+(one+two)%2; //p2 hits if sum is even
    }
}
else // right half
{
    if(two<2) // upper right half
    {
        result = 1+(one+two+1)%2; //p1 hits if sum is even
    }
    else // lower right half
    {
        return 3; //both hit
    }
}

当然,您可以将其压缩为更少的代码,但理解您编写的代码而不是寻找紧凑的解决方案通常是一个好主意。

if((one<2)&&(two<2)) result = 0; //top left
else if((one>1)&&(two>1)) result = 3; //bottom right
else result = 1+(one+two+((one>1)?1:0))%2; //no idea what that means

对复杂的p1/p2点击的一些解释会很棒,看起来很有趣!

试试开关外壳……

看看这里或这里关于它的更多信息

switch (expression)
{ 
  case constant:
        statements;
        break;
  [ case constant-2:
        statements;
        break;  ] ...
  [ default:
        statements;
        break;  ] ...
}

您可以向它添加多个条件(不是同时添加),甚至可以在没有满足其他情况的情况下添加默认选项。

PS:只有在满足一个条件的情况下。

如果两种情况同时出现。我认为开关不能用。 但是您可以减少这里的代码。

Java开关语句多种情况

说实话,每个人都有自己的代码风格。我没想到性能会受到太大影响。如果您比使用开关箱版本更能理解这一点,那么请继续使用此版本。

您可以嵌套if语句,因此最后的if检查可能会略微提高性能,因为它不会经过那么多if语句。但是在你的java基础课程中,它可能不会有什么好处。

else if(one == 3 && two == 3) { result = 3; }

所以,与其…

if(one == 0 && two == 0) { result = 0; }
else if(one == 0 && two == 1) { result = 0; }
else if(one == 0 && two == 2) { result = 1; }
else if(one == 0 && two == 3) { result = 2; }

你会做……

if(one == 0) 
{ 
    if(two == 0) { result = 0; }
    else if(two == 1) { result = 0; }
    else if(two == 2) { result = 1; }
    else if(two == 3) { result = 2; }
}

按照你的喜好重新格式化。

这并没有使代码看起来更好,但我相信它可能会加快一点速度。

由于您的数据集非常小,您可以将所有内容压缩为1个长整数并将其转换为公式

public int fightMath(int one,int two)
{
   return (int)(0xF9F66090L >> (2*(one*4 + two)))%4;
}

更多的位变体:

这利用了所有东西都是2的倍数这一事实

public int fightMath(int one,int two)
{
   return (0xF9F66090 >> ((one << 3) | (two << 1))) & 0x3;
}

神奇常数的起源

我能说什么呢?世界需要魔法,有时某些事情的可能性需要它的创造。

解决OP问题的函数的本质是从2个数字(1,2),域{0,1,2,3}到范围{0,1,2,3}的映射。每个答案都涉及了如何实现该映射。

此外,您可以在许多答案中看到问题的重述,即12个以4为基数的2位数字N(1,2)的映射,其中1是数字1,2是数字2,N = 4* 1 + 2;N ={0,1,2,…,15}——16个不同的值,这很重要。函数的输出是一个以4为基数的1位数字{0,1,2,3}——4个不同的值,这也很重要。

现在,1位以4为底的数可以表示为2位以2为底的数;{0,1,2,3} ={00,01,10,11},因此每个输出只能用2位编码。从上面来看,只有16种不同的输出可能,所以16*2 = 32位是编码整个地图所必需的;这些都可以装进一个整数。

常数M是映射M的编码,其中M(0)以位M[0:1]编码,M(1)以位M[2:3]编码,M (n)以位M[n*2:n*2+1]编码。

剩下的就是索引和返回常量的右边部分,在这种情况下,你可以将M右移2*N次,并取2个最低有效位,即(M >> 2*N) & 0x3。表达式(one << 3)和(two << 1)只是相乘,同时注意到2*x = x << 1和8*x = x << 3。