太多'如果'声明?

时间:2014-03-19 09:24:55

标签: if-statement math formula

以下代码确实可以满足我的需求,但它很难看,过多或其他许多东西。我已经看过公式并尝试编写一些解决方案,但我最终得到了相似数量的陈述。

在这种情况下,是否有一种数学公式会使我受益?如果语句可以接受,是否有16种?

为了解释代码,这是一种基于同步回合的游戏。两个玩家每个都有四个动作按钮,结果来自一个数组(0-3),但是变量'one'和&如果这有帮助,可以分配“两个”。结果是,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;
}

26 个答案:

答案 0 :(得分:595)

如果你不能提出一个公式,你可以使用一个表来获得如此有限的结果:

final int[][] result = new int[][] {
  { 0, 0, 1, 2 },
  { 0, 0, 2, 1 },
  { 2, 1, 3, 3 },
  { 1, 2, 3, 3 }
};
return result[one][two];

答案 1 :(得分:201)

由于您的数据集太小,您可以将所有内容压缩为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个数字(一个,两个),域{0,1,2,3}到范围{0,1,2,3}的映射。每个答案都涉及如何实施该地图。

另外,你可以在一些答案中看到问题的重述,作为1个2位数字4的数字N(一,二)的映射,其中一个是数字1,两个是数字2,N = 4 *一+二; N = {0,1,2,...,15} - 十六个不同的值,这很重要。函数的输出是一个1位数的基数4数{0,1,2,3} - 4个不同的值,也很重要。

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

常数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>&gt; 2 * N)&amp; ; 0x3。表达式(一个<&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 1&gt; 1和8 * x = x&lt;&lt; 3。

答案 2 :(得分:98)

除了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);
}    

现在更清楚的是这里计算的内容:这强调我们计算的是受到攻击的人,并返回两个结果。

然而,这可能会更好;布尔数组有些不透明。我喜欢表查找方法,但我倾向于以这样的方式编写它,以便明确预期的游戏语义。也就是说,而不是&#34; 0的攻击和1的防御导致没有命中&#34;而是找到一种方法使代码更清楚地暗示&#34;低踢攻击和低防御导致没有命中&#34;。 让代码反映游戏的业务逻辑。

答案 3 :(得分:87)

您可以创建包含结果的矩阵

int[][] results = {{0, 0, 1, 2}, {0, 0, 2, 1},{2, 1, 3, 3},{2, 1, 3, 3}};

如果您想获得价值,您将使用

public int fightMath(int one, int two) {
  return this.results[one][two]; 
}

答案 4 :(得分:69)

其他人已经提出了我的初步想法,即矩阵方法,但除了合并if语句之外,您还可以通过确保提供的参数在预期范围内并使用就地返回来避免您拥有的某些内容(我已经看到一些编码标准强制执行功能的单点退出,但我发现多次返回对于避免箭头编码非常有用,并且在Java中存在普遍存在的例外情况&#39;无论如何,严格执行这样一条规则并没有太大意义,因为在方法中抛出的任何未捕获的异常都是可能的退出点。嵌套切换语句是可能的,但是对于您在这里检查的小范围值,我发现语句是否更紧凑并且不太可能导致性能差异,特别是如果您的程序是基于回合的而是比实时。

public int fightMath(int one, int two) {
    if (one > 3 || one < 0 || two > 3 || two < 0) {
        throw new IllegalArgumentException("Result is undefined for arguments outside the range [0, 3]");
    }

    if (one <= 1) {
        if (two <= 1) return 0;
        if (two - one == 2) return 1;
        return 2; // two can only be 3 here, no need for an explicit conditional
    }

    // one >= 2
    if (two >= 2) return 3;
    if (two == 1) return 1;
    return 2; // two can only be 0 here
}

由于输入 - >结果映射的部分不规则,这最终会比其他情况下的可读性差。我喜欢矩阵样式,因为它的简单性以及如何设置矩阵以便在视觉上有意义(尽管这部分受到我对卡诺图的记忆的影响):

int[][] results = {{0, 0, 1, 2},
                   {0, 0, 2, 1},
                   {2, 1, 3, 3},
                   {2, 1, 3, 3}};

更新:鉴于你提到了阻止/命中,这里对使用属性/属性保持枚举类型的输入和结果的功能进行了更彻底的改变,并且稍微修改了结果以解决阻塞问题,这应该会产生更具可读性的功能。

enum MoveType {
    ATTACK,
    BLOCK;
}

enum MoveHeight {
    HIGH,
    LOW;
}

enum Move {
    // Enum members can have properties/attributes/data members of their own
    ATTACK_HIGH(MoveType.ATTACK, MoveHeight.HIGH),
    ATTACK_LOW(MoveType.ATTACK, MoveHeight.LOW),
    BLOCK_HIGH(MoveType.BLOCK, MoveHeight.HIGH),
    BLOCK_LOW(MoveType.BLOCK, MoveHeight.LOW);

    public final MoveType type;
    public final MoveHeight height;

    private Move(MoveType type, MoveHeight height) {
        this.type = type;
        this.height = height;
    }

    /** Makes the attack checks later on simpler. */
    public boolean isAttack() {
        return this.type == MoveType.ATTACK;
    }
}

enum LandedHit {
    NEITHER,
    PLAYER_ONE,
    PLAYER_TWO,
    BOTH;
}

LandedHit fightMath(Move one, Move two) {
    // One is an attack, the other is a block
    if (one.type != two.type) {
        // attack at some height gets blocked by block at same height
        if (one.height == two.height) return LandedHit.NEITHER;

        // Either player 1 attacked or player 2 attacked; whoever did
        // lands a hit
        if (one.isAttack()) return LandedHit.PLAYER_ONE;
        return LandedHit.PLAYER_TWO;
    }

    // both attack
    if (one.isAttack()) return LandedHit.BOTH;

    // both block
    return LandedHit.NEITHER;
}

如果你想添加更多高度的块/攻击,你甚至不需要改变功能本身;但是,添加其他类型的移动可能需要修改该功能。此外,EnumSets可能比使用额外枚举作为主枚举的属性更具可扩展性,例如EnumSet<Move> attacks = EnumSet.of(Move.ATTACK_HIGH, Move.ATTACK_LOW, ...);然后attacks.contains(move)而不是move.type == MoveType.ATTACK,但使用EnumSet s可能会比直接等于检查稍慢。


对于成功阻止导致计数器的情况,您可以将if (one.height == two.height) return LandedHit.NEITHER;替换为

if (one.height == two.height) {
    // Successful block results in a counter against the attacker
    if (one.isAttack()) return LandedHit.PLAYER_TWO;
    return LandedHit.PLAYER_ONE;
}

此外,使用三元运算符(if)替换某些boolean_expression ? result_if_true : result_if_false语句可以使代码更紧凑(例如,前一个块中的代码将变为{{1}但是,这可能会导致难以阅读的oneliners,因此我不建议将其用于更复杂的分支。

答案 5 :(得分:50)

为什么不使用数组?

我将从头开始。我看到一个模式,值从0到3,你想要捕获所有可能的值。这是你的表:

0 & 0 = 0
0 & 1 = 0
0 & 2 = 1
0 & 3 = 2
1 & 0 = 0
1 & 1 = 0
1 & 2 = 2
1 & 3 = 1
2 & 0 = 2
2 & 1 = 1
2 & 2 = 3
2 & 3 = 3
3 & 0 = 2
3 & 1 = 1
3 & 2 = 3
3 & 3 = 3

当我们查看同一个表二进制文件时,我们会看到以下结果:

00 & 00 = 00
00 & 01 = 00
00 & 10 = 01
00 & 11 = 10
01 & 00 = 00
01 & 01 = 00
01 & 10 = 10
01 & 11 = 01
10 & 00 = 10
10 & 01 = 01
10 & 10 = 11
10 & 11 = 11
11 & 00 = 10
11 & 01 = 01
11 & 10 = 11
11 & 11 = 11

现在也许你已经看到了一些模式,但是当我合并第一和第二的价值时,我看到你正在使用所有值0000,0001,0010,...... 1110和1111.现在让我们将值1和2结合起来制作一个4位整数。

0000 = 00
0001 = 00
0010 = 01
0011 = 10
0100 = 00
0101 = 00
0110 = 10
0111 = 01
1000 = 10
1001 = 01
1010 = 11
1011 = 11
1100 = 10
1101 = 01
1110 = 11
1111 = 11

当我们将其转换回十进制值时,我们会看到一个非常可能的值数组,其中一个和两个组合可以用作索引:

0 = 0
1 = 0
2 = 1
3 = 2
4 = 0
5 = 0
6 = 2
7 = 1
8 = 2
9 = 1
10 = 3
11 = 3
12 = 2
13 = 1
14 = 3
15 = 3

然后数组为{0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3},其中索引只是一个和两个组合。

我不是Java程序员,但是您可以删除所有if语句,并将其写下来,如下所示:

int[] myIntArray = {0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3};
result = myIntArray[one * 4 + two]; 

我不知道2比特的移位是否比乘法更快。但值得一试。

答案 6 :(得分:24)

这使用了一点点bitmagic(你已经通过在一个整数中保存两位信息(低/高和攻击/阻止)来做到这一点):

我还没有运行它,只在这里打字,请仔细检查。这个想法肯定有效。 编辑:现在测试每个输入,工作正常。

public int fightMath(int one, int two) {
    if(one<2 && two<2){ //both players blocking
        return 0; // nobody hits
    }else if(one>1 && two>1){ //both players attacking
        return 3; // both hit
    }else{ // some of them attack, other one blocks
        int different_height = (one ^ two) & 1; // is 0 if they are both going for the same height - i.e. blocker wins, and 1 if height is different, thus attacker wins
        int attacker = one>1?1:0; // is 1 if one is the attacker, two is the blocker, and 0 if one is the blocker, two is the attacker
        return (attacker ^ different_height) + 1;
    }
}

或者我应该建议将两位信息分成单独的变量? 主要基于上述位操作的代码通常很难维护。

答案 7 :(得分:20)

说实话,每个人都有自己的代码风格。我不会认为性能会受到太大影响。如果你比使用switch case版本更好地理解这一点,那么继续使用它。

你可以嵌套ifs,因此你的上一次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; }
}

只需按照您的喜好重新格式化。

这并不能使代码看起来更好,但我相信可能会加速它。

答案 8 :(得分:12)

让我们看看我们所知道的

1:对于P1(玩家1)和P2(玩家2),你的答案是对称的。这对于格斗游戏来说是有意义的,但也可以利用它来改善你的逻辑。

2:3节拍0节拍2节拍1节拍3.这些案例未涵盖的唯一案例是0 vs 1和2 vs 3的组合。换句话说,唯一的胜利表如下:0 beats 2 ,1节拍3节拍,节拍1,3节拍0.

3:如果0/1互相攻击,那么就会有一次无可匹敌的抽签,但如果2/3上升,那么两者都会击中

首先,让我们建立一个单向函数告诉我们是否赢了:

// returns whether we beat our opponent
public boolean doesBeat(int attacker, int defender) {
  int[] beats = {2, 3, 1, 0};
  return defender == beats[attacker];
}

然后我们可以使用此函数来组成最终结果:

// returns the overall fight result
// bit 0 = one hits
// bit 1 = two hits
public int fightMath(int one, int two)
{
  // Check to see whether either has an outright winning combo
  if (doesBeat(one, two))
    return 1;

  if (doesBeat(two, one))
    return 2;

  // If both have 0/1 then its hitless draw but if both have 2/3 then they both hit.
  // We can check this by seeing whether the second bit is set and we need only check
  // one's value as combinations where they don't both have 0/1 or 2/3 have already
  // been dealt with 
  return (one & 2) ? 3 : 0;
}

虽然这可能更复杂,并且可能比许多答案中提供的表查找更慢,但我认为它是一种更好的方法,因为它实际上封装了代码的逻辑并将其描述给任何阅读代码的人。我认为这使它成为更好的实现方式。

(自从我做了任何Java以来​​已经有一段时间了,如果语法已经关闭,请道歉,希望如果我有点错误它仍然可以理解)

顺便说一句,0-3显然意味着什么;它们并不是任意值,因此有助于命名它们。

答案 9 :(得分:11)

我希望我能正确理解逻辑。怎么样:

public int fightMath (int one, int two)
{
    int oneHit = ((one == 3 && two != 1) || (one == 2 && two != 0)) ? 1 : 0;
    int twoHit = ((two == 3 && one != 1) || (two == 2 && one != 0)) ? 2 : 0;

    return oneHit+twoHit;
}

检查一个击中高点或一个击中低点不会被阻止,对于玩家二点也是如此。

编辑:算法未完全理解,&#34;命中&#34;阻止时我没有意识到(Thx elias):

public int fightMath (int one, int two)
{
    int oneAttack = ((one == 3 && two != 1) || (one == 2 && two != 0)) ? 1 : (one >= 2) ? 2 : 0;
    int twoAttack = ((two == 3 && one != 1) || (two == 2 && one != 0)) ? 2 : (two >= 2) ? 1 : 0;

    return oneAttack | twoAttack;
}

答案 10 :(得分:10)

我没有Java经验,所以可能会有一些错别字。请将代码视为伪代码。

我选择一个简单的开关。为此,您需要进行单一数字评估。但是,对于这种情况,由于0 <= one < 4 <= 90 <= two < 4 <= 9,我们可以通过将one乘以10并添加two来将两个整数转换为简单的整数。然后在结果数字中使用开关,如下所示:

public int fightMath(int one, int two) {
    // Convert one and two to a single variable in base 10
    int evaluate = one * 10 + two;

    switch(evaluate) {
        // I'd consider a comment in each line here and in the original code
        // for clarity
        case 0: result = 0; break;
        case 1: result = 0; break;
        case 1: result = 0; break;
        case 2: result = 1; break;
        case 3: result = 2; break;
        case 10: result = 0; break;
        case 11: result = 0; break;
        case 12: result = 2; break;
        case 13: result = 1; break;
        case 20: result = 2; break;
        case 21: result = 1; break;
        case 22: result = 3; break;
        case 23: result = 3; break;
        case 30: result = 1; break;
        case 31: result = 2; break;
        case 32: result = 3; break;
        case 33: result = 3; break;
    }

    return result;
}

还有一个简短的方法,我只想指出它是一个理论代码。但是我不会使用它,因为它有一些你通常不想处理的额外复杂性。额外的复杂性来自 base 4 ,因为计数是0,1,2,3,10,11,12,13,20 ......

public int fightMath(int one, int two) {
    // Convert one and two to a single variable in base 4
    int evaluate = one * 4 + two;

    allresults = new int[] { 0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 1, 2, 3, 3 };

    return allresults[evaluate];
}

真的只是附加说明,以防我遗漏了Java中的内容。在PHP中我会这样做:

function fightMath($one, $two) {
    // Convert one and two to a single variable in base 4
    $evaluate = $one * 10 + $two;

    $allresults = array(
         0 => 0,  1 => 0,  2 => 1,  3 => 2,
        10 => 0, 11 => 0, 12 => 2, 13 => 1,
        20 => 2, 21 => 1, 22 => 3, 23 => 3,
        30 => 1, 31 => 2, 32 => 3, 33 => 3 );

    return $allresults[$evaluate];
}

答案 11 :(得分:7)

由于您更喜欢嵌套的if条件,这是另一种方式 请注意,它不使用result成员,也不会更改任何状态。

public int fightMath(int one, int two) {
    if (one == 0) {
      if (two == 0) { return 0; }
      if (two == 1) { return 0; }
      if (two == 2) { return 1; }
      if (two == 3) { return 2; }
    }   
    if (one == 1) {
      if (two == 0) { return 0; }
      if (two == 1) { return 0; }
      if (two == 2) { return 2; }
      if (two == 3) { return 1; }
    }
    if (one == 2) {
      if (two == 0) { return 2; }
      if (two == 1) { return 1; }
      if (two == 2) { return 3; }
      if (two == 3) { return 3; }
    }
    if (one == 3) {
      if (two == 0) { return 1; }
      if (two == 1) { return 2; }
      if (two == 2) { return 3; }
      if (two == 3) { return 3; }
    }
    return DEFAULT_RESULT;
}

答案 12 :(得分:6)

尝试使用切换外壳。 ..

查看herehere了解更多信息

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

你可以添加多个条件(不是同时),甚至都有默认选项,其中没有其他案例得到满足。

PS:仅在满足一个条件时才允许..

如果同时出现2个条件......我不认为可以使用开关。 但是你可以在这里减少你的代码。

Java switch statement multiple cases

答案 13 :(得分:6)

((two&2)*(1+((one^two)&1))+(one&2)*(2-((one^two)&1)))/2

答案 14 :(得分:6)

我遇到的第一件事与Francisco Presencia给出的答案基本相同,但有所优化:

public int fightMath(int one, int two)
{
    switch (one*10 + two)
    {
    case  0:
    case  1:
    case 10:
    case 11:
        return 0;
    case  2:
    case 13:
    case 21:
    case 30:
        return 1;
    case  3:
    case 12:
    case 20:
    case 31:
        return 2;
    case 22:
    case 23:
    case 32:
    case 33:
        return 3;
    }
}

您可以通过将最后一个案例(对于3)作为默认案例来进一步优化它:

    //case 22:
    //case 23:
    //case 32:
    //case 33:
    default:
        return 3;

这种方法的优点是,更容易看到onetwo的哪些值对应于哪些返回值,而不是其他一些建议的方法。

答案 15 :(得分:4)

您可以使用switch case代替多个if

另外要提到的是,因为你有两个变量,所以你必须合并这两个变量才能在开关

中使用它们

选中此Java switch statement to handle two variables?

答案 16 :(得分:3)

当我在一个/两个和结果之间绘制一个表时,我看到一个模式,

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

如果陈述,上述内容将减少至少3个。我没有看到一个固定的模式,也没有从给出的代码中收集到太多东西 - 但如果可以推导出这样的逻辑,那么它会减少一些if语句。

希望这有帮助。

答案 17 :(得分:3)

一个好处是将规则定义为文本,然后您可以更容易地得出正确的公式。这是从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点击的一些解释会很棒,看起来很有趣!

答案 18 :(得分:3)

最短且仍然可读的解决方案:

static public int fightMath(int one, int two)
{
    if (one < 2 && two < 2) return 0;
    if (one > 1 && two > 1) return 3;
    int n = (one + two) % 2;
    return one < two ? 1 + n : 2 - n;
}

甚至更短:

static public int fightMath(int one, int two)
{
    if (one / 2 == two / 2) return (one / 2) * 3;
    return 1 + (one + two + one / 2) % 2;
}

不包含任何“魔法”数字;) 希望它有所帮助。

答案 19 :(得分:2)

static int val(int i, int u){ int q = (i & 1) ^ (u & 1); return ((i >> 1) << (1 ^ q))|((u >> 1) << q); }

答案 20 :(得分:1)

感谢@Joe Harper,因为我最终使用了他的答案的变体。为了进一步减少它,每4个结果相同,我进一步减少了它。

我可能会在某个时候回到这一点,但如果没有多个if语句引起的主要阻力,那么我现在就保留这个。我将进一步研究表格矩阵和切换语句解决方案。

public int fightMath(int one, int two) {
  if (one === 0) {
    if (two === 2) { return 1; }
    else if(two === 3) { return 2; }
    else { return 0; }
  } else if (one === 1) {
    if (two === 2) { return 2; }
    else if (two === 3) { return 1; }
    else { return 0; }
  } else if (one === 2) {
    if (two === 0) { return 2; }
    else if (two === 1) { return 1; }
    else { return 3; }
  } else if (one === 3) {
    if (two === 0) { return 1; }
    else if (two === 1) { return 2; }
    else { return 3; }
  }
}

答案 21 :(得分:1)

我个人喜欢级联三元运营商:

int result = condition1
    ? result1
    : condition2
    ? result2
    : condition3
    ? result3
    : resultElse;

但在您的情况下,您可以使用:

final int[] result = new int[/*16*/] {
    0, 0, 1, 2,
    0, 0, 2, 1,
    2, 1, 3, 3,
    1, 2, 3, 3
};

public int fightMath(int one, int two) {
    return result[one*4 + two];
}

或者,您可以注意到位模式:

one   two   result

section 1: higher bits are equals =>
both result bits are equals to that higher bits

00    00    00
00    01    00
01    00    00
01    01    00
10    10    11
10    11    11
11    10    11
11    11    11

section 2: higher bits are different =>
lower result bit is inverse of lower bit of 'two'
higher result bit is lower bit of 'two'

00    10    01
00    11    10
01    10    10
01    11    01
10    00    10
10    01    01
11    00    01
11    01    10

所以你可以使用魔法:

int fightMath(int one, int two) {
    int b1 = one & 2, b2 = two & 2;
    if (b1 == b2)
        return b1 | (b1 >> 1);

    b1 = two & 1;

    return (b1 << 1) | (~b1);
}

答案 22 :(得分:1)

这是一个相当简洁的版本,类似于JAB's response。这利用了一个地图来存储哪个移动胜过其他人。

public enum Result {
  P1Win, P2Win, BothWin, NeitherWin;
}

public enum Move {
  BLOCK_HIGH, BLOCK_LOW, ATTACK_HIGH, ATTACK_LOW;

  static final Map<Move, List<Move>> beats = new EnumMap<Move, List<Move>>(
      Move.class);

  static {
    beats.put(BLOCK_HIGH, new ArrayList<Move>());
    beats.put(BLOCK_LOW, new ArrayList<Move>());
    beats.put(ATTACK_HIGH, Arrays.asList(ATTACK_LOW, BLOCK_LOW));
    beats.put(ATTACK_LOW, Arrays.asList(ATTACK_HIGH, BLOCK_HIGH));
  }

  public static Result compare(Move p1Move, Move p2Move) {
    boolean p1Wins = beats.get(p1Move).contains(p2Move);
    boolean p2Wins = beats.get(p2Move).contains(p1Move);

    if (p1Wins) {
      return (p2Wins) ? Result.BothWin : Result.P1Win;
    }
    if (p2Wins) {
      return (p1Wins) ? Result.BothWin : Result.P2Win;
    }

    return Result.NeitherWin;
  }
} 

示例:

System.out.println(Move.compare(Move.ATTACK_HIGH, Move.BLOCK_LOW));

打印:

P1Win

答案 23 :(得分:1)

我使用Map,HashMap或TreeMap

特别是如果参数不在表格0 <= X < N

像一组随机正整数..

<强>代码

public class MyMap
{
    private TreeMap<String,Integer> map;

    public MyMap ()
    {
        map = new TreeMap<String,Integer> ();
    }

    public void put (int key1, int key2, Integer value)
    {
        String key = (key1+":"+key2);

        map.put(key, new Integer(value));
    }

    public Integer get (int key1, int key2)
    {
        String key = (key1+":"+key2);

        return map.get(key);
    }
}

答案 24 :(得分:0)

  1. 使用常量或枚举使代码更具可读性
  2. 尝试将代码拆分为更多功能
  3. 尝试使用问题的对称性
  4. 这是一个如何看起来像这样的建议,但在这里使用int仍然有点难看:

    static final int BLOCK_HIGH = 0;
    static final int BLOCK_LOW = 1;
    static final int ATTACK_HIGH = 2;
    static final int ATTACK_LOW = 3;
    
    public static int fightMath(int one, int two) {
        boolean player1Wins = handleAttack(one, two);
        boolean player2Wins = handleAttack(two, one);
        return encodeResult(player1Wins, player2Wins); 
    }
    
    
    
    private static boolean handleAttack(int one, int two) {
         return one == ATTACK_HIGH && two != BLOCK_HIGH
            || one == ATTACK_LOW && two != BLOCK_LOW
            || one == BLOCK_HIGH && two == ATTACK_HIGH
            || one == BLOCK_LOW && two == ATTACK_LOW;
    
    }
    
    private static int encodeResult(boolean player1Wins, boolean player2Wins) {
        return (player1Wins ? 1 : 0) + (player2Wins ? 2 : 0);
    }
    

    对输入和输出使用结构化类型会更好。输入实际上有两个字段:位置和类型(块或攻击)。输出还有两个字段:player1Wins和player2Wins。将其编码为单个整数会使代码更难阅读。

    class PlayerMove {
        PlayerMovePosition pos;
        PlayerMoveType type;
    }
    
    enum PlayerMovePosition {
        HIGH,LOW
    }
    
    enum PlayerMoveType {
        BLOCK,ATTACK
    }
    
    class AttackResult {
        boolean player1Wins;
        boolean player2Wins;
    
        public AttackResult(boolean player1Wins, boolean player2Wins) {
            this.player1Wins = player1Wins;
            this.player2Wins = player2Wins;
        }
    }
    
    AttackResult fightMath(PlayerMove a, PlayerMove b) {
        return new AttackResult(isWinningMove(a, b), isWinningMove(b, a));
    }
    
    boolean isWinningMove(PlayerMove a, PlayerMove b) {
        return a.type == PlayerMoveType.ATTACK && !successfulBlock(b, a)
                || successfulBlock(a, b);
    }
    
    boolean successfulBlock(PlayerMove a, PlayerMove b) {
        return a.type == PlayerMoveType.BLOCK 
                && b.type == PlayerMoveType.ATTACK 
                && a.pos == b.pos;
    }
    

    不幸的是,Java并不擅长表达这些类型的数据类型。

答案 25 :(得分:-2)

而是做这样的事情

   public int fightMath(int one, int two) {
    return Calculate(one,two)

    }


    private int Calculate(int one,int two){

    if (one==0){
        if(two==0){
     //return value}
    }else if (one==1){
   // return value as per condtiion
    }

    }
相关问题